19 stycznia 2009

Relacja z rozdziału 3. "More Advanced Groovy" z "Beginning Groovy and Grails"

4 komentarzy
Jedni na nartach spędzają urlop z rodziną, a ja wciąż przy lekturze Beginning Groovy and Grails: From Novice to Professional. W międzyczasie pojawiają się komentarze innych zainteresowanych własnym rozwojem w tematyce Groovy, co cieszy, bo będzie z kim obgadać temat, czy to podczas 4 Developers 2009, GeeCON 2009 (na której zagości współtwórca Grails - Guillaume Laforge), czy Javarsovia 2009 (auć, ta strona jeszcze w rozsypce!). Tak czy owak, skoro Groovy to Java z pewnymi atrakcjami, to możnaby pokusić się o rozpoznanie możliwości uruchamiania Groovy ze Spring Framework (to już wiem, że jest możliwe, ale nie próbowałem), albo nawet pisząc pakunki OSGi, potencjalnie ze wsparciem Spring-DM. Możnaby również spróbować zbadać wartość płynącą z wdrożenia ziaren EJB 3.1 pisanych w Groovy (groz(n)iej brzmi?* - ciekawostki z tym stwierdzeniem szukaj na samym końcu). Możnaby jeszcze kilka innych tematów zahaczyć, ale czy warto? Właśnie to mnie wciąż nurtuje - skoro programowanie w Groovy daje tyle uproszczeń, to co stoi na przeszkodzie do jego powszechnego użycia? Wyłącznie nieznajomość? Nie, to da się załatwić w kilka dni (czy tygodni) a zysk może być niewspółmierny do kosztów wdrożenia zespołu do nowego języka, który nie różni się wiele od Javy. A może niechęć do nauki nowego?! Eee, to byłoby zbyt straszne, aby było powszechne w javowych zespołach projektowych - wręcz nieprawdopodobne. Na razie dumanie zostawiam na boku i wracam do relacji z lektury książki o Groovy & Grails.

Muszę coś wymyśleć, aby relacje z lektury były bardziej skumulowane, bo czytam znacznie szybciej niż relacjonuję i pojawił się niewielki "backlog". Najlepiej odstawiłbym relacjonowanie i zabrałbym się za coś bardziej praktycznego, ale myślę sobie, że powolne dawkowanie czegoś nowego niejednego z pewnością uzależni i tym samym będzie więcej zainteresowanych rozpoznawaniem tematu. A o to chodzi! Więcej głów w dyskusji, to więcej za i przeciw stosowaniu go. Gdybym tak wszystko wyłożył przy pierwszym razie pewnie niejednego już bym stracił, a tak...może niekoniecznie. Z drugiej strony, chciałoby się przeczytać książkę i zabrać za projekty, ale wtedy rozbieżność między mną a czytelnikami mogłaby być zbyt wielka i też kilku stracę. Jeśli nie pojawią się propozycje, pozostaję przy w miarę codziennym relacjonowaniu kolejnych rozdziałów książki. A może ktoś pokusiłby się na jej przetłumaczenie na polski? To byłoby jeszcze jedno ułatwienie w promowaniu Groovy & Grails.

Kolejny rozdział 3. "More Advanced Groovy" to przegląd cech języka Groovy, które sprawiają, że codzienne bolączki programisty stają się mniej bolące (jeśli w ogóle można rozważać je w kategorii bólu). Rozpoczyna się od prezentacji zalet wykorzystania Groovy do testów jednostkowych. Skoro istnieje opór do wprowadzenia Groovy jako obowiązującego języka w projekcie, to może wykorzystać go do odświeżonego tworzenia testów? Pisanie testów jednostkowych nigdy nie było zbyt popularne, więc wprowadzenie Groovy mogłoby wprowadzić pewną świeżość, a tym samym zwiększyć zainteresowanie ich pisaniem. Groovy zawiera w sobie JUnit i udostępnia klasę groovy.util.GroovyTestCase, która dziedziczy z junit.framework.TestCase i dodaje własne metody assert - assertArrayEquals, assertContains, assertEquals, assertInspect, assertLength, assertScript oraz assertToString. W zasadzie, poza assertInspect oraz assertScript, można domyśleć się, do czego one służą, zgodnie z nazwą. Metoda assertInspect to sprawdzenie wyniku metody inspect() (nic mi to jednak jeszcze nie mówi), a assertScript weryfikuje bezwyjątkowe wykonanie skryptu. Pamiętamy, że groovy.util jest automatycznie importowane w skryptach Groovy, więc pozostaje jedynie rozszerzyć GroovyTestCase i pisać testy. Testy są bezparametrowymi metodami o nazwie test<DalszaNazwaMetodyTestującej> zwracającymi void. Dodatkowe uproszczenie, to brak konieczności deklarowania wyjątków w sygnaturze metody, gdyż Groovy automatycznie zamienia wszystkie wyjątki na niesprawdzane (ang. unchecked exceptions). Autorzy proponują pisanie testów jednostkowych jako sposób na dalsze rozpoznawanie języka Groovy. Uruchomienie testów to po prostu uruchomienie klasy/skryptu, która je zawiera za pomocą interpretera groovy. Na zakończenie sekcji o testach jednostkowych, autorzy zauważają, że skoro testy w Groovy to tak na prawdę testy junitowe, można je włączyć do wykonania w aktualnym zestawie testów projektowych uruchamianych przy pomocy Apache Ant czy Apache Maven.

Zadanie: Rozpoznać uruchomienie testów jednostkowych w Groovy z użyciem Apache Maven.

Kolejnym tematem rozdziału 3. jest obsługa plików XML. Groovy udostępnia klasy do tworzenia plików XML w różnej postaci, np. DOMBuilder, MarkupBuilder, NodeBuilder, ale w tej rodzinie można znaleźć również AntBuilder do budowania i wykonywania skryptów antowych oraz SwingBuilder do tworzenia UI (a może IU - interfejs użytkownika?). Istnieje również klasa XmlSlurper, której działaniem jest GPathResult, który wraz z konstrukcjami ala XPath pozwala na dostęp do różnych obszarów pliku XML (w książce można znaleźć przykłady, które ilustrują temat, więc zainteresowanych zapraszam do samodzielnej lektury). Groovy dostarcza klas do tworzenia szablonów - SimpleTemplateEngine (najczęściej stosowany), GStringTemplateEngine oraz XmlTemplateEngine. Wraz z innymi konstrukcjami w Groovy tworzenie systemów opartych o szablony może być znacznie odchudzone, w porównaniu z ich odpowiednikami w "czystej" Javie.

