Pełną wersję artykułu razem z listingami można pobrać tutaj
Hibernate
Pewnego dnia przyszedł do mnie kierownik projektu z informacją o nowym projekcie. Wymagania funkcjonalne projektu były jasne. Mianowicie chodziło o implementację serwera, gdzie obsługa bazy danych nie była bardzo istotna i nie należało przeznaczyć na to dużo zasobów. Jednocześnie dostęp ten powinien być niezawodny i oparty na silniku Hibernate. Po dyskusji uruchomiłem jedyną słuszną wyszukiwarkę w poszukiwaniu rozwiązania nurtującego mnie problemu. Mianowicie, czy istnieje jeszcze prostszy sposób implementacji dostępu do bazy danych z wykorzystaniem Hibernate?
Po krótkim czasie ukazał mi się rozdział 13 oficjalnego przewodnika serwera aplikacyjnego Jboss 4.0. Rozwiązanie to nazywa się Hibernate MBean lub, jak kto woli Hibernate Archive. Dzięki rozwiązaniu praktycznie zapominamy o fabryce sesji odpowiedzialnej za dostęp do bazy danych i bardzo upraszczamy obsługę bazy, nie tracąc przy tym na niezawodności. Niestety oprócz wspomnianego rozdziału, ciężko było mi znaleźć jakieś inne przystępne źródło informacji o tej funkcjonalności serwera Jboss. W efekcie taki stan rzeczy skusił mnie do napisania tego artykułu.
Tworzenie pliku i konfiguracja źródła danych
MBean jest stworzony jako instancja klasy org.jboss.hibernate.jmx.Hibernate, która jest odpowiedzialna za stworzenie obiektu Hibernate SessionFactory. Następnie fabryka jest dodawana do drzewa JNDI. Aby możliwe było użycie MBean należy stworzyć plik o rozszerzeniu har (jest to skrót nazwy Hibernate Archive). Na Listingu 1 przedstawiono część skryptu programu Apache Ant, który tworzy potrzebne archiwum.
Przedstawiony skrypt może posłużyć jako szablon do rozbudowy dla programisty, który zechce skorzystać z archiwum środowiska Hibernate. Tworząc archiwum można bez problemów użyć zadania jar. Powodem tego jest fakt, iż pliki Hibernate Archive są tak naprawdę zwykłymi archiwami używanymi do tworzenia aplikacji i bibliotek w języku Java.
Aby mieć dostęp do konkretnej bazy danych oraz schematu w tej bazie, należy skonfigurować źródło danych Data Source. Należy to zrobić tworząc plik konfiguracyjny o nazwie kończącej się sekwencją ds.xm, na przykład typowo oracle9ds.xml. Typową konfigurację źródła przedstawiono na Listingu 2.
Konfiguracja MBean
Mając już gotowy skrypt oraz źródło danych, należy skonfigurować fabrykę. Konfiguracja polega na odpowiednim wypełnieniu atrybutów w pliku jbossservice.xml. Przykładowa konfiguracja tego pliku znajduje się na Listingu 3. Jeśli ktoś używał wcześniej środowiska Hibernate to widzi zaskakujące podobieństwo tego pliku konfiguracyjnego z plikiem hibernate.cfg.xml. Otóż dzięki tej konfiguracji nie trzeba ręcznie ustawiać całego środowiska. Wystarczy określenie kilku atrybutów i sprawę konfiguracji ziarna mamy już z głowy.
Liczba atrybutów jest większa, kompletna lista atrybutów znajduje się w rozdziale 13 książki JBoss 4.0 – The Official Guide. Pozwolę sobie jednak wyjaśnić kilka z nich, użytych w tym przykładzie. Atrybut DatasourceName określa nazwę źródła danych w drzewie JNDI, które na początku udało nam się skonfigurować. Atrybut Dialect zaś określa, jakiego rodzaju bazy danych używamy oraz zmusza Hibernate do użycia odpowiedniego dialektu języka SQL. W Tabeli 1 przedstawiono kilka najbardziej popularnych dialektów.
Atrybut SessionFactoryName określa nazwę fabryki sesji. Fabryka w programie używana jest do tworzenia sesji połączeń do bazy (org.hibernate.Session). Możliwe jest stworzenie wielu fabryk przy użyciu wielu plików har tak więc nazwa powinna być jednoznaczna dla danej bazy czy też schematu. Atrybut CacheProviderClass określa klasę obsługującą pamięć podręczną drugiego poziomu (second–level cache). W tym wypadku użyto klasy org.hibernate.cache.HashtableCacheProvider, która nie powinna być użyta przy uruchamianiu aplikacji na serwerach produkcyjnych. Ostatni atrybut ShowSqlEnabled włącza tryb zapisywania wywołań języka SQL. Niestety z racji ogromnej liczby generowanych wpisów jest on mało praktyczny.
Uruchamianie
Aby możliwe było użycie archiwum serwer Jboss musi mieć uruchomiony tzw. HAR Deployer. Definiowany jest w pliku jbosshibernate.deployer, kompletną konfigurację tego pliku można zobaczyć na Listingu 4.
Archiwum Hibernate z powodzeniem można użyć jako wolno stojący plik w katalogu lub zagnieździć go w archiwum EAR. Jednak żeby poinformować HAR Deployer o istnieniu archiwum należy dodać wpis o tym module w pliku jbossapp.xml. Taki wpis wraz z całą zawartością pliku jest przedstawiony na Listingu 5.
Proces uruchamiania archiwum Hibernate zaczyna się w momencie, w którym w katalogu deploy znajdzie się plik z rozszerzeniem har. Uruchomiony na serwerze Deployer przetwarza plik i tworzy instancje zarządzanego ziarna korzystając z wpisów w METAINF/jbossservice.xml oraz zawartości archiwum (standardowych plików modelu *.hbm.xml). Następnie wszystkie wpisy modeli są przetwarzane przez konfiguracje środowiska Hibernate. Od tego momentu w zakresie aplikacji lub całego serwera dostępna jest fabryka sesji.
Struktura pliku har
Przykładową strukturę kompletnego archiwum har przedstawiono na Rysunku 1. Archiwa har można z powodzeniem rozszerzać w taki sposób, aby hermetyzować całą funkcjonalność obsługi bazy danych. Następnie można wywoływać gotowe klasy w innych warstwach aplikacji.
Główną częścią archiwum jest typowy archiwów jar katalog METAINF, gdzie właśnie znajduje się konfiguracja fabryki sesji (jbossservice.xml) oraz zwykły plik MANIFEST.MF. W katalogu głównym znajdują się skompilowane klasy związane z obsługą bazy danych (DTO oraz DAO). I w końcu pliki hbm.xml zawierające informacje o mapowaniu obiektów w relacje bazy danych.
Użycie
Na Listingu 6 przedstawiono przykładową (bardzo prostą i niepozbawioną błędów) klasę korzystającą z fabryki sesji stworzonej przez Hibernate Archive. W konstruktorze klasy pokazano, w jaki sposób ładować fabrykę sesji z drzewa JNDI. Następnie przy użyciu fabryki można otwierać sesje i transakcje do wykonywania operacji na bazie danych.
Podsumowanie
Jednym z problemów jest fakt, iż Apache Maven nie rozpoznaje plików har. Przez to istnieje problem przy zależnościach i kompilacji. Fakt ten jest dosyć frustrujący i wymaga napisania skryptu obchodzącego problem na około. Z reguły wiąże się to ze zmianą rozszerzenia pliku podczas procesu budowania aplikacji, aby modele oraz klasy DAO były widoczne dla innych warstw aplikacji.
Dużym atutem rozwiązania jest jego prostota. Z praktyki wiem, że konfiguracje tworzy się raz i kompletnie zapomina się o obsłudze bazy danych. Jeśli jeszcze używa się do tego silnika XDoclet w celu generowania plików hbm.xml, to kwestia bazy danych i jej obsługi zajmuje najmniej zasobów w projekcie.
Polecam wypróbowanie rozwiązania, jeśli korzystacie z serwera aplikacyjnego JBoss. Na pewno od razu się do niego przekonacie zyskując przy tym czas na dopracowanie reszty warstw aplikacji.