Pokazywanie postów oznaczonych etykietą jpa. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą jpa. Pokaż wszystkie posty

14 października 2011

warsjawa i TomEE już jutro - Java EE 6 Web Profile z Apache TomEE o 16:15

0 komentarzy
Maksym to fajny gość. W poniedziałek stuknął mu tydzień i przeszedł pierwsze badanie kontrolne w szpitalu na Madalińskiego.


Jego poczucie humoru przerasta moje wyobrażenia i na propozycję uśmiechnięcia się do kamery zdecydował skwitować to...figą z makiem (!) No cóż, powiedzmy, że miałem zły dzień, a on dobrą zabawę (a może odwrotnie?! :))

W tę sobotę, 15 października jest warsjawa 2011, a na niej ja jako prelegent z tematem Java EE 6 Web Profile z Apache TomEE. Czym bliżej wystąpienia, tym więcej mam wątpliwości, co może zainteresować publikę. Przy takim natłoku certyfikowanych serwerów aplikacyjnych nie wystarczy jedynie pokazać, że działa, ale musi być w Apache TomEE to coś, co zachęci do jego dalszego poznania.

Możliwość użycia zestawu Java EE 6 Web Profile jest kusząca, ale tylko, jeśli idzie w parze z daleko posuniętą prostotą użycia. Podczas wystąpienia zaprezentuję działanie aplikacji demonstracyjnych dostarczanych w ramach NetBeans IDE 7.1 na TomEE.


Sprawdzimy również, jak to jest skonfigurować TomEE z bazą danych MySQL.

Ideą jest, aby zachęcić do dalszych, pewnie już samodzielnych prób z tym zestawem w zaciszu domowego kominka, a podczas wystąpienia będę miał godzinę, aby ten ogień rozpalić. Powinno być ciekawie.

28 lutego 2010

Recenzja "Pro JPA 2: Mastering the Java Persistence API" - obowiązkowa lektura dla zainteresowanych JPA 2.0

0 komentarzy
Pro JPA 2: Mastering the Java Persistence APIO mojej lekturze książki Pro JPA 2: Mastering the Java Persistence API panów Mike Keith i Merrick Schincariol (wydawnictwo Apress, grudzień 2009) pisałem już kilkakrotnie (patrz Z Pro JPA 2: zapytania natywne w SQL vs JP QL i peany nt. WAS V7, Boimy się nieznanego, regularny wypoczynek z pływaniem i silnie typizowane zapytania w JPA2 czy Java Persistence (JPA) 2.0 praktycznie - zestawienie środowiska z EclipseLink i Apache Maven 2).

Możnaby powiedzieć, że wiele już o tej książce napisano (na Amazonie jest już 5 recenzji tej książki), ale co mnie niezwykle zaskoczyło to fakt, że to, co ja uważam za plus, inni uważają za minus i odwrotnie. Niby nic dziwnego, ale jak tu wybrać kolejną książkę technologiczną do czytania, kiedy Ci, którzy zdecydowali się na jej kupno są równie zachwyceni, co rozczarowani, a Ci, którzy nie kupili, stracili możliwość kreowania własnego poglądu na sprawę samodzielnie, bo akurat negatywna recenzja książki przypadła im bardziej do gustu. Co zrobić? Całkowicie zaniechać czytania recenzji nie polecam i zachęcam do większego samozaparcia, bo akurat w tym przypadku warto skusić się na tę 500-stronicową cegłę. Dla mnie miała wszystko, czego oczekiwałbym od książki tego pokroju - dokładnego opisu JPA 1.0 i wejścia w temat JPA 2.0. Skoro jest częścią Java EE spodziewałem się również, że będzie wiele o powiązaniach między nimi i tak też było. Znalazłem to, czego chciałem, a nawet więcej.

Nie będę ukrywał, że jednocześnie książka mnie niezwykle zmęczyła i pozwolę sobie na lekturę kolejnej książki...nietechnicznej celem odświeżenia umysłu. Trochę gimnastyki w dziedzinie bardziej efektywnego (i efektownego) zarządzania zadaniami dobrze mi zrobi. Zdecydowanie warto czytać książki, a Pro JPA 2: Mastering the Java Persistence API przybliża zmiany w obszarze JPA 2.0 znakomicie. Pewnie możnaby lepiej, ale 500 stron daje wyobrażenie o wysiłku autorów w wytłumaczeniu niuansów tej specyfikacji (a i tak zawarto w niej jedynie wycinki kodów).

Zainteresowanych moją, angielską recenzją książki zapraszam do lektury Book review: Pro JPA 2: Mastering the Java Persistence API (język podyktowany programem wydawnictw anglojęzycznych "Książka za recenzję").

Książka dostępna jest w Bibliotece Warszawskiego JUGa i czeka na kolejnego zainteresowanego jej lekturą i poznaniem tajników specyfikacji JPA 2.0.

16 lutego 2010

Z Pro JPA 2: zapytania natywne w SQL vs JP QL i peany nt. WAS V7

7 komentarzy
Lektura książki Pro JPA 2: Mastering the Java Persistence API z Apress trwa i nie przestaje mnie zdumiewać. Może nawet nie chodzi o nią samą, ale o to, co ma JPA2, co sprawia, że to właśnie sama specyfikacja mnie tak zdumiewa. Niektóre rzeczy były już w JPA1, więc tym bardziej lektura Pro JPA2 sprawia mi tyle przyjemności, bo co strona, to coś nowego. Pisałem, że mam w zwyczaju oznaczać sekcje książki do dogłębniejszego zbadania i kiedy zwykle w książkach jest kilka akapitów per rozdział, tak w Pro JPA2 są to prawie całe strony (!) "Prawie robi różnicę", ale jak by tego nie wartościować, materiału do przetrawienia jest cała masa.

Kiedy to piszę, zaczynam zastanawiać się, czy mógłbym tę książkę polecić adeptom JPA. Książka zakwalifikowana jest dla średniozaawansowanych - User level: Intermediate. Z jednej strony jest w niej wszystko, co poleciłbym początkującym, ale z drugiej jest tego tyle, że czytanie specyfikacji byłoby łatwiejsze - nie ma tam tylu dywagacji. Owe dywagacje sprawiają, że książka należy do obowiązkowych lektur każdego programisty JEE i nie ma co jej porównywać ze specyfikacją, ale jeśli mi rozdział (około 30-40 stron) zajmuje 3-4 dni, aby całość przetrawić, to jak tu polecić ją początkującym?! Serca nie mam?!

Jestem przy rozdziale 11. "Advanced Topics" (strona 333) i mam wrażenie, że czytam ją całe wieki. Z jednej strony, ciągnie mnie do niej, aby poznać więcej, z drugiej zaczynam powątpiewać w sens tak kurczowego się jej trzymania i dobrnięcia do końca. Nie będę ukrywał, że mnie trochę zmęczyła. Coś mi mówi, że gdyby była podzielona na dwie części, byłoby ją przyjemniej czytać. Przypomina mi "Wprowadzenie do algorytmów" Cormena i in., gdzie można znaleźć wszystko o algorytmach i faktycznie poleca się ją początkującym, ale przebrnięcie przez nią zabiera wieki. Fajnie, że można wszystko znaleźć w jednym miejscu, ale nawet najbardziej wytrwali padają w połowie i tylko zdrowy rozsądek podpowiada, że po zakończeniu satysfakcja gwarantowana. Wiedzy po pachy i aż by się chciało przeskoczyć kilka stron, aby mieć to za sobą.

Możnaby zapytać, czy warto tak się katować czytaniem, skoro czytanie powinno sprawiać przyjemność, a z moich słów można wyczytać ból i cierpienie. Możnaby to porównać do wyjścia na siłownię, bieżnię, wiosła, basen w wydaniu zaawansowanym. Wiemy, że będzie bolało i ma boleć, bo bez tego nie będzie wyników. Podobnie jest z Pro JPA 2 (i było z Cormenem) - bolało, ale ostatecznie wiedza była ponadprzeciętną i nawet, jeśli wszystkiego się nie spamiętało, to wiedza, że tam to jest nie raz uratowała tyłek. Bolało i pewnie nie raz jeszcze zaboli, ale lepsze to, kiedy chcemy, niż później podczas projektów, których jedynym rezultatem i tak jest zatonięcie, tyle że okupione większymi stratami i ślęczeniem po nocach (czego nikomu nie życzę).

Wszedłem w temat zaawansowanego JPA, w świat zapytań natywnych w SQL. W JP QL naszym modelem jest model obiektowy, a w SQL model relacyjny (czy jak to ostatnio ujął Michał M. na spotkaniu Warszawa JUG - tabelkowy). Wybór należy do piszącego zapytanie, do czego mu bliżej - obiekty czy tabelki. Co mnie jednak dzisiaj niezwykle przyjemnie zaskoczyło, to fakt, że bez względu na wybór języka zapytań, programista i tak korzysta z tych samych obiektów - wciąż mamy javax.persistence.Query lub wprowadzone w JPA2 - javax.persistence.TypedQuery (!) Czyż to nie jest wspaniałe w tej specyfikacji, że bez względu na język SQL vs JP QL zmiana w wielu przypadkach odbywa się bez zmiany kodu?! Kiedy dodam do tego, że wprowadzenie zapytań nazwanych (mianowanych?, ang. named queries) umożliwia nadpisywanie ich przez deskryptor persistence.xml, wtedy można do zespołu wdrożyć gościa, którego zadaniem będzie optymalizowanie zapytań. Pasuje mu pisać w SQL, niech będzie, woli podciągnąć się z technologii JEE, wchodzi w JP QL. Najważniejsze, że nie trzeba schodzić na poziom JDBC, aby tworzyć wysokowydajną obsługę danych w bazie. Programiści nie zmieniają swoich konstrukcji programistycznych i prą do przodu, a ów człowiek od zapytań, aka człowiek-pytajnik, optymalizuje zapytania w cieple domowego kominka. Niby oczywiste, ale dla mnie niezwykle odświeżające. Kiedy dodam, że wynik zapytania, to wciąż encje zarządzane przez kontekst utrwalania, wtedy świat staje się ułożony. Pamiętajmy jednak, aby zapytanie SQL pobierało całość danych z bazy danych, bo w przeciwnym wypadku, część danych nie spłynie do encji i podczas zatwierdzenia transakcji, albo przy javax.persistence.EntityManager.flush() dane zostaną wyczyszczone (zamazane pustymi wpisami). Zapewnie nie byłoby to czymś, czym chcielibyśmy się pochwalić klientowi ;-)