Następny temat to expandos, czyli klasa groovy.util.Expando, która może być dynamicznie rozbudowywana o nowe atrybuty czy domknięcia w trakcie działania. Jeśli dodamy do tego, "Groovy duck typing", czyli automatyczne rozpoznawanie przez Groovy typu obiektu na podstawie jego własności (atrybutów i metod) możemy sobie wyobrazić, jak łatwo jest dynamicznie zmienić obiekt jednego typu na inny. Wystarczy więc stworzyć egzemplarz Expando z new Expando i po prostu przypisywać wartości polom, jakby były one dostępne oraz definiować metody w postaci domknięć w podobny sposób, aby z niczego zrobić coś. I wszystko dynamicznie! Jeśli dodam, że tworzenie Expando możliwe jest z konstruktorami ze zdefiniowanymi atrybutami i ich wartościami, to robi się niezwykle ciekawie, np.
 def jacek = new Expando([ imie: 'Jacek', nazwisko: 'Laskowski' ])
Na zakończenie rozdziału przedstawione są Meta Object Protocol (MOP) oraz Domain-Specific Languages (DSL). DSL jest sposobem na wprowadzenie języka dziedzinowego, łatwiejszego do czytania przez osoby nieprogramujące, a mogące dostarczyć dużo więcej informacji o oprogramowywanym świecie niż sam programista. Zauważono, że jeśli programy czyta się częściej niż je tworzy, to DSL może znacząco podnieść jego czytelność korzystając z konstrukcji używanych w danej dziedzinie niż języku programowania (niech sobie nie myślą jednak studenci studiów informatycznych, że ominie ich "niezwykle interesujący" egzamin z Semantyki Języków Programowania ;-)). Prostota tworzenia DSLi w Groovy wynika z mechanizmu MOP, który pozwala na zmianę zachowania dowolnych klas (nawet finalnych!). Brrr, powiało grozą - najpierw .@ jako sposób na ominięcie metody odczytu, teraz MOP - zaczynam martwić się o swoje nawyki obiektowe. Działanie MOP opiera się na właściwości metaClass typu groovy.lang.MetaClass, która jest dostępna w każdej klasie, włączając w to klasy javowe (podobnie jak właściwość class we wszystkich klasach javowych). Podczas obsługi komunikatu do obiektu (brzmi jak na zajęciach ze Smalltalka), tj. dostępem do pola, atrybutu, czy metody, Groovy odpytuje MetaClass o dalsze kroki. Wystarczy więc dodać atrybut bądź metodę do metaClass (podobnie jak to miało miejsce przy Expando) i voila - możemy korzystać z nowej funkcjonalności, jak gdyby była ona dostępna od pierwszych dni tej klasy. Niezwykle użyteczna i jednocześnie groźna broń w rękach niewprawionego programisty Groovy. Można wprowadzić niezłe zamieszanie bawiąc się metaClass. Na zakończenie wspomina się jeszcze o pewnym obiekcie delegate, który jest referencją do obiektu, na którym wykonano daną metodę/domknięcie, np.
 String.metaClass.wyslijSmsaNaBlogRoku2008 = {
// tutaj delegate to egzemplarz typu String o wartości "jacek"
}

"jacek".wyslijSmsaNaBlogRoku2008()
I to by było na tyle z relacji lektury rozdziału 3. "More Advanced Groovy". Jak niejednokrotnie wspomniano w książce, więcej informacji można znaleźć na stronach dokumentacji projektu Groovy, bądź też zakupić książkę Koenig et al "Groovy in Action". Żądni wrażeń mają możliwość przestudiowania kodu źródłowego GroovyBlogs.org.

p.s. Zgłosiłem blog do konkursu Blog Roku 2008. Obecnie znajduje się na 36. miejscu i pnie się stopniowo w górę. Dziękuję za wysłane SMSy! Zainteresowani wyrażeniem swojej (dez)aprobaty postępującym schyłkiem tematyki bloga na języki dynamiczne reprezentowanymi przez tak (nie)lubianego Groovy są proszeni o natychmiastowe wysłanie SMSa o treści B00204 (czytaj: be-zero-zero-dwa-zero-cztery) pod numer 7144 za 1,22PLN brutto. Wdzięczność autora gwarantowana!

[*] groz(n)iej brzmi - GROovy + Z(n)Iarna EJB + rzmi - tak mi jakoś przyszło do głowy ;-)

18 stycznia 2009

Wyrażenia regularne, przeciążanie operatorów i operatory specjalne w Groovy z "Beginning Groovy and Grails"

4 komentarzy
Na zakończenie rozdziału 2. "Groovy Basics" z Beginning Groovy and Grails: From Novice to Professional autorzy omawiają temat obsługi wyrażeń regularnych w Groovy. Wyrażenie regularne jest łańcuchem znakowym (symboli), który tworzy wzorzec, za pomocą którego odszukuje się pasujących ciągów znakowych w tekście. Nie zauważyłem różnic w języku wyrażeń Groovy a Javą, więc zakładam, że ich po prostu nie ma. Mam wrażenie, że w języku dynamicznym, takim jak Groovy, znaczenie wyrażeń regularnych znacznie wzrasta. Policzyłbym na palcach jednej ręki, ile razy przyszło mi skorzystać z wyrażeń regularnych w moich programach w Javie, podczas gdy w skryptach uniksowych bądź edycji w vi jest ich cała masa i nie tylko, że jednej, ale dziesięciu rąk nie starczyłoby na ich zliczenie. Wierzę, że praca z Groovy zmieni moje podejście do wykorzystania wyrażeń regularnych w Javie. Uczestniczę w projekcie Apache OpenEJB, w którym David Blevins, główny programista projektu, stosuje wyrażenia regularne do najróżniejszych, często zaskakujących, zadań. Główną różnicą między pracą z wyrażeniami regularnymi w Groovy a Javą są nowe operatory porównania ==~, szukania =~ oraz (konstrukcji) wzorca ~ciąg, w których "cięte ciągi" (ang. slashy strings) znacząco upraszczają pracę, np.
 def wzorzec = ".*c\$"
def wzorzecJakWyzejAleProsciej = /.*c$/
Wynikiem działania operatora szukania jest java.util.regex.Matcher[][], zaś operatora wzorca java.util.regex.Pattern. Autorzy zwracają uwagę na operatory ~ oraz =~, ponieważ wystarczy zapomnieć o spacji i ze wzorca
 def wzorzec = ~/.*c$/
