Projekt seam-gen
Obiecałem omówić TDD w Seam Framework, ale po drodze napotkałem kilka istotnych problemów. Wszystkie błędy oraz ich eliminacja były związane ze sposobem zarządzania plikami projektu. Sprawiło to, że postanowiłem opisać proces rozwoju nowego projektu od samego początku.
Dotąd opisałem jedynie tworzenie projektu Seam z wykorzystaniem JBoss Tools, jednak od dość dawna pracuję z systemem Ubuntu i używam generatora seam-gen.
Instalacja
Nie instalowałem ani serwera JBoss, ani Seam Framework – rozpakowałem pobrane archiwa odpowiednio do katalogów: /home/slawek/jboss i /home/slawek/seam. Apache Ant, JDK 1.6 oraz PostgreSQL zostały zainstalowane z repozytorium pakietów Ubuntu. Jeżeli dobrze pamiętam, były to następujące metapaczki:
sudo aptitude install ant sun-java6-jdk postgresql-8.3
Konfiguracja seam-gen
Automatyczne generowanie nowego projektu seam-gen można podzielić na dwa etapy – konfigurację i utworzenie. Pierwszy z nich realizuje się za pomocą polecenia:
slawek@localhost:~/seam$ ./seam setup
SEAM_HOME: /home/slawek/seam
Using seam-gen sources from: /home/slawek/seam/seam-gen
Buildfile: /home/slawek/seam/seam-gen/build.xml
init:
setup:
[echo] Welcome to seam-gen
Dla MS Windows polecenie będzie mniej więcej tak:
C:\seam> seam.bat setup
Teraz następuje seria pytań dotyczących ustawień nowego projektu. Na początku należy podać katalog, zawierający projekty Seam. W moim przypadku będzie to:
[input] Enter your Java project workspace (the directory that
contains your Seam projects) [] []
/home/slawek/java
Następnie należy wskazać ścieżkę do katalogu głównego serwera JBoss:
[input] Enter your JBoss AS home directory [] []
/home/slawek/jboss
Teraz podaję nazwę projektu – będzie to projekt przykładowy, wykorzystywany na blogu:
[input] Enter the project name [blog] [blog]
blog
[echo] Accepted project name as: blog
Następnie seam-gen proponuje użycie biblioteki ICEfaces zamiast RichFaces. Grzecznie odmawiam:
[input] Do you want to use ICEfaces instead of RichFaces [n] (y, [n])
n
[input] skipping input as property icefaces.home.new has already been set.
Przy wyborze motywu graficznego strony, wskazuję domyślny:
[input] Select a RichFaces skin [DEFAULT] (blueSky, classic,
deepMarine, [DEFAULT], emeraldTown, japanCherry, ruby, wine)
DEFAULT
Kolejne pytanie brzmi, czy projekt ma być rozmieszczany na serwerze w postaci archiwum EAR, czy może WAR. W drugim przypadku utraciłbym wsparcie dla komponentów EJB, zatem wybieram:
[input] Is this project deployed as an EAR (with EJB components)
or a WAR (with no EJB support) [ear] ([ear], war)
ear
Teraz muszę zdefiniować domyślne pakiety dla klas generowanych z użyciem seam-gen. Osobno dla komponentów:
[input] Enter the Java package name for your session beans [] []
pl.info.czerwinski
dla encji:
[input] Enter the Java package name for your entity beans [] []
pl.info.czerwinski
i dla testów:
[input] Enter the Java package name for your test cases [] []
pl.info.czerwinski
Przy wyborze bazy danych, seam-gen daje szeroki wachlarz możliwości. Ja korzystam z PostgreSQL:
[input] What kind of database are you using? [postgres]
(hsql, mysql, oracle, [postgres], mssql, db2, sybase, enterprisedb, h2)
postgres
Hibernate potrzebuje klasy zawierającej bardziej szczegółowe informacje na temat wspieranego przez bazę danych dialektu SQL:
[input] Enter the Hibernate dialect for your database [] []
org.hibernate.dialect.PostgreSQLDialect
Przyda się też archiwum zawierające sterownik JDBC:
[input] Enter the filesystem path to the JDBC driver jar [] []
/home/slawek/java/postgresql-8.3-604.jdbc4.jar
oraz klasa samego sterownika:
[input] Enter JDBC driver class for your database [] []
org.postgresql.Driver
Następnie seam-gen prosi o podanie URL do bazy danych. W przypadku lokalnej bazy PostgreSQL jest to jdbc:postgresql:[NAZWA_BAZY]:
[input] Enter the JDBC URL for your database [] []
jdbc:postgresql:blog
Następnie podaję nazwę użytkownika bazy:
[input] Enter database username [] []
blog
oraz hasło:
[input] Enter database password [] []
blog
Domyślny schemat bazy danych ustawiam na public:
[input] Enter the database schema name (it is OK to leave this blank)
[] []
public
Katalog pozostawiam pusty:
[input] Enter the database catalog name (it is OK to leave this blank)
[] []
Teraz dwa pytania dotyczące działań, jakie Hibernate ma podjąć w momencie rozmieszczenia aplikacji na serwerze. Jeżeli tablice nie istnieją jeszcze w bazie danych, zostaną one utworzone na podstawie mapowania klas encji. Dlatego odpowiadam:
[input] Are you working with tables that already exist
in the database? [n] (y, [n])
n
Następne pytanie dotyczy każdego ponownego rozmieszczenia projektu na serwerze – seam-gen pyta, czy w takiej sytuacji ma usunąć wszystkie dane i utworzyć je ponownie na podstawie mapowania. Na etapie rozwijania projektu jest to przydatne, więc wybieram:
[input] Do you want to drop and recreate the database tables
and data in import.sql each time you deploy? [y] ([y], n)
y
To już było ostatnie pytanie. Teraz jeszcze powinny pojawić się komunikaty o następującej treści:
[propertyfile] Creating new property file:
/home/slawek/seam/seam-gen/build.properties
[echo] Installing JDBC driver jar to JBoss AS
[echo] Type './seam create-project' to create the new project
BUILD SUCCESSFUL
Total time: 1 minute 47 seconds
slawek@localhost:~/seam$
Cała konfiguracja została zapisana do pliku ~/seam/seam-gen/build.properties i w każdej chwili można zmienić dowolne ustawienia edytując tenże.
Utworzenie projektu
Aby utworzyć projekt, należy ponownie uruchomić skrypt seam – tym razem z parametrem create-project:
slawek@localhost:~/seam$ ./seam create-project SEAM_HOME: /home/slawek/seam Using seam-gen sources from: /home/slawek/seam/seam-gen Buildfile: /home/slawek/seam/seam-gen/build.xml […] BUILD SUCCESSFUL Total time: 6 seconds slawek@localhost:~/seam$
Podobny efekt można uzyskać za pomocą polecenia ant:
slawek@localhost:~/seam$ cd seam-gen slawek@localhost:~/seam/seam-gen$ ant create-project
Projekt jest utworzony już po kilku sekundach.
Skrót do bibliotek
Chcę uniknąć kopiowania bibliotek do każdego projektu, aby oszczędzić trochę miejsca na dysku. Dlatego postanowiłem utworzyć w katalogu z projektami nowy katalog lib, zawierający wszystkie biblioteki Seam oraz JDBC:
slawek@localhost:~/java$ cp /home/slawek/seam/lib . slawek@localhost:~/java$ cp postgresql-8.3-604.jdbc4.jar ./lib
Z każdego nowego projektu będę usuwał wygenerowany katalog lib, a następnie tworzył dowiązanie symboliczne (pod MS Windows byłby to zwykły skrót do folderu) do katalogu utworzonego wcześniej:
slawek@localhost:~/java$ cd blog slawek@localhost:~/java/blog$ rm -rf lib slawek@localhost:~/java/blog$ ln -s /home/slawek/java/lib/ .
Teraz nie muszę się już martwić dodawaniem brakujących plików JAR ani zużywaniem wolnej przestrzeni dyskowej.
Dodanie biblioteki jaxrs-api
W Seam Framework 2.1 występuje pewien dość dziwny błąd. Aby go wyeliminować, wystarczy dodać do pliku deployed-jars-ear.list następującą linijkę:
jaxrs-api.jar
Zmiana położenia klas dla testów
Niestety utworzenie jednego katalogu ze wszystkimi bibliotekami sprawia pewne problemy przy uruchamianiu testów. Klasy należące do Apache Wicket znajdują się w kilku archiwach, przez co występują konflikty. Oczywiście można usunąć wszystkie pliki wicket*.jar z katalogu lib, ale bezpieczniej będzie dokonać pewnych zmian w build.xml.
Najpierw utworzę plik zawierający listę bibliotek dołączanych w trakcie uruchamiania testów. Pod Linuxem można to zrobić za pomocą polecenia ls:
slawek@localhost:~/java/blog$ cd lib slawek@localhost:~/java/blog/lib$ ls *.jar > classpath-jars-test.list slawek@localhost:~/java/blog/lib$ cd .. slawek@localhost:~/java/blog$ mv lib/classpath-jars-test.list .
Pod MS Windows przypuszczalnie użyłbym dir z odpowiednimi parametrami.
Oczywiście z listy należy usunąć wszystkie wpisy zaczynające się od wicket.
W build.xml definiuję nowy zestaw plików, pobierany z pliku classpath-jars-test.list – tuż przed pierwszym znacznikiem target:
[…]
<fileset id="test.lib" dir="${lib.dir}">
<includesfile name="classpath-jars-test.list"/>
</fileset>
<path id="test.classpath">
<fileset refid="test.lib"/>
</path>
<target name="init" […]
Przy uruchamianiu testów (target name="test") trzeba wykorzystać nowo utworzoną ścieżkę test.classpath zamiast build.classpath (linia 12):
<target
name="test"
depends="buildtest"
description="Run the tests">
[…]
<path id="test.path">
<path path="${test.dir}"/>
<fileset dir="${lib.dir}/test">
<include name="*.jar"/>
</fileset>
<path path="${bootstrap.dir}"/>
<path refid="test.classpath"/>
</path>
[…]
</target>
Teraz, niezależnie od zawartości katalogu lib na komputerach różnych programistów, testy powinny działać tak samo.
Ant
Kompilacja, budowanie czy testowanie projektu wykonywane są za pomocą Apache Ant. Aby wykonać jakąś czynność, należy wpisać ant [NAZWA_ZADANIA].
Najważniejsze zadanie to zbudowanie i rozmieszczenie na serwerze gotowej aplikacji:
slawek@localhost:~/java/blog$ ant explode
W celu uruchomienia testów automatycznych, należy uruchomić:
slawek@localhost:~/java/blog$ ant test
Czyszczenie odbywa się w dwóch etapach. Pierwszym jest usunięcie odpowiednich katalogów z projektu:
slawek@localhost:~/java/blog$ ant clean Buildfile: build.xml clean: [delete] Deleting directory /home/slawek/java/blog/dist [delete] Deleting directory /home/slawek/java/blog/exploded-archives [delete] Deleting directory /home/slawek/java/blog/test-report BUILD SUCCESSFUL Total time: 0 seconds slawek@localhost:~/java/blog$
Drugim zadaniem jest usunięcie aplikacji z serwera:
slawek@localhost:~/java/blog$ ant unexplode Buildfile: build.xml unexplode: [delete] Deleting: /home/slawek/jboss/server/default/deploy/blog-ds.xml [delete] Deleting directory /home/slawek/jboss/server/default/deploy/blog.ear BUILD SUCCESSFUL Total time: 0 seconds slawek@localhost:~/java/blog$
Skoro już utworzyłem nowy projekt seam-gen, wreszcie jestem gotów na testy – już w kolejnym wpisie.