Chciałoby się popróbować z JPA2 i w zasadzie każdy może. JPA2 jest częścią JEE6, ale może żyć i bez niej. Jak to miało miejsce w JPA1, tak i w JPA2, uruchomienie w samodzielnych aplikacjach czy wręcz środowiskach zubożonych, np. w wersji wcześniejszej JEE5, jest jak najbardziej możliwe i wspierane specyfikacyjnie. Bodajże wczoraj czytałem zajawkę o wsparciu JPA2 przez Hibernate 3.5 CR1, więc pasjonaci Hibernate mają możliwość, a Ci spoza jego strefy wpływów mają do wyboru referencyjną implementację JPA2 - EclipseLink, albo nieodstającego od peletonu Apache OpenJPA. Zdaje się, że Hibernate, który miał niebagatelny wpływ na specyfikację JPA, zaczyna oddawać pola konkurencji. Mamy wybór, a to jest najważniejsze i w sumie (początkowo) nie ma znaczenia, co działa pod spodem.

Ostatnie tygodnie spędziłem nad redbookiem (książki o technologiach IBM) dotyczącym IBM WebSphere Application Server V7 Feature Pack for Service Component Architecture (w skrócie SCA FeP). Zajmowałem się częścią administracyjną, która jest niezwykle prosta, zakładając znajomość administacji IBM WebSphere Application Server V7 samą w sobie. Największym wyzwaniem było stworzenie bogatej technologicznie aplikacji SCA, ale kiedy okazało się, że wraz z SCA FeP przychodzi wiele przykładów, temat był do obsłużenia w ciągu tygodnia, dwóch (niestety, jak to zwykle bywa, sam rozruch trwał prawie 2 miesiące - czas Nowego Roku nie sprzyjał rozpoznaniu terenu).

Jeśli ktokolwiek parał się z SCA, to wie, że jedną z darmowych implementacji jest Apache Tuscany. I SCA FeP jest po prostu opakowaniem Tuscany w odpowiednie rozszerzenia WASowe. Podobnie było z EJB3 czy Web Services z JEE5 dla WAS 6.1. Było, ale kto tego używał? Na moje nieszczęście niewielu. Niestety, ale produkty stosowe, np. IBM WebSphere Process Server V6.2 nie wspierały tych rozszerzeń, więc w produkcyjnych środowiskach, gdzie królowało SCA i WS-BPEL z WPSem, o JEE5 można było zapomnieć chyba, że przez wykonywanie zdalnych usług Web Services, ale to zawsze można.

IBM WebSphereNiezwykłem do wychwalania produktów mojego pracodawcy obawiając się oskarżeń, że jest to spowodowane głównie, gdzie pracuję, a nie zaletom technologicznym i jakoś tak trwało, że ja swoje, a IBM swoje - technologicznie, oczywiście. Z pewnością na moją decyzję miała również wpływ cena, która zwykle w naszych (=moich i czytelników mojego bloga) rozwiązaniach oscylowała głównie wokół bezwzględnego zera, ze względu na użycie produktów darmowych, otwartoźródłowych. Kolejnym powodem, może nawet ważniejszym, było opóźnienie technologiczne w porównaniu z darmowymi rozwiązaniami. Kiedy królowało JEE5 najnowsze wydanie IBM WebSphere Application Server V6.1 to wciąż jedynie (?) J2EE 1.4 z rozszerzeniami do EJB3 i Web Services. Dobrze, że WAS 6.1 to OSGi i dał tym samym możliwość zabawy z nowościami JEE5 przez rozszerzenia zwane Feature Packs. Zbierając to wszystko, niewiele można było u mnie znaleźć o produktach z rodziny IBM WebSphere mimo, że duża część mojego czasu była konsumowana właśnie przez nie.

I tak trwałem w tym stanie zawieszenia między rozwiązaniami OSS, a IBM, aż do grudnia 2009, kiedy pojawiły się produkty na bazie WASv7. Najnowsze wydanie WAS V7 zmienia diametralnie oblicze rynku rozwiązań JEE. W końcu mam(y) wsparcie JEE5 z JSE6 i OSGi pod spodem. To się musi podobać, szczęśliwcom, których firmy weszły w tą wersję. Nie ma wciąż wielu produktów realizujących JEE6, więc sprawa nabrała rumieńców i moloch typu IBM w końcu dotrał do punktu, w którym WAS V7 wybroni się technologicznie z każdego przetargu. W końcu! Sprzedawcom na pewno zrobiło się lepiej/łatwiej.

Jeśli ktokolwiek zadaje sobie pytanie, po co to piszę i czy ma to jakikolwiek związek z JPA2, albo innymi specyfikacjami wokół JEE, to śpieszę donieść, że pojawiły się dwa otwarte programy IBM WebSphere Application Server V7 Feature Pack for OSGi Applications and Java Persistence API (JPA) 2.0 Open Beta. Z nimi, pod płaszczykiem nauki WAS V7 możemy poznawać nowości JEE6 i OSGi Enterprise z wykorzystaniem Apache OpenJPA 2 i Apache Aries. Czyż nasze administracyjno-programistyczne boje z WASem, nie wydają się być od razu przyjemniejsze? W końcu na coś się zda nasz trud i pot. Jeszcze nie tak dawno, zapisałem się do grupy Apache Aries, aby śledzić poczynania w kontekście korporacyjnego OSGi, gdzie łączy się JEE i OSGi w spójną całość, a tu IBM wyjeżdża z możliwością uruchomienia obu na WAS V7. Niezwykłem wychwalać WASa, bo do wersji 6.1, był po prostu znośny, gdzie moja nauka specyfikacji, to zawsze był krok przez nim. Teraz, z WAS V7, sprawa w końcu przybrała inny obrót - teraz ja muszę nadgonić, bo mam go z przodu. Biorąc pod uwagę inne zalety WAS V7, mogę z czystym sumieniem polecić go jako ten serwer aplikacyjny do rozwiązań komercyjnych. Po 4 latach pracy w IBMie, w końcu mogę odetchnąć, że ja też już mogę bawić się najnowszymi zabawkami i jeszcze mi za to płacą! I to jest w tym wszystkim dobre. Jeszcze tylko niech IBM WebSphere Process Server podskoczy do SCA 1.0 i będzie naprawdę cacy. Na razie ni widu, ni słychu.

A czy Wam też płacą za przyjemności w pracy, czy się wciąż katujecie niszowymi rozwiązaniami?! Wytrwałości. I Wam się też, kiedyś powiedzie! ;-)

p.s. Ci, którzy dobrnęli do końca, mogą odetchnąć i z czystym sumieniem oddać swój głos na Notatnik w konkursie Bloger 2009 Roku. Będzie tego więcej.

12 lutego 2010

Boimy się nieznanego, regularny wypoczynek z pływaniem i silnie typizowane zapytania w JPA2

4 komentarzy
Najbardziej uwielbiam te momenty, w których na usta ciśnie się "Eureka!". To jest ten moment, w którym wszystko układa się w jedną całość i brak w nim niewyjaśnionych miejsc. Można wtedy wygodnie rozłożyć się w fotelu i powiedzieć sobie "Udało się!" Wtedy wiem, że wysiłek nie poszedł na marne.

Uważam, że jest wiele rzeczy, które ostatecznie składają się na ten moment wzniosłości. Sam smak zwycięstwa to za mało, aby ucieszyć ślęczącego nad tematem programistę, który tak trwa w tym stanie ciągle, przez kilka ostatnich dni i zrekompensować mu poniesione straty. Ważne, aby w tym całym szaleństwie znaleźć jeszcze umiar w dążeniu do celu i znaleźć czas na relaks i wypoczynek. Właśnie wtedy, kiedy rozwiązujemy problem najbardziej potrzeba nam wypoczynku.

Spotkałem się z dwoma podejściami do rozwiązania problemu - siłować się z nim do momentu, aż albo on, albo ja, lub też, drugie podejście, gryźć problem kawałek po kawałku, rozkładając go na części pierwsze.

Zakładając, że oba kończą się tym samym - zwycięstwem - nie mam wątpliwości, w której ja chciałbym się znaleźć. Oczywiście w tej drugiej. Ostateczne zwycięstwo będzie dodatkowo udekorowane wieńcem końca zadania i wystarczających sił na kolejne.

Takie coś przytrafiło mi się dzisiaj z rana, kiedy po śniadaniu z Agatką, zasiadłem do pewnego tematu (na razie o nim sza) i wszystko wydało się takie oczywiste. A wystarczyły regularność i spanie > 7h. Rozwiązanie samo do mnie przyszło, zamiast mnie biegającego za nim.

Najbardziej w tym wszystkim zdumiewające było to, że problem był niezwykle błahy i wyłącznie moja nieznajomość tematu robiła z niego większego potwora niż było potrzebne. "Boimy się nieznanego", jak powiadają.

I tu jest właśnie sedno sprawy - ciągłe rozwijanie swojej wiedzy, ciągłe próbowanie się z nowym. Kiedy czegoś nieznamy, kolejne nieznane może nas łatwo sfrustrować, prowadząc do błędnego wniosku, że jedyne, co potrafimy, to odkrywać nieznane. To samo w sobie może być wartościowe, ale niewielu pomyśli o tym pozytywnie. Kiedy jednak owe poznawanie wpiszemy w kontrakt naszego działania i wejdzie nam w krew, przedzieranie się przez nieznane, będzie jedynie odkrywaniem kolejnego nieznanego, co z dobrym wypoczynkiem (!) może dawać satysfakcję jego odkrycia. Idąc dalej, to nieznane może być niezwykle dochodowe (przez "dochodowe" rozumiem nową wiedzę, nowe możliwości, itp.) W końcu może się nawet okazać, że nowe dla nas jest nowym dla większości wokoło, a to stawia nas w szeregu nowicjuszy...eee, raczej...nowatorów!

Zostawiając na boku ten cały bełkot psychologiczny, pamiętajmy o wypoczynku, regularnym wypoczynku. 7h minimum i 3 x 1/2h ciągłego pływania/tydzień, to obowiązek każdego programisty. Tak sobie to dzisiaj wymyśliłem. Siedzenie nas wykańcza, a problemy technologiczne nie pomagają.

