27 lutego 2009

Groovy 1.6, Grails 1.1 RC2, GAnt 1.6.1 i NetBeans 6.7 M2

0 komentarzy
Na grupie użytkowników Grails pojawiła się wiadomość Petra Hejla Groovy/Grails & NetBeans 6.7 M2:

For those using NetBeans IDE or considering it for Groovy/Grails - NetBeans 6.7 M2 is available. It is important step on way to 6.7 stable. Contains a lot of fixes in Groovy and Grails area and new features as well.

http://bits.netbeans.org/download/6.7/m2/
http://wiki.netbeans.org/NewAndNoteworthyMilestone2NB67
http://blogs.sun.com/phejl/entry/groovy_and_grails_in_netbeans


Właśnie pobieram ostatnią wersję rozwojową NetBeans 6.7 - netbeans-trunk-nightly-200902270313.zip, która zapewne już zawiera więcej zmian w temacie (i nowe błędy również ;-)) z zamiarem ich sprawdzenia. Jeśli informacje na stronie NewAndNoteworthyMilestone2NB67/ Groovy and Grails się potwierdzą, można przypuszczać, że NetBeans IDE 6.7 stanie się TYM wymarzonym IDE dla programistów Grails. Alternatywną może być IntelliJ IDEA 8, ale jak wieść niesie są jakieś problemy ze współpracą z Grails 1.1 RC1 (niestety nie mogę przypomnieć sobie, gdzie to wyczytałem). Ale właśnie, czy wiadomo już, że mamy Grails 1.1 RC1? A na dniach (jutro, 28.02) możemy spodziewać się RC2. Niecierpliwi mogą już zapoznać się ze szkicem Grails 1.1 RC2 Release Notes. Poza tym mamy nowiuteńkie wersje Groovy 1.6 oraz (niezmieniony funkcjonalnie, aczkolwiek przebudowany z nową wersją Groovy 1.6) GAnt 1.6.1.

We wtorek moja prezentacja o Grails na spotkaniu Warszawa JUG - teoretycznie czuję się mocny (2 książki robią swoje), ale prezentacyjnie daleko w polu :( Zdecydowanie za mało praktyki! Zaczynam się stresować?!

23 lutego 2009

NetBeans 6.7 zamiast NetBeans 7.0 i Spring Security w 15 minut

0 komentarzy
Pojawił się komunikat o nowych wersjach NetBeans IDE numerowanych...6.7. Skąd ta zmiana w numeracji? I to jeszcze na mniejszą? A pikanterii dodaje jeszcze przeskok z 6.5 na 6.7. Wyjaśnienia można szukać w komunikacie "Message from the NetBeans Team - Why NetBeans 6.7?", z czego najważniejsze to:

To get innovation and quality improvements out to the community faster, and to have the NetBeans IDE be better aligned with the release schedules of other technologies that it supports, we have decided to concentrate on a series of smaller releases rather than the traditional two big releases per year.

oraz

NetBeans 6.7 is scheduled for release in June 2009. The main features are Maven and Kenai integration, and there are many smaller features that you can read about on the New and Noteworthy page. Java EE 6 support is planned for a future release. NetBeans 6.7 Milestone 2 is due out next week. We encourage you to download the release when it becomes available and to give us your feedback.

Dzięki temu całemu "zamieszaniu" ze zmianą wersji, kilka rzeczy poukładałem sobie w głowie, bo pytanie o wersję pojawiło się po pojawieniu się zgłoszenia Change cluster nb7.0 to nb6.7. Miałem w ten sposób okazję powyjaśniać sobie wiele z pojęć NetBeans, chociażby cluster. Jeśli dobrze rozumiem, pojęcie cluster oznacza zbiór modułów (ang. NBM - NetBeans Modules) w NetBeans (potwierdza to chociażby What is a Cluster?). Już podczas instalacji modułów JavaFX zauważyłem, że w katalogu domowym NetBeans tworzony jest katalog javafx2 (nie mam niestety pojęcia skąd ta dwójka?!). Spodziewałem się jednak, że w takim klastrze nb67 znajdę moduły, a tam...niewiele. Znalazłem jednak pliki graficzne (PNG) dla ekranu powitalnego i logo NetBeans w różnych rozmiarach. Wystarczy zajrzeć do nb6.7/core/locale/core_nb.jar, a w nim do org/netbeans/core/startup, gdzie mamy (zrzut z wersji rozwojowej z 23. stycznia):
 jlaskowski@work /cygdrive/c/apps/netbeans/nb6.7/core/locale
$ jar -tf core_nb.jar org/netbeans/core/startup/
org/netbeans/core/startup/
org/netbeans/core/startup/Bundle_nb.properties
org/netbeans/core/startup/about_nb.png
org/netbeans/core/startup/frame32_nb.gif
org/netbeans/core/startup/frame48_nb.gif
org/netbeans/core/startup/frame_nb.gif
org/netbeans/core/startup/splash_nb.gif
Zamiast zrzutów ekranu, aby umieścić logo lub ekran powitalny NetBeans, można po prostu sięgnąć do odpowiedniego pliku w klastrze nb67.

Dla zainteresowanych tematyką bezpieczeństwa w aplikacjach webowych z użyciem Spring Framework, Spring Security (dawne Acegi) i rozwojowego NetBeans 6.7 zapraszam do lektury artykułu wprowadzającego Proste uwierzytelnianie i autoryzacja w aplikacji webowej ze Spring Security w 15 minut. Kolejny artykuł zaplanowałem z użyciem CAS i LDAP.

Zastanawiam się, czy tego typu wiedzę nie łatwiej byłoby przyswoić w postaci filmu (z Wink czy podobnie). Dla mnie łatwiej byłoby stworzyć film, ale z oczywistych względów nie będzie można go wydrukować. Mam wrażenie, że w tym przypadku oglądanie krótkiego filmu instruktażowego byłoby mniej męczące niż czytanie artykułu ze zrzutami ekranów. Zapraszam do ankiety Czy artykuł z dużą ilością zrzutów ekranów nie powinien być filmem?, w której zbieram głosy przez kolejny tydzień.

19 lutego 2009

Podział konfiguracji springowej i automatyczny formularz logowania w Spring Security

0 komentarzy
Ostatnimi czasy zajmowałem się niezwykle interesującym tematem wykorzystania JA-SIG Central Authentication Service (CAS) oraz LDAP w ramach aplikacji webowej i natychmiast wskazałem na Spring Security jako platformę integracyjną. CAS dostarczał mechanizmu pojedyńczego uwierzytelnienia (ang. SSO - Single Sign-On), a LDAP informacji o użytkownikach i ich rolach (autoryzacja). O całym przedsięwzięciu później, ale teraz jedynie wspomnę, że podczas konfiguracji Spring Security (co w zasadzie dotyczy jakiegokolwiek projektu korzystającego ze Spring Framework) natrafiłem na ciekawą cechę konfiguracyjną - podział pliku applicationContext na oddzielne pliki, które w całości stanowią konfigurację springową aplikacji (patrz 15.2. Common configuration). Wystarczy zatem umieścić pewne części konfiguracji w oddzielnych plikach i można uprościć jej zarządzanie - w pliku WEB-INF/web.xml aplikacji webowej wystarczy użyć wyrażenia regularnego /WEB-INF/applicationContext*.xml, aby wskazać na nie wszystkie.
 <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
Spring Framework zadba o ich połączenie i w ten sposób pozbywamy się choć części trudności w obsłudze tego xmlowego szaleństwa w Springu.

Kolejną ciekawostką, tym razem bezpośrednio związaną ze Spring Security, które przypomina mi Grails, jest automatyczne tworzenie formularza logowania (strony do podawania loginu i hasła). Wystarczy wdrożyć minimalną konfigurację Spring Security w naszej aplikacji webowej (patrz 2.2. Getting Started with Security Namespace Configuration), w której możemy skorzystać z 2.2.2.2. Form and Basic Login Options:

You might be wondering where the login form came from when you were prompted to log in, since we made no mention of any HTML files or JSPs. In fact, since we didn't explicitly set a URL for the login page, Spring Security generates one automatically, based on the features that are enabled and using standard values for the URL which processes the submitted login, the default target URL the user will be sent to and so on.

Podkreślam "Spring Security generates one automatically". Idealne na szybki start! I faktycznie działa!

17 lutego 2009

JavaFX 1.1 z NetBeans 7.0 DEV

3 komentarzy
Biorę udział w bezpłatnym szkoleniu z JavaFX - "Free" 15-Week JavaFX Programming (with Passion!) Online Course (tak przy okazji, to wciąż można się zapisać) i wiele się mówi o NetBeans IDE 6.5 jako środowisku programistycznym dla JavaFX. Mnie jednak 6.5 nie wystarczy i postanowiłem spróbować JavaFX z rozwojową wersją NetBeans 7.0 DEV.

Niestety wszystkie instrukcje instalacji wtyczek (modułów) JavaFX w NetBeans IDE, jakie udało mi się znaleźć dotyczą wersji 6.5 i niestety nie mają zastosowania dla 7.0, gdyż moduły JavaFX nie istnieją w domyślnie zdefiniowanych repozytoriach modułów NetBeans 7. Okazuje się, że nie jest to wcale jakieś wyrafinowane zadanie i co więcej wszystko zdaje się działać (podkreślam słowo "zdaje", gdyż moja znajomość JavaFX sprowadziła się do popróbowania się z kilkoma niewielkimi funkcjonalnie skryptami).

Zakładam, że NetBeans IDE 7.0 DEV jest już gotowe do użycia (=rozpakowane).

Wybieramy menu Tools > Plugins.


W okienku dialogowym Plugins wybieramy zakładkę Settings, gdzie definiujemy nowe repozytorium modułów (centrum aktualizacji, ang. Update Center) - NetBeans 6.5 Updates pod adresem http://updates.netbeans.org/netbeans/updates/6.5/uc/final/stable/catalog.xml.gz. To jest dokładnie to samo repozytorium, które jest domyślnie dostępne w NetBeans 6.5.


Wciskamy przycisk OK. Na liście centrów aktualizacji powinny być teraz 3 pozycje, w tym jedna nasza.


Przechodzimy do zakładki Available Plugins i w polu Search (prawy górny róg) wpisujemy javafx.


Wybieramy wszystkie 3 moduły i wciskamy przycisk Install (dolny lewy róg).

Po (dłuższej) chwili moduły zostaną zainstalowane i zostaniemy poproszeni o ponowne uruchomienie NetBeansa. Oczywiście zgadzamy się.

Z zainstalowanymi modułami JavaFX wystarczy Ctrl+Shift+N i wybieramy odpowiedni rodzaj projektu JavaFX. Przeczytałem Lesson 1: Getting Started with JavaFX Script, sprawdziłem i działa zgodnie z oczekiwaniami. Inne skrypty również działały. Miłego JeFiXowania!

15 lutego 2009

Dokończenie rozdziału 4. o kontrolerach z "The Definitive Guide to Grails, Second Edition"

0 komentarzy
Nie chciałem dzielić kolejnego rozdziału 5. o widokach w Grails, więc dzisiaj będzie krótko - dokończenie rozdziału 4. "Understanding Controllers" o kontrolerach grailsowych z książki "The Definitive Guide to Grails, Second Edition".

Uwaga: "krótko" nie musi oznaczać tego, co wielu z Wam kojarzy się z "krótko" ;-)

