Posts tagged blazeds

Integracja Spring Flex

Ostatnimi czasy dużą popularność przy tworzeniu bogatych aplikacji internetowych (RIA) zdobywa podejście, w którym warstwę widoku pisze się z użyciem Fleksa lub innej technologii ułatwiającej budowanie interfejsów, a warstwy logiki biznesowej i dostępu do danych implementuje się przy pomocy Javy. Dodatkowo Java jest bardzo często wspierana przez bardzo popularne frameworki – Spring oraz Hibernate.

Do łączenia aplikacji klienckiej napisanej we Fleksie z aplikacją serwerową napisaną w Javie zazwyczaj używa się darmowego BlazeDS lub komercyjnego LiveCycle ES, oba te narzędzia są autorstwa firmy Adobe i udostępniają wiele ciekawych możliwości. Chyba najszybszym i najlepszym sposobem połączenia Fleksa z Javą jest wykorzystanie tzw. remote objects. Jest to po prostu zdalne wywoływanie metod obiektów napisanych w Javie z poziomu Fleksa, cała komunikacja odbywa się przy użyciu bardzo wydajnego, binarnego protokołu AMF (Action Message Format).

Dotychczas, aby z poziomu Fleksa skorzystać z beanów tworzonych przez Springa z użyciem wstrzykiwania zależności, należało wykonać wiele niekoniecznie prostych i oczywistych operacji. Domyślnie sam BlazeDS tworzy skonfigurowane w jego plikach obiekty, co w tym przypadku było działaniem niepożądanym. Trzeba było skonfigurować odpowiednią fabrykę dla BlazeDS, tak aby pozwolił on zająć się tworzeniem odpowiednich obiektów kontenerowi Springa. Były to dość złożone operacje i potrafiły spowodować pojawienie się wielu siwych włosów nawet u doświadczonych developerów.

Sytuacja diametralnie zmieniła się pod koniec zeszłego roku, gdy SpringSource wypuściło na światło dzienne nowy projekt – Spring BlazeDS Integration. Na razie jest to jeszcze dość świeży projekt, jednak pozwala już na użycie beanów tworzonych przez Springa w aplikacjach napisanych we Fleksie przy stosunkowo niewielkim wysiłku. W najbliższych planach jest m.in. implementacja mechanizmu Spring Security, bardzo pożądanego przez developerów tworzących aplikacje Fleksowe.

Aktualnie, przy użyciu Spring BlazeDS Integration, udostępnienie obiektów tworzonych przez Springa sprowadza się do kilku prostych kroków:

1.Po stronie Javy:

a) ustawienie odpowiedniego listenera w pliku web.xml:

<listener>
	<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>

b) praktycznie standardowa konfiguracja springowego servletu w pliku web.xml:

<!-- The front controller of this Spring Web application -->
<servlet>
	<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/config/web-application-config.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

<!-- Map all /spring requests to the DispatcherServlet for handling -->
<servlet-mapping>
	<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
	<url-pattern>/spring/*</url-pattern>
</servlet-mapping>

c) dodanie odpowiedniego MessageBrokera w pliku konfiguracyjnym podanym powyżej jako parametr (web-application-config.xml):

<!-- Bootstraps and exposes the BlazeDS MessageBroker -->
<bean id="mySpringManagedMessageBroker"
	class="org.springframework.flex.messaging.MessageBrokerFactoryBean" />

Będzie on używał pliku konfiguracyjnego BlazeDS z domyślnego miejsca (WEB-INF/flex/services-config.xml). Aby zmienić to miejsce, należy dodać do powyższego beana następujący parametr:

<property name="servicesConfigPath" value="classpath*:services-config.xml" />

d) dodanie mapowania do MessageBrokera z BlazeDS (również w web-application-config.xml):

<!-- Maps request paths at /messagebroker to the BlazeDS MessageBroker -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="mappings">
        	<value>
                	/messagebroker/*=mySpringManagedMessageBroker
            	</value>
	</property>
</bean>

e) dodanie kanału odpowiadającego powyższej konfiguracji w pliku services-config.xml:

<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
	<endpoint url="http://{server.name}:{server.port}/{context.root}/spring/messagebroker/amf"
		class="flex.messaging.endpoints.AMFEndpoint"/>
	<properties>
		<polling-enabled>false</polling-enabled>
	</properties>
</channel-definition>

f) przykładowa definicja obiektu, który ma zostać wystawiony Fleksowi (znowu web-application-config.xml):

<!-- Implementation of HelloService -->
<bean id="blazeHelloService" class="pl.espeo.blog.HelloServiceImpl" >
</bean>

<!-- Expose the blazeHelloService bean for BlazeDS remoting -->
<bean id="helloService"
	class="org.springframework.flex.messaging.remoting.FlexRemotingServiceExporter">
	<property name="messageBroker" ref="mySpringManagedMessageBroker"/>
	<property name="service" ref="blazeHelloService"/>
</bean>

Po takim skonfigurowaniu z poziomu Fleksa powinien być dostępny obiekt o nazwie „helloService” jako remote object.

2.Po stronie Fleksa:

a) odpowiednia konfiguracja do współpracy z BlazeDS – ustawienie projektu do korzystania ze standardowego pliku services-config.xml

b) obiekt „helloService” użyty we Fleksie:

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

Po prawidłowym ustawieniu plików konfiguracyjnych w obu aplikacjach można bezproblemowo cieszyć się springowymi beanami dostępnymi z poziomu Fleksa. Dokumentację dotyczącą projektu Spring BlazeDS Integration można przeczytać na stronie projektu:

http://www.springsource.org/spring-flex

Integracja Grails z Flex

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).