Żeby nie było, że wpis taki umoralniający, bez pierwiastka javnego, to napiszę, że właśnie z ukończeniem rozdziału 9-tego "Criteria API" książka Pro JPA 2: Mastering the Java™ Persistence API stała się dla mnie lekturą obowiązkową każdego parającego się JPA czy ORMem w Javie. Jestem na 10 rozdziale (273. strona) i z trudem idzie mi jej czytanie. Nie dlatego, że taka beznadziejna, ale dlatego, że każda strona wypełniona jest wiedzą JPA po brzegi! Rozdział 9. "Criteria API", który właśnie skończyłem zajął mi prawie 4 dni i cały jest zakreślony notatkami. W zasadzie wszystko było nowe (nie dotykałem wcześniej tematu w Hibernate) i niezwykle zapadające w pamięć swoją złożonością (w sensie pozytywnym, bo w końcu wciąż może być jeszcze trudniej, bo wciąż możemy zejść na poziom SQLa i bawić się z przenośnością aplikacji przechodząc ze środowiska lokalnego, najczęściej z jakąś wbudowaną bazą danych typu HSQL, do testowego z DB2, Oracle, MySQL, czy innym SQLowym stworzeniem).

Co mnie najbardziej zainteresowało, to budowanie zapytań SQL z mechanizmem silnie typizowanych (jak ja nie lubię tego słowa) zapytań w JPA2 (ang. strongly typed query definition) z kanonicznym metamodelem. Brzmi wyniośle, a sprowadza się do zmiany nazw pól w mapowaniu ORM (w postaci napisów) na ich silnie typizowane odpowiedniki (w postaci pól w klasie reprezentującej kanoniczny metamodel encji). Zamiast pisać ...get("ksiazka").get("tytul") można ...get(Ksiazka_.tytul). Kiedy dodam, że dostawcy JPA2 generują takie klasy kanoniczne (zwykle zakończone podkreślnikiem po nazwie encji/klasy) i przy pisaniu zapytania pomaga nam każde IDE, bez specjalnego wsparcia dla JPA2, to zysk jest niebagatelny. Można wręcz całkowicie zapomnieć o trzewiach ORMa w postaci relacyjnej bazy danych - same obiekty i silna typizacja. I znowu zaczynam biegać za nowym :) Bawił się tym już ktoś?

30 stycznia 2010

Niemy film(ik) na weekend - Java Persistence (JPA) 2.0 praktycznie - zestawienie środowiska z EclipseLink i Apache Maven 2

14 komentarzy
Spisałem scenariusz (artykuł Java Persistence (JPA) 2.0 praktycznie - zestawienie środowiska z EclipseLink i Apache Maven 2) i kolejnego dnia przyszło do kręcenia filmiku.

Mimo swoich wad reżyserskich, miernej gry aktorów (poza tymi technologicznymi) i jego dopadło światło dzienne. Na YouTubie pojawił się bez fanfar, nagrody Grammy, Złotych Lwów, czy Oscara, ale doświadczenie jest zdecydowanie większe. Scrinkast można podziwiać na deskach YouTube - Java Persistence (JPA) 2.0 praktycznie - zestawienie środowiska z EclipseLink i Apache Maven 2.

Wiele w nim niedoskonałych cięć, ale z samego produktu jestem niezwykle zadowolony, bo jest to pierwsza edycja, która ujrzała światło dzienne z gadżetami w stylu podświetlanie, spowalnianie, wstawki tekstowe na rozpoczęcie odpowiedniej sesji nagranionej, więc dużo było przy tym pracy edycyjnej, ponagraniowej. Teraz pozostaje zrobić ostatni krok - podłożyć głos narratora, aby poza oglądaniem było trochę życia w nagraniach. Kiedy będzie głos w skrinkastach, będzie mi bliżej do zrealizowania jeszcze jednego pomysłu - podkastów. To takie połączenie przyjemnego z pożytecznym (co jest czym pozostawiam Waszej ocenie). W przypadku skrinkastów, ja kontroluję, co będzie powiedziane, a podkast uważam za ewaluację głosową, gdzie tych rozmówców oczekuje się więcej.

Komentarze odnośnie mojej dotychczasowej pracy nagraniowej są bezcenne na tym etapie, więc śmiało! Potrzeba mi wrażeń w stylu - co było denerwujące, czego za mało/dużo, długość nagrania i sam sposób przedstawiania - wklejanie kawałków kodu zamiast ich wpisywanie. Więcej ich, to mniej Waszego cierpienia później. To tak, jakby powiedzieć "Jak sobie pościelesz, tak się wyśpisz", co oznacza, że jeśli teraz pojawią się (dobre?) rady, to ich wdrożenie na tym etapie będzie przyczynkiem do moich przyzwyczajeń później. Nie ma obawy o mój stan psychiczny. Dam sobie radę nawet z komentarzami w stylu "Do kitu! Zajmij się lepiej hotdogami.", aczkolwiek preferowałbym w takiej sytuacji więcej argumentów.

Przydałaby się jakiś akompaniament muzyczny na podkład, coś w stylu muzyki poważnej, ale delikatnie. Propozycje propozycji pozbawionych praw autorskich, tj. możliwych do użycia bezpłatnie, mile widziane. Ten sam problem będzie i przy podkastach.

A teraz do skrinkasta...

28 stycznia 2010

Java Persistence (JPA) 2.0 praktycznie - zestawienie środowiska z EclipseLink i Apache Maven 2

5 komentarzy
Rozpocząłem lekturę pierwszej książki o najnowszych specyfikacjach spod parasola Java EE 6 - Pro JPA 2: Mastering the Java Persistence API z Apress. Po kilku dniach znalazłem się przy rozdziale 6tym i muszę przyznać, że minęło niewiele ponad 150 stron (z prawie 400), a ja jestem padnięty nawałem informacji. Książka pretenduje do miana książki roku w moim osobistym rankingu książek informatycznych ze względu na formę przekazywania wiedzy w sposób dokładny i przystępny. Mnogość przykładów i wyjaśnień nie pozostawia złudzeń, że to prawdziwa składnica wiedzy mimo, że do końca jeszcze daleko - ja już mam wrażenie, jakbym znał specyfikację JPA2 od podszewki. Oczywiście nie znam, ale moja wiedza teoretyczna wzrosła znacząco. Bardzo podobają mi się dywagacje nt. różnych wzorców projektowych i ich znaczenia w ewolucji JPA2, albo odwrotnie, ich uproszczeniom ze względu na zmiany w JPA2. W przypadku poprzednich książek, jakie ostatnio przeczytałem, normą było przejście przez 1 rozdział w ciągu 1 dnia. Z "Pro JPA 2: Mastering the Java Persistence API" sytuacja zmieniła się diametralnie - nie rozdział/dzień, ale rozdział/3 dni zdaje się być bardziej odzwierciedlający rzeczywistość. Nie sądzę, aby wynikało to z braku cierpliwości, czy coś w ten deseń, ale po prostu z natłoku informacji, jakie przewijają się przez każdą przeczytaną stronę. Jeśli do tej pory, zaznaczałem kilka fragmentów tekstu do późniejszej analizy, to teraz są to całe sekcje (!) Jestem przerażony skomplikowaniem JPA, skoro potrzebna była taka książka, aby wyjaśnić zasady rządzące specyfikacją. Nie jest to wcale wina JPA, ale samego problemu obiektowej reprezentacji danych relacyjnych, którego rozwiązania szukano przez tyle lat i wciąż nie ma tego jedynego.

Pod wpływem uroków JPA2 z "Pro JPA 2: Mastering the Java Persistence API" postanowiłem zestawić środowisko do nauki specyfikacji i tak powstał artykuł Java Persistence (JPA) 2.0 praktycznie - zestawienie środowiska z EclipseLink i Apache Maven 2. Początkowo spisywałem kroki, aby przymierzyć się do screencastu, ale skoro już pojawił się artykuł, pomyślałem, że z nim zawojuję świat :) W artykule wykorzystałem EclipseLink (referencyjna implementacja JPA2), Apache Maven 2 oraz NetBeans IDE i Mercuriala. Pomyślałem o wystawieniu projektu w sieci w jakieś przystępnej formie i padło na Google Code z włączonym Mercurialem. W ten sposób można popróbować się z rozproszonym repozytorium hg i JPA2 jednocześnie. To lubię. Uwagi mile widziane.

p.s. Dostałem informację od Suna, od Oliwi, w związku z tematem Pakiety certyfikacyjne od Suna za 600 PLN do końca stycznia. Dzisiaj, 28.01.2010, jest ostatnim dniem ważności oferty. Śpieszcie się!

23 sierpnia 2008

maven-jetty-plugin i JPA ze springowym SimpleLoadTimeWeaver

0 komentarzy
W mojej krucjacie ku stworzeniu aplikacji webowej z użyciem minimalnego zestawu uruchomieniowego, z facelets oraz maven-jetty-plugin dotarłem do momentu, w którym koniecznym stało się wykorzystanie jakiegoś rozwiązania ORM (mapującego dane relacyjne na obiektowe i vice versa). Nie będę zbyt odkrywczy, jeśli napiszę, że padło na JPA (Java Persistence API). Przypomnę, że nie mam do dyspozycji serwera aplikacyjnego Java EE 5, np. Apache Geronimo, więc postanowiłem skorzystać ze Spring Framework. Zwrócenie się ku Spring Framework było podyktowane chęcią utrzymania minimalnego zestawu uruchomieniowego, którego uruchomienie sprowadzało się do mvn clean jetty:run. Konfigurację JPA oparłem na opisanej w artykule Apache Wicket z JPA z pomocą Spring Framework i Apache Maven 2. Jedyną znaczącą zmianą w stosunku do konfiguracji z artykułu było skorzystanie ze Spring Framework 2.5.5. Ku mojemu zaskoczeniu pierwsze uruchomienie zakończyło się wyjątkiem:
 31  faceletsPU  WARN   [main] openjpa.Runtime - An error occurred while registering a ClassTransformer with PersistenceUnitInfo: 
name 'faceletsPU', root URL [file:/C:/projs/sandbox/facelets-spring/target/classes/].
The error is logged along with this warning. Load-time class transformation will not be available.
java.lang.IllegalStateException: Must start with Java agent to use InstrumentationLoadTimeWeaver. See Spring documentation.
at org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver.addTransformer(InstrumentationLoadTimeWeaver.java:88)
at org.springframework.orm.jpa.persistenceunit.SpringPersistenceUnitInfo.addTransformer(SpringPersistenceUnitInfo.java:80)
at org.apache.openjpa.persistence.PersistenceProviderImpl.createContainerEntityManagerFactory(PersistenceProviderImpl.java:126)
at org.apache.openjpa.persistence.PersistenceProviderImpl.createContainerEntityManagerFactory(PersistenceProviderImpl.java:53)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:224)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:291)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1368)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
Rozwiązaniem okazało się zmiana atrybutu loadTimeWeaver w konfiguracji org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean na org.springframework.instrument.classloading.SimpleLoadTimeWeaver, czyli ostatecznie sekcja dotycząca konfiguracji fabryki zarządcy utrwalania w applicationContext.xml wygląda następująco:
 <bean id="entityManagerFactory" 
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="oracleDS" />
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver" />
</property>
</bean>
Więcej informacji o konfiguracji JPA w Spring Framework, w rozdziale 12.6 "JPA" dokumentacji The Spring Framework - Reference Documentation.

