30 września 2008

Repozytoria pakunków OSGi

1 komentarzy
Istnieje kilka repozytoriów pełnoprawnych pakunków OSGi (z odpowiednimi nagłówkami w manifeście) dla popularnych projektów otwartych:
Naturalnym jest, że skoro pakunki OSGi są zwykłymi plikami jar z odpowiednimi nagłówkami w manifeście (cf. Kolejny łyk OSGi - rozdział 3. Warstwa modułowa) dowolne repozytoria mavenowe (np. http://repo1.maven.org/maven2/) lub dowolne inne udostępniające jary, mogą być używane przy zestawianiu środowiska z wymaganymi zależnościami. Problemem jest określenie zależności między pakunkami poprzez nagłówki Import-Package, Export-Package, Ignore-Package, Private-Package, DynamicImport-Package i in. dla zwykłych plików jar, co nie jest obsługiwane przez Platformę OSGi bez dodatkowej pracy przy ich konfiguracji jako pakunki. Właśnie to jest zaletą pobrania plików jar z w/w repozytoriów - posiadanie gwarancji, że są one poprawnymi pakunkami. Założeniem repozytoriów jest udostępnianie poprawnie skonfigurowanych pakunków ze wszystkimi wymaganymi nagłówkami. Jako, że są to oddzielne repozytoria, zarządzane przez różne osoby, czasami prowadzi to do sytuacji, gdzie pakunek X w repozytorium R1 ma inne wymagania niż pakunek X w repozytorium R2 (niestety w tej chwili nie mogę znaleźć informacji o zgłoszonej rozbieżności między Orbit a BRITS). Światło na ich przydatność może rzucić wątek - BRITS vs. Temporary Spring-DM Repo, gdzie mimo prowadzenia dwóch repozytoriów przez pojedyńczą firmę SpringSource, nawet one mają niepoprawnie zdefiniowane pakunki.

Rozwiązaniem rozmieszczenia pakunków w repozytorium jest specyfikacja OSGi RFC 112 Bundle Repository. Innym sposobem zaradzenia problemom z nieścisłymi deklaracjami pakunków jest projekt Pax URL, który pozwala na instalację dowolnego pliku jar dostępnego poprzez inne protokoły dostępu niż domyślne http czy file, np. classpath, mvn, wrap lub narzędzie bnd. Bez względu jakiego narzędzia zastosujemy, część pracy i tak będziemy musieli wykonać samodzielnie, np. przy wykorzystaniu mechanizmu prześwietlania w Javie (Reflection API), gdzie nazwa klasy podawana jest niejawnie. W takiej sytuacji skorzystanie z gotowego pakunku dla popularnego projektu otwartego z w/w repozytoriów może być najmniej czasochłonnym rozwiązaniem (jeśli istnieje).

Zabawa dla wytrwałych i dociekliwych: Co oznacza skrót BRITS będący alternatywną nazwą dla repozytorium SpringSource Enterprise Bundle Repository? (odpowiedzi można szukać w SpringSource Application Platform ships).

29 września 2008

Eclipse IDE 3.5M2 a Eclipse Equinox i OSGi R4.2

2 komentarzy
Dzisiaj, podczas pobierania pełnej wersji Equinoksa (wraz ze wszystkimi dostępnymi pakunkami) - eclipse-equinox-3.5M1.zip pojawił się poniższy komunikat:

The Equinox downloads are meant as a base for building OSGi applications. As such, they do not include an application of their own and simply running the framework will do nothing.

Teraz już wiem, co autorzy mieli na myśli. Po prostu pobieram samo środowisko uruchomieniowe dla pakunków OSGi (w świecie Eclipse będą to wtyczki), bez których nie ma co oczekiwać funkcjonalności oferowanej przez Eclipse IDE. Podobnie jak z serwerem aplikacyjnym Java EE 5, bez aplikacji korporacyjnych, nie ma czego więcej oczekiwać od niego, poza udostępnieniem usług, na bazie których można je konstruować. Dodatkowo, komunikat może być o tyle ważny, gdyż po pobraniu paczki Eclipse Equinox 3.5M1 i rozpakowaniu, pojawi się katalog eclipse z podkatalogami features oraz plugins, co idealnie odpowiada strukturze bogatego funkcjonalnie Eclipse IDE (w końcu to nic innego jak zestaw wtyczek w katalogu plugins uruchamianych na Equinoksie).

Uważni obserwatorzy projektu Eclipse IDE zauważyli zapewne pojawienie się wersji Eclipse IDE 3.5M2, w której pojawiły się zmiany w obszarze Equinoksa (opisane w dokumencie Eclipse 3.5 M2 - New and Noteworthy dla Equinox):

Security Manager enhancements
This milestone includes an implementation of RFC 120 from the OSGi R4.2 draft specification. RFC 120 specifies enhancements to the Conditional Permission Admin service which is used to manage the permissions assigned to bundles. The enhancements include adding the ability to grant or deny permissions based on conditions, and to manage conditions as an ordered list of rules. For more information see the OSGi R4.2 draft spec.


oraz

New publisher bundle
p2 has introduced a new bundle called the publisher, which provides infrastructure for generating, packaging, and publishing metadata and artifacts into p2 repositories. The publisher provides an extensible API that clients can extend to perform customized publishing to repositories, and includes an advice mechanism for injecting additional metadata into the generation and packaging process.


Nie powinno dziwić, że Equinox przewodzi peletonowi platform OSGi zabierając się za realizację specyfikacji OSGi R4.2, która jakkolwiek w fazie szkicu, potrzebuje środowiska referencyjnego, aby pomóc w akceptacji proponowanych funkcjonalności przez programistów. Dla Java EE 5 referencyjną implementacją jest GlassFish, a dla OSGi jest nią Eclipse Equinox. Zastanawiam się jednak, czy powinienem prowadzić doświadczenia z Equinoksem dystrybuowanym w ramach Eclipse IDE (org.eclipse.osgi_3.5.0.v20080916-2300.jar), czy pobierać bezpośrednio ze strony domowej Eclipse Equinox (org.eclipse.osgi_3.5.0.v20080804-1730.jar). Aktualność samodzielnego Equinoksa nie pozostawia złudzeń - ten dystrybuowany z Eclipse jest aktualniejszy oraz gwarantuje się jego działanie przez włączenie do Eclipse IDE, więc od razu przechodzę na niego. Kilka dni temu próbowałem pobrać wersję Eclipse Equinox 3.5M2 i niestety, ale kończyło się na "404 File Not Found". Może jutro?

p.s. Od momentu zainteresowania OSGi doszła mi kolejna sekcja, którą monitoruję pod kątem zmian w Eclipse - sekcja "Equinox" w "New and Noteworthy". A u Ciebie? ;-)

28 września 2008

Katalog plugins i automatyczna instalacja pakunków OSGi na Equinoksie

2 komentarzy
Już kiedyś wspominałem o tym dokumentcie - Equinox QuickStart Guide - ale nigdy jakoś nie usiadłem nad nim i dokładnie przeanalizowałem jego treści. Tym razem jednak, po kilku dniach zestawiania potrzebnych pakunków do uruchomienia Spring-DM 1.2.0-m2-SNAPSHOT na Eclipse Equinox i przekroczeniu 10 pakunków koniecznych do jego uruchomienia, stwierdziłem, że wystarczy tych ręcznych robótek i pora skrócić moje cierpienia - pójść po rozum do głowy i skorzystać z ułatwień, które są na wyciągnięcie ręki - automatyczne uruchamianie pakunków przy starcie Equinoksa. Przy okazji, poznając działanie Equinoksa poznajemy działanie całego Eclipse, który mechanizm wtyczek oparł całkowicie o OSGi z Equinox w roli środowiska uruchomieniowego.

Podczas uruchamiania Equinoksa poleceniem
 java -jar org.eclipse.osgi_3.5.0.v20080804-1730.jar -console
uruchomiony zostaje automatycznie pakunek systemowy - org.eclipse.osgi. Ma on identyfikator 0 i będzie tak na każdej platformie OSGi (oczywiście nazwa pakunku systemowego będzie inna, specyficzna dla danej platformy).
 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
Przy pierwszym uruchomieniu tworzony jest katalog configuration w katalogu bieżącym (z możliwością wskazania innego parametrem -configuration).
 jlaskowski@work /cygdrive/c/apps/equinox
$ ls -lt
total 988
drwxr-xr-x+ 3 jlaskowski None 0 Sep 28 21:27 configuration
-rwx------+ 1 jlaskowski None 1009283 Sep 22 16:07 org.eclipse.osgi_3.5.0.v20080804-1730.jar
Instalacja pakunków odbywa się poleceniem install <plik_pakunku>. Jeśli założę katalog plugins (na razie przyjmijmy, że jest to nazwa całkowicie przypadkowa), a w nim umieszczę pakunek spring-osgi-core-1.2.0-m2-SNAPSHOT.jar, jego instalacja będzie wyglądała następująco:
 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

osgi> install file:plugins/spring-osgi-core-1.2.0-m2-SNAPSHOT.jar
Bundle id is 1

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.0.v20080804-1730
1 INSTALLED org.springframework.bundle.osgi.core_1.2.0.m2-SNAPSHOT
Kolejne uruchomienie platformy OSGi gwarantuje uruchomienie pakunków do stanu, który był bieżącym przed zatrzymaniem całej Platformy, np. poleceniem close dla Equinoksa. Właśnie katalog configuration jest katalogiem, gdzie utrwalone zostają informacje o stanie pakunku (i skasowanie go powoduje skasowanie danych pakunków, co równoważne jest z uruchomieniem początkowym Equinoksa).
 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
1 INSTALLED org.springframework.bundle.osgi.core_1.2.0.m2-SNAPSHOT
Przy pojedyńczym pakunku sprawa jego instalacji i uruchomienia nie jest poważnym zadaniem. Sprawa zaczyna się komplikować, kiedy przychodzi nam uruchomić, powiedzmy, 20 pakunków. Wtedy pozostaje nam liczyć na poprawny katalog configuration, albo...config.ini.

Plik config.ini w katalogu configuration jest plikiem konfiguracyjnym Equinoksa, w którym definiuje się, jakie pakunki mają zostać uruchomione i gdzie one w ogóle się znajdują. Dodając do tego wsparcie pakunku org.eclipse.update.configurator nie musimy umieszczać nazw wszystkich pakunków do instalacji w pliku config.ini, a wystarczy umieścić je w katalogu plugins.

Zatem plik config.ini prezentuje się następująco:
 eclipse.ignoreApp=true