mamy operator szukania
 "abc" =~ /.*c$/
W jednym z przykładów można spotkać się z metodą tworzenia obiektów przypisując wartości polom przez nazwę.
 class Osoba {
String imie
}

def jacek = new Osoba(imie: "Jacek")
Pamiętam podobną konstrukcję w C++, gdzie definiując konstruktor można było określić wartości domyślne dla pewnych pól instancji.

Temat operatorów i możliwości ich przeciążania jest zamknięciem rozdziału 2. Przeciążanie operatorów nie jest dostępne w Javie, ale programiści C++ znają to nadzwyczaj dobrze. W Groovy definiujemy pewną ustaloną metodę, która będzie wykonywana przy wykonaniu operatora, np. dla a + b będzie to a.plus(b). Jeśli jej brak w naszej klasie będzie wykonywana domyślna obsługa operatora. Proste, nieprawdaż? Już nie pamiętam, aby tak prosto było w C++, ale na pierwszy rzut oka Groovy sprowadza temat przeciążania operatorów do banału. Dodanie elementu do listy to wykonanie lista.add(obiekt), albo, z wykorzystaniem przeciążania, lista << obiekt (co odpowiada wykonaniu metody lista.leftShift(obiekt)). Zdaje się, że ostatnie zdanie w sekcji Operator Overloading "Operator overloading isn't limited to..." sugeruje, że istnieje możliwość definiowania własnych operatorów, ale poza tą wzmianką nic więcej nie ma, więc przyjdzie mi dalej żyć w błogiej niewiedzy, czy mógłbym zdefiniować własny operator czy nie.

Groovy udostępnia kilka specjalizowanych operatorów - spread - *. (ang. spread operator), który jest uproszczeniem wykonania metody lub domknięcia na poszczególnych elementach kolekcji, które udostępniają wywoływaną metodę/domknięcie.
 def lista = ["Agata", "Iweta", "Patryk", "Jacek"]
lista.each { println it }
lista*.length()
Można go interpretować jako "wykonaj metodę/domknięcie na każdym elemencie listy".

Kolejnym operatorem jest Elvis - ?:, który jest uproszczonym operatorem warunkowym ?: znanym z Javy. W Javie mamy trzy składowe, podczas gdy w Groovy wyłącznie dwa i przypisanie wartości (wykonanie operatora Elvis) następuje wyłącznie, kiedy przypisywane pole ma wartość null lub false.
 // jeśli osoba.imie jest null zmienna imieOsoby będzie miało wartość "Nieznane"
def imieOsoby = osoba.imie ?: "Nieznane"
Kolejny operator specjalny to operator bezpiecznego odczytu - ?., który zapobiega NPE (NullPointerException). Zamiast
 if (osoba != null) {
println "${osoba.imie}"
}
wystarczy
 println "${user?.imie}"
Następny operator to operator bezpośredniego dostępu do pola z pominięciem wykonania metody odczytu (ang. getter) - .@, np.
 class Osoba {
String imie

def getImie() {
imie + " (getImie)"
}
}

def jacek = new Osoba(imie: "Jacek")
println jacek.imie
println jacek.@imie
Trudno uwierzyć mi, że może być zainteresowanie na tego typu konstrukcje, które łamią zasady programowania obiektowego - kapsułkowanie (ang. encapsulation) - ale skoro są, to powód ich powstania też musi być. To jest zaleta poznawania nowych języków - człowiek poznaje tym samym powody istnienia rzeczy, o których nie miał nawet pojęcia, że mogłyby istnieć. Nazwalibyśmy to osobistym rozwojem, czy zaśmiecaniem sobie głowy rzeczami, które są niewielkiej wartości?!

Ostatnim operatorem jest operator wykonania domknięcia - .&, który umożliwia potraktowanie dowolnej metody jako domknięcia, np.
 String wyswietl(String tekst) {
println tekst
}

def laskowscy = ["Agata", "Jacek"]
laskowscy.each(this.&wyswietl)
W ten sposób działa w Groovy println, który jest niczym innym jak wykonaniem javowego System.out.println.

Koniec rozdziału 2. "Groovy Basics".

p.s. Zgłosiłem blog do konkursu Blog Roku 2008. Zainteresowani wyrażeniem swojej bezgranicznej wdzięczności za literacką twórczość Jacka w jego Notatniku proszeni są o wysłanie SMSa o treści B00204 (czytaj: be-zero-zero-dwa-zero-cztery) pod numer 7144 za 1,22PLN brutto. Dziękuję!

17 stycznia 2009

Kolekcje w "Groovy Basics" z Beginning Groovy and Grails

1 komentarzy
Kolejna odsłona lektury książki Beginning Groovy and Grails: From Novice to Professional. Dokończyłem rozdział 2 "Groovy Basics" i czuję się już cały gotowy, aby podjąć się jakiegoś wyzwania w Groovy. Nie wiem, co mogłoby to być, ale od kiedy zacząłem przyglądać się temu językowi i Grails wokół mnie coraz więcej informacji o nich. Jedni zachwyceni i pytają, czego nie można zrobić w Groovy - Bruce Eckel asks "What can't Grails do?", a drudzy wręcz przeciwnie - zniechęceni i wręcz zdegustowani przesadną ich reklamą - Nowy rok … stare marzenia :).

Skoro o tworzeniu aplikacji z parą Groovy/Grails to zapewne niejeden zastanawiał się, w czym to cudo poznawać - przydałoby się jakieś IDE (zintegrowane środowisko programistyczne). Ostatnio głośno o tym było na grupie dyskusyjnej użytkowników Grails - Best IDE for grails development, a wystarczy wpisać w Google "grails best ide" i od razu można zorientować się, że temat niezwykle gorący. Osobiście do tej pory próbowałem się jedynie z NetBeans IDE 6.5 i przyznaję, że największym mankamentem było dla mnie ciągła konieczność zatrzymywania serwera, aby móc wdrożyć zmiany. Bez tego zmiany nie były rozpoznawane. Mam w odwodzie IntelliJ IDEA 8 i od dzisiaj jej się przyjrzę (dla tych, którzy nie mają, a chcieliby przypomnę, że wystarczy wystąpić z prezentacją na jednym z lokalnych JUGów i licencja na rok gwarantowana).