10 lipca 2008

Mapowanie encji w JPA - Strategia złączeniowa

1 komentarzy
Dobrym miernikiem nabytej wiedzy o Korporacyjnej Javie 5 (Java EE 5) może być podejście do egzaminów SCBCD, SCWCD czy SCEA , ale również aktywne uczestnictwo w grupach dyskusyjnych poruszających tą tematykę. Jedną z takich grup jest grupa dyskusyjna użytkowników serwera aplikacyjnego Java EE 5 - Apache Geronimo - user@geronimo.apache.org. Ostatnie pytanie error writing tuple to database "the owning entity is not mapped" geronimo 2.1.1 zdopingowało mnie do dokładniejszego przyjrzenia się tematowi odwzorowywania hierarchii dziedziczenia obiektowego klas encji na struktury relacyjne w bazie danych. W zasadzie teoretycznie temat został przedstawiony w mojej relacji z lektury specyfikacji Java Persistence API (JPA) - Java Persistence - Rozdział 2 Entities zakończony, ale pewnie z braku przykładów czułem pewien niedosyt.

Tak rozpoczyna się kolejny artykuł mojego autorstwa Mapowanie encji w JPA - Strategia złączeniowa, do lektury którego zapraszam. Uwagi/komentarze i pomysły dalszych materiałów mile widziane. Miłej lektury!

20 maja 2008

Dalsze atrakcje aplikacji JDA z JPA - @Enumerated

3 komentarzy
Kolejny dzień potyczek z aplikacją zbudowaną przy pomocy JDA (Java Desktop Application). Właśnie niedawno natrafiłem na ten skrót i zaskoczyła mnie zbieżność z JPA (Java Persistence API), którą również wykorzystuję w aplikacji Przychodnia. Jednym z zadań, jakie zaplanowałem w kontekście udoskonalania aplikacji była migracja pola plec typu boolean na typ wyliczeniowy (enum). Pamiętałem jeszcze z lektury specyfikacji i rozmów na grupach, że typy wyliczeniowe nie są czymś nadzwyczajnym dla JPA, więc nie spodziewałem się wielkich trudności, a mimo to i tak owa prostota rozwiązania zaskoczyła mnie.

Najpierw lektura specyfikacji JPA - rozdział 9.1.21 Enumerated Annotation (strona 181):

Domyślnie pole typu wyliczeniowego utrwalane (zapisywane) jest w bazie danych po jego liczbie porządkowej (wywołanie metody java.lang.Enum.ordinal()). Za pomocą adnotacji @Enumerated określany jest sposób mapowania pola typu wyliczeniowego, jako uzupełnienie dane z adnotacji @Basic (oczywiście adnotacja nie jest konieczna w wielu sytuacjach, więc najczęściej bazuje się na wartościach domyślnych adnotacji @Basic). Klasa java.lang.Enum, która reprezentuje wszystkie typy wyliczeniowe w Javie dostarcza dwie metody - ordinal() oraz name(), które uczestniczą w mapowaniu pola wyliczeniowego na struktury bazodanowe. Pierwsza z nich ordinal() wywoływana jest przy konfiguracji ORDINAL dla adnotacji @Enumerated, a druga przy wartości STRING. Domyślnie zakłada się ORDINAL, więc wszystkie typy wyliczeniowe będą zapisywane w bazie jako liczby porządkowe. Za pomocą STRING do bazy trafiają nazwy wartości typu wyliczeniowego.

Adnotacje posiadają swoje odpowiedniki w postaci elementów w pliku konfiguracji mapowania JPA, którym domyślnie jest META-INF/orm.xml (inne można wskazać za pomocą elementu mapping-file w META-INF/persistence.xml - "sercu" konfiguracji JPA lub nie wprost poprzez element jar-file). Odpowiednikiem xmlowym (zawartym w pliku orm.xml) adnotacji @Enumerated jest element enumerated (podelement basic), który akceptuje dwie wartości ORDINAL (domyślna) i STRING.

W mojej aplikacji Przychodnia zadeklarowałem typ wyliczeniowy pl.jaceklaskowski.przychodnia.model.Plec (początkowo był on w ramach klasy Pacjent, ale okazało się, że JDA narzekał na zagnieżdzenie klas wykorzystywanych do mapowania JPA).
 package pl.jaceklaskowski.przychodnia.model;

public enum Plec {

KOBIETA('K', "Kobieta"), MEZCZYZNA('M', "Mężczyzna");

private final char kod;
private final String nazwa;

Plec(char kod, String nazwa) {
this.kod = kod;
this.nazwa = nazwa;
}

public char kod() {
return kod;
}

@Override
public String toString() {
return this.nazwa;
}

public static Plec valueOf(int cyfra) {
return cyfra % 2 == 0 ? KOBIETA : MEZCZYZNA;
}

}
W pliku mapowania JPA - META-INF/orm.xml - wystarczyło dodać
 <basic name="plec" optional="false">
<enumerated>STRING</enumerated>
</basic>
aby do bazy trafiały napisy w postaci MEZCZYZNA lub KOBIETA. Nie rozwiązałem jeszcze kwestii zapisywania samych kodów typów, np. M dla mężczyzny, a K dla kobiety (ma ktoś pomysł jak to zrealizować, aby kod typu był wartością w bazie danych?).

Przy okazji zastosowania typu wyliczeniowego skorzystałem ze statycznego importu (import static) i kod stał się bardziej przejrzysty i czytelny. Wychodzę z założenia, że najpierw działający kod w wersji 1.0, a później jego uaktrakcyjnianie w kolejnych wersjach. W ten sposób podszedłem właśnie do zadania aplikacji Przychodnia.

Dodatkowo pola plec oraz wiek są ustawiane na podstawie obowiązkowego peselu, co sprowadziło się do następującej konstrukcji:
 protected void ustawWiekPlecNaPodstawiePeselu() {

// za Wikipedią o wieku w PESELu:
// http://pl.wikipedia.org/wiki/PESEL#P.C5.82e.C4.87
// Numeryczny zapis daty urodzenia przedstawiony jest w następującym porządku:
// dwie ostatnie cyfry roku, miesiąc i dzień.
// Dla odróżnienia poszczególnych stuleci przyjęto następującą metodę kodowania:
// * dla osób urodzonych w latach 1900 do 1999 - miesiąc zapisywany jest w sposób naturalny
// * dla osób urodzonych w innych latach niż 1900 - 1999 dodawane są do numeru miesiąca następujące wielkości:
// o dla lat 1800-1899 - 80
// o dla lat 2000-2099 - 20
// o dla lat 2100-2199 - 40
// o dla lat 2200-2299 - 60
int rokDzisiaj = Calendar.getInstance().get(Calendar.YEAR);
int rok = Integer.valueOf(this.pesel.substring(0, 2));
int miesiac = Integer.valueOf(this.pesel.substring(2, 4));
if (miesiac > 80) {
miesiac -= 80;
rok += 1800;
} else if (miesiac > 60) {
miesiac -= 60;
rok += 2200;
} else if (miesiac > 40) {
miesiac -= 40;
rok += 2100;
} else if (miesiac > 20) {
miesiac -= 20;
rok += 2000;
} else {
rok += 1900;
}
this.wiek = rokDzisiaj - rok;
if (this.wiek <= 0) {
throw new IllegalArgumentException("Niedozwolony wiek " + this.wiek + " [PESEL:" + this.pesel + "]");
}

// za Wikipedią o płci w PESELu:
// http://pl.wikipedia.org/wiki/PESEL#P.C5.82e.C4.87
// Informacja o płci osoby, której zestaw informacji jest identyfikowany,
// zawarta jest na 10 (przedostatniej) pozycji numeru PESEL.
// * cyfry parzyste (0, 2, 4, 6, 8) – oznaczają płeć żeńską
// * cyfry nieparzyste (1, 3, 5, 7, 9) – oznaczają płeć męską
this.plec = Plec.valueOf(Integer.valueOf(this.pesel.substring(9, 10)) % 2);
}
Coś mi mówi, że można byłoby to zrealizować prościej, ale nic na szybko nie przyszło mi do głowy, poza owym if-(else if)*-else. Sugestie mile widziane.

Niestety, sądziłem, że ta zmiana pociągnie za sobą zmiany w tworzonej dynamicznie tabeli przez JDA, tak że użytkownik będzie mógł wybrać płeć pacjenta z listy tworzonej na podstawie możliwych wartości typu wyliczeniowego, ale nic takiego się nie wydarzyło. W zamian pole stało się niemodyfikowalne, co w zasadzie jest równie dobre, gdyż jego wartość i tak wyliczana jest na podstawie obowiązkowego peselu.

Jutro zaplanowałem zabawę z formatowaniem danych w JTable podczas wyświetlania (renderery komórek) i edycji (edytory komórek).

16 maja 2008

Tworzenie aplikacji desktopowej z Java Desktop Application w NetBeans IDE 6.1

4 komentarzy
W środę żona zrobiła mi niesamowitą niespodziankę! Bodajże na miesiąc przed spytała jedynie, czy mam czas w środę o 19:00 i tyle. Jakbym mógł odmówić mojej Agatce?! Oczywiście wszystkie możliwe inicjatywy przeniosłem zaraz na bezpieczniejszy czwartek i cierpliwie czekałem. W końcu okazało się, że owa niespodzianka to wyjście do Teatru Bajka na przedstawienie Goło i wesoło. Jeju, ale to było przedstawienie! Prawie umarłem ze śmiechu. Płacz murowany! Do tej pory kiedykolwiek przypomnę ją sobie, nie mogę powstrzymać się ze śmiechu. To jest obowiązkowy spektakl, dla każdego lubującego się w dobrze dobranym humorze z doborową obsadą aktorską. Po prostu cudeńko. Nie będę rozpisywał się na temat sztuki, bo szkoda byłoby uchylić chociażby rąbek tajemnicy na temat sztuki. Wystarczy, że napiszę, że jestem gotów iść na nią kolejny raz. Normalnie Góra, Żmuda, Bugi, Gustaw (szczególnie w drugiej części), Norbert i Kierownik to mistrzostwo świata w dobrym humorze. Ubaw po pachy! Dzięki Agata za wspaniały wybór!