W Grails mamy do dyspozycji mechanizm przechwytywania wywołania metod znany z programowania aspektowego (ang. AOP - Aspect-Oriented Programming). Grails jest jedynie zawężeniem dostępnych możliwości AOP i udostępnia "rozszerzenia" (ang. advice) przed (before), po (after) oraz wokół (around) wykonania metod(y). Spełnia to jednak podstawowe potrzeby przechwytywania wywołań akcji kontrolerów w Grails.

Deklaracja metody przechwytującej "przed" sprowadza się do stworzenia atrybutu beforeInterceptor w postaci domknięcia w ramach danego kontrolera, np. (Listing 4-37):
 def beforeInterceptor = {
log.trace("Przechwyciłem wykonanie metody $actionName z parametrami $params")
}
Mamy możliwość bardziej precyzyjnego określenia, kiedy i która akcja ma być przechwycona z literałem mapowym, np. (Listing 4-38):
 class AlbumController {
private trackCountry = {
...
}

def beforeInterceptor = [action:trackCountry, only:"show"]
}
Parametr action określa akcję do wykonania, a drugi - only lub except - wskazują, której akcji kontrolera dotyczy.

Zwrócenie false przez metodę przechwytującą wstrzymuje wykonanie docelowej akcji kontrolera.

Deklaracja metody przechwytującej "po" sprowadza się do deklaracji atrybutu afterInterceptor, której wartością jest domknięcie do wykonania. Parametr wejściowy model domknięcia to model wynikowy z akcji, np. (Listing 4-40):
 def afterInterceptor = {model ->
log.trace("Wykonano akcję $actionName, która zwróciła model $model")
}
Grails udostępnia specjalną klasę testową ControllerUnitTestCase do testowania kontrolerów, w której znajdziemy "zaślepki" (imitacje obiektów, ang. mocks) otaczających kontroler obiektów z Servlet API, np. HttpServletRequest oraz metod render i redirect.

Utworzenie klasy testowej kontrolera to grails create-unit-test <klasa-kontrolera>. Klasa, której nazwa kończy się na Tests, powstanie w katalogu test/unit.

Klasa bazowa ControllerUnitTestCase rozszerza GrailsUnitTestCase, która udostępnia metody pomocnicze z imitacją działania klas dziedzinowych i kontrolerów, np. mockDomain, która przesłania dostęp do bazy danych (Listing 4-42):
 void testList() {
mockDomain(Album, [new Album(title: "Tytuł"),
new Album(title: "Inny tytuł")])
def model = controller.list()
assertEquals 2, model.albumList.size()
}
Za pomocą mockDomain przesłoniliśmy dostęp do bazy danych i wykonanie list() zwróciło (a przynajmniej powinno!) wyłącznie 2 albumy. mockDomain ustanawia aktualne dane do skontruowania modelu i wszystkie metody pracują wyłącznie na nich.

Klasa MockHttpServletResponse pozwala na analizę stanu bieżącej odpowiedzi kontrolera. W szczególności, metoda getContentAsString() zwraca treść odpowiedzi, np. (Listing 4-43):
 void testIndex() {
controller.index()
assertEquals "Welcome...", controller.response.contentAsString
}
W powyższym przykładzie, jeśli zadaniem akcji index() jest wypisanie (np. przez render) tekstu "Welcome..." obiekt controller.response z pomocą metody contentAsString pomoże nam w sprawdzeniu tego.

Jeśli w akcji korzystamy z bardziej zaawansowanej postaci render, np. render(view: "show", model:[album:Album.get(params.id)]), wtedy sprawdzenie tego to skorzystanie z kolejnej imitacji (zaślepki) - renderArgs, np.
 mockParams.id = 1
controller.show()
assertEquals "show", renderArgs.view
assertEquals 1, renderArgs.model.album.id
Użyliśmy również mockParams, który imituje obiekt params. Z jego pomocą możemy wypełnić do właściwymi danymi przez wykonaniem akcji kontrolera.

Mamy do dyspozycji imitacje - mockRequest (typu org.springframework.mock.web.MockHttpServletRequest), mockResponse (typu org.springframework.mock.web.MockHttpServletResponse), mockSession (typu org.springframework.mock.web.MockHttpSession), mockParams oraz mockFlash.

Wskazanie początkowego (domyślnego) kontrolera przy wejściu do aplikacji to zmiana pliku grails-app/conf/UrlMappings.groovy, w którym deklarujemy statyczny atrybut mappings, np. (listing 4-45):
 class UrlMappings {
static mappings = {
"/"(controller: "store")
}
}
Wskazujemy jedynie początkowy kontroler, a nie konkretną akcję (jej wyznaczenie to reguły opisane w Rozdział 4. "Understanding Controllers" z "The Definitive Guide to Grails, Second Edition" - zazwyczaj index).

W zasadzie oczywiste (ale mnie początkowo zaskoczyła ta oczywistość) - pusta akcja w kontrolerze sprowadza się do delegowanie wykonania do widoku w grails-app/views/<kontroler>/<akcja>.gsp.

Kolejne strony to materiał o pisaniu testów jednostkowych z imitacjami obiektów w Grails. Warto pamiętać, że "you can never write too many tests!" (strona 101). Z Grails pisanie testów staje się trywialne. Radek Holewa wyraził również podobny entuzjazm w swoim komentarzu do wpisu Inni klienci aplikacji w Grails - rozdział 13 z "Beginning Groovy and Grails":

Co do samego Groovy'ego to używam go obecnie jako język w którym piszę testy jednostkowe w projektach w których biorę udział. Sprawdza się tam idealnie!

Na koniec wzmianka o klasach polecenia, gdzie wypełnienie danymi obiektu grailsowego bez konieczności zapisu do bazy danych to właśnie zadanie dla niego. Równie oczywista, jak poprzednia oczywistość, a wciąż mnie zaskakuje.

Natknąłem się również na konstrukcje znane mi z wcześniejszego programowania w C/C++, tj. (Listing 4-57):
 class LoginCommand {
String login
private u

User getUser() {
if (!u && login) {
...
}
}
...
}
Znaczy się, że null to w Groovy równoznaczne z false! Myślałem, że mam to już za sobą, a tu powrót do korzeni.

Możemy korzystać z pomocniczej metody MockUtils.prepareForConstraintsTests(), która akceptuje klasę polecenia lub klasę dziedzinową do testowania warunków danych (definiowanych przez static constraints).

p.s. Nie zapomnieliśmy o konkursie Bloger Roku 2008? Wystarczy wejść na stronę do głosowania na Notatnik, gdzie podajemy nasz adres email i zatwierdzamy. Wiadomość z adresem potwierdzającym pojawia się w naszej skrzynce, klikamy w niego potwierdzając nasz wybór. I tyle. Dziękuję!

14 lutego 2009

Rozdział 4. "Understanding Controllers" z "The Definitive Guide to Grails, Second Edition"

0 komentarzy
Kolejny rozdział 4. "Understanding Controllers" to 40 stron mnóstwa wiadomości z podwórka Grails, a dokładniej o kontrolerach. Mimo wcześniejszej lektury "Beginning Groovy and Grails" (patrz Book review: Beginning Groovy and Grails: From Novice to Professional). Już poprzedni rozdział było trudno zrelacjonować w kilku(nastu) zdaniach, a ten nie będzie łatwiejszy. Ostrzegałem.

Kontroler w Grails jest klasą, która jest odpowiedzialna za obsługę żądań w aplikacji (nie powinno to nikogo dziwić, jeśli przypomnieć sobie, że Grails to realizacja wzorca MVC). Instancje kontrolera tworzone są na nowo dla każdego żądania, więc nie zajmujemy się wcale kwestią odporności kodu kontrolera na wielowątkowość. Klasy kontrolerów znajdują się w grails-app/controllers. Nazwa klasy musi kończyć się Controller. Kontrolery nie mają potrzeby rozszerzać jakiejkolwiek klasy bazowej czy implementować specjalny intefrejs.

Akcje w kontrolerze definiowane są jako pola, do których przypisuje się blok kodu w postaci domknięcia Groovy.

Jeśli nie wskazano akcji do wykonania w URL, Grails wykona domyślną akcję. Wyznaczenie domyślnej akcji to następująca sekwencja: pojedyncza akcja w kontrolerze staje się domyślną, przy większej liczbie jest to index lub dowolna inna wskazana przez właściwość defaultAction, np. (Listing 4-3):
 class SampleController {
def defaultAction = 'list'
def list = {}
def index = {}
}
Właściwość log jest wstrzeliwana do każej klasy kontrolera jako egzemplarz org.apache.commons.logging.Log.

Dowolny wyjątek w Groovy jest wyjątkiem niekontrolowanym (ang. unchecked/runtime exception), stąd nie trzeba zajmować się w ogóle ich przechwytywaniem (chyba, że zajdzie taka potrzeba). Przechwycenie wyjątku w Groovy jest identyczne jak w Javie - blok try-catch.

Lista domyślnych atrybutów dostępnych w kontrolerze (nazwy są samowyjaśniające się): actionName, actionUri, controllerName, controllerUri, flash, log, params, request, response, session i servletContext. Odczyt/zapis parametrów/atrybutów w wielu z nich, odbywa się za pomocą operatorów "dot dereference" czy "subscript", np. request.myAttr, albo session.myAttr = 'pewna-wartość'.

Wyróżniamy 4 zasięgi działania obiektów w Grails - request (pojedyncze żądanie), flash (obecne i przyszłe żądanie), session (sesja) oraz servletContext (współdzielone w całej aplikacji przez całe jej istnienie).

Wyświetlenie komunikatu w odpowiedzi na żądanie z poziomu kontrolera to render 'tutaj tekst do wyświetlenia' z opcjonalnym parametrem contentType, np. (Listing 4-11):
 render 'Witaj użytkowniku'
render text: '<b>Witaj użytkowniku</b>', contentType: 'text/xml'
Warto zauważyć, że wykonanie metody z parametrami w Groovy nie wymaga umieszczenia ich w nawiasach.

Wskazanie danego widoku do wyświetlenia w render (standardowo będzie to strona gsp, której nazwa odpowiada nazwie metody w katalogu odpowiadającym nazwie kontrolera), to zadanie dla parametru view. Możliwe jest wskazanie dedykowanego modelu.
 render(view: "display", model: [ song:Song.get(params.id) ])
Można również wskazać adres widok względnego do grails-app/views, np.
 render(view: "/common/song", model: [ song:Song.get(params.id) ])
Przekierowanie to metoda redirect, która akceptuje mapę jako argument wejściowy, w której umieszczamy niezbędne parametry - action (akcja do wykonania), controller (kontroler), id (parametr id w przekierowaniu), params (mapa obowiązujących parametrów), uri (względny adres przekierowania), url (bezwzględny adres przekierowania).