osgi.bundles=org.eclipse.equinox.common@2:start, org.eclipse.update.configurator@3:start
a sama struktura katalogowa tak:
 |____configuration
| |____config.ini
|____org.eclipse.equinox.common_3.4.0.v20080421-2006.jar
|____org.eclipse.osgi_3.5.0.v20080804-1730.jar
|____org.eclipse.update.configurator_3.2.200.v20080417.jar
|____plugins
| |____spring-osgi-core-1.2.0-m2-SNAPSHOT.jar
Pakunek org.eclipse.equinox.common pobrałem ze strony Equinox Stable Build: 3.5M1, natomiast org.eclipse.update.configurator znalazłem w katalogu Eclipse Ganymede w plugins (nigdzie indziej nie mogłem go namierzyć).

Przy powyższej konfiguracji każdy z pakunków umieszczonych w katalogu plugins będzie zainstalowany automatycznie podczas uruchomienia Equinoksa.
 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
1 ACTIVE org.eclipse.equinox.common_3.4.0.v20080421-2006
2 ACTIVE org.eclipse.update.configurator_3.2.200.v20080417
3 INSTALLED org.springframework.bundle.osgi.core_1.2.0.m2-SNAPSHOT
Z pewnością znacząco uprości zabawę z uruchomieniem wszystkich pakunków Spring-DM niezbędnych do uruchomienia aplikacji webowych na Apache Tomcat 6.0.18 w ramach Equinoksa. Do tej pory wymagało to ręcznego uruchamiania około 20 pakunków przy każdorazowym usunięciu katalogu configuration (!)

26 września 2008

WAS 7.0 już jest oraz JDD 2008 i NetBeans Day 2008 nadchodzą

3 komentarzy
Nie mogłem doczekać się, aż to opublikuję i w końcu jest! Wielki dzień dla społeczności Korporacyjnej 5-tki (Java EE 5), gdyż IBM wypuścił na runek długooczekiwany produkt IBM WebSphere Application Server V7.0 (IBM WebSphere Application Server V7.0 delivers an agile, solid foundation for SOA to align the advancements of business and IT). Nie planuję rozpisywać się nad jego możliwościami, bo są one znane i (nie)lubiane ;-) Ważne, że czekamy jedynie na JBoss AS 5, który ma zamknąć okres rozwoju serwerów aplikacyjnych w ich krucjacie do pełnego wsparcia specyfikacji Java EE 5. Szczęśliwcy, którzy mogą już pracować z Korporacyjną 5-tką, a wszystkim pozostałym zaleca się natychmiastową migrację na nową platformę. Zdaje się, że kolejnym obowiązkowym elementem serwerów aplikacyjnych Java EE 5 będzie OSGi. Niewiele serwerów udostępnia możliwość uruchamiania aplikacji korporacyjnych budowanych na bazie pakunków, ale wiele korzysta z nich wewnętrznie. Sądzę, że wsparcie dla OSGi będzie kolejnym dużym krokiem w rozwoju serwerów aplikacyjnych, czym znacznie powinny uprościć tworzenie złożonych aplikacji korporacyjnych. W niezwykle ciekawych czasach żyjemy (i wciąż żyjemy, mimo codziennych ochów, echów, i innych sercowych atrakcji, nie wspominając o wszechobecnym stresie ;-))!

Korzystając z chwili rozgłoszę również dwie nadchodzące imprezy, których mam przyjemność być aktywnym uczestnikiem - JDD 2008 w Krakowie oraz NetBeans Day 2008 w Poznaniu i Gdańsku. Pierwsza już za niecałe 3 tygodnie - 16 października, a druga tydzień później - 25 października w Poznaniu, po czym kolejnego dnia - 26 października - przenosi się do Gdańska. Już nie mogę doczekać się podzielenia się z Wami nowinkami z obszaru OSGi i Spring Dynamic Modules (Spring-DM) w Krakowie, a przeglądem nowości NetBeans 6.5 w Poznaniu i Gdańsku. Już od miesięcy przygotowuję się do występów, więc merytorycznie jestem przygotowany conajmniej na 3+ ;-) Dodatkowe pytania i sugestie, o czym chcielibyście posłuchać w kontekście Spring-DM, a później NetBeans IDE 6.5 mile widziane. Nikt nie życzy sobie spędzenia godziny na moim przedłużającym się wystąpieniu, więc stwórzmy miejsce wymiany doświadczeń, gdzie zostanie zaprezentowanego wiele technicznego materiału i pojawią się ciekawe pytania. Liczę na Was, nie mniej niż Wy na mnie!

Za kilka dni - 7 października o godz. 19:00 - w Warszawie odbędzie się pierwsze spotkanie blogerów piszących o IT dla pasjonatów IT - Bloggers Underground. Spotkanie organizowane przez grupę microsoftową, aczkolwiek obiecano, że będzie wyłącznie merytorycznie (czyli nie pojawią się wstawki jaka to Vista jest cacy i takie tam). Zaproszony, od razu zapisałem się z nadzieją podpatrzenia, jak inni sobie radzą w temacie dzielenia się wiedzą poprzez blogi (nawet, jeśli zajmują się niszowymi rozwiązaniami spod znaku MS ;-)). Zawsze wierzę, że poznawanie nowych osób, to miejsce na nowe pomysły i tym razem jestem przekonany, że nie będzie inaczej. Zapraszam w imieniu organizatorów.

Jeśli Ty wciąż zastanawiasz się, czy blog mógłby być dla Ciebie źródłem inspiracji i pomysłów zapraszam do lektury Najlepsze nasiona (gdzie nie będzie ziaren EJB, a jedynie nasiona, ale i tak warto). Autorka już niejeden raz ciekawie przedstawiła otaczającą mnie rzeczywistość i chętnie czytam jej wpisy, a teraz mogę wskazać jeden jako argument do założenia własnego bloga. Jeśli go nie masz, to właśnie dzisiaj jest ten dzień, abyś miał. Jeśli nie blog, to przynajmniej udział w grupie jugowej w Twoim mieście, organizacja konferencji, albo chociażby nieformalne spotkanie w grupie entuzjastów javowych. Cokolwiek, ale odejdź w końcu od komputera i spotkaj się z kimś nowym! Niedługo Warsjava+Eclipse DemoCamp 2008 w Warszawie, więc będzie okazja się spotkać i przegadać to i owo. A może udział w spotkaniu Warszawa JUG na MIMUW 30-tego? Będzie Szimano, więc dobra zabawa murowana (a że się doktoryzuje, więc i naukowo trochę również będzie ;-)). Zapraszam!

24 września 2008

Equinox i jego diag do analizy wymagań pakunku OSGi

2 komentarzy
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.

23 września 2008

34. spotkanie Warszawskiej Grupy Użytkowników Technologii Java (Warszawa JUG)

0 komentarzy
Warszawska Grupa Użytkowników Technologii Java (Warszawa JUG) zaprasza na 34. spotkanie, które odbędzie się 30.09.2008 o godzinie 18:00 w sali 5440 Wydziału MIMUW przy ul. Banacha 2 w Warszawie.

Temat prezentacji: Podstawy języków formalnych, ANTLR i ANTLRWorks
Prowadzący: Tomek Szymański (vel szimano)

Pisząc różne programy często zdarza się, że mamy jakieś źródło, które wcale nie jest w XMLu ani nawet JSONie... są różne Scannery, Matchery, wyrażenia regularne, ale często to jest za mało i więcej czasu tracimy na "przeczytanie" tego źródła niż na jego "obrobienie". I tutaj wybawieniem jest ANTLR, którego staram się pokazać.

Ale niech nie zrazi was straszny tutuł - podstawy języków formalnych poznać trzeba, ale będzie jak naprzystępniej a potem to już zajmiemy się wyłącznie kodowaniem w naszej ulubionej Javie !

Co jeszcze ? ANTLRWorks - narzędzie z ładnym GUI i różnymi bajerami ułatwiające prace z ANTLRem, zrobienie tego, co mamy na myśli mówiąc "kompilator" - czyli czegoś co wygeneruje program z naszego języka, robienie parserów, obalanie paru mitów i tymczasowe oderwanie od, mogących się na chwile znudzić, technologii webowych, którymi karmimy się na codzień.

Tomek Szymański (vel szimano) - Kontraktor pewnej firmy, która właśnie wypuściła CR2 Application Servera zgodnego z EE 5.0. Zainteresowany narzędziami typu compiler-compiler od momentu, kiedy uczestniczył w odpowiednim przedmiocie na studiach... potem napisał pracę magisterską na ten temat, żeby przez pół roku prowadzić, już jako doktorant (którym nie jest), laboratorium z tych zajęć. Postanowił, że skoro jeszcze coś z tego pamięta, to się podzieli zanim zapomni. Poza tym jest miły, sympatyczny, kulturalny i lubi chodzić w kaszkiecie.

Planowany czas prezentacji to 1,5 godziny, po której planuje się 15-30-minutową dyskusję.

Wstęp wolny!

Zapraszam w imieniu grupy Warszawa JUG!

22 września 2008

Pakunki częściowe OSGi w akcji z Equinox

0 komentarzy
Już wiem, że pakunki częściowe (ang. fragment bundles) nie są wspierane przez Apache Felix (więcej o nich i braku wsparcia przez Feliksa w OSGi - 3.14 Pakunki częściowe), więc nie pozostaje mi nic innego jak korzystać z Eclipse Equinox do dalszych testów. Tak długo, jak wymagane będzie wsparcie pakunków częściowych Platformą OSGi nie będzie Apache Felix. To jest właśnie ów techniczny powód, dla którego, w kontekście Spring-DM, często pojawiał się będzie Equinox. Zainteresowanych zmianami w tej materii uprasza się o śledzenie rozwoju zgłoszenia FELIX-29 Implement bundle fragments.

Rozpocznę praktyczne rozpoznanie pakunków częściowych od stworzenia dwóch pakunków - pakunku macierzystego i pakunku częściowego - z pomocą spring-osgi-bundle-archetype.

UWAGA: Użyłem zadania archetype:generate z parametrem -Darchetype.interactive=false, gdyż wcześniejużywany archetype:create został oznaczony jako nieaktualny ([WARNING] This goal is deprecated. Please use mvn archetype:generate instead)

Najpierw pakunek macierzysty springdm-host-bundle:
 mvn archetype:generate \
