Ci, którzy śledzą “życie” technologii Grails, prawdopodobnie zauważyli kształtujący się od pewnego czasu trend wykorzystania tandemu Grails oraz Flex do budowy systemów internetowych. Nie jest to póki co trend dominujący w świecie Grails i prawdopodobnie nim nie będzie. Z całą pewnością jednak jest dość ciekawym pomysłem na wytwarzanie RIA (ang. Rich Internet Application).

Zasadnicza koncepcja jest prosta: użyć Flex jako front-end, Grails jako back-end i zintegrować jedno z drugim. Brzmi łatwo, ale bardziej doświadczeni developerzy (szczególni Ci, zajmujący się systemami rozproszonymi) zapewne dostali właśnie dreszczy, widząc magiczne słowo: “zintegrować”. Mam dobrą wiadomość: w tym przypadku integracja obu technologii jest łatwa, szybka i przyjemna. Wydaje mi się, że jest to jedna z głównych przyczyn rosnącej popularności omawianego rozwiązania.

Na początek warto zastanowić się po co właściwie nam Grails + Flex. Można przecież zbudować aplikację internetową w Grails od początku do końca, podobnie zresztą jak we Flex. Użycie kombinacji obu technologii ma sens w przypadku, gdy robimy RIA, ale implementację logiki biznesowej chcielibyśmy pozostawić na serwerze, a także, dodatkowo, chcemy to wszystko wykonać w możliwie dobrych technologiach, które całą sprawę nam ułatwią, a nie utrudnią i zapewnią, przy okazji, realizację kilku wymagań niefunkcjonalnych (jak choćby duża przenośność), na których na pewno nam zależy. Grails + Flex = dokładnie to. Flex jest świetną technologią, która oferuje nam pełną potęgę graficzną Flash’a, ale w formie przyjaznej programiście (a nie grafikowi). Grails natomiast pozwala wykorzystać w całości moc platformy Java EE (czyli również jej bogactwo bibliotek, framework’ów oraz innych narzędzi), czyniąc jednak programowanie łatwiejszym i szybszym dzięki takim cechom jak choćby zasady DRY (Don’t Repeat Yourself – Nie powtarzaj się) i Convention Over Configuration (Konwencja ponad konfigurację), język programowania Groovy czy technologie Spring i Hibernate podane “na tacy”, bez żadnego dodatkowego wkładu pracy w konfigurację itp. Więcej na ten temat przeczytać można we wcześniejszym wpisie Pawła.

Teraz czas na właściwą integrację. Po stronie Grails nie musimy właściwie nic robić, bo wszystko załatwia jeden plug-in. Wystarczy go zainstalować, wydając z konsoli (w katalogu głównym projektu Grails) polecenie:

grails install-plugin flex

oraz dodać w klasie usługowej (ang. service), która implementuje logikę biznesową, którą chcemy udostępnić aplikacji Flex, jedno pole statyczne:

static expose = ['flex-remoting']

i to wszystko! Usługa będzie od teraz udostępniona. Powiedzmy, że wygląda ona tak:

class HelloService {
    static expose = ['flex-remoting']
    def hello() {
        return "Hello World!"
    }
}

W aplikacji Flex wystarczy powołać obiekt RemoteObject:

<mx:RemoteObject id="myService" destination="helloService"/>

by móc korzystać z naszej usługi. Przykładowa aplikacja może wyglądać tak:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:RemoteObject id="myService" destination="helloService"/>
    <mx:Button label="Hello" click="myService.hello()"/>
    <mx:TextInput text="{myService.hello.lastResult}"/>
</mx:Application>

Nic dodać, nic ująć. Zero konfiguracji. To po prostu działa… i już!

Ale właściwie… jak to działa? Otóż nie ma tu żadnej “magii”, wbrew temu co widać na pierwszy rzut oka. “Pod maską” siedzi magiczny komponent BlazeDS i odrobina Convention Over Configuration. BlazeDS jest technologią serwerową, która obsługuje styk Grails <=> Flex (a tak naprawdę to Java <=> ActionScript) poprzez implementację mechanizmu RPC, tak jak to pokazano wyżej. Przez “obsługuje” rozumiem wszystko, co jest potrzebne do zdalnego wywołania metody logiki biznesowej: udostępnienie usługi w sieci (pod konkretnym URL), ustalenie protokołu komunikacyjnego ponad warstwą HTTP oraz zapewnienie konwersji typów między światem Java, a światem ActionScript. Część “magii”, jak sądzę, została już wyjaśniona. Idźmy dalej. Przenieśmy naszą aplikację Flex do osobnego projektu, czyli rozdzielmy całość na projekt Grails i projekt Flex. Okaże się, że nagle wszystko przestało działać, co zresztą nie dziwi, bo niby skąd aplikacja Flex ma mieć pojęcie co zrobić z:

<mx:RemoteObject id="myService" destination="helloService"/>

skoro nie wie gdzie jest helloService (przypominam, że aplikacja Grails jest już osobnym projektem). Oto rozwiązanie: uruchamiamy naszą aplikację Grails poleceniem:

grails run-app

i (zakładając, że aplikacja jest dostępna pod adresem http://localhost:8080/hello) modyfikujemy powyższą definicję obiektu RemoteObject:

<mx:RemoteObject id="myService" destination="helloService"
    endpoint="http://localhost:8080/hello/messagebroker/amf"/>

Mamy URL, pod którym udostępnione są nasze obiekty usługowe, i mamy “magika” łączącego świat typów Java ze światem typów ActionScript, którym są biblioteki BlazeDS. Dodam tylko (żeby nie pozostawić żadnych wątpliwości), że protokołem komunikacyjnym nad warstwą HTTP jest AMF (ang. ActionScript Message Format), którym “rozmawiają” aplikacja Flex (wykonująca zdalne wywołanie metody) i BlazeDS (uruchamiający na żądanie metody logiki biznesowej i zwracający ich rezultat).