niedziela, stycznia 11, 2009

Nieznane ścieżki ClassLoader'a ;-)

Nieznane są ścieżki jakimi podąża ClassLoader ;-)

Jeden z użytkowników OOo2GD zgłosił mi problem z rozszerzeniem objawiający się komunikatem: no object DCH for MIME type application/atom+xml.

Komunikat ten oznacza, że biblioteka activation nie była w stanie zidentyfikować typu MIME opisanego jako application/atom+xml.

Zaglądając głębiej można stwierdzić, co stwierdziłem już ponad rok temu gdy podobne problemy pojawiały się po zmianach w OpenOffice.org, że ten typ MIME application/atom+xml jest "ładowany" do kodu biblioteki activation przez kod wykonywany w bibliotekach Google'a....

Ale tak się składa, że kod "ładujący" wykonuje się w jednym wątku z jednym ClassLoader'em, a drugi wykonuje się w innym wątku z innym ClassLoader'em... Przez co biblioteka activation próbuje dosięgnąć kod który w danym ClassLoader'ze nie jest załadowany.

Poprawiłem ten problem i wszystko wyglądało pięknie.......

Okazuje się jednak, że w "sprzyjających" warunkach moja poprawka nie działa :-)

W momencie kliknięcia przez użytkownika na ikonkę lub po wyborze opcji z menu OpenOffice.org uruchamia w swojej JVM kod rozszerzenia. W tym kodzie znajduje się ważny kod, który tworzy nowy wątek tworzący okno odpowiadające wybranej funkcji, ale wcześniej ustawia odpowiedni ClassLoader dla tego nowego wątku. A musi to być ClassLoader który jest w stanie "zobaczyć" biblioteki wtyczki.
I tu niby jest wszystko OK, bo okienko się tworzy i zaczyna działać, a gdy użytkownik klika na odpowiednie klawisze w okienku tworzą się kolejne wątki które przecież "dziedziczą" ClassLoader'a....... ale nie zawsze ;-)
Swing jest przebiegły i ma swój własny wątek zwany EDT, którego zadaniem jest obsługa klikania, odrysowywania i innych podobnych. Stąd każdy kod podpięty pod przyciski i inne funkcje okienka zostaje wykonany w EDT. Żeby okienko nie wisiało dobrym zwyczajem jest uruchamiać długotrwałe zadania w oddzielnych wątkach.
A kontakt z siecią jest zawsze długotrwałym zadaniem, stąd i ja tworzę w wielu miejscach nowe wątki.... Wszystko super...

ALE!!! Ale wszystko opiera się na założeniu, że wątek EDT wykonuje się z odpowiednim ClassLoader'em który powinien zostać ustawiony tak jak to wyżej opisałem.

EDT jest jeden na całą JVM, a kontekst ClassLoader'a wątkowi można ustawić tylko przed jego uruchomieniem. Wystarczy więc by EDT wystartował przed pierwszym uruchomieniem kodu rozszerzenia i nieszczęście gotowe :-)

Aby to obejść trzeba w momencie pierwszego wykonania się kodu rozszerzenia zapamiętać ClassLoader i wykorzystywać go później do "zasilania" każdego z nowo tworzonych wątków.


Podobne problemy można napotkać w JBoss'ie, który ma takie widzimisię, że wątek odpowiedzialny za finalizację obiektów [czyli za wołanie ich metody finalize()] jest uruchomiony z ClassLoader'em który nie ma dostępu do klas aplikacji. Wystarczy więc by w trakcie finalizacji klasa próbowała dostępu do niezaładowanej jeszcze klasy i obiekt nie zostanie sfinalizowany... a na dodatek ta klasa nie będzie już możliwa do załadowania przez ClassLoader'y które mają do niej dostęp ;-)

A teraz refleksje ;-)
1) Smutne jest to, że choć nadal mało rozumiem ClassLoader'y to i tak wiem o nich więcej od 90 albo i 95% piszących w Java'ie.
2) SCJP się przydaje.
3) Pisanie czegokolwiek w wolnym czasie się przydaje.
4) Muszę się jeszcze DUŻO nauczyć.


Podobne postybeta
OOo2GD 1.5.0 - drżyjcie arkusze! ;-)
Frustracja....
Wpis próbny, czyli rozproszona wirtualna maszyna Java'y
Klasy .NET w Java'ie....
Swing - największe zło Java'y ;-)