Kończąc rozdział 2 "Groovy Basics" jeszcze raz zerknąłem na sekcję o domknięciach. W wolnym tłumaczeniu to po prostu metoda bez nazwy i zwracanego typu. Wszystko inne jest oraz domknięcie to obiekt w Groovy. To już było wczoraj, ale o czym nie wspomniałem, to właśnie parametry. Tak, domknięcia mogą mieć parametry wejściowe, np.
 def domkniecie = { parametrWejsciowy -> println "Parametr wejsciowy to ${parametrWejsciowy}" }
i wystarczy wywołać podając parametr z lub bez nawiasów (przy bezparametrowym wywołaniu nawiasy są obowiązkowe):
 domkniecie "Prezentacja domknięcia w Groovy"
Jeszcze nie rozumiem, dlaczego deklaracja domknięcia domkniecie z def w powłoce groovysh kończy się ERROR groovy.lang.MissingMethodException: No signature of method: groovysh_evaluate.domkniecie() is applicable for..., ale to później.

Kolej na przegląd typów zbiorowych - kolekcji. Mamy listy, zakresy, zbiory, tablice i mapy. W zasadzie podobnie jak w Javie, poza zakresem. Różnica między kolekcjami w Groovy, a w Javie to ich deklaracja. Zawsze można skorzystać z new <nazwa_typu_z_Javy>, np. new ArrayList(), ale kto by tak pisał w Groovy, skoro można trochę bardziej szałowo (ang. groovy). Jako pierwszą z kolekcji opisano listę. Lista w Groovy jest de facto egzemplarzem java.util.List i tworzymy ją nawiasami kwadratowymi
 def lista = []
Na moment pojawia się wzmianka o przeciążaniu operatorów (dobrze znane programistom C++), gdzie przedstawiono dodawanie i odejmowanie elementów z listy, odpowiednio, operatorami -= oraz +=.

Kolejnym typem zbiorowym jest zakres (ang. range), niedostępny programistom javowym. Jest to typ, w którym egzemplarze deklarowane są przez .., który oznacza "kolejne wartości w pewnym porządku", np.
 def cyfry = 0..9
Zakres jest po prostu pewną listą obiektów implementujących java.lang.Comparable. Interesującą konstrukcją jest użycie zakresu z < (znak mniejszości), co oznacza prawy otwarty koniec zbioru elementów, np.
 def cyfryInaczej = 0..<10
Jest to równoważne z deklaracją cyfry. Istnieje również możliwość odwrócenia kolejności, np.
 def cyfryMalejaco = 9..0
Następnie sekcja o zbiorach, które są, podobnie jak w Javie, nieuporządkowaną kolekcją obiektów bez duplikatów. Deklaracja odbywa się jak deklaracja listy z frazą as Set, np.
 def zbiorPusty = [] as Set
Domyślnie "pod spodem" będzie javowy java.util.HashSet. Wystarczy skorzystać z konstrukcji new <inny_rodzaj_zbioru>, aby otrzymać egzemplarz innego typu zbioru. Istnieje konstrukcja as List, aby ze zbioru stworzyć listę.

Dalej mamy przedstawiony typ tablicowy - tablicę, która jest sekwencją obiektów, jak w Javie. Konstrukcja tablicy to po prostu
 def tablica = new String[3]
Na zakończenie sekcji o kolekcjach przedstawiony jest typ mapa - nieuporządkowana kolekcja par klucz/wartość, w której klucz jest unikatowy. Jest to implementacja javowego java.util.Map i deklarowana jest przez nawiasy klamrowe z parami z dwukropkiem oddzielone przecinkiem. Domyślnie będzie to java.util.LinkedHashMap.
 def pustaMapa = [:]
def mapaZDwomaElementami = ["java":"Dobra sprawdzona", "groovy":"Potencjalnie dobry, właśnie sprawdzany"]
Ciekawostką map w Groovy jest możliwość przypisania wartości do klucza przez
 mapaZDwomaElementami.java = "Tylko dobra?! Jest wspaniała!"
Na koniec pojawia się sekcja o wyrażeniach regularnych. Potężne narzędzie, ale o nim w kolejnej odsłonie. Warto już teraz popróbować się z dotychczasową wiedzą o Groovy w powłoce Groovy - groovysh.
 C:\Documents and Settings\jlaskowski
> groovysh
Groovy Shell (1.6-RC-1, JVM: 1.6.0_11)
Type 'help' or '\h' for help.
--------------------------------------------------
groovy:000> println "I jak, podoba się Groovy?"
I jak, podoba się Groovy?
===> null
p.s. Ten blog uczestniczy w konkursie Blog Roku 2008. Wystarczy wysłać SMSa o treści B00204 (czytaj: be-zero-zero-dwa-zero-cztery) pod numer 7144 za 1,22PLN brutto i ma się zapewnioną wdzięczność blogera Jacka ;-)

16 stycznia 2009

Relacja z pierwszych rozdziałów Beginning Groovy and Grails: From Novice to Professional

7 komentarzy
Zabrałem się za książkę Beginning Groovy and Grails: From Novice to Professional. Przy lekturze specyfikacji EJB 3.0 przekonałem się, że relacje z jej lektury na blogu, przykłady, wykłady/prezentacje w obu rolach, jako mówiący i słuchający, rozmowy z zainteresowanymi, odpowiedzi na grupach i tak w kółko to najlepszy sposób na dogłębne poznanie tematu. Zauważyłem również, że to właśnie publiczne relacje i prezentacje były odpowiedzialne za utrzymanie tempa rozpoznawania tematu EJB 3.0. Powinno sprawdzić się również przy Grails. Nie inaczej zamierzam podejść do Groovy & Grails. Pierwsze rozdziały książki niejednokrotnie kończyły się "ochami" i "echami", i nie ukrywam, że poddałem się euforii języków skryptowych i ich możliwości. W tym przypadku jest to Groovy, ale pewnie nie inaczej byłoby z JRuby (przyszło mi pracować swego czasu z Jythonem i nie zrobił on na mnie takiego wrażenia). Jedno, co mnie martwi to brak możliwości wykorzystania możliwości Grails w publicznej odsłonie - brakuje hostingu. Podobnie jak sprawa hostingu aplikacji javowych. Generalnie posucha w Polsce i co bardziej zaradni migrują na serwery zachodnie. Coś należałoby w tej materii zdziałać, bo nie wierzę, że nie ma zainteresowania firm hostujących dodatkowym zarobkiem w nowym segmencie rynku hostingowego. Przytłacza wszechobecność rozwiązań LAMP (Linux+Apache Web Server+MySQL+PHP), a tak niewiele ofert javowych. To powinno być zadanie #1 dla wszystkich polskich JUGów, aby wesprzeć inicjatywy lokalnych firm hostujących. Może jakaś firma hostująca umożliwiłaby próby za niewielką opłatą? Chętnie skorzystam i poreklamuję oferenta ;-)