A wracając do Javy to ostatnio natrafiłem na ciekawe zadanie, które dotyczyło stworzenia aplikacji desktopowej korzystającej z bazy danych. Czasu na jej utworzenie nie było wiele i wskazano na NetBeans IDE 6.1 jako narzędzie, które w ciekawy sposób upraszcza jej tworzenie za pomocą projektu Java Desktop Application. Podczas rozpoznawania funkcjonalności NetBeans natrafiłem na ciekawy wycinek specyfikacji Java Persistence API (JPA), gdzie mapowanie relacji jeden-do-wielu (adnotacja @OneToMany lub element <one-to-many>) można sprowadzić do konfiguracji opartej o 2 tabele z pojedyńczym kluczem obcym (z domyślnie wykorzystywanych 3 tabel z dwoma kluczami obcymi w tabeli łączącej). Użyteczna funkcjonalność NetBeans IDE 6.1 i ciekawostka JPA to równie ciekawie spędzony czas, co zaowocowało nowym artykułem Tworzenie aplikacji desktopowej z Java Desktop Application w NetBeans IDE 6.1. Zapraszam do lektury, a znudzonych siedzeniem przed kompem na spektakl Goło i wesoło. Koniecznie napisz, jak podobał się spektakl. Dla mnie był najwyższych lotów.

p.s. Kilka godzin temu przejeżdżałem koło podwrocławskiej wioski Jugowiec (a może to było miasto?). Jakby na przypomnienie, że niedługo JAVArsovia 2008 (dokładnie za 2 tygodnie - 31 maja 2008), gdzie jugowiczów będzie co nie miara. Ciekawe, czy będzie ktoś z podwrocławskiego Jugowca? Zapraszam! Wstęp wolny.

15 marca 2008

Apache Wicket z JPA z pomocą Spring Framework i Apache Maven 2

0 komentarzy
Kolejne wrażenia z pracy z Wicket w połączeniu z JPA i Spring Framework zaowocowały artykułem Apache Wicket z JPA z pomocą Spring Framework i Apache Maven 2 w moim Notatniku-Wiki. Dużo dobrej zabawy podczas zestawiania środowiska przypominającego serwer aplikacyjny Java EE z pomocą Spring Framework. Do tego wykorzystałem JPA do obsługi danych a całością zarządzał Apache Maven 2, co m.in. sprowadziło uaktualnienie Wicketa do wersji 1.3.2 do niewielkiej modyfikacji pom.xml. Zresztą podobnie było i ze Springiem, który również pojawił się w wersji 2.5.2. Najciekawszym elementem artykułu, jakkolwiek o Wicket, jest sama konfiguracja Springa, w taki sposób, że w żaden sposób nie wpłynął na inne pliki aplikacji. W zasadzie mógłbym wyrzucić Springa z aplikacji i nie wymagałoby to żadnej zmiany (poza klasą pl.jaceklaskowski.wicket.model.OsobaDaoImpl, gdzie użyłem adnotacji @Transactional, bez której babranie się z konfiguracją xmlową byłoby dla mnie marnotrawstem czasu). Ciekawym dodatkiem jest konfiguracja encji Osoba bez użycia adnotacji za pomocą pliku orm.xml. W ten sposób klasa encji w żaden sposób nie przypomina encji JPA. Jest to przykład bezinwazyjnej konfiguracji, gdzie istnienie pliku orm.xml potrafi zmienić zachowanie klasy. Poza tym konfiguracja Wicketa ze Springiem i dodanie JPA do pobrania danych z bazy danych HSQLDB uruchamianej w pamięci daje niezwykłe pole do popisu dla dalszych możliwych rozszerzeń w aplikacji. Zaczyna być niezwykle ciekawie. Zachęcam do lektury artykułu i przesyłanie komentarzy. Ciekawym ich bardzo.

W międzyczasie rozwiązano moje zgłoszenie WICKET-1333 Update wicket javadoc to 1.3.1 and place it on wicket.apache.org for stable referencing dotyczące stabilnego miejsca do publikacji javadoc Wicketa i teraz dostępne jest w menu Documentation > JavaDocs, tj. http://wicket.apache.org/docs/wicket-1.3.2/wicket/apidocs/index.html dla ostatniej wersji produkcyjnej 1.3.2.

19 grudnia 2007

Ciekawostki JPA z XX spotkania Warszawa JUG

0 komentarzy
Podczas wczorajszego, XX spotkania grupy Warszawa JUG tematem przewodnim było Java Persistence API (JPA). Zajęliśmy się aktualizacją bazy danych przez dostawcę JPA o zmiany w encjach w trakcie trwania transakcji. Temat wcześniej opisałem w artykule Zasady zapisu zmian do bazy danych w JPA. Okazało się, że z 3 dostawców JPA - Apache OpenJPA, Hibernate EntityManager i TopLink Essentials, jedynie dwa ostatnie - Hibernate i TopLink działają tak samo, tzn. podczas pierwszego testu można zauważyć, że przed wykonaniem zapytania oba zapisują zmiany w bazie danych, a następnie wykonują zapytanie. W przypadku OpenJPA tak się nie dzieje. I tu możnaby zastanowić się, czy przypadkiem nie jest to błąd (!)

Piotr Tabor zauważył ciekawą rzecz, która unaocznia potencjalny problem z OpenJPA. Zmodyfikujmy zadanie o wyszukanie encji Osoba, których imię to Agata. Czego możemy spodziewać się od następującego fragmentu kodu?

System.out.println("\n=== Test #1: FlushModeType.AUTO z transakcja ===");

em.getTransaction().begin();
Osoba osoba = em.find(Osoba.class, osobaId);

System.out.println("\n>>> Zmieniamy imie osoby\n");
osoba.setImie("Agata");

System.out.println(">>> Wczytujemy wszystkie osoby\n");
Query query = em.createNamedQuery("Osoba.osobyPoImieniu");
query.setParameter("imie", "Agata");
List osoby = query.getResultList();
System.out.println("\n>>> Wszystkie osoby wczytane\n");

assert osoby.size() == 1 : "Liczba osób powinna być 1";
assert osoby.get(0).getImie().equals("Agata") : "Oczekujemy Agaty";

System.out.println(">>> Zatwierdzamy transakcje\n");
em.getTransaction().commit();

Czy oba warunki określone przez instrukcje assert powinny być spełnione? Z niecierpliwością czekam na odpowiedzi ;-) Zainteresowanych potyczkami z JPA zachęcam do skorzystania ze wspomnianego artykułu, w którym jest gotowe środowisko do odtworzenia sytuacji. Nie należy zapominać o stworzeniu zapytania nazwanego Osoba.osobyPoImieniu.

16 grudnia 2007

Zasady zapisu zmian do bazy danych w JPA

0 komentarzy
Z każdym dniem na grupie pl.comp.lang.java pojawiają się coraz ciekawsze pytania i problemy związane z Java Persistence API (JPA) oraz Enterprise JavaBeans 3.0 (EJB3). Tym razem Marx zadał pytanie o zasady rządzące zapisem zmian encji do bazy danych w JPA - EJB3 - select robi update. W ten sposób sprowokował mnie do napisania kolejnego artykułu z serii przedstawiającej tajniki specyfikacji JPA - Zasady zapisu zmian do bazy danych w JPA.

Podobnie jak w poprzednich artykułach dotyczących JPA - Dynamiczny dostęp do wielu baz danych w JPA oraz Testowanie złączeń FETCH JOIN w JPA artykuł rozpoczyna się od przedstawienia teorii JPA, którą następnie zademonstrowałem w działaniu za pomocą aplikacji demonstracyjnej. Skorzystałem z konfiguracji projektu nadzorowanego przez Apache Maven 2, aby możliwe było uruchomienie go z 3-ma głównymi dostawcami JPA - Apache OpenJPA, Hibernate EntityManager oraz TopLink Essentials.

Drobnym acz ciekawym elementem konfiguracji Maven2 na potrzeby naszego projektu jest zależność javax.persistence.persistence-api, która występuje w wersji 1.0 w repozytorium Maven 2 oraz w wersji 1.0.2 w repozytorium Maven 1 na java.net. Biorąc pod uwagę, kto nadzoruje wersjami w repozytorium java.net (Sun) wydaje się być stosowne stosowanie bibliotek Korporacyjnej Javy właśnie z tego repozytorium. I tak też czynię w artykule.

14 grudnia 2007

Dynamiczny dostęp do wielu baz danych w JPA

1 komentarzy
Kolejny raz zostałem zainspirowany przez użytkownika grupy pl.comp.lang.java. Tym razem, Michał Chmielarz zadał pytanie o Dostęp do wielu baz danych przez JPA w ramach EJB 3.0, które sprowokowało mnie do dokładniejszego spojrzenia we wnętrze JPA. Już wczoraj próbowałem się z tematem z użyciem Raven i Buildr, ale nie miałem wiele szczęścia z nimi i ostatecznie skorzystałem ze sprawdzonego Mavena 2. Zresztą nie tak dawno zestawiłem środowisko do pracy z JPA z wykorzystaniem Maven (Testowanie złączeń FETCH JOIN w JPA), więc miałem w zasadzie wszystko gotowe.

W moim kolejnym artykule nt Java Persistence API (JPA) - Dynamiczny dostęp do wielu baz danych w JPA pobieżnie wprowadzam do teorii JPA w kontekście dynamicznego zarządzania wieloma bazami danych, po którym demonstruję kompletną (acz bardzo podstawową) aplikację w działaniu z wykorzystaniem zaprezentowanej teorii. Miłej lektury!

08 grudnia 2007

Wrażenia po wykładzie o EJB3/JPA na Politechnice Poznańskiej

1 komentarzy
Jak to ze mną bywa i tym razem nie starczyło czasu, aby treściwie przedstawić EJB3/JPA i jednocześnie w pełni zaangażować audytorium do dyskusji. Starałem się jak mogłem, obiecywałem sobie, że nie będzie wycieczek myślowych, dywagacji, żartów, itp., ale nie mogłem się opanować...a wszystko za sprawą dobrej atmosfery podczas prezentacji, w której dało się odczuć zainteresowanie tematem.

Chciałbym tym samym gorąco podziękować dr Dawidowi Weissowi za zaproszenie mnie na Politechnikę Poznańską celem przedstawienia tematu EJB3/JPA dla tak wspaniałego audytorium. Bawiłem się dobrze i wierzę, że inni również.