Kiedy akcja kontrolera zwraca mapę, staje się ona bieżącym modelem dla widoku, np. (Listing 4-14):
 def show = {
[ song: Song.get(params.id) ]
}
Warto zaznaczyć, że w Groovy ostatnie wyrażenie to wartość zwracana (czyli return jest opcjonalny). W tym przypadku widok będzie mógł odczytać song, który wskazany jest w tym modelu.

Można tak (Listing 4-17):
 def save = {
def album = new Album()
album.genre = params.genre
album.title = params.title
...
}
jednakże dla wielu parametrów może to być bardzo pracochłonne, więc łatwiej przypisać parametry z żądania korzystając z automatycznie generowanego w Grails konstruktora:
 def save = {
def album = new Album(params)
...
}
W tym momencie pojawia się uwaga dotycząca potencjalnych ataków, przy wykorzystaniu tego automatycznego ustawiania właściwości z parametrów żądania, które występuje również w Ruby on Rails, Spring MVC, WebWork i in. Rozwiązaniem jest metoda bindData (o której za moment) oraz dokładna kontrola poprawności.

Można również w prosty sposób przypisać wszystkie wartości atrybutów już istniejącego egzemplarza klasy dziedzinowej z wykorzystaniem automatycznie dodawanego atrybutu properties, np.
 def update = {
def album = Album.get(params.id)
album.properties = params
album.save()
}
Przypisane zostaną jedynie parametry, które należą do pustej (domyślnej) przestrzeni nazw, tj. nazwy parametrów są proste, np. title, name. Poprzedzenie nazwy parametru pewną nazwą (przestrzenią klasy dziedzinowej), np.
 <input type="text" name="album.title" />
<input type="text" name="artist.title" />
to możliwość pobrania jedynie pewnego zbioru parametrów, np.
 def album = new Album( params["album"] )
def artist = new Artist( params["artist"] )
Bez względu na przestrzenie nazw parametrów możemy zawężać automatyczne przypisanie wartości do określonych parametrów z bindData, np. (Listing 4-21):
 bindData(album, params, [include:"title"])
include oznacza przypisanie jedynie parametru title, podczas gdy exclude to wyłączenie podanych z przypisania. Możemy również zawęzić rozważane parametry do zadanej przestrzeni nazw parametrów, np.:
 bindData(album, params, [include:"title"], "album")
Kontrola wartości jest oparta na mechaniźmie springowego org.springframework.validation. Każdorazowa kontrola poprawności instancji klasy dziedzinowej to stworzenie obiektu org.springframework.validation.Errors, który jest następnie do niej przypisywany. Wypisanie wszystkich błędów to:
 album.errors.allErrors.each { println it.code }
Możemy jedynie sprawdzić, czy klasa ma jakiekolwiek błędy z hasErrors(), np.
 if (album.hasErrors()) println "Błędy!"
W GSP będzie to znacznik <g:renderErrors>, np.
 <g:renderErrors bean="${album}" />
Na stronie 82. w podrozdziale "Working with Command Objects" pojawia się materiał o obiektach-polecenie (ang. command object), których opisu nie znalazłem w książce "Beginning Groovy and Grails". Całkowite novum!

Klasa polecenia to klasa, która ma wszystkie cechy klasy dziedzinowej, poza trwałością, tj. możliwe jest automatyczne przypisywanie wartości oraz kontrola ich poprawności. Możemy definiować warunki klasy polecenia i sprawdzać ich poprawność, jak w klasie dziedzinowej.

Klasa polecenia znajduje się w katalogu grails-app/controllers, a nawet w samej klasie kontrolera (Groovy wspiera umieszczanie wielu klas w pojedynczym pliku, co może przydać się, jeśli klasa polecenia wykorzystywana jest jedynie przez pojedynczy kontroler). Nazwa klasy polecenia kończy się Command.

Wykorzystanie polecenia w kontrolerze sprowadza się do podania go jako pierwszy argument w akcji, np. (listing 4-24):
 def save = { AlbumCreateCommand cmd ->
...
}
Podczas wykonania akcji, tworzona jest nowa instancja polecenia, do której przypisywane są parametry żądania. Możemy skorzystać z automatycznie generowanej metody validate() do sprawdzenia, czy parametry żądania są spełniają nałożone warunki, np. (Listing 4-26):
 def save = { AlbumCreateCommand cmd ->
if (cmd.validate()) {
...
redirect(action: "show", id:album.id)
} else {
render(view: "create", model: [cmd:cmd])
}
}
Podobnie jak z klasami dziedzinowymi, mamy automatycznie związywany z klasą polecenia obiekt Errors, który w GSP odczytujemy przez
 <g:renderErrors bean="${cmd}" />
Za pomocą atrybutu allowedMethods określamy jakie typy żądania HTTP są dozwolone dla danej akcji (domyślnie wszystkie żadania są dozwolone), np. (Listing 4-28):
 class SomeController {
def allowedMethods = [action1: 'POST', action3: ['POST', 'DELETE']]
def action1 = {}
def action2 = {}
def action3 = {}
}
Niespełnienie warunku to kod błędu "405 Method Not Allowed" w odpowiedzi.

Obsługa przesłania pliku na serwer jest oparta na springowym org.springframework.web.multipart.MultipartHttpServletRequest i znacznikach - <g:uploadForm> (przypisuje formularzowi typ enctype na multipart/form-data) oraz <input> z atrybutem type="file", np. (Listing 4-30):
 <g:uploadForm action="upload">
<input type="file" name="myfile" />
<input type="submit" value="Upload!" />
</g:uploadForm>
Pobranie przesłanego pliku to wykonanie metody MultipartHttpServletRequest.getFile() z parametrem, który odpowiada wartości atrybutu name w input type="file", np. (Listing 4-31):
 def upload = {
// Zmienna file jest typu org.springframework.web.multipart.MultipartFile
// Brak pliku w żądaniu, to getFile() zwraca null
def file = request.getFile('myFile')
// file to przesłany plik
}
Grails, dzięki Spring MVC, automatycznie przypisuje przesłane pliki do atrybutu klasy dziedzinowej zgodnie z regułami - jeśli typ atrybutu to byte[], wtedy przypisane są bajty pliku, a kiedy String zawartość pliku będzie tekstem. Wystarczy nadać nazwę atrybutowi name w input z type="file", która odpowiada nazwie atrybutu klasy dziedzinowej i z pomocą automatycznego przypisywania wartości zlecenia (przez konstruktor i params) Grails zapisze zawartość do atrybutu, np.:
 // klasa dziedzinowa z polem art typu byte[]
class Album {
byte[] art
...
}

// input typu file z atrybutem name o nazwie art
<input type="file" name="art" />

// automatyczne przypisanie wartości przez konstruktor klasy dziedzinowej
def user = new Album(params)
Odczytanie treści zlecenia to request.inputStream.text.

Przesłanie binarnych danych do klienta (w odpowiedzi) to (Listing 4-36):
 def createZip = {
byte[] zip = ... // pobierz zawartość pliku binarnego
response.contentType = "application/octet-stream"
// przeciążony operator << w akcji!
response.outputStream << zip
response.outputStream.flush()
}
Reszta rozdziału przy kolejnej relacji. Zrobiło się trochę przy długo...

p.s. Nie zapomnieliśmy o konkursie Bloger Roku 2008? Wystarczy wejść na stronę do głosowania na Notatnik, gdzie podajemy nasz adres email i zatwierdzamy. Wiadomość z adresem potwierdzającym pojawia się w naszej skrzynce, klikamy w niego potwierdzając nasz wybór. I tyle. Dziękuję!

13 lutego 2009

Relacja z rozdziału 3. w "The Definitive Guide to Grails, Second Edition"

0 komentarzy
Kiedy poznawałem możliwości Grails z perspektywy książki "Beginning Groovy and Grails: From Novice to Professional" sądziłem, że przedstawia ona wszystko, czego mógłbym sobie życzyć. Podchodząc do kolejnej książki o Grails "The Definitive Guide to Grails, Second Edition" jedyne, co gwarantowało sensowność kolejnej lektury, to jej autorzy - liderzy projektu Grails - Graeme Rocher i Jeff Brown oraz wersja, której dotyczyła - Grails 1.1. Miałem pewne obawy, czy dobry programista może być równie dobrym autorem książki informatycznej, ale po kolejnych rozdziałach (już 4 mam za sobą) poznałem tyle nowych cech Grails, które nie znalazły się w pierwszej książce, że mam pewność, że miałem dużo szczęścia rozpoczynając poznawanie Grails w tej kolejności - najpierw "Beginning Groovy and Grails", a teraz "The Definitive Guide to Grails, 2nd Edition". Pewnie wystarczyłaby jedynie ta druga, ale polecam obie i to właśnie w tej kolejności. W ten sposób udaje mi się rozszerzać wiedzę, a nie ją deaktualizować, czy zamazywać. Ta kolejność gwarantuje płynne wejście (przynajmniej teoretyczne) w temat Grails.

Rozdział 3. "Understanding Domain Classes" dotyczy warstwy modelu, który w Grails jest oparty na klasach dziedzinowych (odpowiadają one encjom w JPA). Każda z klas dziedzinowych składa się z właściwości (atrybutów), które domyślnie są mapowane na tabele w bazie danych, aby możliwy był trwały zapis stanu ich egzemplarzy (instancji). Poza kolumnami, które odpowiadają właściwościom klasy dziedzinowej, Grails dodaje kolumny id (unikatowy identyfikator) oraz version (służy do obsługi optymistycznego blokowania).

Warunki jakie muszą spełniać atrybuty klasy dziedzinowej wyrażane są przez statyczną właściwość constraints, której wartością jest domknięcie. Domknięcie może zawierać ograniczenia dla podzbioru atrybutów. Wykonanie save() klasy dziedzinowej to automatyczne wykonanie domknięcia constraints, którego niespełnienie skutkuje błędem kontroli i wstrzymaniem zapisu do bazy danych.

Z klasą dziedzinową związany jest automatycznie generowany atrybut errors - egzemplarz klasy org.springframework.validation.Errors. Jedną z metod interfejsu Errors jest getAllErrors(), więc dostęp do wszystkich błędów kontroli poprawności danej klasy dziedzinowej sprowadza się do:
 <egzemplarz-klasy-dziedzinowej>.errors.allErrors.each { 
// wykonaj operację na pojedynczym błędzie reprezentowanym przez it, np.
println it.defaultMessage
}
Grails dostarcza metodę validate() do każdej klasy dziedzinowej, która zwraca wartość logiczną true, przy poprawnie zakończonej kontroli poprawności. Mamy do dyspozycji również metodę clearErrors(), która czyści zgłoszone do tej pory błędy (błędy są kumulowane).

Poza prostymi warunkami (ograniczeniami) określonymi w domknięciu constraints (w książce wymieniono 19 reguł), możemy zdefiniować własne przez domknięcie validator, która zwraca wartość logiczną true przy poprawnie zakończonej kontroli. Domknięcie validator akceptuje dwa argumenty - pierwszy jest wartością atrybutu do kontroli, a drugi egzemplarz klasy dziedzinowej. Możemy również zwrócić wartość typu String, która będzie identyfikatorem komunikatu błędu (domyślnie <klasa-dziedzinowa>.<atrybut>.validator.error).