Pierwszy rozdział książki "Introduction to Groovy" to opis instalacji Groovy i poznanie niektórych jego cech na przykładzie migracji klasy javowej z main na odpowiednik w Groovy. Niewiele do relacji, a dodatkowo można go przeczytać samodzielnie. Po prostu jest dostępny bezpłatnie - Ch. 01 - Introduction to Groovy. Pierwsza cenna wiedza jaka płynie z tego rozdziału to taka, że wszyscy programujący w Javie są programistami Groovy. Wystarczy po prostu zmienić rozszerzenie dowolnej klasy javowej na .groovy i uruchomić przez interpreter groovy. Jednak to dopiero początek. Podobnie jak w Javie import java.lang.* jest domyślny, tak w Groovy domyślnie importowane pakiety to java.lang.*, java.util.*, java.net.*, java.io.*, groovy.lang.* oraz groovy.util.*. Pojawiła się wzmianka o GString, który za pomocą ${obiekt.pole} pobiera wartość do pola obiektu. Ciekawym porównaniem słabego typowania w Groovy jest tzw. "duck typing", tj. automatyczne rozpoznawanie typu obiektu na podstawie jego zachowania - jeśli chodzi się jak kaczka (ang. duck) i wydaje głos jak kaczka, to musi być kaczką. Po raz pierwszy można spotkać niejawne użycie domknięć w konstrukcji .each{}. Dla uczących się angielskiego, szczególnie 3rd conditional, warto zwrócić uwagę na ostatne zdanie w rozdziale (zaraz przed Summary):

If we had started with the Groovy idioms to begin with, the Groovy approach would have been much more productive.

Kolejny rozdział "Groovy Basics" to przegląd języka. Możnaby zaliczyć go do kwintesencji specyfikacji języka, ale od czasu do czasu pojawiają się ciekawostki w formie przykładów. Zdecydowanie nie warto przechodzić do kolejnych rozdziałów bez jego lektury, aczkolwiek zapewne wielu doświadczy zawiłości^H^H^Hodmienności języka Groovy już podczas pracy z nim. Ważne - skrypt Groovy można skompilować do postaci klasy javowej z użyciem kompilatora groovyc (odpowiednik javowego javac). Następnie uruchomienie tak skompilowanego skryptu Groovy następuje jak każda inna klasa z java z podaniem biblioteki Groovy - embeddable/groovy-all-*.jar. Pojawił się przykład połączenia klasy w Javie z Groovy i tutaj "zwykłe" javowe IDE nie ma szans - koniecznie musi być wsparcie dla typów definiowanych w Groovy, aby można było bez komplikacji z nich korzystać w silnietypowanych klasach javowych. Konwencją Groovy jest zawsze zwracanie wyniku działania metod. Pojawił się przykład z assert w Groovy, który ma składnię dokładnie jak w Javie, a jego wprowadzenie było wymuszone przez udostępnienie w nim użycia możliwości Groovy - konstrukcji, które nie są znane assert w Javie. Dodatkowo assert zwraca warunek w komunikacie przy jego niespełnieniu (false). Następnie autorzy przeszli do typu znakowego - w cudzysłowach, pojedyńczych cudzysłowach i (inaczej niż w Javie) ukośnikach zwanych "slashy strings" (cięte ciągi? - a może po prostu cięgi). W ciętych ciągach niekonieczne jest używanie wstecznych ukośników do pozbycia się specjalnego znaczenia specjalnych symboli, np. $, poza samym ukośnikiem. Poza ciągami z pojedyńczymi cudzysłowami korzysta się z konstrukcji ${obiekt.pole} (czego nie ma w Javie). Można również tworzyć wielolinijkowe ciągi przy pomocy potrójnych cudzysłowów lub pojedyńczych cudzysłowów. Kolejna odmiana od Javy. I w końcu przychodzi pora na domknięcia (ang. closures). Nigdy do końca nie mogłem zrozumieć ich siły, ale mam to już za sobą - w końcu dostrzegłem ich zalety. Domknięcie jest blokiem z pewną liczbą konstrukcji językowych Groovy, który można przypisać do pola, zmiennej lub przekazać jako parametr metody. Szukając analogi do Javy, to jest to metoda bez nazwy i zwracanego typu, tj. samo ciało metody między nawiasami klamrowymi. Podobnie jak definiujemy metodę w Javie i możemy ją wykorzystywać w wielu miejscach, podobnie jest z domknięciami w Groovy. Domknięcie jest obiektem, a metoda nie. Jeśli domknięcie nie przyjmuje parametrów należy używać nawiasów, a przy podaniu parametrów nie są konieczne. Domknięcie może korzystać ze zmiennych w zasięgu (widocznych dla) jego definicji. Domyślnym parametrem dostępnym w domknięciu jest it. Po przykłady zapraszam do książki (albo należy uzbroić się w cierpliwość, bo zapewne niebawem pojawią się i u mnie). Później opisane są kolekcje, o których w następnej odsłonie. Książka zapowiada się niezwykle ciekawie.

Dla zainteresowanych wsparciem (moralnym) blogera nadmienię, że blog wystartował w konkursie Blog Roku 2008, który wszedł w etap II - nominowania blogów. Oddajemy głos na Notatnik przez wysłanie SMSa o treści B00204 (czytaj: be-zero-zero-dwa-zero-cztery) pod numer 7144. I tyle! Ja już wysłałem ;-) Zgodnie z informacją na stronie konkursu koszt SMSa to 1,22PLN brutto. Więcej formalności w Ogólne zasady tegorocznej edycji. Ciekawym jakim zainteresowaniem cieszy się Notatnik?!

15 stycznia 2009

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

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

Temat prezentacji: Coś między ORM a JDBC, czyli iBATIS Data Mapper
Prowadzący: Mariusz Lipiński

Podczas spotkania przyjrzymy się projektowi Apache iBATIS Data Mapper od podstaw, więc nie wahajcie się przyjść, nawet jeśli nigdy wcześniej nie zetknęliście się z tą nazwą! A co to jest iBATIS? Mówiąc krótko: prosty i miły w użyciu szkielet dla warstwy trwałości danych; nakładka na JDBC, która pozwala zachować zalety starego dobrego SQLa zwalniając nas jednocześnie z konieczności mozolnego dłubania, tak dobrze znanego programistom JDBC. W dokumentacji dla programisty twórcy iBATISa piszą, że dostarcza 80% możliwości JDBC przy redukcji nakładów na programowanie do 20%. Przyjdź i przekonaj się sam.