Zaczęliśmy o 13:30 po tym, jak widząc więcej, niż przewidywaną liczbę, osób zdecydowaliśmy się na zmianę sali na większą. Sala pierwsza klasa. Nie liczyłem ile osób przyszło, ale możnaby naliczyć około 80 osób (w tym kilka kobiet!). I muszę przyznać, że audytorium nie zawiodło. Tak mi się świetnie dyskutowało na tematy EJB3 i (pobieżnie) o JPA, że czas minął tak szybko, że nie mogłem uwierzyć, że prezentacja dobiegła końca - wybiła 16:15, a o 16:44 miałem pociąg powrotny do Warszawy. Ledwie zdążyłem na pociąg. Ech, szkoda, że to tak szybko minęło. Zaprezentowałem około 20 slajdów (z 60 dostępnych!) i widząc wlepione we mnie oczy błagające o coś ciekawszego na moje pytanie o prezentację tematu za pomocą przykładów - jakby publikę coś trafiło. Wszyscy się ożywili i na prawdę było widać duże zainteresowanie. Zanim zacząłem zabawę zapytałem o użycie narzędzi. Przeczuwając, że NetBeans może nie cieszyć się dużą popularnością, zapytałem o jego użycie. Naliczyłem około 6 osób. Po tym zapytałem o vi (tak przypadkiem dla poprawy nastroju) i okazało się, że więcej osób podniosło ręce niż przy NetBeans (!). Kiedy w końcu zapytałem o Eclipse miałem wrażenie, że wszyscy podnieśli ręce. Było to jedyne pytanie tak licznie przyjęte z aprobatą wszystkich. Kiedy, więc oznajmiłem, że przykłady będą prezentowane z użyciem...NetBeans powiało grozą. Nie trwało to jednak długo, bo wsparcie dla tworzenia aplikacji korporacyjnych w Javie to jedna z cech wiodących NetBeans. Pojawiła się nawet sugestia, aby nie korzystać ze skrótów klawiszowych, aby można było śledzić poszczególne kroki dokładniej. Podobnie z przyjęciem było w przypadku serwerów aplikacyjnych - wielu miało do czynienia z JBoss AS, niektórzy pracowali z Glassfish, ale nikt nie zgłosił się przy pytaniu o użycie Apache Geronimo (musiałem wywołać kogoś z tłumu dla poprawienia sobie samopoczucia ;-)). Zaprezentowałem kilka przykładowych aplikacji z użyciem NetBeans 6 oraz Glassfish v2 i dopiero, co zacząłem, a już musiałem kończyć. Szkoda.

Głosy jakie mnie dochodzą mogą świadczyć, że moja prezentacja o EJB3/JPA mogła się podobać, ale są też takie, które wskazują na pewne niedopracowanie tematu od strony samego prowadzenia prezentacji. Jak zwykle górę wzięła moja chęć przedstawienia tematu o EJB3/JPA w 2,5 godziny z najdrobniejszymi szczegółami (co wydaje mi się teraz za zadanie niemożliwe do wykonania, gdyż nawet przy 5 dniach warsztatów możnaby spodziewać się, że nie wszystkich mogłoby to satysfakcjonować pod względem dostępnego czasu).

Były takie głosy (od Darka):

feedback po wykładzie.

Generalnie super! Ale...

Było ciężko, skakanie po tematach, wchodzenie w szczegóły nie zawsze potrzebnie :/ Zrzuciłeś odpowiedzialność za przebieg wykładu na publiczność, kiepski pomysł. To wykładowca wie lepiej w jakiej kolejności i o czym mówić na temat danej technologii. (ludzie nie znający EJB nie mogli podpowiadać na jaki tamt mówić bo nie wiedzieli, ci znający pytali o szczegóły :/)

Generalnie udało mi się połapać, jednak przez to zamieszanie, pozostał niedosyt i wątpliwość, czy aby na pewno wiem już o co chodzi w EJB3 :/

Mimo tego, wykład bardzo mi się podobał! Dzięki, że przyjechałeś, że podzieliłeś się z nami swoją pasją! Super!


ale też i takie (to już z mojej skrzynki od Marcina):

Chciałbym podziękować za prelekcje na Politechnice Poznańskiej, która odbyła się w dniu wczorajszym.
Muszę przyznać, że przeżyłem 6 lat wykładów na Politechnice Gdańskiej oraz kilkanaście szkoleń w pracy zawodowej jednak muszę przyznać, że Twój wykład był poprowadzony w sposób fenomenalny i nie zdarzyło mi się być na żadnej inne prelekcji, która nie znudziła by mnie w ciągu 30 min.
Gratuluje podejścia do tematu. Myślałem, że w Polsce nie ma osoby, która byłaby wstanie podejść do tematu w sposób, który od wielu lat prezentują anglojęzyczni autorzy w swoich publikacjach (podejście do tematu w sposób luźny, a jednak bardzo merytoryczny).

Pozdrawiam i życze wielu sukcesów!!!


Mogę więc wnioskować, że jest jeszcze wiele do poprawienia, ale przy kilku dokładnych szlifach możnaby stworzyć jakąś serię wykładów poświęconych EJB3/JPA i na jej bazie stworzyć profesjonalne 5-dniowe szkolenie z przykładami i dokładnym omówieniem tematu. Pomysł mi się podoba. Są chętni, aby zagwarantować sobie (darmowe) miejsce przez zaproponowanie potencjalnych tematów? Jeśli męczy Cię jakikolwiek temat związany z EJB3/JPA już kolejny dzień i nie widać potencjalnego rozwiązania może wartoby zrzuć to na moje barki? Po co męczyć się samemu, jak ten czas możnaby poświęcić czemuś bardziej reklaksującego, np. siedzenie przed telewizorem z chipsami/paluszkami i napojem ;-)

Prezentacja dostępna jest do pobrania jako JacekLaskowski-PolitechnikaPoznanska-EJB3-07.12.2007.pdf.

Nota bene, pojawiły się głosy o moim potencjalnym wystąpieniu nt. Korporacyjnej Javy (może właśnie o EJB3/JPA) na Uniwersytecie Gdańskim. Kuba Neumann z Uniwersytetu Gdańskiego organizuje w semestrze letnim wykład poświęcony zaawansowanym technologiom w Javie. Spora część wykładów będzie poświęcona Korporacyjnej Javie (JSF, EJB, JPA, Web Services) i towarzyszącym nowoczesnym technologiom np. AJAX. Niektóre specjalistyczne wykłady wygłoszą zaproszeni goście.
Jeśli są chętni spoza Uniwersytetu Gdańskiego, którzy byliby zainteresowani w przedsięwzięciu oraz dyskusjach (w trakcie i po wykładach oraz na forum) sugeruje się kierowanie sugesti i wniosków bezpośrednio na jego ręce.

29 listopada 2007

Testowanie złączeń FETCH JOIN w JPA

0 komentarzy
Miało być prosto i szybko, bo planowałem to na nie więcej niż 30 minut. Skończyło się na kolejnym artykule i 1,5 dnia poszło w zapomnienie. Na szczęście wiedza pozostała i może się nawet okazać, że znalazłem błąd w OpenJPA w kontekście złączenia INNER JOIN. Na ostateczną ocenę przyjdzie mi jeszcze poczekać, a tym którzy nie mają zamiaru tego robić polecam lekturę mojego artykułu o złączeniach JPA - Testowanie złączeń FETCH JOIN w JPA.

A zaczęło się całkiem niewinnie, kiedy na grupie użytkowników Geronimo Tomasz Mazan (aka Beniamin) zadał pytanie Force to load subobjects in OpenJPA o wymuszenie wczytywania danych relacji w Java Persistence API (JPA). Domyślnie JPA wczytuje pola relacyjne z opóźnieniem, jednakże istnieje kilka możliwości zmiany tego zachowania. Tak się złożyło, że wcześniej badałem temat złączeń (ang. joins), więc krótka odpowiedź, uściślenie i ostatecznie problem został rozwiązany. Jest kilka możliwości zaprezentowania tematu, z czego ja wybrałem sposób praktyczny z kilkoma wspierającymi narzędziami. Będzie OpenJPA, Maven, JUnit 4 i Derby wszystko, aby zestawić środowisko do potwierdzenie działania złączeń w JPA. Miłej lektury!

28 października 2007

Aplikacja Java EE 5 z MDB z JPA w trybie JTA i PostgreSQL w Apache Geronimo 2

0 komentarzy
Podczas konferencji Java Developers Day 2007 w Krakowie, na której wystąpiłem z tematem Tworzenie aplikacji Java EE z Apache Geronimo 2 nie udało mi się zaprezentować wszystkich, 3-ech przykładów. Padło na najbardziej interesujący technologicznie przykład Ziarno MDB z JPA w trybie JTA. Nadrabiając straty udało mi się opisać to, co miało zostać powiedziane i stworzyłem kolejny artykuł przybliżający serwer Apache Geronimo wraz z ziarnem MDB i encji JPA w trybie JTA - Aplikacja Java EE 5 z MDB z JPA w trybie JTA i PostgreSQL w Apache Geronimo 2. Przykład prezentuje możliwości Geronimo w zakresie obsługi transakcji JTA w warstwie EJB 3.0, na poziomie MDB i JPA. W artykule zawarłem kilka informacji specyficznych dla Geronimo, co powinno przybliżyć sposób jego działania i być może sprowokować do dalszych prób technologicznych. Uruchomienie klienta zdalnego za pomocą wtyczki exec:exec mavena może być również ciekawe. Wszelkie komentarze o merytorycznej stronie artykułu mile widziane, a wskazówki do dalszych eksperymentów nawet bardziej. Miłej lektury!

p.s. Grupa Warszawa JUG organizuje warsztaty javowe - Warsjava - na których będzie dużo takich technologicznych perełek. Zapraszam zainteresowanych do udziału, czy to jako prelegent, czy uczestnik. Wstęp wolny, a dobrej, technicznej zabawy, będzie co nie miara!

14 października 2007

Konwertery w JavaServer Faces część 6

2 komentarzy
Podczas mojej prezentacji mechanizmu konwerterów w JSF korzystałem z pomocy tymczasowej klasy pl.jaceklaskowski.konwerter.TymczasowaBazaDanych, której czas się właśnie kończy. Klasę TymczasowaBazaDanych zastąpię bardziej wartościową usługą dostarczaną przez serwer aplikacji Java EE 5 - Java Persistence (JPA). Wprowadzenie JPA służy usprawnieniu działania konwertera stworzonego w poprzednich częściach z serii Konwertery w JavaServer Faces.