-DarchetypeGroupId=org.springframework.osgi \
-DarchetypeArtifactId=spring-osgi-bundle-archetype \
-DarchetypeVersion=1.2.0-m2-SNAPSHOT \
-DgroupId=pl.jaceklaskowski.springdm.fragment \
-DartifactId=springdm-host-bundle \
-Dversion=1.0 \
-Darchetype.interactive=false
, po którym tworzę pakunek częściowy springdm-fragment-bundle:
 mvn archetype:generate \
-DarchetypeGroupId=org.springframework.osgi \
-DarchetypeArtifactId=spring-osgi-bundle-archetype \
-DarchetypeVersion=1.2.0-m2-SNAPSHOT \
-DgroupId=pl.jaceklaskowski.springdm.fragment \
-DartifactId=springdm-fragment-bundle \
-Dversion=1.0 \
-Darchetype.interactive=false
Możnaby utworzyć je w ramach większego projektu mavenowego (packaging=pom), ale pozostawiam to dla zaangażowanych.

Na początku zadeklaruję pakunek springdm-fragment-bundle jako pakunek częściowy dla springdm-host-bundle za pomocą nagłówka Fragment-Host. Jako, że projekt pakunku częściowego springdm-fragment-bundle zarządzany jest przez Apache Maven 2 nagłówek dodaję do konfiguracji wtyczki maven-bundle-plugin w pom.xml.
 <Fragment-Host>pl.jaceklaskowski.springdm.fragment.springdm-host-bundle</Fragment-Host>
Nazwę pakunku macierzystego można poznać przez utworzenie docelowego manifestu przez wykonanie polecenia mvn package i odczytanie nagłówka Bundle-SymbolicName w utworzonym META-INF/MANIFEST.MF.

Tworzę pakunki poleceniem mvn package i uruchamiam na Equinoksie (najświeższa wersja do pobrania ze strony equinox osgi downloads, np. Equinox Stable Build: 3.5M2, chociaż adres na stronie nie działa! Można skorzystać z jeszcze innego adresu equinox osgi downloads, gdzie można pobrać Equinox Stable Build: 3.5M1). Początkowo korzystałem z Equinoksa dostarczanego w ramach Eclipse Ganymede - plugins/org.eclipse.osgi_3.4.0.v20080605-1900.jar, ale przy finalnym uruchomieniu przeniosłem się na nowszą wersję - org.eclipse.osgi_3.5.0.v20080804-1730.jar, wyłącznie ze względów bycia na bieżąco.

Dla dociekliwych zaleca się lekturę niewielkiego podręcznika Equinoksa - Equinox QuickStart Guide.
 jlaskowski@work /cygdrive/c/apps/eclipse
$ java -jar plugins/org.eclipse.osgi_3.4.0.v20080605-1900.jar -console

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900

osgi> install file:/C:/projs/sandbox/springdm-fragment-bundle/target/springdm-fragment-bundle-1.0.jar
Bundle id is 1

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900
1 INSTALLED pl.jaceklaskowski.springdm.fragment.springdm-fragment-bundle_1.0.0

osgi> start 1
org.osgi.framework.BundleException: A fragment bundle cannot be started:
file:/C:/projs/sandbox/springdm-fragment-bundle/target/springdm-fragment-bundle-1.0.jar [1]
at org.eclipse.osgi.framework.internal.core.BundleFragment.startWorker(BundleFragment.java:224)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:265)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:257)
at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._start(FrameworkCommandProvider.java:257)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpreter.java:150)
at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:302)
at org.eclipse.osgi.framework.internal.core.FrameworkConsole.console(FrameworkConsole.java:287)
at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:223)
at java.lang.Thread.run(Thread.java:595)

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900
1 INSTALLED pl.jaceklaskowski.springdm.fragment.springdm-fragment-bundle_1.0.0

osgi> install file:/C:/projs/sandbox/springdm-host-bundle/target/springdm-host-bundle-1.0.jar
Bundle id is 2

osgi> start 2

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900
1 RESOLVED pl.jaceklaskowski.springdm.fragment.springdm-fragment-bundle_1.0.0
Master=2
2 ACTIVE pl.jaceklaskowski.springdm.fragment.springdm-host-bundle_1.0.0
Fragments=1

osgi> bundle 1
file:/C:/projs/sandbox/springdm-fragment-bundle/target/springdm-fragment-bundle-1.0.jar [1]
Id=1, Status=RESOLVED Data Root=C:\apps\eclipse\plugins\configuration\org.eclipse.osgi\bundles\1\data
No registered services.
No services in use.
Exported packages
pl.jaceklaskowski.springdm.fragment; version="0.0.0"[exported]
No imported packages
Host bundles
file:/C:/projs/sandbox/springdm-host-bundle/target/springdm-host-bundle-1.0.jar [2]
No named class spaces
No required bundles

osgi> bundle 2
file:/C:/projs/sandbox/springdm-host-bundle/target/springdm-host-bundle-1.0.jar [2]
Id=2, Status=ACTIVE Data Root=C:\apps\eclipse\plugins\configuration\org.eclipse.osgi\bundles\2\data
No registered services.
No services in use.
Exported packages
pl.jaceklaskowski.springdm.fragment; version="0.0.0"[exported]
No imported packages
Fragment bundles
file:/C:/projs/sandbox/springdm-fragment-bundle/target/springdm-fragment-bundle-1.0.jar [1]
Named class space
pl.jaceklaskowski.springdm.fragment.springdm-host-bundle; bundle-version="1.0.0"[provided]
No required bundles

osgi> close
Dodam do pakunku macierzystego funkcjonalność, która przy każdorazowym zainstalowaniu nowego pakunku będącym rozszerzeniem (pakunkiem częściowym) dla niego, wypisze dostępne pliki wchodzącego w skład przestrzeni pakunku. Dzięki metodzie org.osgi.framework.Bundle.findEntries(String,String,boolean) pakunek ma możliwość przejrzenia wszystkich zasobów zawartych w nim (bezpośrednio w jego pliku jar) oraz wszystkich rozszerzeniach (pakunkach częściowych). Nie należy mylić działania tej metody z metodą Bundle.getResource(String) czy Bundle.getResources(String), które działają na całej przestrzeni klas dostęnych dla pakunku (co może być rozbudowane w porównaniu z przestrzenią pakunku o deklaracje w nagłówku Import-Package).

Definiuję aktywator w pakunku macierzystym, który zarejestruje słuchacza reagującego na zdarzenia rozwiązania (stan RESOLVED) pakunków (podpieram się artykułem Bundle.findEntries() i spring-osgi-bundle-archetype w akcji - monitorowanie pakunków OSGi z określoną strukturą katalogową).
 package pl.jaceklaskowski.springdm.fragment.internal;

import java.util.Dictionary;
import java.util.Enumeration;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;

public class Aktywator implements BundleActivator {

private final class Sluchacz implements BundleListener {
private String nazwaPakunkuMacierzystego;

public Sluchacz(String nazwaPakunkuMacierzystego) {
this.nazwaPakunkuMacierzystego = nazwaPakunkuMacierzystego;
}

public void bundleChanged(BundleEvent event) {
Bundle bundle = event.getBundle();
String nazwaPakunku = bundle.getSymbolicName();
// Sprawdź, czy jest pakunkiem częściowym
Dictionary<?, ?> headers = bundle.getHeaders();
String pakunekMacierzysty = (String) headers.get("Fragment-Host");
if (!nazwaPakunkuMacierzystego.equalsIgnoreCase(pakunekMacierzysty)) {
return;
}
switch (event.getType()) {
case BundleEvent.RESOLVED:
System.out.println("Pakunek czesciowy " + nazwaPakunku + " w stanie RESOLVED");
wyswietlLiczbeDostepnychPlikow(bundle);
break;
case BundleEvent.STOPPED:
System.out.println("Pakunek czesciowy " + nazwaPakunku + " w stanie STOPPED");
wyswietlLiczbeDostepnychPlikow(bundle);
break;
}
}
}

private BundleListener sluchacz;

public void start(BundleContext context) throws Exception {
String nazwaPakunku = context.getBundle().getSymbolicName();
System.out.println("Pakunek macierzysty " + nazwaPakunku + " w stanie STARTING");
sluchacz = new Sluchacz(nazwaPakunku);
System.out.println("...instalacja " + sluchacz);
context.addBundleListener(sluchacz);
wyswietlLiczbeDostepnychPlikow(context.getBundle());
}

public void stop(BundleContext context) throws Exception {
String nazwaPakunku = context.getBundle().getSymbolicName();
System.out.println("Pakunek macierzysty " + nazwaPakunku + " w stanie STOPPING");
System.out.println("...usuniecie " + sluchacz);
context.removeBundleListener(sluchacz);
wyswietlLiczbeDostepnychPlikow(context.getBundle());
}

private void wyswietlLiczbeDostepnychPlikow(Bundle bundle) {
int liczbaPlikow = 0;
Enumeration<?> entries = bundle.findEntries("/", "*", true);
for (; entries.hasMoreElements(); entries.nextElement()) {
liczbaPlikow++;
}
System.out.println("+++ Liczba plikow: " + liczbaPlikow);
}

}
Pierwsze uruchomienie przykładu zakończyło się niepowodzeniem.
 jlaskowski@work /cygdrive/c/apps/eclipse
$ java -jar plugins/org.eclipse.osgi_3.4.0.v20080605-1900.jar -console

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900

osgi> install file:/C:/projs/sandbox/springdm-host-bundle/target/springdm-host-bundle-1.0.jar
Bundle id is 1

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900
1 INSTALLED pl.jaceklaskowski.springdm.fragment.springdm-host-bundle_1.0.0

osgi> start 1
org.osgi.framework.BundleException: The bundle could not be resolved. Reason:
Missing Constraint: Import-Package: pl.jaceklaskowski.springdm.fragment.internal; version="0.0.0"
at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:305)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:265)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:257)
at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._start(FrameworkCommandProvider.java:257)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpreter.java:150)
at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:302)
at org.eclipse.osgi.framework.internal.core.FrameworkConsole.console(FrameworkConsole.java:287)
at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:223)
at java.lang.Thread.run(Thread.java:595)

osgi> close
O dziwo nie doświadczałem tych problemów podczas pracy z Apache Felix (!) Najwyraźniej Equinox jest bardziej restrykcyjny i sprawdzając poprawność nagłówków, dla każdego Import-Package weryfikuje widoczność pakietów w przestrzeni klas. Jako, że domyślnie pakiet pl.jaceklaskowski.springdm.fragment.internal jest domyślnie wyłączany z Export-Package przez Spring-DM (a właściwie niewprost przez bnd wywoływane przez wtyczkę maven-bundle-plugin, która jest tak konfigurowana przez archetyp spring-osgi-bundle-archetype w pom.xml) pojawia się komunikat błędu o niespełnieniu wymagania nałożonego przez Import-Package. Analizując źródła projektu Spring-DM (dokładniej pomy w spring-osgi-extender oraz spring-osgi) kończę z następującą konfiguracją dla maven-bundle-plugin:
 <plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<version>1.4.0</version>