Agenda spotkania obejmuje:
  • Co to jest Apache iBATIS Data Mapper
  • Jak wygląda projekt używający iBATISa
  • Poznajemy iBATISa na przykładach
  • Narzędzia dla iBATISa i wtyczki do IDE
  • Zagadnienia zaawansowane
  • Apache iBATIS kontra ORM
  • Rozważania, pytania i dyskusja
Mariusz Lipiński jest inżynierem oprogramowania, pasjonatem technologii, IT i Javy w szczególności. Magister Informatyki, absolwent Wydziału Matematyki, Informatyki i Mechaniki Uniwersytetu Warszawskiego (MIMUW). Członek Warszawskiej Grupy Użytkowników Technologii Java, współorganizator konferencji JAVArsovia 2008. Prowadzi blog O technologiach dla języka Java okiem Mariusza Lipińskiego.

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!

13 stycznia 2009

Spring Security z CAS w aplikacji webowej

0 komentarzy
Zabrałem się za acegi z Grails, ale coś mi nieszło, więc zszedłem na poziom samego Acegi, a właściwie to Spring Security 2.0.4 w "zwykłych" aplikacjach webowych z użyciem facelets. Instrukcja w Tutorial: Adding Security to Spring Petclinic zadziałała bezbłędnie. Przykładowy projekt, który zabezpieczałem Spring Security zarządzany jest przez Apache Maven, więc nie kopiowałem bibliotek, a jedynie zdefiniowałem konieczne zależności w pom.xml:
 <properties>
<spring-security.version>2.0.4</spring-security.version>
</properties>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core-tiger</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas-client</artifactId>
<version>${spring-security.version}</version>
</dependency>
i dodałem /WEB-INF/applicationContext-security.xml:
 <?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">

<http auto-config="true">
<intercept-url pattern="/**" access="ROLE_USER"/>
</http>
<!--
Usernames/Passwords are
rod/koala
dianne/emu
scott/wombat
peter/opal
-->
<authentication-provider>
<password-encoder hash="md5"/>
<user-service>
<user name="rod" password="a564de63c2d0da68cf47586ee05984d7"
authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER"/>
<user name="dianne" password="65d15fe9156f9c4bbffd98085992a44e" authorities="ROLE_USER,ROLE_TELLER"/>
<user name="scott" password="2b58af6dddbd072ed27ffc86725d7d3a" authorities="ROLE_USER"/>
<user name="peter" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>

</beans:beans>
Prawie tak jak opisano w dokumencie, poza wymaganiem, że wszystkie strony <intercept-url pattern="/**" access="ROLE_USER"/> są chronione. Jest jednak drobny błąd w dokumentacji, która wymaga, aby zdefiniować /WEB-INF/applicationContext-security.xml w context-param w deskryptorze wdrożenia web.xml, podczas gdy przez cały dokument mówi się o applicationContext-security-ns.xml. Już zgłosiłem jako SEC-1079 applicationContext-security.xml in Tutorial: Adding Security to Spring Petclinic.

Pozostało zabrać się za CASowanie mojej przykładowej aplikacji. Zabrałem się za 3.4. CAS Sample, a tam...dwa (drobne?) błędy. Pierwszy to wskazanie na dokument z opisem jak pobrać źródła "...as described in the introduction.":

Not Found
The requested URL /spring-security/site/reference/html/get-source was not found on this server.


a kiedy już dobrałem się do właściwego dokumentu 1.4. Getting the Source okazało się, że http://acegisecurity.svn.sourceforge.net/svnroot/acegisecurity/spring-security/trunk/ jest już nieaktualny i faktycznie powinien być https://src.springframework.org/svn/spring-security/trunk
. Niezły bałagan! Zgłosiłem jako SEC-1080 3.4. CAS Sample refers to incorrect get-source document and incorrect svn repo URL. Warto odnotować, jak szybko nastąpiła reakcja ze strony członków zespołu Spring Security - niecała godzina i już znalazł się chętny do wdrożenia poprawek!

Wracając do CAS i Spring Security, w porównaniu z poprzednią konfiguaracją teraz to beans jest wiodącą przestrzenią nazw (poprzednio security). To jest akurat niewielka zmiana i wyłącznie dotyczy organizacji pliku xmlowego niż samej konfiguracji Spring Security.
 <?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">

<sec:http entry-point-ref="casProcessingFilterEntryPoint">
<sec:intercept-url pattern="/**" access="ROLE_USER" requires-channel="https"/>
</sec:http>
<sec:authentication-manager alias="authenticationManager"/>

<bean id="casProcessingFilter" class="org.springframework.security.ui.cas.CasProcessingFilter">
<sec:custom-filter after="CAS_PROCESSING_FILTER"/>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureHandler">
<bean class="org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/casfailed.jsp"/>
</bean>
</property>
<property name="authenticationSuccessHandler">
<bean class="org.springframework.security.ui.SimpleUrlAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/"/>
</bean>
</property>
<property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
<property name="proxyReceptorUrl" value="/secure/receptor" />
</bean>

<bean id="casProcessingFilterEntryPoint" class="org.springframework.security.ui.cas.CasProcessingFilterEntryPoint">
<property name="loginUrl" value="https://localhost:9443/cas/login"/>
<property name="serviceProperties" ref="serviceProperties"/>
</bean>

<bean id="casAuthenticationProvider" class="org.springframework.security.providers.cas.CasAuthenticationProvider">
<sec:custom-authentication-provider />
<property name="userDetailsService" ref="userService"/>
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="https://localhost:9443/cas" />
<property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
<property name="proxyCallbackUrl" value="https://localhost:8443/cas-sample/secure/receptor" />
</bean>
</property>
<property name="key" value="an_id_for_this_auth_provider_only"/>
</bean>

<bean id="proxyGrantingTicketStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl" />

<bean id="serviceProperties" class="org.springframework.security.ui.cas.ServiceProperties">
<property name="service" value="https://localhost:8443/cas-sample/j_spring_cas_security_check"/>
<property name="sendRenew" value="false"/>
</bean>

