Transformata xslt w javie

Dawno nie było nic o javie, to dziś pora na transformatę XSLT. Bardzo ciekawa rzecz, która pozwoli nam zwykłego xml przekształcić do postaci, która można pokazać zwykłemu użytkownikowi i on nie ucieknie. Nie wiem czy to będzie dobre porównanie ale pliki xsl są dla xml tym samym co css dla html.

Teraz przykład transformaty xslt w javie:

Result fin = new StreamResult(response.getWriter());

InputStream ins = new ByteArrayInputStream(content);
UnicodeInputStream uis = new UnicodeInputStream(ins, “UTF-8″);

Source str = new StreamSource(new InputStreamReader(uis, "UTF-8"));

InputStream vins = new ByteArrayInputStream(visualization);
UnicodeInputStream vuis = new UnicodeInputStream(vins,”UTF-8″);
Source xsl = new StreamSource(new InputStreamReader(vuis,”UTF-8″));

TransformerFactory transFact = TransformerFactory.newInstance();
Transformer trans = transFact.newTransformer(xsl);
trans.transform(str, fin);

I co my tu mamy. Content to zawartość naszego xml już w postaci bajtowej a visualization to xsl. Należy je przekształcić do typu Source aby można je było wykorzystać przy transformacie, którą wykonujemy na końcu i wynik mamy w fin.

Nie pamiętam bibliotek z których tutaj korzystałem ale jest kilka, które implementuje transformatę. Rzeczą na którą należy tu zwrócić uwagę jest klasa UnicodeInputStream. Ja korzystałem i lekko zmodyfikowałem tą klasę ale widziałem, że apache udostępnia własną klasę, która może być lepsza od tej przeze mnie używanej. Dzięki tej klasie możemy obejść problem z BOM. A czym jest BOM? Jest to kilka bajtów na początku pliku określających kodowanie. Niestety java go nie ignoruje i nie zanosi się na to aby zostało to rozwiązane. Tutaj z pomocą przychodzą na takie klasy jak UnicodeInputStream. Jak byśmy użyli standardowego InputStream to przy próbie transformaty otrzymalibyśmy błąd, że content is not allowed in prolog.

Logowanie sql w javie - log4jdbc

Zdecydowana większość pewnie słyszała o log4j, wiele osób też go używało i uważa za dobre narzędzie. Jednak co zrobić jak chcemy sprawdzić jakie operacje na bazie danych są wykonywane w naszej aplikacji a jeszcze lepiej ich czasy. Tutaj z pomocą przychodzi nam log4jdbc. Proste narzędzie, które pozwala nam logować informacje o zapytaniach, kwerendach i to dosyć szczegółowo.

W log4jdbc dostajemy 4 loggery:

  1. jdbc.sqlonly - najprostszy, pokazuje tylko zapytania SQL.
  2. jdbc.sqltiming - ukazane czasy wykonywania operacji, w większości przypadków ten jest wystarczający.
  3. jdbc.audit - wszystkie wywołania SQLowe oprócz ResultSet.
  4. jdbc.resultset - wszystko łącznie z ResulSet.

Całą konfigurację log4jdb możemy zdefiniować w pliku log4j.xml a tutaj znajduje się przykładowy plik log4j.xml z włączonym logowaniem zapytań do bazy danych.
Osobiście polecam takiego appendera

<appender name=”sql-timing-appender” class=”org.apache.log4j.RollingFileAppender”>
<param name=”File” value=”ścieżka_gdzie_zapisać_log/sql.log”/>
<param name=”Append” value=”true”/>
<param name=”Encoding” value=”UTF-8″/>
<param name=”MaxFileSize” value=”10000KB”/>
<layout class=”org.apache.log4j.PatternLayout”>
<param name=”ConversionPattern” value=”—–> %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n%n”/>
</layout>
</appender>

ponieważ możemy zdefiniować tutaj rozmiar logów a także plik za każdym razem będzie dopisywany do wcześniejszych logów a nie tworzony nowy.