<configuration>
<manifestLocation>META-INF</manifestLocation>
<instructions>
<Export-Package>!pl.jaceklaskowski.springdm.fragment.*internal*</Export-Package>
<Private-Package>pl.jaceklaskowski.springdm.fragment.*internal*</Private-Package>
<Include-Resource>src/main/resources</Include-Resource>
<Bundle-Activator>pl.jaceklaskowski.springdm.fragment.internal.Aktywator</Bundle-Activator>
<Bundle-Version>2</Bundle-Version>
</instructions>
</configuration>
</plugin>
Kluczem do sukcesu jest nagłówek Private-Package.

Warto pomiędzy uruchomieniami Equinoksa usuwać jego katalog konfiguracyjny - configuration, aby poprzednia konfiguracja nie kolidowała na bieżące testy. Katalog configuration tworzony jest w katalogu, w którym znajduje się uruchomieniowy jar Equinoksa.
 jlaskowski@work /cygdrive/c/apps/equinox
$ rm -rf configuration
Podczas analizy poniższego działania pakunków macierzystego i częściowego na Equinoksie proszę zwrócić uwagę na komunikat +++ Liczba plikow, który informuje o liczbie plików dostępnych w pakunku macierzystym (przypominam, że pakunek częściowy nie jest pełnoprawnym pakunkiem OSGi, tzn. obostrzenia OSGi zugożają go sprowadzając do roli pakunku rozszerzającego).
 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

osgi> install file:/C:/projs/sandbox/springdm-host-bundle/target/springdm-host-bundle-1.0.jar
Bundle id is 1

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.0.v20080804-1730
1 INSTALLED pl.jaceklaskowski.springdm.fragment.springdm-host-bundle_2.0.0

osgi> start 1
Pakunek macierzysty pl.jaceklaskowski.springdm.fragment.springdm-host-bundle w stanie STARTING
...instalacja pl.jaceklaskowski.springdm.fragment.internal.Aktywator$Sluchacz@ca470
+++ Liczba plikow: 18

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.0.v20080804-1730
1 ACTIVE pl.jaceklaskowski.springdm.fragment.springdm-host-bundle_2.0.0

osgi> install file:/C:/projs/sandbox/springdm-fragment-bundle/target/springdm-fragment-bundle-1.0.jar
Bundle id is 2

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.0.v20080804-1730
1 ACTIVE pl.jaceklaskowski.springdm.fragment.springdm-host-bundle_2.0.0
2 INSTALLED pl.jaceklaskowski.springdm.fragment.springdm-fragment-bundle_1.0.0

osgi> refresh 1

osgi> Pakunek macierzysty pl.jaceklaskowski.springdm.fragment.springdm-host-bundle w stanie STOPPING
...usuniecie pl.jaceklaskowski.springdm.fragment.internal.Aktywator$Sluchacz@ca470
+++ Liczba plikow: 18
Pakunek macierzysty pl.jaceklaskowski.springdm.fragment.springdm-host-bundle w stanie STARTING
...instalacja pl.jaceklaskowski.springdm.fragment.internal.Aktywator$Sluchacz@42552c
+++ Liczba plikow: 29


osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.0.v20080804-1730
1 ACTIVE pl.jaceklaskowski.springdm.fragment.springdm-host-bundle_2.0.0
Fragments=2
2 RESOLVED pl.jaceklaskowski.springdm.fragment.springdm-fragment-bundle_1.0.0
Master=1

osgi> uninstall 2

osgi> refresh 1

osgi> Pakunek macierzysty pl.jaceklaskowski.springdm.fragment.springdm-host-bundle w stanie STOPPING
...usuniecie pl.jaceklaskowski.springdm.fragment.internal.Aktywator$Sluchacz@42552c
Pakunek macierzysty pl.jaceklaskowski.springdm.fragment.springdm-host-bundle w stanie STARTING
...instalacja pl.jaceklaskowski.springdm.fragment.internal.Aktywator$Sluchacz@1113622
+++ Liczba plikow: 18


osgi> close

Pakunek macierzysty pl.jaceklaskowski.springdm.fragment.springdm-host-bundle w stanie STOPPING
...usuniecie pl.jaceklaskowski.springdm.fragment.internal.Aktywator$Sluchacz@1113622
+++ Liczba plikow: 18
Ciekawe przedstawienie tematu dostępne również w bezpłatnej książce OSGi in Practice w rozdziale The Extender Model.

Pojawił się nowy harmonogram nowej wersji NetBeans 6.5 - NetBeans NB65Milestones. Przyjdzie jeszcze trochę poczekać na finalną wersję NetBeans 6.5 - 12 listopada 2008.

21 września 2008

Spring Dynamic Modules a aplikacje webowe

5 komentarzy
Już pisałem o tym 4 maja 2008 w Aplikacja webowa jako pakunek OSGi ze Spring Dynamic Modules, ale po sobie widzę, że warto wspomnieć o tym jeszcze raz.

Rozdział 8. Web Support nie pozostawia złudzeń, czego możemy dodatkowo oczekiwać od Spring Dynamic Modules (Spring-DM) poza podstawową cechą jako jest wsparcie dla tworzenia pakunków OSGi korzystając ze Spring Framework. Mowa w nim o wsparciu dla aplikacji webowych (będącymi dystrybuowane jako war - plik jar z odpowiednią strukturą katalogową, np. konieczność istnienia WEB-INF/web.xml) będącymi de facto pakunkami OSGi. Jeśli ktokolwiek zastanawiał się nad sensownością zastosowania OSGi w swoich aplikacjach, to przynajmniej obszar aplikacji webowych powinien być już rozwikłany z pomocą tego rozdziału. Spring-DM łączy cechy OSGi z Korporacyjną Javą udostępniając niezbędne elementy jako pakunki OSGi - kontener servletów jak i samą aplikację webową - które wiąże mechanizmami OSGi. Spring-DM to po prostu warstwa wspierająca uruchamianie aplikacji springowych oraz webowych na Platformie OSGi.

Przyjrzyjmy się dokładniej, co takiego oferuje Spring-DM, czego nie znajdziemy w innych środowiskach. Do poprawnego uruchomienia aplikacji webowej potrzebny jest kontener servletów (być może z jsp, ale kto by tego obecnie używał?!). Podstawowym bytem Platformy OSGi jest pakunek. Jeśli cokolwiek miałoby być uruchomione na Platformie OSGi musi być pakunkiem. Pakunek OSGi to zwykły plik jar z odpowiednimi nagłówkami w META-INF/MANIFEST.MF i stąd wypływa niezwykłość OSGi - niby nic szczególnego, a za darmo mamy możliwości niebagatelnej wartości, m.in. wersjonowanie, dedykowane ładowarki klas, uprawnienia, co z kolei składa się na funkcjonalność uktualniania aplikacji bez konieczności jej zatrzymywania. Połączenie elementów Java EE z OSGi polega na udostępnieniu tych pierwszych jako pakunków OSGi i...tyle. Już możemy okrzyknąć nasze rozwiązanie jako zgodne z pryncypiami OSGi. Do tego wcale nie potrzeba Spring-DM. Gdzie dostrzeżemy zaletę jego wykorzystania, to w sposobie integracji trzech (!) technologii OSGi, Java EE oraz Spring Framework - podczas uruchomienia pakunku OSGi z rozszerzeniem pliku .war, lub zawierającego specyficzne dla Spring-DM nagłówki w manifeście, nastąpi ich automatyczne "związanie" z pakunkiem będącym kontenerem servletów (obecnie Tomcat i Jetty). Właśnie owe rozszerzenie Platformy OSGi o funkcjonalność rozpoznawania pakunków będących faktycznie aplikacjami korporacyjnymi - aplikacjami webowymi - jest wartością Spring-DM. Wprowadzając Spring-DM do naszej aplikacji wprowadzamy jednocześnie cechy OSGi, Spring Framework oraz Java EE. Takie 3-w-1, albo po prostu OSprin-JEE-i.

Porównując wsparcie Spring-DM dla uruchamiania aplikacji springowych a aplikacjami webowymi (potencjalnie korzystającymi z elementów springowych) można zauważyć, że w przypadku aplikacji webowych są one jedynie rozpoznawane i przekazywane do kontenera servletów (który uruchomiony jest na Platformie OSGi jako pełnoprawny pakunek OSGi). Nic poza rozpoznaniem aplikacji webowych nie pozostaje w gestii Spring-DM. Tymczasem rozpoznanie aplikacji springowych skutkuje wzbudzeniem Spring-DM Extender, który wykonuje całą pracę uruchomienia pełnej maszyneri springowej.