<sec:user-service id="userService">
<sec:user name="rod" password="rod" authorities="ROLE_SUPERVISOR,ROLE_USER" />
<sec:user name="dianne" password="dianne" authorities="ROLE_USER" />
<sec:user name="scott" password="scott" authorities="ROLE_USER" />
</sec:user-service>
</beans>
Nie podoba mi się odwołanie do https://localhost:8443/cas-sample w pliku konfiguracyjnym. Niby jest do zmiany podczas wdrażania aplikacji, ale wystarczy zmiana kontekstu webowego i już muszę pamiętać, aby zmienić coś w deskryptorze (!) Tutaj oczekiwałbym jakiejś zmiany.

Jeszcze tylko zmiana w web.xml i rozpoczynam testowanie.

Testy zakończyły się niepowodzeniem:
 Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: 
Cannot find class [org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler] for
bean with name 'org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler#e3f429'
defined in ServletContext resource [/WEB-INF/applicationContext-security.xml]
bo klasa org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler dostępna jest dopiero od wersji Spring Security 2.5.0-SNAPSHOT. Aby z niej skorzystać należy rozbudować konfigurację pom.xml o
 <build>
<extensions>
<extension>
<groupId>org.springframework.aws</groupId>
<artifactId>spring-aws-maven</artifactId>
<version>1.2.2</version>
</extension>
</extensions>
</build>
<repositories>
<repository>
<id>spring-snapshot</id>
<name>Spring Snapshot Repository</name>
<url>s3://maven.springframework.org/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
Po tym posypało się większymi uaktualnieniami, gdyż
 11:09:55,421 WARN  [BasicLifecycleMonitor] Exception occured while notifying listener
java.lang.NoClassDefFoundError: org/springframework/beans/factory/config/BeanExpressionResolver
Zdaje się, że jest to pierwszy raz, kiedy przyjdzie mi skorzystać ze Spring Framework 3.0.0.M1, bo ta klasa dopiero w tej wersji się pojawiła - org.springframework.beans.factory.config.BeanExpressionResolver. W takiej sytuacji mam dwa podejścia - brnąć dalej w uaktualnienia licząc, że ze zmianami nie przyjdzie mi zajmować się problemami, które wynikają z błędów w oprogramowaniu, a nie mojej nieznajomości Spring Security, albo po prostu doczytać, co należy zmienić, aby nie korzystać z nowości Spring Security 2.5.0-SNAPSHOT. Na razie wybieram podejście pierwsze - brnę dalej (i cichutko się modlę).

W komentarzach do komunikatu o Spring Framework 3.0.0.M1 można znaleźć odpowiedź dla poszukujących repozytorium mavenowego dla tego wydania.

Przede wszystkim zmieniamy artifactId na odpowiadający pakietowi (konwencja zapożyczona z nazewnictwa pakunków OSGi, którą SpringSource krzewi przez Spring-DM, a następnie SpringSource dm Server) i dodajemy odpowiednie repozytoria:
 <properties>
<spring.version>3.0.0.M1</spring.version>
</properties>
...
<repository>
<id>SpringSource Enterprise Bundle Repository - External Bundle Milestones</id>
<url>http://repository.springsource.com/maven/bundles/milestone</url>
</repository>
<repository>
<id>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</id>
<url>http://repository.springsource.com/maven/bundles/release</url>
</repository>
<repository>
<id>SpringSource Enterprise Bundle Repository - External Bundle Releases</id>
<url>http://repository.springsource.com/maven/bundles/external</url>
</repository>
...
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.web</artifactId>
<version>${spring.version}</version>
</dependency>
Zbudować zbudowałem, ale przy uruchomieniu aplikacji pojawił się komunikat o niedostępności org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean, więc dodałem kolejną zależność do projektu:
 <dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.orm</artifactId>
<version>${spring.version}</version>
</dependency>
Ponownie budowanie i wdrożenie do Geronimo. Teraz jest cacy! Nawet działa! Coś jeszcze będę musiał poczytać o CASie (albo przegadać temat z Michałem Margielem, który oferował swoją pomoc w temacie - podobno się zna ;-)).

Oczywiście korzystając z atrybutu autowire możnaby znacząco uprościć plik konfiguracyjny Springa applicationContext-security.xml, gdzie wiązania typu <property name="authenticationManager" ref="authenticationManager"/> byłyby tworzone dynamicznie przez Spring Framework.

12 stycznia 2009

cas-client idzie w odstawkę - acegi ciekawsze

2 komentarzy
Po ostatnich nieudanych bojach z wtyczką Grails do Wicketa zabrałem się za kolejne. Przeglądając dostępne wtyczki poleceniem grails list-plugins wybrałem cas-client. I to z czysto pragmatycznego powodu - wersja 1.0 daje pewną gwarancję stabilności wtyczki, a i tak miałem rozpoznać temat wykorzystania JA-SIG CAS, więc połączę przyjemne z pożytecznym.
 jacek@dev /cygdrive/c/projs/WicketGrailsDemo
$ grails plugin-info cas-client
Welcome to Grails 1.1-beta2 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: c:/dev/grails

Base Directory: C:\projs\WicketGrailsDemo
Running script c:\dev\grails\scripts\PluginInfo_.groovy
Environment set to development
Reading remote plugin list ...

--------------------------------------------------------------------------
Information about Grails plugin
--------------------------------------------------------------------------
Name: cas-client | Latest release: 1.0
--------------------------------------------------------------------------
This plugin provides client integration for JA-SIG CAS
--------------------------------------------------------------------------
Author: Chen Wang
--------------------------------------------------------------------------
Author's e-mail: contact@chenwang.org
--------------------------------------------------------------------------
Find more info here: http://grails.org/CAS+Client+Plugin
--------------------------------------------------------------------------

The plugin handles configurations of JA-SIG CAS client integration using
its Java client library versioned 2.1.1. Please note there is another Java
client library which is heavily Spring based; Although it seems a natual
fit for Grails applications, it requires more configuration works to
kickstart.

The client integration page of the library supported by this plugin is

http://www.ja-sig.org/products/cas/client/javaclient/index.html

Please make sure necessary configurations are made in your Grails
application's Config.groovy file.

--------------------------------------------------------------------------
Available full releases: 0.1 0.2 1.0

To get info about specific release of plugin 'grails plugin-info [NAME] [VERSION]'

To get list of all plugins type 'grails list-plugins'

To install latest version of plugin type 'grails install-plugin [NAME]'

To install specific version of plugin type 'grails install-plugin [NAME] [VERSION]'

For further info visit http://grails.org/Plugins
Instalacja przebiegła bez zakłóceń i po chwili miałem już ją zainstalowaną w mojej przykładowej aplikacji.
 jacek@dev /cygdrive/c/projs/WicketGrailsDemo