Wyłączenie pola z mechanizmu utrwalania (zapisu do bazy) - oznaczenie pola jako ulotne (ang. transient) - to umieszczenie jego nazwy w liście w statycznym atrybucie transients, np.:
 class Wyrazenie {
Integer poleUlotne

static transients = ['poleUlotne']
}
To jest pierwsza z konstrukcji, które nie podobają mi się, bo przede wszystkim wymagają wsparcia IDE, aby nie popełnić błędu - literówki - w nazwie pola ulotnego. Aż się prosi o mechanizm adnotacji, albo stworzenie nowego podobnego do constraints, gdzie podaje się nazwy atrybutów jako metody. Skoro tam można, tu również. Muszę zapytać o to na grupie użytkowników Grails. ...po chwili...Już!

Nie wszystkie atrybuty klasy dziedzinowej muszą odpowiadać polu (instancji) klasy. Wystarczy metoda odczytu (ang. getter) albo zapisu (ang. setter), aby Grails potraktował to jako atrybut klasy. Zasada ulotności działa również i w tym przypadku. Wyłączenie z zapisu to transients z nazwą atrybutu.

Grails, za pomocą GORM, mapuje klasy dziedzinowe bez konieczności plików XML - "objaw" zasady konwencji-ponad-konfigurację. Możliwe jest zdefiniowanie własnego mapowania za pomocą dedykowanego DSL zwanego Custom Database Mapping DSL lub ORM DSL. Warto z niego skorzystać przy wdrażaniu aplikacji z istniejącym schematem bazodanowym, który nie przystaje do domyślnego mapowania w Grails. Użycie ORM DSL jest możliwe przez deklarację publicznego atrybutu statycznego mapping jako domknięcia z column, np. (Listing 3-13):
 class Person {
String firstName

static mapping = {
id column: 'person_id'
firstName column: 'person_first_name'
version false
}
}
Dodatkowo w przykładzie wyłączono wersjonowanie - version false, które służy do optymistycznego blokowania.

Domyślna nazwa tabeli odpowiada nazwie klasy dziedzinowej - zmiana przez table 'nazwa-tabeli' w mapping.

Relacje w Grails - zadeklarowanie atrybutu w klasie dziedzinowej typu innej klasy dziedzinowej to relacja jeden-do-jednego, w której obie strony są równoważne (nie ma właściciela relacji). Określenie strony wiodącej - właściciela relacji - to static belongsTo = [car:Car], gdzie klasa zawierająca tą deklarację będzie automatycznie posiadała atrybut car typu Car. Nazwa atrybutu może być dowolna, ale naturalnie nazwać ją zgodnie z jej typem (bo ta nazwa będzie nazwą bytu w dziedzinie/modelu, więc będzie intuicyjna). Jeśli nie chcemy modelować zależności zwrotnej (zależnej), np. w klasie Car z powrotem do klasy wiodącej, wystarczy w klasie wiodącej zadeklarować belongsTo z typem Class zamiast mapą, np. static belongsTo = Car. Oczywiście w obu przypadkach operacje są przekazywane kaskadowo w dół grafu (powiązań) i np. skasowanie klasy wiodącej będzie kasowało klasę zależną.

Relacja jeden-do-wielu modelowana jest atrybutem hasMany, która jest mapą, która z kolei składa się z klucza będącego automatycznie dodawanym do klasy dziedzinowej atrybutem-kolekcją oraz wartością mapy będącej typem obiektów w kolekcji. Domyślną kolekcją jest java.util.Set. Jeśli potrzebujemy bardziej wyrafinowanej kolekcji musimy zadeklarować jej typ explicite, np. (Listing 3-19):
 class Album {
String title

static hasMany = [songs:Song]

SortedSet songs
}
Klasa dziedzinowa w Grails może rozszerzać inną za pomocą typowej konstrukcji Groovy/Java - słowo kluczowe extends. W/g autorów dobry model charakteryzuje się co najwyżej 2-poziomową hierarchią dziedziczenia. Domyślnym mapowaniem dla hierarchii dziedziczenia jest tablica-per-hierarchia. Włączenie mapowania tablica-per-klasa to deklaracja tablePerHierarchy false w static mapping w klasie macierzystej (najbardziej ogólnej). tablica-per-hierarchia nie pozwala na włączanie warunków typu "niepuste", ale jest szybka w działaniu, podczas gdy tablica-per-klasa to powolne zapytanie złączeniowe (JOIN) na kilku tabelach. Strategia mapowania jest deklarowana na poziomie hierarchii/klasy i może być różna dla różnych klas dziedzinowych.

Włączenie zanurzenia klasy jakby była integralną częścią składową innej, tak aby pojedyncza tabela zawierała kolumny obu to deklaracja static embedded = ['nazwa-atrybutu'], gdzie typ nazwa-atrybutu to klasa zanurzana.

Grails wspiera dwa typy testowania - jednostkowe i integracyjne. Pierwsze znajdują się w klasach w katalogu test/unit, a drugie w test/integration. Rozbudowywanie klas dziedzinowych o metody dynamiczne, np. validate(), save() jest wyłącznie w testach integracyjnych. Stąd testy jednostkowe są bardzo szybkie (bez całego bagażu "integracyjnego"). Każdorazowe wykonanie polecenia grails create-* tworzy poza właściwym bytem, również klasę z testem integracyjnym.

12 lutego 2009

41. spotkanie Warszawskiej Grupy Użytkowników Technologii Java (Warszawa JUG)

0 komentarzy
Warszawska Grupa Użytkowników Technologii Java (Warszawa JUG) zaprasza na 41. spotkanie, które odbędzie się 17.02.2009 (wtorek) o godzinie 18:00 w sali 5440 Wydziału MIMUW przy ul. Banacha 2 w Warszawie.

Temat prezentacji: Envers
Prowadzący: Adam Warski

Envers, "dodatek" do Hibernate'a, a od niedawna jego część, ma jedno zadanie: ułatwić zapamiętywanie historii zmian dokonywanych na encjach oraz jej odczytywanie i wykonywanie na niej zapytań. Problem wersjonowania encji pojawia się dosyć często, czy to z powodu wymagania prowadzenia ciągłego "audytu" danych, czy też z powodu konkretnych funkcji naszego systemu, jak to ma miejsce w przypadku różnych wiki.

Prezentacja rozpocznie się wprowadzeniem do problemu wersjonowania encji oraz sposobu, w jakim rozwiązuje go Envers. Następnie, trochę o założeniach projektu, konfiguracji oraz pojęciu "rewizji" w przypadku encji. W drugiej, głównej części przyjrzymy się różnym funkcjom Enversa "na żywo" z wykorzystaniem gotowego "szkieletu" prostej aplikacji konsolowej; jest ona dostępna do ściągnięcia jako http://www.warski.org/envers-wjug.zip.

Envers jest prosty w obsłudze i nie wymaga dużej ilości kodu, więc jeżeli ktoś chciałby poeksperymentować na własnym laptopie podczas prezentacji, zachęca się do pobrania paczki. Wystarczy mieć Javę, Anta i skonfigurowaną (prawie dowolną) bazę danych. Przyda się też jakieś narzędzie do oglądania zawartości bazy danych.

Na koniec Adam przedstawi "wnętrzności" Envers, czyli pokazać prostotę tworzenia biblioteki ala Envers, dzięki możliwościom, jakie daje Hibernate. Przedstawiony zostanie model metadanych Hibernate'a, "listenery" i inne trochę rzadziej używane funkcje.

Adam Warski jest informatykiem i absolwentem MIMUWu. Przez jakiś czas pracował w JBossie, a teraz na codzień zajmuje się "zwykłym" programowaniem aplikacji w Javie/JEE. W wolnych chwilach pisze Enversa i inne, mniej lub bardziej przydatne programy (szczegóły na jego stronie domowej i blogu).

Planowany czas prezentacji to 1,5 godziny, po której planuje się 15-30-minutową dyskusję.

Wstęp wolny!

Zapraszam w imieniu grupy Warszawa JUG!

11 lutego 2009

Pierwsze kroki z Grails - rozdział 2. w "The Definitive Guide to Grails"

0 komentarzy
Pierwsze dwa rozdziały mam za sobą i gdybym mógł wszystko rzucić pewnie obróciłbym całe 500+ stron książki "The Definitive Guide to Grails", wydanie 2. w jeden dzień. Wciąż zdumiewa mnie mój zachwyt Grails. Wszystko wydaje się być takie proste. Oby zachwyt nim nie minął z rozpoczęciem pierwszej aplikacji webowej. Podczas mojego wystąpienia na 4Developers 7. marca w Krakowie przedstawię Grails praktycznie oraz jego okolice - Groovy i Project Zero. Wartoby do tego czasu rozpracować wszelkie niuanse, aby nie zostać zaskoczonym bardzo podstawowym pytaniem, a już nieciekawie byłoby nie móc skonfrontować mojego entuzjazmu z faktycznymi wdrożeniami w Grails. Stąd wszelkie uwagi i pytania proszę zadawać teraz. Podglądam opis wykładu Python i Django: Szybkie i latwe tworzenie aplikacji webowych Marcina Mierzejewskiego, tak aby uczestnicy mogli porównać ich cechy (Django wymienia się jako protoplastę Grails), ale niestety jego i moje wystąpienie są w tym samym czasie! No cóż, my wiemy co dobre i pojawimy się na Grails, czyż nie?!

Wracając do rozdziału 2. "Getting Started with Grails" to wiele już z tego było podczas mojej lektury "Beginning Groovy and Grails". Niektóre z porównań czy uwag są nowością dla mnie, ale ogólnie nic nowego.

W poprzednim rozdziale autorzy stworzyli zrąb aplikacji gTunes z pojedynczym kontrolerem. Teraz przedstawiają mechanizm rusztowania (ang. scaffolding), za pomocą którego można niezwykle szybko (< 1 minuta) stworzyć prototyp aplikacji CRUD dla danego modelu (klas dziedzinowych). To musi się podobać! I się podoba. Wyróżniamy dwa typy rusztowania: dynamiczny i statyczny. Dynamiczne rusztowanie budowane jest "na bieżąco" podczas uruchomienia aplikacji. Tworzone są widoki (strony GSP) oraz kontroler. Korzysta z mechanizmu prześwietlania (ang. reflection) oraz cechy Groovy. Wystarczy zdefiniować klasę dziedzinową (poleceniem grails create-domain-class) i w odpowiadającym jej kontrolerze (stworzonym poleceniem grails create-controller) definiujemy atrybut scaffold, np.
 package pl.jaceklaskowski.nauczyciel

class SlowoController {
def scaffold = Slowo
}
Dla Groovy Slowo == Slowo.class, więc nie ma konieczności podania rozszerzenia .class jawnie.

Podczas dynamicznego rusztowania Grails rozpoznaje typy poszczególnych atrybutów klas dziedzinowych i dostraja widok, np. dla atrybutów typu String tworzy pole tekstowe w GSP, a dla atrybutów typu Date wyświetli pole rozwijalne do wyboru daty.