Jest kilka istotnych kwestii do zapamiętania, aby aplikację webową uruchomić w ramach Spring-DM, które są implikowane przez prawa rządzące OSGi - kwestia widoczności klas. Domyślnie klasy należące do pakietów javax.servlet.*, WEB-INF/lib/*.jar oraz WEB-INF/classes są widoczne dla aplikacji webowej w "zwykłym" kontenerze servletów. Dodatkowo kontener ma możliwość zdefiniowania wspólnej przestrzeni klas/bibliotek dołączanych do aplikacji webowych, o którą ją rozszerza. W przypadku środowiska OSGi obowiązują bardziej restrykcyjne reguły wymagające, aby pakunek deklarował swoją przestrzeń klas przez nagłówki Import-Package oraz Bundle-Classpath w manifeście. Za ich pomocą należy skonstruować wymaganą przestrzeń klas - zawartość ładowarki klas związanej z pakunkiem. Bez nich zasady obowiązujące w specyfikacji Java Servlet są niepełne w środowisku Spring-DM. Zgodnie z adnotacją w 8. Web Support możnaby oczekiwać, aby owe deklaracje były automatycznie dodawane do pakunku przez Spring-DM, ale póki co, taka funkcjonalność nie jest dostępna. Cechą, która jest niezwykle interesująca, a wręcz wskazana, przy konstruowaniu aplikacji webowej w ramach OSGi (za pomocą Spring-DM) jest wyniesienie bibliotek aplikacji poza jej strukturę katalogową, co przy bardzo radykalnym podejściu skończy się pustymi katalogami WEB-INF/lib oraz WEB-INF/classes, a ich zawartość zostanie uruchomiona w ramach OSGi jako osobne pakunki związane z aplikacją przez nagłówki Import-Package (opcjonalnie Require-Bundle) w manifeście. Uaktualnienie aplikacji o nową funkcjonalność, bądź wdrożenie poprawek, to wyłącznie uaktualnienie pakunków OSGi. Niezwykle potężne oręże upraszczające tworzenie aplikacji webowych ze Spring-DM.

18 września 2008

OSGi - 3.14 Pakunki częściowe

1 komentarzy
Ostatnimi czasy wielokrotnie spotykałem się z terminami OSGi fragment lub OSGi fragment bundle i zawsze kończyło się na...odłożeniu rozpoznania tematu na później (nawet podczas relacji lektury rozdziału 3. Warstwa modułowa w Kolejny łyk OSGi - rozdział 3. Warstwa modułowa nie napisałem o nich ani słowa!). Rozdział 3.14 Fragment Bundles to jedynie 4 strony (plus niewielki diagram), więc samej lektury na niecałe 5-10 minut i można ją powtórzyć (nawet kilkakrotnie).

Przyjrzyjmy się dokładniej, cóż specyfikacja ma do powiedzenia nt. pakunków częściowych w rodziale 3.14 Fragment Bundles.

Pakunki częściowe (ang. fragment bundles) są całkowicie zależne od pakunku wiodącego (przewodniego, ang. host bundle). Podczas fazy rozwiązywania (zależności) pakunku wiodącego Platforma OSGi dołącza do niego wszystkie dostępne pakunki częściowe. Innymi słowy pakunki częściowe stają się logicznie integralną częścią pakunku wiodącego (aczkolwiek fizycznie są wciąż osobnymi bytami). Stąd też pakunki częściowe współdzielą ładowarkę klas (ang. classloader) pakunku wiodącego.

Specyfikacja OSGi określa rolę pakunków częściowych jako dostawców tłumaczeń, co umożliwia dostarczanie ich niezależnie od pakunku wiodącego (w późniejszym terminie). Można sobie wyobrazić działanie pakunku wiodącego jako aplikacji webowej, do której tłumaczenia są dostarczane jako osobne pakunki częściowe, które ostatecznie stają się częścią aplikacji webowej. Wszystko obsługuje Platforma OSGi.

Aktualizacja pakunku częściowego jest widoczna dla pakunku wiodącego dopiero po ponownym uruchomieniu Platformy OSGi lub odświeżeniu pakunku wiodącego. Do tego momentu uaktualniony pakunek częściowy jest dołączony do pakunku wiodącego równolegle do poprzedniej wersji, ale pozostaje nieaktywny.

Usługa Package Admin zwraca ostatnią wersję dołączonego pakunku częściowego.

Pakunek częściowy może deklarować import części chronionej (prywatnej) pakunku wiodącego.

Podczas rozwiązywania środowiska dla pakunku częściowego jakikolwiek konflikt w deklaracjach z pakunkiem wiodącym działają na niekorzyść tego pierwszego, co w efekcie prowadzi do niezwiązania go z pakunkiem wiodącym. Poprawne rozwiązanie pakunku częściowego to pomyślnie związanie go z pakunkiem wiodącym i przejście do stanu RESOLVED.

Przeszukiwanie zasobów pakunku częściowego odbywa się po przeszukaniu zawartości pakunku wiodącego.

Pakunek częściowy nie może być zadeklarowany jako obowiązkowy przez nagłówek Require-Bundle.

Deklaracja środowiska pakunku częściowego zadeklarowana w jego META-INF/MANIFEST.MF jest dołączana na końcu odpowiednich deklaracji pakunku wiodącego (patrz: Bundle-Classpath). Kolejność dowiązania pakunków częściowych odpowiada porządkowi ładowania poszczególnych pakunków częściowych, czyli zgodnie z ich identyfikatorami, rosnąco.

Pakunek staje się pakunkiem częściowym przez użycie nagłówka Fragment-Host ze wskazaniem na pakunek wiodący z opcjonalnym wskazaniem na jego wersję (domyślnie najwyższa), np.
 Fragment-Host: org.springframework.bundle.osgi.extender;bundle-version=1.1.0
Nazwa pakunku wiodącego użyta w Fragment-Host musi być inna niż pakunku częściowego.

Pakunek wiodący zezwala na dowiązanie pakunków częściowych, jeśli zadeklarował BundlePermission[<nazwa symboliczna pakunku>,HOST], podczas gdy pakunek częściowy musi zadeklarować BundlePermission[<nazwa symboliczna pakunku>,FRAGMENT], aby został związany.

Pakunek częściowy jest związany, dopóty jego pakunek wiodący jest w stanie RESOLVED. Przejście w stan INSTALLED powoduje odłączenie pakunków częściowych. Wywołanie metod org.osgi.service.packageadmin.PackageAdmin.refreshPackages(Bundle[] bundles) lub org.osgi.service.packageadmin.PackageAdmin.resolveBundles(Bundle[] bundles) z pakunkiem wiodącym i/lub częściowym może spowodować zmianę stanu pakunku częściowego na INSTALLED.

Zabronione jest, aby pakunek częściowy deklarował własny aktywator (nagłówek Bundle-Activator).

Ostatecznie, dla utrwalenia wiadomości, warto zapoznać się z dokumentem E.1. OSGi Fragments w dokumentacji Spring Dynamic Modules (Spring-DM).

Niezwykle istotną informacją dotyczącą wsparcia pakunków częściowych (i potencjalnie dalszej ewaluacji Spring-DM) przez dostępne platformy OSGi jest jego brak w Apache Felix - FELIX-29 Implement bundle fragments oraz FELIX-656 Implement fragment support for extending a host's bundle class path. Ciekawy jest komentarz do zgłoszenia FELIX-656, gdzie można przeczytać "I got some feedback from the GlassFish team that after I fixed the last bug it has started working for their test case, so I am resolving this for now, but there is definitely more work to be done in this area." autorstwa Richard'a Hall'a, a przecież Richard przeszedł niedawno do Sun - Sun Hires Richard Hall, więc można spodziewać się więcej tego typu komentarzy (w końcu GlassFish v3 pracuje na kontenerze OSGi, podobnie jak IBM WebSphere Application Server 6.1 czy Eclipse IDE).

Dla zainteresowanych do czego zmierzam z rozpoznawaniem roli pakunków częściowych polecam lekturę dokumentu 8.4. Configuring the web extender w dokumentacji Spring-DM. Zdaje się, że bez zrozumienia pakunków częściowych nie ma co marzyć o zrozumieniu działania Spring-DM i jego poprawnej konfiguracji (z potencjalnym rozwiązywaniem błędów). Wciąż żądni wiedzy o OSGi?! Niedługo kolejne odsłony i relacje z moich rekonesansów po terenach OSGi.

16 września 2008

Nowy sezon spotkań Warszawa JUG rozpoczęty i moje lokalne repozytorium SVN

3 komentarzy
Nie potrafię tego wytłumaczyć, ale czy to wdzięk i powab Bolesława Dawidowicza, czy też tematyka - LDAP, czyli kiedy relacyjna baza danych nie jest najlepszym rozwiązaniem, ale na otwierające, 33. spotkanie grupy Warszawa JUG przyszły tłumy - naliczyłem ponad 60 osób, w tym kilka płci żeńskiej (!) Tym samym nowy sezon spotkań grupy mamy rozpoczęty, a kolejne - 30 września - powinno spotkać się z niemniejszym zainteresowaniem, gdyż nie tylko, że temat ciekawy Zrób to sam: kompilator - podstawy języków formalnych, ANTLR i ANTLRWorks, ale któż będzie go prezentował - sam Tom (aka Szimano) ;-) Co tu dużo ukrywać - po prostu zapowiada się "tłumny" wrzesień. Szkoda, że nie wziąłem aparatu, bo zdjęcia z pewnością uatrakcyjniłyby wpis i sami moglibyście przekonać się o celowości przybycia na spotkanie (chociażby, aby znaleźć się na zdjęciu). A jakie dyskusje się toczyły. Widać, że ludzikom brakowało rzeczowych dyskusji o technologiach, bo można było odczyć pewny letni "niedosyt technologiczny". Przygotowujemy się do kolejnej konferencji Warsjava + Eclipse DemoCamp 2008 w dniu 22 listopada 2008 i dyskusje będą z pewnością jeszcze bardziej ożywione. Do zobaczenia na kolejnym 34. spotkaniu 30-tego!

Zanim jednak pojawiłem się na spotkaniu rozwiązałem pewien problem organizacyjny. Ileż to razy przyszło mi pracować lokalnie z dokumentem czy projektem, kiedy to chciałem móc wrócić do poprzedniej wersji? Na pewno uzbierałoby się tego trochę, ale jakimś cudem, mimo ciągłej pracy z repozytoriami SVN, nigdy nie przyszło mi do głowy, aby założyć własne...lokalnie. W końcu nic nie kosztuje, a może uratować cenny czas. Dzisiaj przypadkiem trafiłem na stronę Subversion Cheat Sheet i zrozumiałem, że koniec dumania czy warto, a po prostu należy skorzystać, bo jest i to całkowicie bezpłatnie (finansowo i czasowo). Teraz każdorazowo przy utrzymywaniu jakiegokolwiek pliku tekstowego umieszczę go w moim lokalnym repozytorium. W końcu zamiast serii Ctrl+Z można skorzystać z svn revert, czyż nie?

Rozpoczynam od utworzenia lokalnego repozytorium SVN.
 jlaskowski@work /cygdrive/c/projs/sandbox
$ svnadmin create 'c:/projs/sandbox/.svn_repo'
Pora na zestawienie początkowej struktury katalogowej projektu, który trafi do repozytorium. Zaleca się utworzenie podkatalogów trunk (główna gałąź rozwojowa), branches (odgałęzienia) oraz tags (wersje oznakowane).
 jlaskowski@work /cygdrive/c/projs/sandbox/projekt
$ mkdir trunk branches tags
W trunk umieszczam przykładowy plik README.txt.
 jlaskowski@work /cygdrive/c/projs/sandbox/projekt
$ ls -lR
.:
total 0
drwxr-xr-x+ 2 jlaskowski None 0 Sep 16 23:24 branches
drwxr-xr-x+ 2 jlaskowski None 0 Sep 16 23:24 tags
drwxr-xr-x+ 2 jlaskowski None 0 Sep 16 23:24 trunk

./branches:
total 0

./tags:
total 0

./trunk:
total 0
-rw-r--r-- 1 jlaskowski None 0 Sep 16 23:23 README.txt
Wszystko do tej pory robię z poziomu katalogu projektu, który ostatecznie importuję do lokalnego repozytorium.
 jlaskowski@work /cygdrive/c/projs/sandbox/projekt
$ svn import . 'file:///c:/projs/sandbox/.svn_repo/projekt' -m 'Rozpoczynamy'
Adding trunk
Adding trunk/README.txt
Adding branches
Adding tags

Committed revision 1.
Pierwsza wersja znalazła się w repozytorium. Teraz wystarczy pobrać projekt na dowolne miejsce na dysku.
 jlaskowski@work /cygdrive/c/projs/sandbox
$ svn co 'file:///c:/projs/sandbox/.svn_repo/projekt/trunk' projekt
A projekt/README.txt
Checked out revision 1.

jlaskowski@work /cygdrive/c/projs/sandbox
$ ls -l projekt/
total 0
-rw-r--r-- 1 jlaskowski None 0 Sep 16 23:26 README.txt
I tyle. Projekt jest już utrzymywany przez SVN. Oczywiście nie uchroni to przed awarią komputera, ale jako wsparcie kopii zapasowych, powinno być wręcz nieodzowne. Teraz mogę już zmieniać pliki dowolnie i przy najmniejszym wahaniu wrócić do poprzednich wersji. Mam wybór i o to chodzi.

15 września 2008

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

2 komentarzy
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!

13 września 2008

33. spotkanie Warszawskiej Grupy Użytkowników Technologii Java (Warszawa JUG)

0 komentarzy
Warszawska Grupa Użytkowników Technologii Java (Warszawa JUG) zaprasza na 33. spotkanie, które odbędzie się 16.09.2008 (nadchodzący wtorek) o godzinie 18:00 w sali 5440 Wydziału MIMUW przy ul. Banacha 2 w Warszawie.

Temat prezentacji: LDAP - czyli kiedy relacyjna baza danych nie jest najlepszym rozwiązaniem
Prowadzący: Bolesław Dawidowicz

Celem spotkania jest zaprezentowanie podstaw technologii LDAP oraz jej zastosowań. Słuchacze dowiedzą się czym różni się serwer katalogowy od bazy danych oraz w jakich sytuacjach warto rozważyć jego użycie. Zostanie przedstawione w jaki sposób można wykorzystywać usługi katalogowe z poziomu Javy oraz w jaki sposób mogą one wspomóc zabezpieczanie aplikacji JEE

Plan prezentacji:
- Wprowadzenie do technologii usług katalogowych
- Historia i zastosowanie protokołu LDAP oraz dostępne serwery
- LDAP a Java - krótkie wprowadzenie do JNDI
- LDAP i testy jednostkowe - Embedded OpenDS
- JEE Security i JAAS - krótkie wprowadzenie
- Uwierzytelnienie i autoryzacja aplikacji JEE w oparciu o LDAP - na przykładzie JBoss AS

Prezentacja prowadzona głównie w oparciu o slajdy acz nie zabraknie również kilku pokazów "na żywo" z otwartym IDE:

Wymagana wiedza: minimalna

Bolesław Dawidowicz - miłośnik i pasjonat Javy, zawodowo związany z projektem JBoss Portal. Interesuje się rozwiązaniami z kręgu Identity Management. Stara się aktywnie uczestniczyć w życiu Warszawa JUG. Przyrzeka spróbować tym razem nic nie powiedzieć o portletach ;)

Planowany czas prezentacji to 1,5 godziny, po której planuje się 15-30-minutową dyskusję.

Wstęp wolny!

Zapraszam w swoim imieniu i grupy Warszawa JUG!

11 września 2008

DSL dla konfiguracji Spring Framework

2 komentarzy
Nie pamiętam, co dokładnie sprawiło, że zacząłem poszukiwania znaczenia plików META-INF/spring.handlers oraz META-INF/spring.schemas w Spring Framework, ale pamiętam, że jednym z powodów było z pewnością znalezienie ich w źródłach Spring Dynamic Modules (moduł spring-osgi-core). A może to była lektura OSGi at LinkedIn: Integrating Spring DM (Part 1)? Postanowiłem samodzielnie spróbować się z tematem i po lekturze Appendix B. Extensible XML authoring sprawdzić w działaniu.

I po 10-15 minutach miałem temat rozpoznany. Na tyle, że kiedy dzisiaj pojawiło się pytanie w temacie The matching wildcard is strict, but no declaration can be found for element 'osgi:reference' od razu pośpieszyłem z odpowiedzią. To się nazywa proaktywna postawa wobec potrzeb klientów ;-)

Więcej o mechaniźmie upraszczania konfiguracji Spring Framework w moim artykule DSL dla konfiguracji Spring Framework.

10 września 2008

Silesia JUG już jest!

1 komentarzy
I po spotkaniu. Po rozgłoszeniu go przez Łukasza Lipkę na grupie pl.comp.lang.java - JUG Śląsk??? i spotkanie z Jackiem kilka osób z Katowic i okolic wyraziło chęć uczestnictwa, i o 18-tej raźno powędrowaliśmy...zjeść...pogadać...a może jedno i drugie. Sami zresztą zobaczcie poniżej na zdjęciu. Poszliśmy porozmawiać o Javie i możliwości założenia grupy jugowej w tym rejonie, a tu proszę - wszyscy od razu do spaghetterii!


Przegadaliśmy ponad 2 godziny i (pomijając moje przydługie monologii na tematy różne) było wspaniale! Mówi się o chęci założenia grupy JUG na terenie aglomeracji Silesia (potencjalna nazwa dla Katowic i przyległych miast, coś na wzór Trójmiasta), więc naturalnie można oczekiwać nazwy Silesia JUG. Uważam, że obszar katowicki wymaga reprezentacji w postaci JUGa i mówi się, że coś może się pojawić niebawem.


Na zdjęciu (od lewej): Łukasz Lipka, Ja(cek), Łukasz Grzesik, Michał Kroliczek, Marcin Kołoczek i Damian Łukasik (wierzę, że nie pomieszałem kolejności). Od tej pory w sprawach założycielskich Silesia JUG można kierować pytania do nich.

Na zakończenie naszego spotkania Łukasz wytłumaczył mi, jak robi się takie fajne zdjęcia z długim czasem naświetlania. Po prostu super. Sami zobaczcie.


Jest to zdjęcie autostrady A4 z kładki nad nią, koło której mam hotel (nie, nie, w hotelu cisza, jakbym był w środku lasu).
Nigdy wcześniej nie robiłem tego typu zdjęć, ale teraz z pewnością będzie ich więcej. Już wiem, o co poproszę Św. Mikołaja - statyw (Agacia, czytasz?! ;-)). Bez niego nici z zabawy.

Z ostatniej chwili - właśnie otrzymałem zaproszenie do Silesia JUG! Zatem zaczęło się. Gratulacje dla nowopowstałego JUGa na południu! Moja wizyta w Katowicach nie pójdzie na marne (poza wykonaniem służbowego planu poprowadzenia szkolenia z WPSa). Zmieniam, więc temat notatki na "już jest" z "będzie niebawem".

08 września 2008

Budowanie Spring-DM ze źródeł

1 komentarzy
Kolejny raz potwierdziła się stara maksyma, która mówi, aby rozpoczynać pracę z projektem od lektury jego dokumentacji. Tym razem od kilku dni borykałem się ze zbudowaniem Spring-DM ze źródeł i wciąż trafiałem na błąd kompilacji z braku pakietu org.osgi. Dzisiaj po uaktualnieniu wtyczki m2eclipse udało mi się zaimportować projekt Spring-DM do Eclipse Ganymede i natrafić na przysłowiową żyłę złota - readme-building.txt, gdzie napisano:

The following Maven profiles are available for selecting an OSGi platform:

equinox - Equinox 3.2.x
knopflerfish - Knopflerfish 2.0.x/2.1.x
felix - Apache Felix 1.0.x

The OSGi platform should be always specified otherwise the project will not compile.


co sprowadza się do uruchomienia polecenia mvn clean install z określeniem profilu z bibliotekami Platformy OSGi, np. equinox, tj.
 mvn -P equinox clean install
Po tym proces budowania Spring-DM zakończył się z BUILD SUCCESSFUL po niespełna 3 minutach (!)
 [INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] Spring Dynamic Modules ................................ SUCCESS [2.968s]
[INFO] Spring OSGi Mocks ..................................... SUCCESS [1:05.110s]
[INFO] Spring OSGi IO ........................................ SUCCESS [8.625s]
[INFO] Spring OSGi Core ...................................... SUCCESS [36.407s]
[INFO] Spring OSGi Extender .................................. SUCCESS [7.422s]
[INFO] Spring OSGi Testing Framework ......................... SUCCESS [18.828s]
[INFO] Spring OSGi Web Support ............................... SUCCESS [21.906s]
[INFO] Spring OSGi Web Extender .............................. SUCCESS [5.109s]
[INFO] Spring OSGi Archetype ................................. SUCCESS [2.750s]
[INFO] Spring OSGi Annotations ............................... SUCCESS [2.516s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 minutes 54 seconds
Bajecznie! Zastanawiam się, dlaczego nie zdefiniowano equinox jako domyślnego profilu w głównym pom.xml projektu? Z m2eclipse to jedynie włączenie Active by default w zakładce Profiles.


Zgłosiłem jako OSGI-618 Define equinox as default OSGi platform while builing i dołączyłem łatkę. To już kolejne (drobne) zgłoszenie w Spring-DM.

07 września 2008

Nadchodzący tydzień w Katowicach

6 komentarzy
Przez kolejne 5 dni (8-12.09.2008) będę w Katowicach i z przyjemnością spotkałbym się z lokalną społecznością javową. Będę prowadził szkolenie WB111 - Developing Business Integration Solutions for IBM WebSphere Process Server - I i jakkolwiek nie mogę zaproponować udziału w szkoleniu (zainteresowanych kieruję do Centrum Edukacyjnego IBM) to z przyjemnością spotkałbym się i porozmawiał o rzeczach różnych acz wciąż okołojavowych. Gdyby udało się zorganizować jakieś mini-spotkanie, albo nawet zainspirować kilku ochotników do stworzenia lokalnego katowickiego JUGa (ang. Java User Group) odznaczyłbym wyjazd jako niezwykle udany. Chętni proszeni są do kontaktu.

05 września 2008

OSGi - 4.5 Pakunek systemowy, 4.6 Zdarzenia oraz 4.7 Uruchomienie i zatrzymanie Platformy

0 komentarzy
Podstawowym bytem specyfikacji OSGi jest pakunek. Każda aplikacja oparta o OSGi to zestaw pakunków dostarczających pewnej funkcjonalności. Podobnie jest z samą Platformą OSGi, która nie tylko, że jest środowiskiem uruchomieniowym (kontenerem) pakunków, to sama jest również pakunkiem - pakunkiem systemowym.
 jlaskowski@work /cygdrive/c/apps/felix
$ java -jar ./bin/felix.jar

Welcome to Felix.
=================
...
-> ps
START LEVEL 1
ID State Level Name
[ 0] [Active ] [ 0] System Bundle (1.0.4)
[ 1] [Active ] [ 1] Apache Felix Shell Service (1.0.1)
[ 2] [Active ] [ 1] Apache Felix Shell TUI (1.0.1)
[ 3] [Active ] [ 1] Apache Felix Bundle Repository (1.0.3)
W powyższym zrzucie z pracy Felix'a będzie to System Bundle o identyfikatorze 0.

Pakunek systemowy udostępnia interfejs rejestrowania nowych usług, np. Package Admin.
 -> services 0

System Bundle (0) provides:
---------------------------
objectClass = org.osgi.service.startlevel.StartLevel
service.id = 1
----
objectClass = org.osgi.service.packageadmin.PackageAdmin
service.id = 2
Pakunek systemowy jest zawarty w liście zainstalowanych pakunków zwracanej przez BundleContext.getBundles() (jak można przekonać się po wykonaniu polecenia ps w Felix).

Cechy pakunku systemowego:
  • Posiada identyfikator 0
  • Metoda getLocation() zwraca ciąg System Bundle zgodnie z deklaracją w Constants
  • Nazwa pakunku (Bundle-SymbolicName) jest unikalna dla danej wersji Platformy, jednakże nazwa system.bundle musi być rozpoznawana jako jej alias
  • Obsługa cyklu rozwojowego jest odmienna od typowych pakunków w ten sposób, że:
    • start jest operacją "pustą" (noop) - pakunek musi być zawsze uruchomiony
    • stop kończy pracę całej Platformy
    • update zatrzymuje i ponownie uruchamia Platformę
    • uninstall powoduje zgłoszenie wyjątku BundleException, gdyż pakunek systemowy nie może zostać odinstalowany
Rozdział 4.6 Zdarzenia przedstawia typy zdarzeń wspierane z warstwą zarządzania cyklem rozwojowym pakunków (dalej: warstwa rozwojowa) - BundleEvent oraz FrameworkEvent. Pierwszy, BundleEvent zawiera zmiany w cyklu rozwojowym pakunków, podczas gdy FrameworkEvent niesie informacje o uruchomieniu Platformy, zmianie w poziomie startowym, odświeżeniu pakietów lub wystąpieniu błędu.

Typ zdarzenia można odczytać za pomocą metody getType(), która zwraca wartość typu int odpowiadającą stałej zdefiniowanej w klasie zdarzenia. Nierozpoznane typy zdarzeń powinny być ignorowane.

Ze zdarzeniami związani są słuchacze (ang. listeners) - BundleListener oraz SynchronousBundleListener dla zdarzeń BundleEvent i FrameworkListener dla zdarzeń FrameworkEvent.

Zarządzanie rejestracjami słuchaczy odbywa się za pomocą metod interfejsu BundleContext.

Zdarzenia są (zazwyczaj) dostarczane asynchronicznie w wątku innym niż ten, w którym je zgłoszono.

Platforma zgłosi FrameworkEvent.ERROR, jeśli wystąpił niekontrolowany wyjątek podczas przekazywania zdarzenia do słuchacza (chyba, że miałoby to prowadzić do nieskończonej pętli, gdy przekazanie zdarzenia FrameworkEvent.ERROR spowodowałoby jego wystąpienie).

Zaleca się, aby pakunek wywoływał metody słuchacza poza sekcją objętą monitorem (sychronizacji), co mogłoby prowadzić do wystąpienia zakleszczenia.

W rozdziale 4.7 Uruchomienie i zatrzymanie Platformy znajdziemy informacje o krokach podejmowanych przez implementację podczas uruchamiania i zatrzymywania Systemu.

Uruchomieniu Systemu towarzyszy uruchomienie podsystemu obsługi zdarzeń, tak aby zdarzenia mogły być dostarczane do zainteresowanych słuchaczy, pakunek systemowy przechodzi w stan STARTING, wszystkie pakunki poprzednio zarejestrowane jako uruchomione zostają uruchomione, a wszelkie błędy opakowane jako BundleException, które z kolei są publikowane jako FrameworkEvent.ERROR, pakunek systemowy przechodzi w stan ACTIVE i rozgłaszane jest zdarzenie FrameworkEvent.STARTED.

Podczas zatrzymania Systemu pakunek systemowy przechodzi w stan STOPPING, wszystkie aktywne pakunki są zatrzymane z wyjątkami opakowanymi jako BundleException i rozgłoszone jako FrameworkEvent.ERROR i ostatecznie podsystem obsługi zdarzeń zostaje zatrzymany.

Jakby w prezencie pojawiła się nowa wersja Spring-DM (Spring Dynamic Modules for OSGi Service Platforms) 1.2.0 M1 - Spring Dynamic Modules 1.2.0 M1 Released. Jeszcze się z nią nie próbowałem, ale gdyby komuś się to udało, pożądanym jest podzielenie się wrażeniami ze światem. Na uwagę zasługuje przykład aplikacji webowej opartej o Spring-MVC dystrybuowanej w ramach Spring-DM.

03 września 2008

JSF 1.2 - rozdział 7.4 NavigationHandler

3 komentarzy
Rozdział 7 specyfikacji JavaServer Faces przedstawia API z pakietu javax.faces.application, które stanowi podwaliny dla mechanizmu rozszerzania (w tym i zmiany) zachowania działania szkieletu JSF. Wielokrotnie spotykam się z opinią o bardzo nieprzyjaznym dla programisty rozwiązaniu jakim jest JSF i tyleż samo napotykam w nim interesujących konstrukcji programistycznych. Przykładem możliwości jakie można uzyskać w JSF jako szkielecie aplikacyjnym może być JBoss Seam, którego głównym celem jest (a może jedynie początkowo była) integracja technologi interfejsu użytkownika w Java EE - JavaServer Faces 1.2 - oraz technologii komponentów biznesowych opartych o Enterprise JavaBeans (EJB) 3.0. Dodając do tego projekty facelets oraz RestFaces, którymi parałem się przez ostatnie tygodnie i coraz bardziej intrygowało mnie, co spowodowało, że stało się to możliwe. Wystarczy dostarczyć pewne rozszerzenie (ala wtyczkę) do JSF deklarując w faces-config.xml i już JSF może działać inaczej niż byśmy mogli sobie początkowo wyobrazić. Na pierwszy ogień poszedł javax.faces.application.NavigationHandler, który opisany jest w rozdziale 7.4 NavigationHandler specyfikacji JavaServer Faces 1.2.

NavigationHandler jest to część szkieletu aplikacyjnego JSF uruchamiania do obsługi łańcucha znakowego będącego logicznym identyfikatorem zwróconym przez wykonaną akcję w aplikacji i wybraniem nowego widoku do wyświetlenia. Jeśli wynik akcji jest null ten sam widok, który spowodował wykonanie akcji zostanie ponownie wyświetlony. W zasadzie najlepiej możnaby to uzmysłowić prezentując sygnaturę jedynej metody abstrakcyjnej klasy NavigationHandler:
 public void handleNavigation(FacesContext context, String fromAction, String outcome)
Na podstawie przekazanego kontekstu FacesContext oraz wyniku outcome działania akcji fromAction handleNavigation podejmuje decyzję o kolejnej stronie do wyświetlenia.

Implementacja JSF musi dostarczyć domyślną realizację NavigationHandler, który pozwala na zdefiniowanie przepływów (przejść między stronami w aplikacji) w plikach konfiguracyjnych (domyślnie faces-config.xml). Do konfiguracji przepływu służy znacznik <navigation-rule>. Znacznik może zawierać opcjonalny <from-view-id>, który akceptuje wartości wyrażenia regularnego dla aktualnego identyfikatora widoku postaci dosłownej (pełne dopasowanie)
 <navigation-rule>
<from-view-id>/stworzKategorie.jsp</from-view-id>
<navigation-case>
<from-action>#{kategoriaAgent.stworz}</from-action>
<to-view-id>/wyswietl.jsp</to-view-id>
</navigation-case>
</navigation-rule>
, początek widoku (!) zakończonego gwiazdką
 <navigation-rule>
<from-view-id>/stworz*</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/wyswietl.jsp</to-view-id>
</navigation-case>
</navigation-rule>
, gwiazdkę, która określa wszystkie możliwe widoki (strony)
 <navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-action>#{kategoriaAgent.stworz}</from-action>
<to-view-id>/wyswietl.jsp</to-view-id>
</navigation-case>
</navigation-rule>
lub po prostu bez określenia <from-view-id>, co przekłada się również na dowolny widok:
 <navigation-rule>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/wyswietl.jsp</to-view-id>
</navigation-case>
</navigation-rule>
W ramach <navigation-rule> znajduje się dowolna liczba <navigation-case>, które precyzują dopasowanie.

Możliwe jest określenie wielu <navigation-rule> dotyczących tego samego <from-view-id>, ale niepoprawnym jest określenie tej samej kombinacji <from-*> dla danego <from-view-id>.

Zwrócenie null z akcji informuje NavigationHandler, aby nie przeszukiwał reguł i ponownie wyświetlił aktualny widok.

Elementy <from-outcome> oraz <from-action> odpowiadają parametrom wejściowym metody handleNavigation.

Możliwe jest skorzystanie z elementu <redirect/> do określenia przekierowania aktualnego żądania do zadanej strony, po którym następuje zatrzymanie przetwarzania żądania JSF (wywołując javax.faces.context.FacesContext.responseComplete()). Wyjątkiem jest środowisko portletowe, gdzie przekierowania nie są dozwolone.
 <navigation-rule>
<from-view-id>/stworz*</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/wyswietl.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>failure</from-outcome>
<to-view-id>/failure.jsp</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
Brak <navigation-rule>, która pasuje do parametrów metody handleNavigation nie zmienia aktualnego widoku (podobnie jak wartość null).

Znalezienie pasującego widoku powoduje zbudowanie nowego, tracąc stan poprzedniej (uwaga: może być czasochłonne).

Podmiana domyślnego NavigationHandler następuje programowo poprzez wykonanie metody javax.faces.application.Application.setNavigationHandler(NavigationHandler handler) lub deklaratywnie w faces-config.xml w sekcji <application>.
 <application>
<navigation-handler>klasa.realizujaca.NavigationHandler</navigation-handler>
</application>
Można wyobrazić sobie implementację, której konfigurację przepływów definiujemy w faces-config.xml oraz bazie danych. Dobrym źródłem wiedzy nt. temat będzie z pewnością wątek How the way for create a new NavigationHandler w stosunkowo młodym forum GlassFish WebTier. Możnaby również oprzeć NavigationHandler na regułach pisanych w Groovy czy umożliwić kreowanie przepływów z poziomu interfejsu użytkownika. Chętnie zapoznałbym się z wdrożonymi pomysłami.

Pozostaje życzyć sobie, żeby konstruowanie nowych kontrolek JSF było równie proste. Jest to bodajże najbardziej pracochłonne zadanie w JSF. Na razie jest nie na moje siły i wydaje się, że jedynie facelets mógłby być panaceum (acz wprowadza własny ViewHandler i znaczniki JSP należy migrować do znaczników facelets, co ponownie może być nie lada wyzwaniem).

02 września 2008

OSGi 4.2 Early Draft i Spring-DM w roli RI

2 komentarzy
W Early draft of OSGi Service Platform Release 4.2 specification now available Adrian Colyer przedstawił jedną ze zmian dotyczącą nazewnictwa pakunków OSGi w RFC 124 "A Component Model for OSGi", który stanie się specyfikacją komponentów OSGi i jakie to pociąga za sobą zmiany w samym Spring Dynamic Modules (Spring-DM). W/g Adriana zmian na skalę rewolucji nie będzie, a jedynie zmiana/mapowanie nazwy znacznika bean (podstawowy znacznik konfiguracyjny w Springu, nie tylko DM) na component i tyle. Reszta to po prostu Spring-DM (stąd dla samego Adriana nie będzie rewolucji, a dla wielu właśnie wdrożenie Spring-DM pod skrzydła specyfikacji nią jak najbardziej jest). Znamienny jest sposób przedstawiania roli Spring-DM w samej specyfikacji. Przypomina mi to peany jakie pisała o sobie grupa Hibernate i jej wpływie na specyfikację JPA oraz grupie JBoss Seam na specyfikację WebBeans. Czyżbym był przewrażliwiony? Obserwując wykorzystanie JPA w projektach daje się zauważyć, że dla wielu JPA to faktycznie Hibernate (a szczególnie jego część Criteria API). Mimo mojego dzisiejszego minorowego nastroju odnośnie RFC 124 i Spring-DM wierzę w dobre intencje wszystkich wymienionych grup i już nie mogę doczekać się popróbowania z platformą referencyjną dla RFC 124 (aka RFC124 RI). Jeśli ma to uprościć tworzenie aplikacji korporacyjnych, to dlaczegóżby nie skorzystać z niego?! Samo OSGi ma wiele do zaoferowania na poziomie uproszczenia architektury aplikacji, gdzie duży nacisk kładzie się na odseparowanie deklaracji (interfejsy usług) od realizacji (implementacja usług), więc czym więcej OSGi w naszych rozwiązaniach, tym lepiej (nota bene, to samo możnaby również napisać o Spring Framework). I nie mógłbym nie wspomnieć o niezwykłym podobieństwie specyfikacji Service Component Architecture (SCA) do RFC 124. Mógłbym napisać, że są łudząco podobne, ale jest to jedynie moje przeczucie nie podparte lekturą RFC 124. A może ktoś z czytelników już się z nim zapoznał i zechciałby przedstawić swój punkt widzenia? Zachęcam do opublikowania go na swoim blogu, tutaj, albo w...JAVA exPress Grzegorza Dudy.

Upór Grzegorza w stworzeniu czegoś namacalnego i wartościowego dla społeczności javowej znalazł swój finał w pierwszym numerze niezależnego, niekomercyjnego, itp. czasopisma o tematyce javowej - JAVA exPress Numer 1 (1) Sierpień 2008, w którym znajdziemy "Hello World!" maszynisty Grzegorza, 5 artykułów, w tym 2 przewodnie, o tytułach, w których liczba słów "kolejowych" odpowiada "javowym" i...a co ja będę się rozpisywał. Zainteresowany/-a?! Pobierz darmowy numer JAVA exPress ze strony czasopisma (uwaga na rozróżnienie słów gazeta vs czasopisma - gdzieś ktoś o tym wspominał na jednej z grup javowych po publikacji JAVA exPress, ale nie mogę tego teraz znaleźć).

A wracając do OSGi i jego specyfikacji to Craig Walls (autor książek o Spring Framework - Spring in Action dostępnej również w Bibliotece Warszawskiego JUGa) wyraził swoje wątpliwości odnośnie wpływu OSGi na Spring-DM, albo...na odwrót? - Spring and OSGi R4.2. Jako stały użytkownik Springa (mowa o Craigu), jak i OSGi w wykonaniu Spring-DM zdaje sobie sprawę z podobieństw między Spring a OSGi. Nawet stworzył ciekawy akronim, który oddaje trend konwergencji między OSGi i Java EE - OS-JEE-i, a może powinno się dodać i Springa - OSprin-JEE-i? ;-) Na szczęście nasze aplikacje na pewno nie ucierpią, a znacznie łatwiej będzie tworzyć dynamiczne systemy, gdzie przez "dynamiczność" rozumiem możliwość zmiany funkcjonalności aplikacji bez konieczności jej zatrzymywania.

Na dokładkę nie mógłbym nie wspomnieć o Richard S Hall (Apache Felix) Joins Sun, co pozwala przypuszczać, że w ofercie Suna również OSGi nie zabraknie. W kontekście RFC 124 natrafić można na pracę Richard'a - Beanome : A Component Model for the OSGi Framework. Cóż za zbieg okoliczności w kontekście Spring-DM i jego roli na RFC 124 (!) Dodając do tego OSGi w GlassFish v3 wygląda, że coś z tych doświadczeń OS-JEE-i-owych znajdziemy również już niedługo w ofercie wszystkich dostawców serwerów aplikacyjnych Java EE. Na odświeżenie spojrzenia o roli usług i OSGi, który wręcz wymusza ich tworzenie w naszych aplikacjach warto zapoznać się z Why Services are Important oraz OSGi - A Component of the Next Generation Platform?. Chwila lektury, a o ile poszerza się nasz horyzont programistyczny.

I dla tych zainteresowanych dokładniejszym spojrzeniem współprzewodniczącego OSGi EEG na prace nad OSGi V4.2 i zmianami zapraszam do lektury Early Draft OSGi V4.2 Docs Available. W nim dowiadujemy się o wspomnianym na początku the Spring-DM inspired component model design (RFC 124). Jeśli uważasz, że kierunek jaki obrała grupa OSGi EEG jest niewłaściwy, albo nieprecyzyjny, albo...tu wpisz jakikolwiek z powodów, dla których warto wyrazić swoją opinię...przyłączam się do apelu Eric'a, pobrania dokumentu OSGi V4.2 Early Draft i wyrażenia siebie. Może być na swoim blogu, tutaj, w JAVA exPress bądź na stronie OSGi EEG. Możliwości jest na prawdę wiele.

Nie długo trwa, abym przekonał się, że rola Spring-DM nie będzie wyłącznie pomocnicza, a raczej główna, gdyż jak napisał Costin Leau (za How Spring DM (greatly) influenced the upcoming OSGi 4.2):

Spring-DM will become the RI. We haven't sorted out the technical details, but it's likely it's going to be platform agnostic so one could just take out the implementation and use whatever 4.2 platform it likes.

Uzupełnieniem lektury z pewnością będzie (technicznie) Some thought on the OSGi R4.2 early draft oraz (strategicznie) Eclipse Swordfish SOA runtime mixes SCA, JBI and OSGi, gdzie można zapoznać się z zależnościami między SOA, SCA, JBI, OSGi, Java EE, Spring Framework, Eclipse i jeszcze wielu innych akronimów oraz produktów je realizujących (aż trudno uwierzyć, że aż tak tłoczno jest wokół OSGi). Ciekawostką może być wycinek, w którym podkreśla się rolę OSGi względem wad Java EE oraz Springa:

He rates Java EE 5 as too heavyweight and complex with static deployment descriptors. Spring, on the other hand, does not allow dynamic deployment or reconfiguration, and lacks support for "true modularization," he said.

oraz

It's dynamic. It's easy to use. It is mature. We believe that OSGi gets momentum in the future and will diminish JEE and Spring.

czy w końcu:

SCA provides a common programming model and a common description format. JBI provides a common messaging model. OSGi provides a common deployment model and a common runtime component model.

I na zakończenie serii linków (sznurków?) odnośnie OSGi i jego wpływu na nasze i innych rozwiązania - Plugins 2.0: a heads-up z Attlasianu - producenta m.in. Confluence Wiki. Wygląda na to, że OSGi będzie warstwą realizującą mechanizm wtyczek w Confluence (!) Skoro wtyczki to plugins, a tu już tylko krok "myślowy" do OSGi (za sprawą Eclipse). Czy ma znaczenie, jaką rolę posiada wtyczka? Wtyczka to rozszerzenie podstawowego produktu, więc czy to IDE czy serwer aplikacyjny, wtyczka może wprowadzić dużo pożądanej funkcjonalności...w tracie działania aplikacji. Pozostaje tylko czekać, kiedy pojawią się projekty w Polsce oparte bezpośrednio na OSGi. Pamiętam pewną lubelską firmę programistyczną, która podczas JAVArsovii 2008 wypytywała mnie o rolę OSGi w tworzeniu aplikacji webowych (widoczność sesji, itp.) i niestety nie było wtedy wiele czasu na dyskusje. A szkoda! Ciekawym ile z tych planów się zmaterializowało?!

Więcej o OSGi na tegorocznym Java Developers Day (JDD) 2008 16. października 2008 w Krakowie, gdzie podjąłem się zadania przedstawienia go w różnych realizacjach. Otrzymałem 1h na prezentację i to zaraz przed gwiazdą wieczoru Nealem Fordem, więc spodziewam się Was tam wszystkich zobaczyć i rozpoznamy nasze rozpoznanie tematu OSGi ;-) Fajnie byłoby "strzelić" jakieś nagranie z naszej dyskusji (podkreślam słowo dyskusji). Zapraszam!