Jak już mamy konfigurację zapisu to jeszcze potrzebujemy biblioteki. W pracy korzystałem z następujących (nie mogę tutaj wrzucić archiwów a na jakiś hostingu plików to zginie szybko, więc po nazwach będzie można je znaleźć) .

  • log4jdbc3-1.1beta
  • slf4j-api-1.4.3
  • slf4j-log4j12-1.4.3

Ostatnia rzeczą jaką wykonujemy jest zdefiniowanie połączenia z bazą danych na nowych ustawieniach. Zmieniamy sterownik na net.sf.log4jdbc.DriverSpy , który obsługuje najbardziej popularne bazy danych. Jeśli, którejś nam brak to zawsze możemy ustawić we właściwościach log4jdbc aby wskazywał na dany sterownik. A także zamieniamy stary adres lokalizacji bazy:
jdbc:derby://localhost:1527//db-derby-10.2.2.0-bin/databases/MyDatabase na
jdbc:log4jdbc:derby://localhost:1527//db-derby-10.2.2.0-bin/databases/MyDatabase


Po zakończeniu zbierania logów należy przywrócić poprzednie ustawienia połączenia z bazą, ponieważ na tym sterowniku baza danych chodzi dużo wolniej niż na natywnym, zaobserwowane na przykładzie sterownika posgresql

Webservice - krótki wstęp

Do niedawna nie miałem pojęcia o webservice’ach, wiedziałem że takie coś istnieje ale jak działa to była czarna magia. Ale teraz mogę się stać ekspertem z racji tego, że w pracy jeden projekt jest prawie skończony oparty na nich (implementacja klienta) i drugi też będę robił (strona serwera).

Czym są webservicy, jak sama nazwa wskazuje są to usługi sieciowe i dzielą się jak wspomniałem wyżej na implementację po stronie klienta i po stronie serwera. Aby wygenerować webserice jest potrzebny plik wsdl. Ma on strukturę xmlową i kilka chyba obowiązkowych węzłów:

  • types
  • message
  • portType
  • binding
  • service

Aby wygenerować usługę lub klienta z wsdla moża użyć wbudowanego kreatora w eclipsie bądź skorzystać z narzędzia dostarczanego przez fundację apache w ich własnej implementacji ws Axis2 - wsdl2java. Osobiście nie polecam wizarda w eclipsie ponieważ jego działanie nie jest zbyt stabilne i trochę trzeba się namęczy. Wsdl2java i java2wsdl są prostymi konsolowymi aplikacjami o prostej składni. Również z kodu javy można wygenerować wsdl.

Zacznijmy może od usługi. Po wygenerowaniu w eclipsie usługi dostajemy kilka plików. W głównej mierze są to interfejsy, implementacje jakiś naszych typów zadeklarowanych w wsdl ale nas najbardziej będzie interesował plik z końcówką Impl od implementation. Są w nim metody naszego webservicu, które nie posiadają implementacji tylko zwracają jakieś wartości. Naszym zadaniem jest obudowanie ich i sprawienie aby wykonywały to co jest w założeniach projektu.

Strona klienta jest jeszcze prostsza. Szukamy w wygenerowanych plikach, jednego w którym nazwa zawiera słowo Locator. To się tyczy Axis 1. Tworzymy nową instancję tej klasy i poprzez tego lokatora łączymy się z ws. Pozostaje nam tylko wywołać metody z odpowiednimi parametrami chyba, że chcemy jakoś wykorzystać wartości zwracane przez te metody to wtedy tworzymy odpowiedni kod.

Dodawanie certyfikatów w javie

Czasem jak korzystamy z klienta webservicu to potrzebujemy dodać certyfikat danej strony do aplikacji. O ile w przeglądarce zaakceptowanie certyfikatu jest proste i sprowadza się do paru kliknięć, to w aplikacji może to być trochę utrudnione.

Należy dodać certyfikat do listy certyfikatów w systemie ale jak to zrobić. Jest kilka sposobów aby to wykonać ale nie sprawdzałem ich dokładnie tylko skorzystałem ze sposobu opisanego tuta . Ta możliwość jest bardzo prosta do dodania pożądanego przez nas certyfikatu.