Utworzenie relacji jeden-do-wielu między klasami dziedzinowymi możliwe jest dzięki statycznemu polu hasMany, którego wartością jest mapa, w której klucz to nazwa atrybutu, a wartość to typ elementu, z którym klasa jest związana, np.
 static hasMany = [slowa:Slowo]
Deklarując atrybut statyczny hasMany w klasie A ustawiamy jedynie relację jednokierunkową. Klasa docelowa nie ma świadomości uczestniczenia w niej. Dodanie pola o typie klasy źródłowej relacji zmienia relację na dwukierunkową.

Domyślna implementacja metody toString() w Grails to nazwa klasy i identyfikator obiektu. Ma to znaczenie przy wyświetlaniu listy obiektów w relacji jeden-do-wielu, dla widoku klasy wiodącej w relacji.

Rusztowanie statyczne opiera się na szablonach, które można dowolnie modyfikować. W Grails możemy stworzyć konieczne kontrolery i widoki GSP dla klas dziedzinowych - wystarczy grails generate-views, grails generate-controller czy grails generate-all. Dzięki stworzonym artefaktom możemy poznać jak właściwie działa Grails.

Warto wtrącić uwagę autorów (str. 17), że Grails is not just a CRUD framework. Ostatnio chyba za bardzo naciskam na ten CRUD w Grails i może nawet (pochopnie) postawiłem znak równości między nimi. Zdaje się, że pospieszyłem się (chociaż nie widzę innych zastosowań na razie).

Domyślną metodą (domknięciem) wykonywanym przez Grails w kontrolerze jest index. Nie podano akcji w URI, wykonana zostanie index.

Konwencją w Grails jest wiązanie strony GSP dla danego kontrolera i jego domknięcia tak, że dla kontrolera XControler i akcji (domknięcia) y zostanie wyświetlona strona grails-app/views/x/y.gsp.

W GSP możemy skorzystać z metod redirect i render, odpowiednio do przekierowania na podanego w action domknięcia (akcji) oraz wyświetlenia podanej strony (parametr view).

Możemy korzystać z atrybutu scaffold ustawionego na daną klasę dziedzionową, dla której istnieje "nasz" kontroler bez konieczności tworzenia stron GSP - zostaną stworzone dynamicznie (uzupełnią braki).

Dalej autorzy przedstawiają konfigurację reagującą na środowisko, w którym Grails pracuje. Pojawia się konfiguracja bazy danych (za pomocą konfiguracji Hibernate w grails-app/conf/DataSource.groovy) na przykładzie MySQL. Warto zauważyć, że można konfigurować dostęp do bazy danych przez podanie wszystkich parametrów połączenia (per środowisko), albo wskazanie wpisu w drzewie JNDI parametrem jndiName (w dataSource dla danego środowiska).

Stworzenie paczki wdrożeniowej to wykonanie grails war. Domyślna konfiguracja Jetty znajduje się w GRAILS_HOME/conf/webdefault.xml, a uruchomienie WARa to grails run-war. Polecenie grails run-app jest zalecane do uruchamiania "rozwojowego".

Pełne polecenie grails war to grails [środowisko (opcjonalne)] war [katalog-zapisu-war (opcjonalnie)].

p.s. Zainteresowani wsparciem moralnym pisarza Notatnika proszeni są o wzięcie udziału w konkursie Bloger Roku 2008. Wystarczy wejść na stronę do głosowania na Notatnik, gdzie podajemy nasz adres email i zatwierdzamy. Wiadomość z adresem potwierdzającym pojawia się w naszej skrzynce, klikamy w niego potwierdzając nasz wybór. I tyle. Dziękuję!

10 lutego 2009

Wieści z rozdziału 1. w "The Definitive Guide to Grails, 2nd Ed."

7 komentarzy
Zgodnie z zapowiedzią zabrałem się za lekturę książki The Definitive Guide to Grails, 2nd Ed. autorstwa Graeme Rochera oraz Jeffa Browna. Obaj panowie wielce zasłużeni dla projektu Grails, więc nie byłem wcale zdziwiony sposobem, w jaki obaj przedstawiają go - w samych superlatywach i to w niezwykle kwiecistym języku angielskim. Można połączyć przyjemne - poznawanie Grails - z pożytecznym - nauka zwrotów angielskich (nawet pojawiło się zdanie z Future perfect!). Czyta się niezwykle przyjemnie i jakkolwiek wszystko to już czytałem w poprzedniej książce o Grails - Wieści z rozdziału 4. "Introduction to Grails" z "Beginning Groovy and Grails" oraz Tworzenie interfejsu użytkownika w Grails - rozdział 5 z "Beginning Groovy and Grails", to wtedy były dwa rozdziały, a teraz jeden. To samo, a jakby inaczej.

Rozdział 1. "The Essence of Grails" rozpoczyna się mottem Leonardo da Vinci "Simplicity is the ultimate sophistication.", które w zasadzie podsumowuje peany autorów na temat prostoty jaką wprowadziły Groovy i Grails w życie programistów javowych. Należy przypomnieć, że Ci, którzy nie mają przyjemności pracować z tandemem Groovy/Grails jedynie "conjure up unknown horrors and nightmarish thoughts of configuration, configuration, configuration." (z Grails, the Platform, str. 3). Tak przy okazji, w życiu nie spotkałem tego zwrotu conjure up.

Autorzy rozpoczynają książkę przedstawieniem genezy Grails - "dramatically simplify enterprise Java web development." (str. 1). Z konwencją-nad-konfiguracją (ang. CoC - Convention over Configuration), DRY (ang. Don't Repeat Yourself), domyślnymi ustawieniami, gotowym do użycia środowiskiem na bazie Spring Framework, Hibernate, SiteMesh, Jetty, HSQLDB oraz Groovy (przez co mamy dostęp do pełnego zestawu możliwości platformy Java) możemy czerpać garściami z podobnych rozwiązań jak Ruby on Rails, Django czy TurboGears (wspomina się później również CakePHP), które do tej pory były poza zasięgiem programistów javowych. Z Grails mamy tą kwestię rozwiązaną. Jako programiści aplikacji grailsowych nie musimy wiedzieć, że nasze rozwiązania bazują na Spring Framework oraz Hibernate (a już na pewno nie musimy schodzić na poziom ich konfiguracji w XMLu), ale gdy poczujemy taką potrzebę możemy je dodatkowo "dostroić" do naszych potrzeb. Za autorami - Grails jest "a platform with ambitious aims to handle everything from the view layer down to your persistence concerns." (str. 3) oraz jako programista "you have the assurance that you are standing on the shoulders of giants with the technologies that underpin Grails: Spring, Hibernate, and, of course, the Java platform." (str. 1). Mało? Mnie wystarczy. Chyba nie da się nie zauważyć, że trudno byłoby znaleźć mi w tej chwili lepsze rozwiązanie do tworzenia aplikacji webowych niż Grails.

Po tych wyniesieniach przechodzimy do zapoznania się z krokami do utworzenia pierwszej niezwykle trywialnej, bo składającej się z pojedynczego kontrolera, aplikacji grailsowej - gTunes. Aplikacja gTunes to sklep muzyczny ala Apple, Amazon czy Napster. Oczywiście krótki przerywnik w postaci instrukcji instalacji Grails - pobieramy paczkę dystrybucyjną z http://grails.org, rozpakowujemy do wybranego katalogu, ustawiamy zmienną GRAILS_HOME i PATH, i tyle. Przepis na aplikacyjkę to grails create-app, grails create-controller, grails test-app, aby zakończyć grails run-app. Nie wiemy, po co nam każde z tych poleceń?! Wystarczy grails help <polecenie>. Warto podkreślić, że książka opisuje rozwojową wersję Grails 1.1 (aktualnie mamy dopiero Grails 1.1 beta 3). Nie od parady nosi tytuł "The Definitive Guide to Grails".

Jakkolwiek możemy korzystać z pomocy poleceń grails (który jest skryptem Gant) to mamy również możliwość tworzenia wszystkiego "z ręki". Wybór należy do nas samych.

Podkreśla się znaczenie testów jednostkowych i integracyjnych, chociażby ze względu na dynamiczną naturę Groovy, który, podobnie jak inne języki skryptowe - Ruby i Python - nie posiadają takiego arsenału weryfikacyjnego jak statycznie typowane języki, np. Java. Właśnie z tego powodu wielu wybiera Groovy, ale ma to swoje ograniczenia - większość kontroli poprawności programu przesunięta jest na czas jego uruchomienia. Jeśli kiedykolwiek myślałeś o znaczeniu testów w projekcie, teraz masz powód. Szczęśliwie Grails tworzy odpowiedni byt (kontroler, klasę domenową) wraz z odpowiadającymi testami jednostkowym i integracyjnym.

Podczas grails create-controller tworzony jest kontroler z domyślną akcją (domknięciem) index. Zgodnie z konwencją Grails wykonanie index to wyświetlenie strony grails-app/views/<nazwa-kontrolera (bez Controller)>/index.gsp. Poznajemy metodę render, która m.in. wyświetla tekst na stronie.

Wykonanie testów jednostkowych w Grails wiąże się z taką jego konfiguracją opartą na bytach-zaślepkach (ang. mocks and stubs), które symulują faktyczne zachowanie bytu, dla którego stanowią zaślepkę. Grails umożliwia sprawdzenie, czy wykonanie żądania zwróci zadany tekst (zadaną stronę) przez (Listing 1-9):
 controller.index()
assertEquals "tekst z render", controller.response.contentAsString
Grails podstawia za servletowy HttpServletResponse springowy MockHttpServletResponse z metodą contentAsString. Wykonanie grails test-app to uruchomienie wszystkich testów jednostkowych, ale możliwe jest również zawężenie testów do pojedynczego podając parametr do grails test-app <nazwa-klasy-testowej (bez Tests)>. W katalogu test/reports znajdują się raporty z wykonania testów w formacie XML, HTML i TXT.

Uruchomienie aplikacji to wykonanie polecenia grails run-app (domyślnie na porcie 8080). Jeśli podamy parametr -Dserver.port=<numer-portu>, obowiązującym portem będzie podany.

W ten sposób poznaliśmy podstawowe tajniki tworzenia aplikacji. W kolejnym rozdziale autorzy przygotowali dla nas zestaw cudów do sprawnego tworzenia aplikacji typu CRUD z "some of Grails' Create, Read, Update, Delete (CRUD) generation facilities that allow you to flesh out prototype applications in no time" (str. 15). Jeju, jak tak dalej pójdzie to połowa działu rozwoju pójdzie z torbami (!) W tych czasach należy jeszcze bardziej uważać, co się proponuje w projekcie, bo z 30-osobowego zespołu może zostać trzech i jeszcze dwóch może się nudzić. ;-)

09 lutego 2009

Recenzja "Service Oriented Architecture with Java" i nowa o Grails