Zanim zacznę warto zauważyć, że do chwili obecnej przykłady można było uruchomić na kontenerze servletów, np. Apache Tomcat, Jetty, czy Resin. Kolejne zmiany będą wymagały pełnego serwera aplikacji Java EE (chociaż znawcy tematu JPA mogliby wskazać na taką konfigurację JPA, któraby tego nie wymagałaby). Poprzednie przykłady uruchamiałem na Glassfish, który jest serwerem aplikacji Java EE 5 i tak pozostanie i tym razem, więc dla mnie nie będzie żadnej zmiany środowiska (wybór podyktowany był wyłącznie wsparciem serwera przez NetBeans IDE 6.0).

W Konwertery w JavaServer Faces część 4 przedstawiłem sposób związania konwertera z kontrolką za pomocą atrybutu converter w h:selectOneMenu. Później, w Konwertery w JavaServer Faces część 5 wykorzystałem możliwość konfiguracji konwertera w pliku faces-config.xml. Wykorzystanie JPA zarządzanego przez serwer aplikacji wymaga, aby powrócić do wykorzystania możliwości atrybutu converter. Powód zostanie wyjaśniony za moment.

Rozpocznę od modyfikacji konwertera pl.jaceklaskowski.konwerter.PracownikConverter.

package pl.jaceklaskowski.konwerter;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.persistence.EntityManager;

public class PracownikConverter implements Converter {

private EntityManager em;

public PracownikConverter(EntityManager em) {
this.em = em;
}

public Object getAsObject(FacesContext context, UIComponent component, String value) {
return em.find(Pracownik.class, Long.valueOf(value));
}

public String getAsString(FacesContext context, UIComponent component, Object value) {
return Long.toString(((Pracownik) value).getNumer());
}
}
Zmiana polega na użyciu zarządcy trwałego JPA i tym samym usunięciu wykorzystania klasy pl.jaceklaskowski.konwerter.TymczasowaBazaDanych jako dostawcy informacji o pracownikach z bazy danych. Możnaby zapytać o cel wprowadzenia konstruktora konwertera z parametrem będącym zarządcą trwałym, skoro w środowisku serwera Java EE 5 można użyć adnotacji @PersistenceContext? Właśnie tu tkwi problem i to, co za chwilę zaprezentuję będzie możliwym obejściem braku obsługi konwerterów przez mechanizm wstrzeliwania zależności (ang. DI - dependency injection). Z niezrozumiałych dla mnie powodów, konwertery zostały wyłączone z obsługi mechanizmu DI, tj. nie są komponentami zarządzanymi z punktu widzenia specyfikacji Java EE 5, a tylko w nich można oczekiwać poprawnego działania adnotacji. Brak wsparcia dla DI dla konwerterów rekompensuję przez wprowadzenie konstruktora, który akceptuje parametr wejściowy będący referencją do egzemplarza typu javax.persistence.EntityManager (który, gdyby serwer Java EE 5 wspierał DI dla konwerterów byłby wstrzelowny automatycznie). Rozwiązanie będzie polegało na przekazaniu zarządcy encji z komponentu, który z funkcjonalności DI może korzystać. Warto więc odpowiedzieć na pytanie, który z elementów aplikacji JSF ma taką możliwość? Oczywiście jest to ziarno zarządzane (zgodnie z jego nazwą). Jeśli do tego dodać, że ziarno może udostępniać właściwość, której wartość może być wykorzystana w atrybutach kontrolek, np. converter, to dalsze kroki powinny być już jasne. Pora na zmiany w aplikacji.

Po pierwsze, aby skorzystać z JPA musimy ustanowić klasę pl.jaceklaskowski.konwerter.Pracownik encją JPA, co pociąga za sobą dodanie kilku adnotacji JPA (bądź ustawieniem odpowiedniej konfiguracji w pliku orm.xml). Wybieram podejście pierwsze - dodanie adnotacji. Zmienił się również konstruktor, który niepotrzebuje już parametru wejściowego numer, który od tej pory jest generowany automatycznie przez JPA.

package pl.jaceklaskowski.konwerter;

import java.io.Serializable;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@NamedQuery(name = "Pracownik.wszyscyPracownicy", query = "SELECT p FROM Pracownik p")
public class Pracownik implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long numer;

private String imie;

@Temporal(TemporalType.DATE)
private Date zatrudnionyOd;

public Pracownik() {
}

public Pracownik(String imie, Date zatrudnionyOd) {
this.imie = imie;
this.zatrudnionyOd = zatrudnionyOd;
}

public long getNumer() {
return numer;
}

public void setNumer(long numer) {
this.numer = numer;
}

public String getImie() {
return imie;
}

public void setImie(String imie) {
System.out.println("setImie(" + imie + ")");
this.imie = imie;
}

public Date getZatrudnionyOd() {
return zatrudnionyOd;
}

public void setZatrudnionyOd(Date zatrudnionyOd) {
System.out.println("setZatrudnionyOd(" + zatrudnionyOd + ")");
this.zatrudnionyOd = zatrudnionyOd;
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Pracownik other = (Pracownik) obj;
if (this.numer != other.numer) {
return false;
}
if (this.imie.equals(other.imie) && (this.imie == null || !this.imie.equals(other.imie))) {
return false;
}
if (this.zatrudnionyOd != other.zatrudnionyOd && (this.zatrudnionyOd == null || !this.zatrudnionyOd.equals(other.zatrudnionyOd))) {
return false;
}
return true;
}

@Override
public int hashCode() {
int hash = 5;
hash = 47 * hash + (int) (this.numer ^ (this.numer >>> 32));
hash = 47 * hash + (this.imie != null ? this.imie.hashCode() : 0);
hash = 47 * hash + (this.zatrudnionyOd != null ? this.zatrudnionyOd.hashCode() : 0);
return hash;
}
}
Metody equals() oraz hashCode(),które zazwyczaj są pomijane, w tym przypadku są kluczowe. Podczas kontroli poprawności wyboru (w etapie przetwarzania zlecenia JSF - uruchomienie kontrolerów - ang. process validations) tworzone są nowe egzemplarze Pracowników, które bez użycia wspomnianych metod, powodowałyby błąd kontroli. Gdyby, więc polegać na domyślnej implementacji metod, pojawiałby się błąd kontroli, gdyż sprawdzenie, czy wybrana opcja była na liście opcji odbywa się między innymi na podstawie porównania egzemplarzy przy pomocy metody equals(). Nieufnym polecam uruchomienie przykładu bez wspomnianych metod - equals() oraz hashCode(), a dla dociekliwych taką modyfikację aplikacji, aby equals() straciło na znaczeniu (podpowiedź: aktualna żywotność ziarna to pojedyńcze zlecenie - request).

Po zmianie konwertera modyfikuję ziarno zarządzane pracownikAgent, które jest reprezentowane przez klasę pl.jaceklaskowski.konwerter.PracownikAgent.

package pl.jaceklaskowski.konwerter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public class PracownikAgent {

private Pracownik pracownik;

@PersistenceContext
private EntityManager em;

public PracownikConverter getKonwerterDlaPracownika() {
return new PracownikConverter(em);
}

public void wykonajAkcje(ActionEvent event) {
System.out.println("Wykonano akcję z pracownikiem: " + pracownik);
}

public Collection<SelectItem> getPracownicySelectItems() {
Collection<SelectItem> pracownicy = new ArrayList<SelectItem>();
for (Pracownik p : getPracownicy()) {
pracownicy.add(new SelectItem(p, p.getImie()));
}
return pracownicy;
}

public List<Pracownik> getPracownicy() {
return em.createNamedQuery("Pracownik.wszyscyPracownicy").getResultList();
}

public Pracownik getPracownik() {
return pracownik;
}

public void setPracownik(Pracownik pracownik) {
this.pracownik = pracownik;
}
}
Zmiana polega na dodaniu właściwości konwerterDlaPracownika (metoda odczytująca - getKonwerterDlaPracownika()) oraz pola egzemplarza em, w której serwer aplikacji umieści zarządcę encji korzystając z adnotacji @PersistenceContext. Zmodyfikowana została również metoda getPracownicy(), która opiera swoje działanie na JPA poprzez zapytanie nazwane (mianowane) - Pracownik.wszyscyPracownicy - do pobrania listy wszystkich pracowników.

Wykorzystanie zarządcy encji wymaga stworzenia pliku konfiguracji JPA - persistence.xml.

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="Konwerter-czesc6PU" transaction-type="JTA">
<jta-data-source>jdbc/sample</jta-data-source>
<properties>
<property name="toplink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>
Przechodzę do utworzenia strony strona6.jsp.

<%@page contentType="text/html" pageEncoding="UTF-8"%>

<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Mini-aplikacja JSF - konwerter</title>
</head>
<body>
<f:view>
<h:form>
<h:selectOneMenu value="#{pracownikAgent.pracownik}"
converter="#{pracownikAgent.konwerterDlaPracownika}">
<f:selectItems value="#{pracownikAgent.pracownicySelectItems}" />
</h:selectOneMenu>
<br/>
<h:commandButton value="Zatwierdź" actionListener="#{pracownikAgent.wykonajAkcje}"/>
<br/>
<h:messages showSummary="true" errorStyle="color: red" />
</h:form>
</f:view>
</body>
</html>
Na stronie korzystam z przekazania konwertera do kontrolki h:selectOneMenu poprzez #{pracownikAgent.konwerterDlaPracownika}, czyli wywołanie metody PracownikAgent.getKonwerterDlaPracownika(), która z kolei utworzy nowy egzemplarz konwertera z przekazanym zarządcą encji.

W pliku faces-config.xml usuwamy sekcję dotyczącą związania konwertera PracownikConverter z klasą Pracownik.

<?xml version='1.0' encoding='UTF-8'?>

<faces-config version="1.2"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<managed-bean>
<managed-bean-name>pracownik</managed-bean-name>
<managed-bean-class>pl.jaceklaskowski.konwerter.Pracownik</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>pracownikAgent</managed-bean-name>
<managed-bean-class>pl.jaceklaskowski.konwerter.PracownikAgent</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>
I to wszystkie zmiany, aby oprzeć działanie konwertera na JPA i wykorzystać bazę danych z prawdziwego zdarzenia. Pozostało jeszcze kilka ciekawych usprawnień, które mógłbym wprowadzić do aplikacji, a które wynikają z zastosowania JPA, jednakże miałoby to niewielki związek z tematem przewodnim, więc pozostawiam je na później.