Ściągamy ten kod i kompilujemy go. Później uruchamiamy w konsoli skompilowany program z parametrem, gdzie tym parametrem jest nazwa hosta strony gdzie jest certyfikat. Musi on być bez żadnego http:// ani tym podobnych ani żadnych slashy na końcu. Po uruchomieniu z tym parametrem zostanie wypisany wyjątek, że nie można odnaleźć certyfikatu a także treść certyfikatu ze strony z możliwością dodania go do zaufanych certyfikatów. W katalogu gdzie jest nasz skompilowany program tworzy się plik “jssecacerts”, który zawiera zaufane certyfikaty z pliku cacerts oraz nasz nowy certyfikat. Można tamten plik podmienić tym naszym ale moim zdaniem lepiej tego nie robić. Ostatnią rzeczą jaką musimy zrobić jest w wpisanie w kodzie w miejscu gdzie łączymy się ze stroną z certyfikatem takiego fragmentu

System.setProperty(”javax.net.ssl.truststore”, “sciezka/do/pliku/jssecacerts”);

Parsowanie XML 3-wiele atrybutów o takiej samej nazwie

Dziś w pracy miałem za zadanie wyciągnąć dane z dokumentu XML i zapisać je do tablicy longów. Dla naszego przykładu przyjmijmy, że miał postać:
<GlownyElement>
<Numer>1</Numer>
<Numer>2</Numer>
<Numer>3</Numer>
<Numer>4</Numer>
</GlownyElement>

Jak to sparsować? w poprzednich notkach przetwarzaliśmy dokumenty gdzie były pojedyncze elementy więc tamtych sposobów nie można zastosować, bo będziemy mieli tylko jeden element a potrzebujemy wszystkie. Można zastosować taki sposób, korzystając ze znanego nam Digestera.

Digester dig = new Digester();
dig.setValidating(false);
dig.addCallMethod(”*/Numer”, “add”, 1);
dig.addCallParam(”*/Numer”, 0);
List<String> list = new ArrayList<String>();
dig.push(list);
dig.parse(new StringReader(document));
long [] retar = new long[list.size()];
for(int i=0;i < list.size();i++){
retar[i] = Long.parseLong(list.get(i));
}

Pierwsze 2 linijki są nam znane, ale ciekawe rzeczy zaczynają się od kolejnej addCallMethod(”*/Numer”,”add”,1) oznacza to, że dla atrybutu */Numer wywołujemy metodę add a 1 to ilość paremetrów do przetworzenia czyli nasz Numer. Metoda addCallParam(”*/Numer”,0) mówi nam, że wartość elementu Numer będzie zapisywana na wierzchu stosu. Później jest tworzona lista stringów i wkładana na stos. Bardzo ważne aby to był string, bo jeśli damy inny typ to rzuci nam wyjątkiem. Kolejnym etapem jest parsowanie gdzie document to String z zawartością naszego dokumentu xml. Ostanie 3 linijki to utworzenie potrzebnej mi tablicy longów.

Druga część
Pierwsza część

Parsowanie XML część 2

W poprzedniej notce ogólnie omówiłem parsowanie dokumentów xml w javie przy użyciu klasy Digester. Teraz troszkę rozbudujmy nasz dokument xml o dane kontaktowe

<Osoba>
<DaneOsobowe>
<Imie>Jan</Imie>
<Nazwisko>Iksisnki</Nazwisko>
</DaneOsobowe>
<Adres>
<AdresZamieszkania>
<Ulica>Nowa</Ulica>
<Nr>4</Nr>
<Miejscowosc>Kraków</Miejscowosc>
</AdresZamieszkania>
</Adres>
</Osoba>

Do naszej klasy w której były pola Person w której były pola name i surname dodajemy pola street, number i localization z oraz settery i gettery dla tych pól. I teraz wywołujemy metodę parsującą bardzo podobną jak ostanio.