0 komentarzy
Kolejny dzień odnotowuję jako książkowy. Właśnie co skończyłem czytać książkę "Service Oriented Architecture with Java", kiedy pojawiła się nowa - "The Definitive Guide to Grails, Second Edition". Pierwsza pozostawia wiele do życzenia i jakkolwiek nie zaliczam spędzonego nad nią czasu jako straconego (głównie za wyjaśnienie różnicy między architekturą Hub and Spoke a ESB) to spodziewałem się więcej. Miało być o SOA dla programistów lub architektów javowych, a nie znalazłem w niej więcej niż za dużo teorii a za mało praktyki. Dosyć obszernie (jak na zawartość książki) o JAX-WS, niewiele o Apache Axis, Spring-WS, XFire (CXF), a nawet JBI i OpenEJB. Było również o SCA i SDO, więc wszystko i nic. Zbyt obszernie. Recenzję opublikowałem na Amazonie - Perhaps, your time won't be lost either oraz moim Wiki - Book review: Service Oriented Architecture with Java. Recenzja w języku angielskim ze względu na wymagania wydawcy. Poprosiłem tym samym o kolejne:
Pora zabrać się poważniej za UML, jeśli marzy mi się Sun Certified Enterprise Architect (SCEA).

Wracając do tej drugiej pozycji o Grails, to niezwykle szybko działają w Apress. Dopiero, co wysłałem recenzję do wydawnictwa z prośbą o kolejne książki (patrz: Groovy i Grails, Bloger Roku 2008, 4Developers i Refaktoryzacja) i mijają niecałe 4 dni, a książka już u mnie! Miła niespodzianka poniedziałkowa. Oczywiście (chwilowo) zarzucam lekturę JAX-WS na rzecz "The Definitive Guide to Grails, Second Edition". W końcu taki był plan. Książka to "cegła" na 570 stron autorstwa samego Graeme Rochera, który jest głównodowodzącym w projekcie Grails, więc pewnie odpłynę do końca tygodnia. Właśnie zbudowałem nowiuteńką wersję rozwojową Apache Geronimo 2.2 i z nim zamierzam popróbować uruchomienie aplikacji grailsowych. Na początek zabiorę się za artykuł z developerWorks - Apache Geronimo on Grails.

p.s. Konkurs Bloger 2008 roku trwa, w którym zgłosiłem Notatnik. Wystarczy wejść na stronę do głosowania na Notatnik, gdzie podajemy nasz adres email i zatwierdzamy. Coś tam pojawia się w naszej skrzynce, klikamy link potwierdzający w wiadomości i voila. Dziękuję!

07 lutego 2009

Sun Certified Developer for Java Web Services 5 (SCDJWS) zdany!

4 komentarzy
Okazuje się, że w przeciwieństwie do mojego wczorajszego pesymizmu o mojej znajomości tematu usług sieciowych (patrz: Zabieram się za JAX-WS), dzisiaj, ku mojemu zdumieniu, otrzymałem następującą wiadomość:

Dear Jacek (Certification ID#: SUN295099)

Congratulations on completing all the requirements for the
Sun Certified Developer for Java Web Services 5 certification. You were certified on 12/10/2008.

Congratulations!

Certification Department

W ten sposób stałem się posiadaczem certyfikatu Sun Certified Developer for Java Web Services 5 (SCDJWS5). Do pełni szczęścia brakuje mi jeszcze informacji o wynikach z poszczególnych obszarów tematycznych, bo pakiet certyfikacyjny jeszcze w drodze.

Jeśli ktoś zapyta, jak się przygotowywałem, z jakich książek korzystałem, to niestety nie będę miał satysfakcjonującej odpowiedzi - po prostu podszedłem do egzaminu "z biegu" i okazuje się, że najwięcej wiedzy dało mi wcześniejsze rozpoznawanie tematu EJB3 z jego @WebService i próby uruchomienia usług sieciowych na bazie EJB3 z Apache Geronimo. Zapomniałem nawet, że udało mi się opublikować kilka artykułów na ten temat - Tworzenie usługi sieciowej z JAX-WS, Tworzenie usługi sieciowej z JAX-WS, Apache Geronimo 2 i NetBeans 6 czy SCAlanie z JAX-WS.

Chciałbym podziękować Grzegorzowi Dudzie za jego wpis SCDJWS za darmo, który był początkiem całej historii (patrz: Sun Certified Developer for Java Web Services (SCDJWS) bezpłatnie do 10 grudnia!). Wielkie dzięki Grześ!

Czy ktoś jeszcze podchodził do tego certyfikatu? Jak poszło?

Wracam do lektury Service Oriented Architecture with Java autorstwa Vincenzo Caselli, Binildas A. Christudas, Malhar Barai (Packt, June 2008). Już się naczekała na swoje "5 minut" na półce Biblioteczki Warszawskiego JUGa. Pierwszy rozdział to porażka - masło maślane, literówki, nuda, ale rozdział 2. czyta się przyjemnie(j). I jest ciekawy przykład z uruchomieniem usługi sieciowej JAX-WS z Endpoint.publish(String address, Object implementor). Takie ciekawostki sprawiają, że czytanie książek, nawet tych początkowo nudnych, może mile zaskoczyć.

06 lutego 2009

Zabieram się za JAX-WS

1 komentarzy
Nowe książki o Groovy i Grails jeszcze nie dotarły, więc pomyślałem, aby zabrać się za rozpoznanie tematu Java API for XML-Based Web Services (JAX-WS) 2.0. Do tej pory tematyka usług sieciowych (ang. web services) była przeze mnie traktowana po macoszemu, a na mojej liście do rozpoznania leżała od miesięcy i nie ma co więcej czekać. Uzbrojony w wiedzę o Groovy (po lekturze książki Book review: Beginning Groovy and Grails: From Novice to Professional) wydaje mi się, że teraz każdy temat pójdzie gładko, więc dlaczego nie zająć się JAX-WS i przyjrzeć mu się bliżej, może nawet z Groovy w tle?

Zacząłem od pobrania materiałów - specyfikacji JAX-WS 2.0 oraz referencyjnej implementacji JAX-WS RI ze strony domowej specyfikacji, dokumentacji Java Web Services Tutorial 2.0 oraz ostatniego wydania rozwojowego NetBeans IDE 7.0 (ten niestety mnie zaskoczył brakiem pliku uruchomieniowego dla Windows w dzisiejszej wersji rozwojowej, więc będę musiał poczekać na kolejną!). Jest jeszcze do nauki (Free) Web Services and SOA Programming (with Passion!) Hands-on Online Course.

Instalacja JAX-WS RI to uruchomienie instalatora i można próbować się z tematem.
 jlaskowski@work /cygdrive/c/apps
$ java -jar JAXWS2.1.1_20070501.jar
jaxws-ri
...
installation complete
Poza tym gotowe środowisko jest dystrybuowane w Java SE 6, więc nawet ten krok nie jest konieczny.

Nie potrafię wytłumaczyć dlaczego, ale zawsze wspominając o JAX-WS na myśl przychodził mi projekt Apache CXF. Zacząłem przeszukiwać jego dokumentację i o dziwo trafiłem na powiązanie CXF z...OSGi - Distributed OSGi. Jeśli jeszcze dostanę się do informacji, że można połączyć Groovy z CXF (dlaczego by nie, skoro Groovy to Java?), a w tle będzie OSGi, może i Grails, byłbym w ogóle szczęśliwy. Na razie wezmę się za lekturę specyfikacji JAX-WS i podłubię po trochu w NetBeans. Później wrócę do CXF, a w międzyczasie przyjdą kolejne książki o Groovy i Grails, i wrócę do nich. Wszystko ustawione. Skoro wszystko mam, wracam do czytania i (potencjalnie) relacji na blogu. Kto by pomyślał, że tak mi przypadnie to czytanie do gustu?!

05 lutego 2009

Groovy i Grails, Bloger Roku 2008, 4Developers i Refaktoryzacja

4 komentarzy
Skończyłem książkę o Groovy i Grails - Beginning Groovy and Grails: From Novice to Professional, co czytelnicy mojego bloga mogli dostrzec przez ostatnie 2 tygodnie. Od razu wziąłem się za recenzję i opublikowałem ją u siebie w Wiki Book review: Beginning Groovy and Grails: From Novice to Professional, którą również opublikowałem na Amazonie - The book made me a single-technology addict. Wystarczył jeden dzień i "1 of 1 people found the following review helpful". Nie spodziewałem się tak szybkich reakcji.

Skoro wszedłem w nastrój na czytanie książek poprosiłem o kolejne z Apressu:
Nie trwało długo, zanim otrzymałem odpowiedź z Apressu od Cheryl Martinez (osoba odpowiedzialna za kontakty z JUGami):

Thanks so much Jacek! What a great review. We will indeed have the books you requested out to you soon.

Zdaje się, że Groovy i Grails nie opuszczą mnie tak prędko, czego sobie i Wam życzę ;-)

Jeden konkurs minął, a zaczął się kolejny - Bloger Roku 2008. Ten będzie trochę tańszy, bo nie wymaga żadnych SMSów, tylko 3 sekundy Twojego czasu. Wchodzimy na stronę konkursową dla Notatnika (niestety bez potwierdzenia, że faktycznie na niej jesteście!), wpisujemy poprawny adres email i OK. Wdzięczność gwarantowana!

Jeśli jeszcze nie masz planów na 7 marca 2009 (sobota) i będziesz w pobliżu Krakowa warto rozważyć udział w konferencji "dla programistów tworzona przez programistów" - 4Developers. Będzie wiele ciekawych osób (Grzegorz Duda z "Java Underground", Waldemar "Waldi" Kot ze swoim CEPem i Adam Bien, nie zapominając o Nealu Fordzie) , więc i Ciebie nie powinno zabraknąć. Będę i ja z tematem "Zwinne i lekkie aplikacje webowe w Javie z Groovy, Grails i Project Zero". Jest jeszcze trochę czasu, aby podstroić temat i przygotować się na serię pytań, których spodziewam się nie będzie mało. Może warto rozważyć przesłanie mi kilku zawczasu, abym przygotował odpowiedź inną niż "Zapiszę i sprawdzę"? Czekam z niecierpliwością, bo szkoda byłoby powtarzać coś, co wielu dobrze już zna.

