Kilka dni mi to zajęło, ale dopiero lekkie zapalenie gardła połączone z finałem leczenia za pomocą dwóch napojów piwopochodnych Somersby spowodowało, że mam rozwiązanie.

W czym problem leżał

Mamy sobie task polegający na dopisaniu do istniejącego portletu dodatkowego modułu. W dużym skrócie portlet pobiera dane z formularza www, zamienia je na PDFa i wysyła mailem. My mamy dodać webservice, który będzie niejako dodatkowym kanałem komunikacji. Inaczej mówiąc zamiast pieprzyć się z klikaniem formularza na www wyślemy sobie go z appki po WSie.
Samo implementowanie WS jako elementu istniejącego portletu w liferay zasługuje na osobny wpis, bo tak pojebanej technologii to tylko wśród phpowców szukać, a i tu wygląda to logiczniej. Dla nas istotne jest to, że w zależnościach naszego rozwiązania pojawia się cglib-2.1\_3 i commons-logging-1.0.4.

Objawy problemu

Dewelopujemy, paczkujemy, deployujemy. Na localhoście (goły tomcat) śmiga wyśmienicie. Deploy lokalny wykonujemy jako „rm -rf ; cp” deploy, czyli za pomocą czarnego ekranu, ale wała… deploy na test, odpalamy SoapUI i mamy… InvocationTargetException. Ok… bywa… generalnie ten błąd jest zwracany przez AXISa gdy coś się grubi wyjebie. Niestety w konstruktorze klasy tego błędu mamy:

Listing 1. konstruktor ITE

    protected InvocationTargetException() {
	super((Throwable)null);  // Disallow initCause
    }

Wot, bolszoj’ technika. Dla niekumatych… po chuj nam przyczyna błędu. Taki kod podobny jest w swej istocie do pustego bloku catch i powinno się autora na spalić na stosie… hm… stosie… hm… somersbiak się skończył… szit…

Ok, debbuger podpinamy się na wywołanie metody WS i metodą eliminacji dochodzimy do momentu gdzie się wywala. Okazuje się, że przyczyną błędu jest NoClassDefFoundError, który oznacza, że klasa została załadowana, ale w trakcie pierwszego jej wywołania, kiedy następuje jej weryfikacja, niezależenie metody statycznej czy konstruktora, coś nie bangla. I to solidnie nie bangla…

Klasą, która powodowała syf była… springowa ValidationUtils. Chwila zastanowienia… i okazuje się, że rzeczywistą przyczyną był problem z klasami ze wspomnianego wcześniej commons-logging. Tak błąd oznacza najczęściej, że w classpathie leża dwie klasy o identycznej nazwie. Oczywiście szybko się okazało, że rzeczywiście w WEB-INF/lib mam dwie paczki commons-logging, ale tylko na serwerze testowym. Przy okazji okazało się, że zdublowany jest jeszcze cglib tzn. jest jar „pełen” i wersja „nodep”… to nasunęło mi pewną myśl…

Przyczyna problemu

Po kilku krótkich testach znalazłem przyczynę problemu. Mechanizm instalujący portlety w liferayu wykonuje operację kopiowania. Problem pojawia się w momencie gdy z paczki usuwamy jakieś pliki. W trakcie instalacji stara wersja jest nadpisywana przez ekwiwalent bashowej operacji cp, ale nie przez ciąg operacji kasowania i kopiowania. W efekcie jeżeli podbijemy numer wersji jakiejś biblioteki to stara wersja pozostanie na swoim miejscu i będzie bruździć. Zazwyczaj problem ten nie występuje, bo „zabezpieczeniem”, jest „naturalne” działanie użytkowników, którzy ręcznie usuwają stary portlet, a nie zdają się na mechanizmy instalatora. W efekcie nawet gdy wystąpi tego typu awaria następuje paniczne usuwanie portletu z katalogu roboczego i nieświadome gaszenie pożaru. Ja nie zachowałem się jak typowy user, chyba dlatego, że ręczne usunięcie starej wersji gdy instaluje się nową jest dla mnie czymś głupim, tym samym spowodowałem problem, a ze względu na dodatkowo dziwne zachowanie się serwera testowego, ale nie localhosta zacząłem drążyć temat…