Digester dig = new Digester();
dig.setValidating(false)
//tutaj uwaga bo brak linijki dig.addObjectCreate(”*/DaneOsobowe”, Person.class);
dig.addBeanPropertySetter(”*/DaneOsobowe/Imie”, “name”);
dig.addBeanPropertySetter(”*/DaneOsobowe/Nazwisko”, “surname”);
dig.addBeanPropertySetter(”*/AdresZamieszkania/Ulica”, “street”);
dig.addBeanPropertySetter(”*/AdresZamieszkania/Nr”, “number”);
dig.addBeanPropertySetter(”*/AdresZamieszkania/Miejscowosc”, “localization”);
//tutaj kolejna różnica
dig.push(new Person());
Person person = (Person) dig.parse(new StringReader(documentContent));

Czym się rożni ten kawałek kodu od poprzedniego. Usunięta linijka dig.addObjectCreate(”*/DaneOsobowe”, Person.class); Mamy 2 wzorce, jeden */DaneOsobowe a drugi */AdresZamieszkania. Najprawdopodobniej można dodać kolejną linijkę addObjectCreate, nie sprawdzane przeze mnie. Ale rozwiązaniem na to jest dodanie na stos nowej instancji naszej klasy Person, które wykonuje się w linijce dig.push(new Person()). Tylko jeśli w dokumencie będzie więcej atrybutów o takich samych nazwach ale leżących w innych gałęziach, trzeba pamiętać o dobrym ustawieniu wzorców w addBeanPropertySetter.

Trzecia część- wiele atrybutów

Parsowanie XML w javie część 1

Obecnie w pracy robię obsługę pewnego webservicu i o webservicach też zamierzam coś napisać w przyszłości. Częścią tego projektu jest przetworzenie dokumentu xml i wyciągnięcie z niego interesujących nas danych.

Do parsowania korzystam z dobrodziejstwa fundacji apache i jej klasy Digester. Jako przykład, może przetworzę prosty dokument.

<Osoba>
<DaneOsobowe>
<Imie>Jan</Imie>
<Nazwisko>Iksisnki</Nazwisko>
</DaneOsobowe>
</Osoba>

Mamy prosty dokument xml, który podaje nam imię i nazwisko jakiejś osoby i chcemy te dane wyciagnać. Tworzymy prostą klasę w javie z polami name i surname oraz geterami i sereami.

public class Person{
String name;
String surname;

//setter and getters
}

W miejscu gdzie nam są potrzebne te dane wywołujemy następujący kod.

Digester dig = new Digester();
dig.setValidating(false)
dig.addObjectCreate(”*/DaneOsobowe”, Person.class);
dig.addBeanPropertySetter(”*/DaneOsobowe/Imie”, “name”);
dig.addBeanPropertySetter(”*/DaneOsobowe/Nazwisko”, “surname”);
Person person = (Person) dig.parse(new StringReader(documentContent));

Pierwsza linijka to utworzenie nowego obiektu Digester i zaraz po niej ustawienie flagi validate, która musi być ustawiona przed metodą parse(). Kolejna linijka jest dosyć ciekawa addObjectCreate. Pierwszy parametr tej metody to wzorzec, w którym będziemy poszukiwać interesujących nas danych a drugi to klasa gdzie będziemy je przechowywać. Gwiazdka zastępuje nam element główny i wydaję mi się, że możliwe jest zastąpienie następnych elementów ale tego nie sprawdzałem. Kolejne linijki ustawiają w naszej klasie Person pola name i surname wartościami jakie są w XML przypisane atrybutom Imie i Nazwisko. W ostatniej linijce dokonuje się parsowanie rzutowanie na naszą klasę. Metoda parse może przyjmować jako argumenty różne argumenty. Ja wykorzystuję StringReader, który czyta wcześniej podaną zawartość pliku XML. Dostęp do tych pól mamy przez settery i gettery.

Należy pamiętać o obudowaniu parsowania wyjątkami ale to eclipse nam podpowiada, kiedy je wstawiać. Więcej informacji i tutorial można znaleźć tutaj.

Druga część
3 część wiele atrybutów