Mimo, iż pojawia się jako ostatnia wiadomość, lektura książki "Jak odmienić sposób programowania używając refaktoryzacji" zajęła mi dłuższą chwilę w ostatni weekend. Przyznaję, że nigdy wcześniej nie rozważałem refaktoryzacji jako specjalnego tematu do rozważań - po prostu temat wydawał mi się na tyle integralny w zestawie "narzędzi" programisty, że nie było się czym zajmować. Po prostu był i sądziłem, że wiedza jaką posiadałem była wystarczająca. Właśnie ta książka ukazała mi jak bardzo się myliłem, a w tym całe piękno refaktoryzacji i...prozy Mariusza Sieraczkiewicza. 110 stron czyta się niezwykle przyjemnie dzięki odpowiednio dobranej fabule. Czyta się ją z podobnym zacięciem jak inne książki sensacyjne, w których znajdziemy wprowadzenie do tematu, aby później rozwiązać go bardzo wyrafinowanymi acz prostymi w użyciu metodami. Nie inaczej było w tej książce - (trochę przydługawy) wstęp bodajże przez 2 czy 3 rozdziały, aby w kolejnych pokazać, co w trawie piszczy. Na bazie przykładowej aplikacji Mariusz przedstawia poszczególne kroki w dobrze przemyślanym procesie refaktoryzacji. Jakkolwiek w wielu miejscach, nie popełniłbym tak karygodnych błędów jak krótkie nazwy zmiennych, nieodpowiadające treści nazwy metod, przydługie ify, to nie przeszkodziło to wcale znaleźć w przykładzie wartościowych refaktoryzacji - oczywistych, a wciąż za rzadko stosowanych przeze mnie (zbyt często technika Copy-Paste'a zwycięża). Pora to zmienić i mam świadomość, że książka miała na tą decyzję niemały wpływ. Teraz stałem się wrażliwy refaktoryzacyjnie. Czujcie się ostrzeżeni! ;-)

04 lutego 2009

Inni klienci aplikacji w Grails - rozdział 13 z "Beginning Groovy and Grails"

3 komentarzy
Ostatni rozdział 13. "Alternative Clients" w książce Beginning Groovy and Grails: From Novice to Professional przedstawia temat klientów aplikacji grailsowej innych niż przeglądarka. Już w poprzednim rozdziale o REST mieliśmy możliwość poznać klienta RESTowego w postaci skryptu Groovy, a teraz autorzy omówili tworzenie skryptów Groovy, które korzystają z usług sieciowych (ang. web services) i posiadają bardziej zaawansowany interfejs użytkownika.

Tworzenie aplikacji GUI w Groovy wymaga pobrania dodatkowych bibliotek - SwingXBuilder, SwingX, JGoodies Forms i Glazed Lists. Ich instalacja w Groovy (teraz jesteśmy na poziomie Groovy, a nie Grails) to umieszczenie ich w CLASSPATH, w <katalog-domowy-groovy>/lib lub <katalog-domowy-użytkownika>/groovy/lib.

SwingXBuilder to Groovy "builder" (jak ja miałbym to przetłumaczyć?! Może budowniczy...Bob?!) do tworzenia interfejsu użytkownika w Swingu. Pod spodem korzysta z biblioteki SwingX. JGoodies FormLayout jest popularnym zarządcą układu (ang. layout manager) dla Swinga. Glazed Lists natomiast jest bardzo zaawansowanym komponentem Swing do tworzenia tabel. Ze SwingXBuilder oraz komponentami SwingX tworzymy okienka dialogowe, podpowiedzi i pasek statusu, z Glazed Lists sortowane tabele, a JGoodies Forms obsłuży ich rozkład.

Do skryptu Groovy przekazywany jest parametr args, który jest listą parametrów wejściowych skryptu, np. (Listing 13-1):
 if (args.size() < 2) {
...
}
def userid = args[0]
def password = args[1]
Uruchomienie skryptu Groovy to wykonanie groovy <nazwa-skryptu> <parametry>.

W skryptach możemy skorzystać z narzędzia JLine do obsługi wprowadzanego przez użytkownika tekstu z linii poleceń, np. ukrycia wpisywanego hasła, np. (Listing 13-2):
 import jline.ConsoleReader

ConsoleReader cr = new jline.ConsoleReader()
print "User id: "
def userid = cr.readLine()
print "Password: "
def password = cr.readLine(new Character('*' as char))

// można również połączyć print i readLine
def uzytkownik = cr.readLine("Użytkownik: ")
JLine jest dystrybuowany z Groovy.

Groovy może wszystko, co potrafi Java. Według autorów, tworzenie GUI w Javie to wybór między Java Swing a Eclipse Standard Widget Toolkit (SWT). Można, więc zamiast programować w Javie i korzystać ze wspomnianych bibliotek, programować w Groovy. Znaczne uproszczenie daje skorzystanie z "budowniczych" (ang. builders) w Groovy - SwingBuilder, SwingXBuilder czy JideBuilder dla Swing oraz SwtBuilder dla SWT. Rozkład komponentów, definiowanie ich akcji jest znacznie prostsze z ich pomocą, np. (Listing 13-5):
 swing = new SwingXBuilder()
swing.lookAndFeel('system')

swing.action(id: 'exitAction',
name: 'Exit'
closure: this.&exit,
mnemonic: 'x',
accelerator: 'F4'
shortDescription: 'Exit SimpleUI'
}

void exit(event) {
System.exit(0)
}
Potwierdzeniem możliwości SwingXBuilder jest wersja Groovy Console, która znajduje się w repozytorium SwingXBuilder w demos/Console.

Podsumowaniem rozdziału są zdania

"The important thing to remember is that "Groovy is Java" and that allows you to use any of the Java components and libraries you want to build an application."

oraz

"Our goal was to give you a sample of what is possible. You are only limited by your imagination."

Wyjdzie w praniu, jak bardzo się (nie)pomylili. ;-)

W ten sposób, dobrnąłem do samego końca książki Beginning Groovy and Grails: From Novice to Professional, którą wpisuję na listę książek przeczytanych "od deski do deski". Czy warto było? Zdecydowanie TAK! Sama dokumentacja Grails jest bardzo wartościowym źródłem wiedzy o nim, ale książki mają to do siebie, że ich treść prowadzona jest jak pewien projekt, w którym kolejne rozdziały dotykają funkcjonalności wymaganej w kolejnych iteracjach rozwoju aplikacji. Tak też było w przypadku tej książki. Dodatkowo miałem okazję poznać wiele wspomagających projektów, o których nawet nie wiedziałem, że istnieją (!) Jeśli przyjdzie mi realizować projekt aplikacji webowej Grails będzie z pewnością mocnym kandydatem do jego realizacji (obok Apache Wicket, JBoss Seam i JSF - chociaż samo JSF wydaje się być bardzo prymitywne przy poprzednikach). Grails, swoją funkcjonalnością nie odbiega od innych znanych mi szkieletów webowych, a w wielu miejscach przebija ich o głowę (chociażby scaffolding, klasy dziedzinowe z metodami bazodanowymi, "builders", zintegrowany tandem Hibernate+Spring Framework czy Groovy jako język programowania), a jedynym problemem, jaki mógłbym podnieść teraz, to brak własnego doświadczenia wdrożeniowego, w którym mógłbym sprawdzić siłę Grails w boju. Po lekturze książki nie spodziewałbym się wielu wpadek, ale diabeł tkwi w szczegółach i nie twierdzę, że ich nie byłoby. Może dzięki zmniejszeniu ilości czasu potrzebnego na stworzenie aplikacji (dzięki wspomnianym wcześniej cechom Grails) miałbym czas na rozwiązanie potencjalnych niedoskonałości? Mam wrażenie, że tak. A jak Wam idzie wdrażanie aplikacji opartych na Grailsie? Wciąż działają? Z kim konkurowały podczas etapu wyboru tego właściwego szkieletu webowego?

03 lutego 2009

Wdrażanie i aktualizacja aplikacji w Grails - rozdział 12 z "Beginning Groovy and Grails"

0 komentarzy
Po bardzo burzliwych rozdziałach przedstawiających architekturę Grails i potencjał jego wtyczek przyszła pora na niewielkie "podsumowanie" w postaci rozdziału 12. "Deploying and Upgrading". Autorzy wyjaśniają w nim, w jaki sposób uruchamiamy aplikacje grailsowe w ramach serwerów aplikacyjnych Java EE oraz aktualizujemy wersję Grails w aplikacji. Pojawi się również Gant, w którym stworzone zostanie nowe polecenie grails.

Grails dystrybuowany jest z całym środowiskiem rozwojowym opartym na Jetty oraz relacyjnej bazie danych HSQLDB. Wystarczy wykonać polecenie grails run-app, aby uruchomić aplikację w kompletnym środowisku uruchomieniowym - serwerem aplikacji i bazą danych. Brakuje w nim jednak cech środowisk produkcyjnych, z mechanizmami równoważenia obciążenia (ang. load balancing), wysokiej dostępności (ang. high availability) oraz klastrowania (ang. clustering) dla serwera aplikacyjnego oraz wydajnej i transakcyjnej bazy danych.

Wdrożenie (ang. deployment) aplikacji grailsowej składa się z trzech kroków. Najpierw definiujemy konfigurację aplikacji dla poszczególnych środowisk (rozwojowego, testowego i produkcyjnego), tworzymy wersję wdrożeniową w postaci pliku WAR (ang. Web ARchive), aby w końcu wdrożyć go na serwerze aplikacyjnym (kontenerze webowym/servletów).

W każdym ze środowisk, przyjdzie nam zdefiniować specyficzne parametry konfiguracyjne. Polecenie grails uruchamia środowisko w zależności od swojego drugiego parametru na linii poleceń lub w plikach konfiguracyjnych DataSource.groovy lub Config.groovy. Wyróżniamy trzy predefiniowane wartości dla każdego ze środowisk. Dla rozwojowego środowiska jest to dev (na linii poleceń) oraz development w plikach konfiguracyjnych, test (oba parametry) dla testowego oraz prod i production dla środowiska produkcyjnego. Możemy zdefiniować dodatkowe środowiska, np. testów integracyjnych, testów akceptacyjnych (ang. UAT - user Acceptance Tests) oraz testów wydajnościowych (ang. PT - Performance Tests) z dowolnie wybranymi przez nas identyfikatorami. Wskazanie własnego środowiska to wykonanie polecenia grails z parametrem grails.env, np. grails -Dgrails.env=uat run-app.

Grails zawiera 4 główne kategorie konfiguracyjne - konfiguracja adresów URL, domknięcie do wykonania przy uruchomieniu i zatrzymaniu aplikacji, źródła danych i poziomy komunikatów. Katalog grails-app/config jest katalogiem konfiguracyjnym Grails.

Domknięcie init z parametrem servletContext typu javax.servlet.ServletContext w grails-app/config/Bootstrap.groovy jest wykonywane każdorazowo przy uruchomieniu aplikacji (włączając w to sytuację ponownego wdrożenia), a destroy przy zatrzymaniu, aczkolwiek nie jest to gwarantowane, np. podczas zatrzymania serwera aplikacyjnego.

Za pomocą GrailsUtil.environment() możemy określić środowisko, w którym uruchomiona jest aplikacja i podjąć stosowne czynności.

Domyślnie, Grails skonfigurowany jest z wbudowaną bazą danych HSQLDB w trybie pamięciowym (ang. in-memory). Tym samym każde uruchomienie aplikacji to pusta baza danych. W grails-app/config/DataSource.groovy konfigurujemy bazę (sekcja dataSource) i Hibernate (sekcja hibernate). Możliwa jest konfiguracja obu per środowisko w sekcji environments, która nadpisuje bardziej ogólną konfigurację w sekcjach dataSource i hibernate. Nie zapominajmy o umieszczeniu pliku jar sterownika bazy danych w katalogu lib w projekcie. Podczas tworzenia paczki wdrożeniowej Grails umieści go w WEB-INF/lib.