$ grails install-plugin cas-client
Welcome to Grails 1.1-beta2 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: c:/dev/grails

Base Directory: C:\projs\WicketGrailsDemo
...
Plugin cas-client-1.0 installed
Otwieram projekt WicketGrailsDemo w NetBeans IDE bez problemu - wystarczy wskazać katalog projektu i NetBeans zadba o resztę (doda ikonkę i pogrupuje artefakty projektowe we właściwych kategoriach). Uruchamiam (menu Run) i w międzyczasie otrzymuję komunikat:

CAS CLIENT PLUGIN ERROR: Please make sure that required parameters [cas.loginUrl, cas.validateUrl, cas.urlPattern] are set up correctly in Config.groovy of your application!
PLEASE CORRECT THE ERROR ABOVE!


Idzie wspaniale - lubię być prowadzony za rękę przy nowym oprogramowaniu. W końcu kto jak nie autorzy wiedzą, które cechy projektu są najciekawsze i jak ich użyć najefektywniej?! Komunikat wpisuję na listę zalet wtyczki.

Potrzebowałem zmienić trochę widok aplikacji, więc pora na kolejne polecenie Grails - generate-views
 jacek@dev /cygdrive/c/projs/WicketGrailsDemo
$ grails generate-views
Welcome to Grails 1.1-beta2 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: c:/dev/grails

Base Directory: C:\projs\WicketGrailsDemo
Running script c:\dev\grails\scripts\GenerateViews.groovy
Environment set to development
[groovyc] Compiling 1 source file to
C:\Documents and Settings\Administrator\.grails\1.1-beta2\projects\WicketGrailsDemo\classes
CAS CLIENT PLUGIN INFO: added section in web.xml
CAS CLIENT PLUGIN INFO: added section(s) in web.xml
CAS CLIENT PLUGIN INFO: /cas.gsp?u=USERNAME is available for mocking cas-ified user session
CAS CLIENT PLUGIN WARNING: Please take extra care as mocking should NOT be allowed for production environment!
Domain Class name not specified. Please enter:
Slowo
[groovyc] Compiling 1 source file to
C:\Documents and Settings\Administrator\.grails\1.1-beta2\projects\WicketGrailsDemo\classes
CAS CLIENT PLUGIN INFO: added section in web.xml
CAS CLIENT PLUGIN INFO: added section(s) in web.xml
CAS CLIENT PLUGIN INFO: /cas.gsp?u=USERNAME is available for mocking cas-ified user session
CAS CLIENT PLUGIN WARNING: Please take extra care as mocking should NOT be allowed for production environment!
Generating views for domain class Slowo ...
Finished generation for domain class Slowo
Po chwili jednak, kiedy kończyłem lekturę dokumentacji wtyczki w Alternatives to using the Java CAS client natrafiłem na wzmiankę o Acegi Security. Już nim kiedyś się zajmowałem, ale niedługo i nigdy nie było czasu na więcej. Jakoś bliżej mi było do niego niż cas-client, więc od razu przeskoczyłem na kolejną wtyczkę acegi.
 jacek@dev /cygdrive/c/projs/WicketGrailsDemo
$ grails install-plugin acegi
...
Plugin acegi-0.4.1 installed
Plug-in provides the following new scripts:
------------------------------------------
grails create-auth-domains
grails generate-manager
grails generate-registration
Od razu widać, że bardziej rozbudowana, skoro wprowadza swoje polecenia. Zaczerpnięcie języka o wtyczce rozpoczynam od standardowego grails plugin-info:
 jacek@dev /cygdrive/c/projs/WicketGrailsDemo
$ grails plugin-info acegi
Welcome to Grails 1.1-beta2 - http://grails.org/
...
--------------------------------------------------------------------------
Information about Grails plugin
--------------------------------------------------------------------------
Name: acegi | Latest release: 0.4.1
--------------------------------------------------------------------------
Grails Spring Security 2.0 Plugin
--------------------------------------------------------------------------
Author: Tsuyoshi Yamamoto
--------------------------------------------------------------------------
Author's e-mail: tyama@xmldo.jp
--------------------------------------------------------------------------
Find more info here: http://grails.org/AcegiSecurity+Plugin
--------------------------------------------------------------------------
Plugin to use Grails domain class and secure your applications with Spring Security filters.
--------------------------------------------------------------------------
Available full releases: 0.2 0.2.1 0.3 0.4 0.4.1
Rzut oka na stronę wtyczki Spring Security Plugin i ma się wrażenie, że wszystko jest. Strona jest wręcz doskonała - wszystko opisane krok po kroku, poza jednym drobnym acz istotnym elementem - nazwą dołączanej strony - _ajaxLogin.gsp zamiast _ajaxForm.gsp. Zaraz ją poprawiłem i już mam swój udział w rozwoju Grails (!) ;-) Dokumentacja nie pozostawia złudzeń, że wciąż mogę liczyć na wsparcie CASa (AcegiSecurity Plugin - Implementation Overview):

Optional support for LDAP, OpenID, Kerberos, CAS, and NTLM.

I w końcu data ostatniej zmiany wtyczki jest budująca - December 9, 2008. Zdaje się, że mam wszystko. "Niestety", właśnie w trakcie rozpoznawania wtyczki acegi dostaję informację o aktualizacji grailsowego Wiki, a konkretnie wpisu o Stark Security Plugin:

The Stark Security plugin -- 'stark' as in simple, but also 'strong' in Swedish -- is an implementation of Spring Security for Grails. The purpose of the plugin is two-fold, as its name implies: to be simple to install, configure, and maintain, and to strongly secure your web application.

a po chwili kolejna informacja o aktualizacji Wiki - tym razem już dotycząca AcegiSecurity Plugin - Upgrading from 0.4.1 to 0.5. I jeszcze kilka innych zmian w dokumentacji Acegi Security Plugin. Jakkolwiek cieszy możliwość wyboru, to dla nowicjusza, nie tylko w Grails, ale i w temacie bezpieczeństwa, może to być nie lada problem. Ja decyduję się na acegi. Nie mam dla niego wiele czasu, więc liczę, że mnie nie zawiedzie.

p.s. Właśnie dostałem książkę Beginning Groovy and Grails: From Novice to Professional, którą zamierzam przeczytać w nadchodzących dniach. Ciekawa? Ktoś już ją ma za sobą? Warta uwagi, czy raczej pozostać przy dokumentacji dostępnej publicznie?