Dla pełności obrazu wprowadzonych zmian należy jeszcze wspomnieć o pewnej funkcjonalności, która służy jedynie do wypełnienia bazy danych pracownikami, aby można było w pełni zaprezentować działanie aplikacji. W obecnej konfiguracji każdorazowe uruchomienie aplikacji kasuje bazę danych i tworzy schemat ponownie. Pusta baza danych pracowników nie pozwoliłaby na wybór pracownika w liście rozwijalnej. Dla obejścia tej niedogodności, podczas uruchomienia aplikacji internetowej, deklaruję wykonywanie słuchacza pl.jaceklaskowski.konwerter.DodajPracownikowListener.

package pl.jaceklaskowski.konwerter;

import java.util.Calendar;
import java.util.Date;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.transaction.UserTransaction;

public class DodajPracownikowListener implements ServletContextListener {

@PersistenceContext
EntityManager em;

@Resource
UserTransaction ut;

public void contextInitialized(ServletContextEvent event) {
System.out.println("Dodaję pracowników do bazy danych");
Date dzisiaj = Calendar.getInstance().getTime();
Pracownik agata = new Pracownik("Agatka", dzisiaj);
Pracownik jacek = new Pracownik("Jacek", dzisiaj);
try {
ut.begin();
em.persist(em.merge(agata));
em.persist(em.merge(jacek));
ut.commit();
} catch (Exception e) {
System.out.println("Ignorowany wyjątek: " + e.getLocalizedMessage());
}
}

public void contextDestroyed(ServletContextEvent event) {
}
}
, który zarejestrowany jest w głównym pliku konfiguracyjnym aplikacji internetowej - web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>com.sun.faces.verifyObjects</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.validateXml</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<listener>
<listener-class>pl.jaceklaskowski.konwerter.DodajPracownikowListener</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
</web-app>
Ciekawostką słuchacza DodajPracownikowListener jest skorzystanie z adnotacji @PersistenceContext oraz @Resource do wykorzystania z JPA.

Uruchomienie aplikacji nie zmienia się w stosunku do poprzednich części, więc pozostawiam to jako zadanie domowe. Przedstawię jedynie fragment dziennika zdarzeń Glassfish, który wskazuje na wykorzystywanego dostawcę JPA jakim jest TopLink Essentials 2.0.

Initializing Sun's JavaServer Faces implementation (1.2_04-b20-p03) for context '/konwerter'
Dodaję pracowników do bazy danych
TopLink, version: Oracle TopLink Essentials - 2.0 (Build b58g-fcs (09/07/2007))
Server: unknown
file:/Konwerter-czesc6/build/web/WEB-INF/classes/-Konwerter-czesc6PU login successful
Wykonano akcję z pracownikiem: pl.jaceklaskowski.konwerter.Pracownik@b73d3e3
Gotowy projekt aplikacji Konwerter dostępny jest jako jsf-konwerter-czesc6.zip.

Tym samym zakończyłem prezentację konwerterów JSF wieńcząc dzieło użyciem JPA. Dalsze udogodnienia mogłyby wykorzystać kolejne możliwości EJB3, m.in. ziarno bezstanowe do interakcji z JPA w celu usunięcia użycia transakcji po stronie aplikacji internetowej, itp. Wszelkie sugestie mile widziane.

Niepokoi mnie brak komentarzy do poszczególnych części serii o konwerterach JSF. Czyżby wszystko było jasne i działało od pierwszego uruchomienia?! Z ankiety Czy odpowiada Ci sposób prezentacji tematu w postaci krótkich części jak Konwertery JSF? wydaje się, że prezentacja tematu zdaje się być odpowiednia dla 14 osób, co cieszy, jednakże aż 3 osoby nie są w pełni zadowolone. Dlaczego? Dobrze byłoby podnieść swój warsztat techniczny uwzględniając ich uwagi (a może niekoniecznie techniczy, a literacki ;-)).

Przy okazji, dzisiejsze otwarcie NetBeans IDE 6.0 Nightly prezentuje Start Page z tłumaczeniem mojego artykułu Building an EJB 3.0 application using GlassFish v2, Apache Maven 2 and NetBeans IDE 6.0 (polska wersja to Tworzenie aplikacji EJB 3.0 z GlassFish v2, Apache Maven 2 i NetBeans IDE 6.0).

04 października 2007

Kwadrans w Bibliotece z JSF 1.2, EJB 3.0 i JPA

3 komentarzy
Podczas ostatniego spotkania Warszawa JUG Wiktor Gworek przedstawił temat związany bardzo blisko z tematami, z którymi ostatnio przyszło mi się zmagać - głównie JPA oraz JSF. Jakież było moje zdziwienie, kiedy znaleziska jakie udało mi się znaleźć i z których byłem niezwykle dumny, pojawiły się na...prezentacji Wiktora (!) Moje zdziwienie było tym większe, kiedy Wiktor przedstawił się jako 2-latek w tworzeniu aplikacji z Korporacyjną Javą, a może nawet z jej standardową wersją. Na szczęście jednak Wiktor skoncentrował się na zestawieniu całego środowiska poza serwerem aplikacji Java EE 5, co pozwoliło mi na zachowanie twarzy i opisanie moich dokonań w postaci kolejnego artykułu Kwadrans w Bibliotece z JSF 1.2, EJB 3.0 i JPA, który opisuje aplikację Biblioteka opartą o JavaServer Faces (JSF), Enterprise JavaBeans 3.0 (EJB3) oraz Java Persistence (JPA) uruchomioną na serwerze Glassfish v2. Pomysł na artykuł zaczerpnąłem z wątku hibernate one-to-many - czy tak? na pl.comp.lang.java. Nie będąc pewny odpowiedzi postanowiłem zestawić środowisko i stworzyć aplikację, aby znaleźć odpowiedź empirycznie. Jestem w trakcie testowania NetBeans IDE 6.0, więc pozostało usiąść i stworzyć aplikację. Postanowiłem wykorzystać wszelkie dobrodziejstwa płynące z Korporacyjnej Javy 5 i minimalizowałem kod potrzebny do ukończenia przedsięwzięcia. O tym, co wyszło można przekonać się w artykule i załączonym do niego kodzie źródłowym aplikacji. Mnie się podoba - szczególnie wykorzystanie konwertera w JSF i automatyczne zarządzanie transakcjami przez serwer, gdzie wraz z wykorzystaniem transakcyjnego zarządcy trwałego dostęp do danych jest niezwykle prosty. Komentarze mile widziane!

26 lipca 2007

Java Persistence - Rozdział 8. Adnotacje metadanych (podstawowe) i jej sekcje 8.1 Entity oraz 8.2 Adnotacje zwrotne

0 komentarzy
Rozdział 8. Adnotacje metadanych (adnotacje podstawowe, ang. metadata annotations) przedstawia adnotacje opisujące klasy POJO jako klasy encji. Wszystkie adnotacje należą do pakietu javax.persistence.

Adnotacja @Entity definiuje klasę encji i może jedynie wystąpić na poziomie klasy. Adnotacja składa się z pojedyńczego elementu name, który przypisuje nazwę encji do późniejszego odwołania się do niej w zapytaniach JPQL. Domyślna wartość elementu odpowiada niekwalifikowanej (skróconej) nazwie klasy encji.

W poniższym przykładzie element name jest nadmiarowy, ponieważ jej domyślna wartość odpowiada dokładnie podanej wartości.

import javax.persistence.Entity;

@Entity(name = "Osoba")
public class Osoba implements Serializable {

private static final long serialVersionUID = 1L;

@Id
private String imie;

}

Adnotacja @EntityListeners definiuje klasy nasłuchujące zdarzeń rozwojowych encji lub mapowanej nadklasy (ang. mapped superclass), która może dekorować klasę encji bądź mapowaną nadklasę.
Adnotacja @EntityListeners posiada pojedyńczy element o typie Class[].

import javax.persistence.Entity;
import javax.persistence.EntityListeners;

@Entity(name = "Osoba")
@EntityListeners(OsobaListener.class)
public class Osoba implements Serializable {

private static final long serialVersionUID = 1L;

@Id
private long numer;

}

Adnotacja @ExcludeSuperclassListeners wyłącza wykonanie klas nasłuchujących deklarowanych przez nadklasy encji dla udekorowanej encji lub mapowanej nadklasy oraz ich podklas. Innymi słowy wyłącza się wykonanie klas nasłuchujących zdefiniowanych wyżej w hierarchii dziedziczenia dla wszystkich klas poczynając od klasy, w której występuje adnotacja oraz jej potomków. Adnotacja może dekorować klasę i nie posiada elementów.

import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.ExcludeSuperclassListeners;

@Entity
@ExcludeSuperclassListeners
@EntityListeners(PracownikSpecjalnyListener.class)
public class PracownikSpecjalny extends Osoba {

private static final long serialVersionUID = 1L;

}

Adnotacja @ExcludeDefaultListeners wyłącza wykonanie domyślnych klas nasłuchujących dla encji lub mapowanej nadklasy oraz ich potomków. Adnotacja może dekorować klasę i nie posiada elementów.

import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.ExcludeDefaultListeners;
import javax.persistence.ExcludeSuperclassListeners;

@Entity
@ExcludeSuperclassListeners
@EntityListeners(PracownikSpecjalnyListener.class)
@ExcludeDefaultListeners
public class PracownikSpecjalny extends Osoba {

private static final long serialVersionUID = 1L;

}

Adnotacje
  • @PrePersist
  • @PostPersist
  • @PreRemove
  • @PostRemove
  • @PreUpdate
  • @PostUpdate
  • @PostLoad
wskazują metody zwrotne wywoływane dla odpowiednich zdarzeń rozwojowych związanych z encją. Adnotacje mogą dekorować metody klasy encji, mapowanej nadklasy lub klasy nasłuchującej encji.

import javax.persistence.Entity;
import javax.persistence.EntityListeners;

@Entity(name = "Osoba")
@EntityListeners(OsobaListener.class)
public class Osoba implements Serializable {

private static final long serialVersionUID = 1L;

@Id
private long numer;

@PostPersist
protected void nowaOsobaUtworzona() {
logger.info("Utworzono osobę o identyfikatorze " + numer);
}

}

lub dla klasy nasłuchującej:

package pl.jaceklaskowski.jpa.entity.listeners;

import java.util.logging.Logger;

import javax.persistence.PostPersist;

import pl.jaceklaskowski.jpa.entity.Osoba;

public class OsobaListener {

private static final Logger logger = Logger.getLogger(OsobaListener.class.getName());

@PostPersist
protected void nowaOsobaUtworzona(Osoba osoba) {
logger.info("Utworzono osobę o identyfikatorze " + osoba.getNumer());
}
}