Konfiguracja (poziomu) komunikatów oparta jest na Apache Commons Logging oraz Apache log4j. Znajduje się w grails-app/config/Config.groovy. Grails posiada kilka specjalnych kanałów (ang. loggers) - grails.app.controller dla komunikatów wszystkich kontrolerów, grails.app.domain dla klas domenowych, grails.app.service dla usług oraz grails.app.taglib dla znaczników GSP.

Tworzymy paczkę wdrożeniową aplikacji poleceniem grails war. Autorzy sugerują jednak bardziej wyrafinowany sposób składający się z...7 kroków - pobranie aktualnej wersji z repozytorium, wykonanie testów, zmianę parametru app.version w application.properties samodzielnie bądź poleceniem grails set-version, aby ustawić wersję przygotowywanej aplikacji, np. w formacie X.Y.Z, grails clean, dopiero wtedy grails war (prawdopodobnie ze wskazaniem środowiska produkcyjnego, np. grails prod war), ponowna zmiana app.version i zatwierdzenie application.properties do repozytorium.

W sekcji "Deploying to an Application Server" autorzy piszą "a WAR file can be deployed to Java EE application servers such as JBoss, GlassFish, Apache Geronimo...". I to jest to, co mi się bardzo spodobało. Jest Apache Geronimo! Tylko dlaczego dopiero na 3. pozycji?!

Grails umożliwia uruchomienie aplikacji na porcie HTTPS poleceniem grails run-https. Poza domyślnym portem 8080, aplikacja będzie dostępna na 8443.

Grails nie udostępnia specjalnych poleceń upraszczających wdrożenie aplikacji. Zaleca się użycie narzędzia Gant do tego celu. Gant jest narzędziem automatyzującym pracę w projekcie przez połączenie cech Apache Ant z Groovy - z pierwszego mamy gotowe zadania, a z drugiego język do ich oskryptowania (zamiast korzystać tradycyjnie z XML w Ant). Tak na prawdę polecenia grails to uruchamianie odpowiednich "skryptów" Gant. Stworzenie nowego polecenia dla grails to napisanie skryptu Gant i umieszczenie go w dowolnym z poniższych katalogów - <katalog-domowy-użytkownika>/.grails/scripts, <katalog-projektu>/scripts, <katalog-projektu>/plugins/*/scripts oraz <katalog-domowy-grails>/scripts. Autorzy przedstawiają przykładowy skrypt - a tym samym nowe polecenie grails deploy - do wdrożenia aplikacji na serwerze JBoss AS. Więcej na stronie http://www.beginninggroovyandgrails.com (dlaczego dopiero teraz pojawia się wzmianka o tej stronie?!).

Podczas uruchomienia aplikacji poleceniem grails run-app(s) Grails sprawdza parametr app.grails.version w application.properties, który znajduje się w katalogu głównym projektu aplikacji. Jeśli wartość app.grails.version nie jest zgodna z bieżącą wersją Grails pojawi się komunikat informujący o rozbieżności wersji. Wykonanie grails upgrade uaktualni pliki Grails w projekcie...nadpisując już istniejące (!) Kolejny powód, aby utrzymywać projekt aplikacji w repozytorium.

Jest to ostatni rozdział dotyczący zagadnień projektowych Grails jako szkieletu webowego Java EE. Kolejny i tym samym ostatni będzie o tworzeniu różnego rodzaju klientów dla naszej aplikacji.

02 lutego 2009

40. spotkanie Warszawskiej Grupy Użytkowników Technologii Java (Warszawa JUG)

0 komentarzy
Warszawska Grupa Użytkowników Technologii Java (Warszawa JUG) zaprasza na 40. spotkanie, które odbędzie się 03.02.2009 (wtorek) o godzinie 18:00 w sali 5440 Wydziału MIMUW przy ul. Banacha 2 w Warszawie.

Temat prezentacji: Liferay / WebSynergy - portal (miś) na miarę naszych możliwości
Prowadzący: Piotr Pietrzak

Prezentacja przedstawi funkcjonalność Liferay Portal, który jest kontenerem portletów. Zobaczymy jak dostosować portal do swoich wymagań (wygląd, polonizacja) oraz jak wygodnie/wydajnie można programować w środowisku portletowym. Porównane zostaną sposoby komunikacji międzyportletowej i wykorzystamy mechanizm Comet. Na koniec zobaczymy języki skryptowe (na przykładzie PHP) jako języki do tworzenia portletów.

Piotr Pietrzak jest pracownikiem Działu Aplikacji Komputerowych (DAK) Uniwersytetu Warszawskiego. Zainteresowany głównie Javą, bazami danych (najchętniej nierelacyjnymi), w wolnych chwilach troluje na grupach i tworzy ciekawe, lecz zupełnie nieprzydatne projekty w Javie, PHP i od niedawna w Erlangu.

Planowany czas prezentacji to 1,5 godziny, po której planuje się 15-30-minutową dyskusję.

Wstęp wolny!

Zapraszam w imieniu grupy Warszawa JUG!

01 lutego 2009

Przetwarzanie wsadowe w Grails - rozdział 11 z "Beginning Groovy and Grails"

2 komentarzy
Rozdział 11. "Batch Processing" w książce Beginning Groovy and Grails: From Novice to Professional omawia temat przetwarzania wsadowego w Grails. Zdumiewające jest pierwsze zdanie rozpoczynające rozdział "Grails is more than just a web framework - it is an application framework". Wydaje się, że może być to bardzo zdumiewające, nie tylko dla takich nowicjuszy grailsowych jak ja. Od jakiegoś czasu śledzę grupę dyskusyjną Grails User, przeglądałem dokumentację na oficjalnej stronie Grails i do tej pory nie trafiłem na podobne stwierdzenie.

Prawie wszystkie aplikacje zawierają funkcjonalność, która musi być wykonywana o określonych porach lub co zadany interwał, którą nazywamy przetwarzaniem wsadowym (ang. batch processing).

W Grails obsługa przetwarzania wsadowego opiera się na otwartym projekcie Quartz, który dostarczany jest w ramach podstawy infrastrukturalnej Grails - Spring Framework. Quartz jest podobny do uniksowego crona, który uruchamia zadania w przyszłości, z tą różnicą, że może korzystać z komponentów aplikacyjnych udostępnianych w ramach serwera aplikacyjnego.

Pracę z Quartz w Grails rozpoczynamy jego instalacją poleceniem grails install-plugin quartz. Wtyczka dostarcza nowe polecenie grails create-job.

Zadanie (ang. job) jest aplikacją, którą chcemy wykonać o zadanej porze. Określamy co i kiedy ma być wykonywane.

Tworzymy zadanie poleceniem grails create-job <nazwa-zadania>. Powstanie klasa <NazwaZadania>Job w grails/job. Konwencją Grails jest, że polecenia create-* tworzą klasy o zadanej przez użytkownika nazwie dodając przyrostek odpowiadający poleceniu, np. create-job first tworzy klasę FirstJob. Domyślna klasa zbudowana jest z atrybutu timeout, który określa, co ile wykonywane będzie zadanie zdefiniowane przez domknięcie execute().

W rozdziale znajduje się przykład tworzenia funkcjonalności tworzenia i rozsyłania raportów w trybie wsadowym oparte na klasach i usługach stworzonych w rozdziałach wcześniejszych.

Klasa zadania może zawierać opcjonalne atrybuty name oraz group. Definiują one, odpowiednio, nazwę zadania oraz jego grupę.

Domyślnie zadanie związane jest z sesją Hibernate, więc pobieranie danych z bazy nie wymaga specjalnych czynności. Wyłączenie wiązania zadania z sesją Hibernate jest możliwe, jeśli ustawimy atrybut sessionRequired na false.

Mamy dwie możliwości definiowania pory wykonania zadania - atrybuty startDelay z timeout lub cronExpression. Atrybut startDelay (domyślnie 0) określa, kiedy wykonane zostanie zadanie, licząc od uruchomienia aplikacji. Atrybut timeout (domyślnie 60000 ms = 1 min) określa interwał (w milisekundach) między kolejnymi wykonaniami zadania. Atrybut cronExpression to możliwość wykorzystania własnej wiedzy uniksowej dotyczącej demona cron. Deklarujemy wykonanie zadanie w formacie crontab.

Może się zdarzyć, że wykonanie zadania nie zakończy się, a kolejne zostanie uruchomione. Kontrola równoległego wykonywania zadań jest możliwa przez logiczny atrybut concurrent (false/true).

Format cronExpression składa się z 6 pól oddzielonych białym znakiem (spacja/tabulacja). Poszczególne pola odpowiadają sekundom, minutom, godzinom, dniom, miesiącom, dniom tygodnia i opcjonalnie, w 7. polu, latom. Specjalne znaki to gwiazdka (*), znak zapytania (?), myślnik (-), przecinek (,) oraz ukośnik (/).

Zadanie ma dostęp do automatycznego wiązania zależności bez specjalnej konfiguracji, więc dostęp do usługi grailsowej to po prostu zadeklarowanie pola o odpowiednim typie bądź nazwie. Tworzymy usługę poleceniem grails create-service Batch, a następnie w klasie zadania def batchService (alternatywnie BatchService batchService). Spring Framework zajmie się resztą i zagwarantuje, że pole nie będzie niezainicjowane.

Usługa BatchService pobiera wszystkich użytkowników z niepustym polem email (Listing 11-4):
 def users = User.withCriteria {
isNotNull('email')
}
a następnie, wyłącznie jeśli users jest niepuste, pobiera listę zadań dla każdego z nich (Listing 11-4):
 users?.each { user ->
def inputCollection = Todo.findAllByOwner(user)
}
Niesamowita "skromność" kodu w Grails! Przypomina mi to dawne konkursy w C, w którym zawodnicy tworzyli zaawansowane programy w formie jednolinijkowców i z bardzo wyrafinowanymi konstrukcjami. Trzeba było nie lada umysłu i doświadczenia, aby docenić "zalet" takiego programowania. W Grails to "przykrycie" funkcjonalności Hibernate oraz Spring Framework wraz z dynamizmem Groovy (chociażby przez "doklejenie" metod bazodanowych) nasuwa mi takie skojarzenia. Kod nie jest jednak tak zawiły, jak to miało miejsce w tych jednolinijkowcach w C.

W poprzedniej relacji z rozdziału 10. "Reporting" (patrz Raporty w Grails - rozdział 10 z "Beginning Groovy and Grails") mieliśmy okazję poznać sposób na dotarcie do ziaren springowych za pomocą atrybutu sesyjnego GrailsApplicationAttributes.APPLICATION_CONTEXT. Tym razem autorzy zademonstrowali inny, alternatywny sposób - użycie interfejsu ApplicationContextAware. Interfejs dostarcza metodę void setApplicationContext(ApplicationContext applicationContext), która przekazuje kontekst springowy, który z kolei możemy wykorzystać do pobrania dowolnego ziarna springowego:
 EMailProperties eMailProperties = applicationContext.getBean("eMailProperties")
Tak też można, skoro Grails to "nakładka" na Spring Framework, a Groovy to "nakładka" na Javę. Nie zapomnieliśmy o tym, prawda?