12 stycznia 2010

Każdemu będzie w końcu dane - wreszcie Java EE 5 w projektach!

Nowy rok i nowe projekty, a tak się złożyło, że część z nich nawet rozwojowa - dosłownie i w przenośni. Znalazłem się więc w projekcie, w którym tworzone jest oprogramowanie do synchronizacji danych między bazami danych (tym samym kłaniam się nisko uczestnikom - klimat "Piratów z Karaibów", których oglądałem przez ostatnie 3 dni się udziela :]).

Architektura obejmuje WASv7 z DB2 (centrala) oraz WASCE z DB2 Express (satelitarne, lokalne instalacje). Nareszcie projekt w IBMie, gdzie serwer aplikacyjny wspiera najnowszą specyfikację Java EE 5 (może niekoniecznie najnowszą, bo na dniach wyszła nowiuteńka wersja Java EE 6, ale jej wsparcie nie jest jeszcze na tyle rozpowszechniona, aby nawet próbować się z nią w ramach prac domowych). Przyznaję, że trochę dziwnie mi się pisze oprogramowanie w Java EE 5 z udziałem IBM WebSphere. Jakoś przyzwyczaiłem się do starszych specyfikacji, których unikałem, jak tylko mogłem i większość pracy sprowadzałem do odpowiednich funkcjonalności w RADzie. Udało się i teraz zostało mi to wynagrodzone - wreszcie można oddychać pełną piersią, a jeśli dodać do tego, że teraz wszystkie zabawki IBMa z rodziny WebSphere działają na WASv7 - serwerze aplikacyjnym zgodnym z Java EE 5 i działającym na Java SE 6 - to możecie sobie wyobrazić, jak bardzom z tego rad. Do niedawna jeszcze o Java EE mogłem sobie pomarzyć w cieple domowego kominka, a w pracy...brrr...lepiej nie wspominać, wciąż J2EE. Teraz się odmieniło, bo kiedy się bardzo chce, to się kiedyś ziści. Wiedza, którą zdobywałem w ostatnim roku teraz się przydaje...produkcyjnie. Wreszcie!

Wracając do mojego bieżącego projektu, miałem dzisiaj przygodę z synchronizacją realizowaną przez...stronę JSP. Wszystko było wykonywane z jej poziomu i jej autor zdawał się mieć tego całego programowania w Javie najwyraźniej dosyć (nieprawdaż Paweł?). Szkoda było chłopaka, bo zacny z niego gość, ale brakowało mu wiedzy, ciut więcej i takiej ukierunkowanej na mocne strony Java EE. A skoro już mają Java EE, to nie byłoby dobrze nie skorzystać z dobrodziejstw. Zadanie na rozgrzewkę w sam raz dla mnie - można błysnąć i to przy niewielkim nakładzie pracy. To lubię! ;-)

Przed moimi oczyma jawi się strona JSP, a w niej jeden wielki try/catch z dostępem do bazki, sprawdzeniem tego i owego, aby ostatecznie zbudować odpowiedź XMLową. Dla mnie naturalnym było zaciągnąć @WebService i @Resource do pracy, aby z niecnego JSP zrobić całkiem przyzwoitą klaskę, powtórzę, zwykłą klaskę z kilkoma "wskazaniami" dla serwera, aby traktował ją specjalnie.

Wystarczyło więc, uruchomić NetBeans IDE 6.8.1, zaciągnąć aktualne źródła aplikacji webowej z repozytorium CVS (brrr, że też wciąż tego ustrojstwa się używa) i dodać tę oto klaskę (niektóre elementy usunięte dla poprawienia czytelności):
package pl.tufirma;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.sql.DataSource;

@WebService
public class Synchronizator {

private final String AUTH_SQL = "SELECT ID FROM AUTHORIZE WHERE AUTH = ?";

@Resource(name = "jdbc/mak")
DataSource makDS;

public String synchronizacjaPoczatkowa(@WebParam(name = "key") String klucz) {
return synchronizeFirst(klucz);
}

protected String synchronizeFirst(String key) {
try {
String id_authorize = pobierzIdAuthorize(key);
MessageFormat SQLQUERY = new MessageFormat("WITH ...");

StringBuffer queryParam = new StringBuffer(id_authorize);
String query = SQLQUERY.format(new Object[]{queryParam.toString()});

System.out.println("SQLQUERY: " + query);
Connection conn = makDS.getConnection();
PreparedStatement stmt = conn.prepareStatement(query);
ResultSet rs = stmt.executeQuery();
String XMLResult = "";
if (rs.next()) {
XMLResult = rs.getString(1);
}
return XMLResult;
} catch (SQLException ex) {
Logger.getLogger(Synchronizator.class.getName()).log(Level.SEVERE, null, ex);
throw new IllegalStateException("Problemy z bazka", ex);
}
}

protected String pobierzIdAuthorize(String key) {
try {
Connection conn = makDS.getConnection();
PreparedStatement authStmt = conn.prepareStatement(AUTH_SQL);
authStmt.setString(1, key);
ResultSet authRs = authStmt.executeQuery();
if (!authRs.next()) {
throw new IllegalArgumentException("NIe odnaleziono klucza dla " + key);
}
return authRs.getString(1);
} catch (SQLException ex) {
Logger.getLogger(Synchronizator.class.getName()).log(Level.SEVERE, null, ex);
throw new IllegalArgumentException("NIe odnaleziono klucza dla " + key, ex);
}
}
}
Jak widać wiele jeszcze do zrobienia, ale sam szkielet klasy już jest odpowiednio dopasowany. Propozycje dalszych zmian mile widziane. Mamy wystawioną usługę jako usługę sieciową za pomocą @WebService, a dostęp do bazy danych kontrolowany jest przez serwer aplikacyjny i dostępny klasie przez @Resource. Czyż nie ładniej, chciałoby się zapytać? Teraz pozostaje obsłużyć właściwe tworzenie pliku XML (pewnie JAXB, ale nie będę ukrywał, że aż mnie rwie do Groovy), klient po stronie bazy lokalnej, który czyta odpowiedź od usługi, zapis do lokalnej bazy danych i powinno być całkiem cacy. Terapia szokowa w postaci Groovy i Grails czeka w kolejce (jeszcze im nic nie mówiłem, nawet nie wspominałem, więc prośba o dochowanie tajemnicy, zgoda?).

Jeśli są zainteresowani, aby dowiedzieć się więcej o szczegółach działania tej klasy, wystarczy się odezwać w komentarzu, np. tak: "Wyjaśnień potrzebowałbym więcej...". Chętni? Artykuł czy skrinkast*?

Ach i przy okazji tych doświadczeń z adnotacjami Java EE 5, sprawdziłem jeszcze jedno połączenie, tym razem NetBeans IDE z Eclipse. Sam projekt tworzony był w Eclipse IDE i tak został zapisany w repozytorium. Ja wystartowałem z NetBeans, więc konieczny był import, który sądziłem początkowo, że trochę pozamienia w projekcie. Okazało się, że nie tylko nie pozamieniał, ale moja zmiana była widoczna w Eclipse bez jakichkolwiek specjalnych kroków poza cvs update. Nie było mi dane ukryć mojego zdumienia, że tak łatwo poszło. Miałem przez moment stracha, że może się nie udać, ale, jak to mówią, diabeł ma wielkie oczy.

[*] Z tym "skrinkast" to przegiąłem, co?