You are on page 1of 84

SPIS TREŚCI

Kilka słów od pomysłodawców tego wydania 06 Opis DVD


Krystian Rajski
Mają Państwo przed sobą prawdziwy hit. Kilka słów o tym co znajduje się na płycie,
Powodem powstania tego magazynu były: brak drukowanych czyli o Flex SDK 3 i Flex Builder.
publikacji w języku polskim na temat Flex, prawie nieograniczo-
ne możliwości tego środowiska, o którym powinni dowiedzieć 10 Aktualności
się i z niego korzystać wszyscy programiści pragnący tworzyć Nowinki ze świata Flex.
interaktywne i multimedialne projekty dla Internetu i na de-
sktop, duże zainteresowanie tematyką (o czym świadczyć mo- 12 Pierwsza aplikacja we Flex
że chociażby ilość osób biorących udział w warszawskiej edy- Krystian Rajski
cji onAIR), nasza chęć rozpowszechniania wiedzy o technolo- Krystian uczy jak tworzyć aplikację wyświetlającą dane z pliku XML,
giach przyszłości. mówi jak korzystać z klasy HttpService i komponenetu Datagird.
Do współpracy przy SDJ Extra Flex zaprosiliśmy pasjonatów – Poznacie podstawowe informacje o technologii Flex i środowisku
osoby, które tworzą i rozwijają społeczność Flex, Flash i AIR, pi- Flex Builder 3.
szą blogi, udzielają rad na forach tematycznych oraz zawodow-
ców, którzy codziennie w pracy korzystają z programistycznych 15 Od formularza do RIA – Adobe Form Guides
rozwiązań Adobe. Tomek Lichota
Tematy wybraliśmy w konsultacji z polską społecznością Flex, Tomek opowiada o tym jak przy pomocy narzędzia Adobe LiveCycle
Tadeuszem Chełkowskim - Dyrektorem Technicznym z Adobe, Designer ES szybko stworzyć formularz PDF, aby zebrać dane i jak na
beatatestermi wśród, których znajdują się programiści WWW, podstawie przygotowanego formularza utworzyć Form Guide.
webdesignerzy, deweloperzy. Za pomoc wszystkim zaanga-
żowanym w ten projekt serdecznie dziękujemy i wierzymy, że 18 Flex i AIR
dzięki ich wsparciu oddajemy w Państwa ręce wartościowy me- Wojciech Siudziński
rytorycznie magazyn. Wojtek opisuje jak zacząć pracę w Adobe AIR, prezentuje możli-
W numerze tym zetkniecie się Państwo z przekrojem tematów wości tego środowiska i przykładowe użycie np. Technikę przecią-
powiązanych z Flex. Znajdziecie tu przepis na stworzenie pierw- gnij i upuść, zaokrąglone rogi w CSS3 i kilka innych pożytecznych
szej fleksowej aplikacji, oraz dowiecie się jak zabezpieczyć i te- zastosowań.
stować oprogramowanie. Poznacie technikę pracy na frame-
worku MVC dla Flex – Cairngormie. Poza tym przeczytacie arty- 22 Adobe AIR – Powrót na desktop
kuł o tworzeniu interaktywnych map Yahoo i o innowacyjnych Szymon Kosydor
formularzach Form Guides. Dowiecie się też o powiązaniach Artykuł Szymona traktuje o tym jak łatwo i przyjemnie jest two-
Flex z Java, PHP, AIR. Wszystko zostało opisane na konkretnych rzyć aplikacje okienkowe wykorzytując Flex Builder i Adobe AIR.
przykładach, a kody źródłowe, które mogą się przydać do ćwi- Szymon m.in. podaje przepis na aplikację wykorzystującą dane w
czeń udostępniamy na www.sdjournal.org. Na DVD zamieścili- formacie RSS.
śmy projekty opisywane w artykułach oraz Flex Builder 3 i Flex
SDK przydatne do programowania.
Numer ten oczywiście nie wyczerpuje tematu. Niniejszy egzem-
plarz to pierwszy numer z serii SDJ Extra w całości poświęcony
Adobe Flex. Podczas pracy nad magazynem dochodziły do nas Le périodique
Magazyn SDJ hakin9 est wydawany
Extra jest publié par przez Software-Wydawnictwo Sp. z o.o.
sygnały, że są Państwo bardzo zainteresowani tą technologią, zSoftware-Wydawnictwo
siedzibą w Warszawie,Sp. z o.o.ul. Bokserska 1.
02-682,
Bokserska, 02-682 Varsovie, Pologne
że szukacie materiałów, że chcecie się uczyć i pracować w RIA. Tél. +48 22
Dyrektor 887 10 10, Fax.
wydawniczy: +48Małecka
Sylwia 22 887 10 11
Myślimy więc nad wydaniem regularnego, odrębnego tytułu www.phpsolmag.org
w języku polskim o Flex, Flash i AIR. Do tego czasu tematykę Redaktor prowadzący: Anna Adamczyk anna.adamczyk@software.com.pl
Directeur de la publication : Jarosław Szumski
Rich Internet Applications będziemy kontynuować w miesięcz- Kierownik produkcji: Marta Kurpiewska marta.kurpiewska@software.com.pl
niku Software Developer’s Journal. Imprimerie, photogravure : 101 Studio, Firma Tęgi
Skład i łamanie:
Ekonomiczna Tomasz
30/36, 93-426Kostro
Łódźtomasz.kostro@software.com.pl
Imprimé en Pologne/Printed in Poland
Życzymy przyjemnej lektury, Projekt okładki: Agnieszka Marchocka
Abonnement (France métropolitaine, DOM/TOM) : 1 an
Korekta: Mateusz
(soit 6 numéros) 38Lipiński

Anna Adamczyk
Software-Wydawnictwo Wyróżniony
Dépôt légal : àbetatester:
parution Leszek Sewastanowicz
Rafał Maciejewicz ISSN : 1731-7037
Adobe Systems Distribution : MLP
Dział reklamy: de
Parc d’activités adv@software.com.pl
Chesnes, 55 bd de la Noirée
Prenumerata:
BP 59 F - 38291 Marzena Dmowska pren@software.com.pl,
SAINT-QUENTIN-FALLAVIER CEDEX
tel. +48 22 427 36 tous
(c) 2005 Software-Wydawnictwo, 79; +48 22 427réservés
les droits 36 53

4
www.sdjournal.org

32 Aplikacje wykorzystujące mapy w Adobe Flex 64 Dostęp do danych z apli-


Wojciech Ptak kacji Flex – Adobe LiveCycle
Wojtek opisuje jakiego typu aplikacje możemy stworzyć za pomo- Data Services w praktyce
cą technologii Flex, jakich biblio- Bartłomiej Soin
tek możemy używać wraz z tą plat- Bartek uczy jak przy pomocy języka
formą i jak stworzyć przykładowe PHP tworzyć usługi internetowe oraz
elementy projektu opartego o Flex jak w języku ActionScript tworzyć
i Yahoo Maps. aplikacje wykorzystujące usługi SOAP
i Flash Remoting.
38 Flex na Javie
Roger Zacharczyk 67 Flex i PHP – wykorzystanie technologii
Roger przedstawia w jaki sposób Web Services i Flash Remoting do komunikacji
tworzyć aplikacje RIA na przykła- klient – serwer
dzie forum internetowego, wyko- Jakub Węgrzyn
rzystując różne technologie internetowe, a w szczególności Javę Jakub w artykule przedstawia możliwości wykorzystania technolo-
oraz SQL, JSP, no i oczywiście Flex. gii PHP. Opisuje dwie metody pozwalające na komunikację aplikacji
Flex z serwerem PHP – Web Services i Flash Remoting.
44 Flex.Security.allowSecureCommunication('*');
Łukasz Zmywaczyk, Jakub Matuszewski 72 Podstawowe wzorce projektowe oraz idiomy ko-
Łukasz i Jakub opisują sposoby wymiany informacji pomiędzy ser- dowania w języku ActionScript 3.0
werem a użytkownikiem, dostępne dla języka ActionScript 3.0 Jakub Węgrzyn
z dodatkowym wykorzystaniem gotowych komponentów środo- Jakub opisuje w jaki sposób implementować podstawowe wzor-
wiska Flex 3. Ponad to opowiadają o systemie zabezpieczeń języka ce projektowe w ActionScript 3 i jak radzić sobie z ograniczeniami
ActionScript 3.0, zabezpieczeniach komunikacji, nowych crossdo- w tym języku.
mains oraz mówią dlaczego warto używać Flash Media Server.
76 TIPS & TRICKS
50 Test Driven Development – Testuj kod zanim go Wojciech Siudziński
napiszesz Wojtek pokazuje kilka sztuczek dla przyszłych specjalistów RIA.
Paweł Cichoń, Tomasz Kulczycki
Paweł i Tomasz tłumaczą co to jest TDD, dlaczego i kiedy warto ko- 78 Micke Chambers dla SDJ Extra – wywiad
rzystać z tej techniki i jak używać biblioteki FlexUnit. rozmowa przeprowadzona podczas konferencji onAIR w Warszawie.

56 Adobe Cairngorm – Framework architektoniczny


dla Adobe Flex
Wojciech Ptak
Wojtek w artykule skupia się na najpoularniejszym frameworku
MVC dla Adobe Flex – Cairngormie, opisuje zasadę jego działania
oraz pokazuje jak wykonać prosty projekt podręcznej biblioteczki.

Rédacteur
Nakład: en chef
6 000 egz.: Marek Bettman marekb@software.com.pl La rédaction
Osoby fait tout son współpracą
zainteresowane possible pourprosimy
s’assurero que les logiciels sont à
kontakt:
Rédacteurs : Aneta Cejmańska anetta@software.com.pl jour, pourtant elle décline toute responsabilité pour leur utilisation. Elle ne
cooperation@software.com.pl
Ewa Dudzic ewal@software.com.pl fournit pas de support technique lié à l’installation ou l’utilisation des logiciels
Préparation
Dołączoną do dumagazynu
CD : Auroxpłytę
CoreCDTeam
przetestowano programem AntiVirenKit firmy enregistrés sur le CD-ROM. Tous les logos et marques déposés sont la
Maquette : Anna Osiecka
G DATA Software Sp. z o.o.annao@software.com.pl propriété
Druk: 101de leurs propriétaires
Studio, respectifs.
Drukarnia Tęgi
Couverture : Agnieszka Marchocka ul. Ekonomiczna 30/36
Traduction : Iwona Czarnota, Aneta Lasota, Marie-Laure Perrotey, La rédaction
91-426 Łódź utilise le système PAO
Grazyna Wełna
Redakcja dokłada wszelkich starań, by publikowane w piśmie i na towarzyszących mu Pour créer les diagrammes on a utilisé le programme
Bêta-testeurs
nośnikach : Thomas
informacje Bores, były
i programy Tonypoprawne,
Boucheau, Pascalnie
jednakże Foulon,
bierzePascal Miquet,
odpowiedzialności
Romain
za efektyLévy, Augustin Pascual,
wykorzystania Julien Poulalion,
ich; nie gwarantuje Alain Ribault
także poprawnego działania programów Wysokość
Le CD-ROMnakładujoint auobejmuje
magazinerównież dodruki.
a été testé Redakcja nie
avec AntiVirenKit deudziela pomocy
la société G
shareware, freeware i public domain. technicznej
Data Software w instalowaniu
Sp. z o.o i użytkowaniu programów zamieszczonych na płycie
Les personnes intéressées par la coopération sont priées de nous contacter : CD-ROM dostarczonej razem z pismem.
cooperation@software.com.pl AVERTISSEMENT
Uszkodzone podczas wysyłki płyty wymienia redakcja. Les techniques présentées dans les articles ne peuvent être utilisées qu'au
Abonnement : abonnement@software.com.pl Sprzedaż aktualnych
sein des réseaux lub archiwalnych numerów pisma po innej cenie niż
internes.
Fabrication : Marta Kurpiewska marta@software.com.pl wydrukowana
La rédaction duna okładcen'est
magazine – bez
paszgody wydawcy
responsable de –l'utilisation
jest działaniem na des
incorrecte jego
Diffusion
Wszystkie: Monika Godlewska
znaki firmowe monikag@software.com.pl
zawarte w piśmie są własności odpowiednich firm zostały szkodę
techniquesi skutkuje odpowiedzialnością sądową.
présentées.
Publicité
użyte : publicite@software.com.pl
wyłącznie w celach informacyjnych. L'utilisation des techniques présentées peut provoquer la perte des données !

Si vous êtes intéressé par l’achat de licence de publication de revues merci de


contacter :używa
Redakcja Monika Godlewska
systemu monikag@software.com.pl
automatycznego składu , tél : +48 (22) 887 12
66 fax : +48 (22) 887 10 11

5
Opis DVD

N
a dołączonej do SDJ extra płycie DVD czytelnicy znaj-
dą znakomity tandem dla Adobe Flex 3 - pełną dar-
mową wersje Flex Software Developement Kit w wer-
sji 3 oraz ograniczoną czasowo, 60-cio dniową wersję Flex Buil-
der 3, a także projekty i pliki pomocnicze do artykułów: Pierw-
sza aplikacja we Flex, Aplikacje wykorzystujące mapy w Adobe
Flex, Adobe Cairngorm – Framework architektoniczny dla Ado-
be Flex, Adobe AIR – Powrót na desktop, Test Driven Develop-
ment – Testuj kod zanim go napiszesz.

Flex SDK 3
Flex SDK jest w pełni darmowym, dystrybuowanym na zasa-
dach open sorce kompleksowym rozwiązaniem przeznaczonym
do budowy zaawansowanych aplikacji webowych. Historia śro-
dowiska została zapoczątkowana w 2002 roku wraz z wprowa-
dzeniem przez firmę Macromedia terminu Rich Internet Appli-
cation (RIA).
W skład środowiska wchodzi m.in. Flex framework znany rów-
nież jako Flex class library, kompilator Flex dostępny z linii pole-
ceń, debugger Flex oraz ASDoc utility.
Flex SDK 3 to środowisko przeznaczone do programowa- Wśród najistotniejszych zmian w stosunku do wersji 2 nale-
nia, kompilowania oraz rozszerzania aplikacji Flex w połącze- ży wymienić dodanie natywnego wsparcia dla Adobe Integra-
niu z takimi technologiami jak XML i web serwisy SOAP. Roz- ted Runtime (AIR), znanego wcześniej jako Adobe Apollo, któ-
wiązanie umożliwia wykorzystanie różnych technologiami ser- ry stał się integralną częścią Flex 3. Nowa wersja rozszerza funk-
werowych takich jak PHP, ColdFusion, Java i .NET z użyciem cjonalność środowiska o możliwość tworzenia aplikacji deskto-
np. BlazeDS. Dostarcza języka i narzędzi umożliwiających de- powych. Programiści korzystając z gotowych komponentów i na-
veloperom maksymalizację efektywności podczas tworzenia za- rzędzi wspierających Adobe AIR, mogą tworzyć oprogramowanie
awansowanych aplikacji Internetowych. Obecnie dostępna jest web działające zarówno w przeglądarce jak i bezpośrednio na sta-
3-cia wersja SDK, którego oficjalna premiera odbyła się 15 lu- cjach roboczych.
tego 2008 roku. Trwają prace nad wersją 4. której nazwa kodo- Flex 3 SDK został wyposażony w nowy komponent Advan-
wa brzmi Gumbo. ced DataGrid, który rozszerzył możliwości komponentu Data-

6 FLEX
Opis CD

Jeśli nie możesz odczytać zawartości


płyty DVD, a nie jest ona uszkodzona
mechanicznie, sprawdź ją na co
najmniej dwóch napędach DVD. W razie
problemów z płytą, prosimy pisać pod
adres: cd@software.com.pl

Redakcja nie udziela pomocy technicznej


w instalowaniu i użytkowaniu
programów zamieszczonych na płytach
DVD-ROM dostarczonych razem
z pismem.

www.sdjournal.org
Opis DVD

Grid m.in. o tworzenie hierarchicznej prezentacji danych i tabe- nych komponentów graficznych umożliwiających budowanie
le przestawne. layout'u aplikacji, a także umożliwiono korzystania z kompo-
OLAP DatatGrid jest nowym komponentem, dostępny jedynie nentów wchodzących w skład Advanced Datagrid.
z Flex Builder Professional, pozwalającym na agregowanie i prezen- Warty uwagi jest wizualny edytor CSS, dzięki któremu w ła-
tację danych w wielowymiarowej strukturze analitycznej. twy sposób możemy zaprojektować arkusz stylów definiujący
Flex Component Kit for Flash CS3 umożliwia łatwą integrację po- wygląd komponentów graficznych. Podczas pracy na bieżąco mo-
między aplikacjami Flex, a projektami wykonanymi we Flash CS3. żemy śledzić efekt naszych modyfikacji bez konieczności ponow-
Developerów JavaScript ucieszy funkcjonalność biblioteki Flex nej kompilacji projektu.
Ajax Bridge umożliwiającej wykorzystanie klas ActionScript w Ja- Nowy Builder oferuje możliwość pełnej integracji z Adobe Cre-
vaScript. ative Suit 3 pozwalając na łatwy import elementów wykonanych
Wraz z wersją trzecią Flex został przekształcony w projekt open we Flashu, Fireworks, Photoshop czy Illustartorze.
source, wiec zainteresowani developerzy mogą uzyskać dostęp do Programistów ucieszy funkcjonalność refactoringu kodu, która
kodu źródłowego framework'a, kompilatora i debugger'a. jest istotnym udogodnieniem w stosunku do wersji poprzedniej.
Flex SDK 3 jest dostępny na wszystkie najpopularniejsze platfor- Dzięki natywnemu wsparciu dla Adobe AIR, Flex Builder 3 wy-
my - platformę Windows, Linux oraz Macintosh. posażony został w narzędzia umożliwiające tworzenie również tra-
dycyjnych aplikacji desktopowych.
Flex Builder 3 W wersji Professional aplikacja posiada narzędzie testujące,
Wraz z trzecią wersją Flex SDK firma Adobe zaprezentowała nową które pozwala poprawić wydajność tworzonych aplikacji za po-
wersję znanego narzędzia programistycznego Flex Builder 3. mocą bieżącego monitorowania i analizowania zużycia pamięci
Adobe Flex Builder 3 jest nowoczesnym i wydajnym rozwią- i procesora. Builder pozwala również wykorzystywać zewnętrz-
zaniem opartym o Eclipse, umożliwiającym intuicyjne tworze- ne programy przeznaczone do automatycznego testowania opro-
nie aplikacji we Flex. Stanowi potężne narzędzie developerskie gramowania.
wspomagające programistę w tworzeniu kodu źródłowego, debu- Wykorzystując Flex Builder 3 programista może tworzyć apli-
gowaniu w trybie krok po kroku oraz wizualnym projektowaniu kację zarówno w oparciu o Flex SDK 3 jak również w wersji Flex
aplikacji RIA z wykorzystaniem bogatej palety gotowych kompo- SDK 2.
nentów. Dzięki zastosowaniu nowego kreatora, ułatwiono również in-
Flex Builder dostępny jest w dwóch wersjach - Standard oraz Pro- tegracje tworzonych aplikacji z technologiami serwerowymi jak
fessional edition. PHP, ColdFusion czy Java. Nowa wersja środowiska dostępna jest
Wśród najważniejszych komponentów wymienić należy intu- też w darmowej wersji edukacyjnej przeznaczonej dla uczniów
icyjny edytor kodu dla języków MXML, ActionScript oraz CSS oraz studentów po wypełnieniu i wysłaniu odpowiedniego formu-
wyposażony w funkcję kolorowania i wyróżniania kodu, podpo- larza rejestracyjnego, który znajduje się na specjalnej stronie pro-
wiadanie składni. W wersji 3 rozszerzono bibliotekę wbudowa- ducenta http://www.flexregistration.com/.

8 FLEX
Aktualności

Interaktywne
aktualności z firmy Janmedia Beta Dreamweaver,
Fireworks i Soundbooth
Janmedia Interactive zacieśnia współpracę
z Adobe. Kooperacja obu firm służy popu-
laryzacji technologii Flex i AIR jako atrak-

F
cyjnego narzędzia budowania skutecznych irma Adobe zaprezentowała przedpre- cie Adobe PDF. Najważniejszą cechą nowej
i efektownych aplikacji biznesowych. mierową wersję trzech aplikacji z na- wersji Fireworks jest pełna zgodność ze śro-
To strategiczne partnerstwo umożliwia
stępnej edycji pakietu Adobe Creati- dowiskiem Adobe AIR, technologią HTML
nam dostęp do najnowszych technologii
związanych z obiegiem dokumentów, podpi- ve Suite, zestawu programów do projektowa- i Adobe Flash oraz oprogramowaniem Ado-
sem cyfrowym, zaawansowanym streamin- nia graficznego, tworzenia serwisów interne- be Flex Builder, dzięki czemu użytkownicy
giem video oraz budową aplikacji Flash, Flex towych i edycji wideo. Firma udostępniła do mogą tworzyć uniwersalne projekty i wdra-
oraz AIR – mówi Monika Mikowska, Dyrek- bezpłatnego pobrania z serwisu Adobe Labs żać je na dowolnej platformie. Z kolei wersja
tor Sprzedaży i Marketingu Janmedia. publiczne wersje beta nowych edycji progra- beta oprogramowania Soundbooth zawiera
Janmedia to firma, która kompetencjami
i wielkim entuzjazmem dla technologii Adobe
mów Adobe Dreamweaver, Adobe Fireworks szereg nowych funkcji umożliwiających
zdobyła renomę wśród polskich i zagranicz- i Adobe Soundbooth. twórcom efektywniejszą realizację zadań
nych klientów – komentuje Tadeusz Chełkow- Właśnie udostępnione wersje beta ob- związanych z produkcją dźwięku, w tym no-
ski, Dyrektor Techniczny Adobe. W ramach razują kierunek dalszego rozwoju pakietu wą funkcję obsługi wielu ścieżek, która po-
współpracy powstają pierwsze wdrożenia Adobe Creative Suite. Zastosowane w nim zwala użytkownikom edytować wiele klipów
korporacyjne w technologiach Flex i AIR dla
nowe funkcje i technologie mają uprościć dźwiękowych na różnych ścieżkach, a tak-
klientów Janmedia z Europy i USA. Janmedia
pracuje nad aplikacją RIA dla wydawcy ame- i usprawnić projektowanie oraz przepływ że nową możliwość dostosowywania przez
rykańskiej prasy codziennej oraz Flexowym pracy z wykorzystaniem rówżnych narzę- użytkowników poziomów głośności plików
systemem transakcyjnym dla polskiej insty- dzi. Jak zwykle firma Adobe liczy też na kry- dźwiękowych. Wersja umożliwia również
tucji finansowej – szczegóły współpracy do tyczne uwagi i sugestie przyszłych uzytkow- przeglądanie ustawień kompresji plików
momentu zakończenia prac projektowych są ników dotyczące dalszego rozwoju oprogra- MP3 przed ich zapisaniem. Zawiera tak-
objęte klauzulami poufności.
mowania. Wersja beta nowego Dreamwe- że nową technologię rozpoznawania mowy,
Janmedia Interactive jest agencją interak-
tywną założoną w 2002 roku i ukierunkowa- avera zawiera pasek narzędzi Related Files która pozwala użytkownikom szybko two-
ną na obsługę klientów międzynarodowych. oraz funkcję Code Navigator, które pozwa- rzyć transkrypcje ścieżek dialogowych oraz
Obecnie Janmedia posiada dwa oddziały lają użytkownikom wnikać głęboko w złożo- przeszukiwać je na ścieżce czasu pod kątem
w USA (Waszyngton i Richmond) oraz jeden ne strony zawierające pliki HTML, łącza do występowania określonych słów i fraz.
w Polsce (Wrocław). Janmedia specjalizu- dokumentów JavaScript i zintegrowane da-
je się w zarządzaniu projektami interaktyw-
nymi, technologiami Java i innymi techno-
ne XML. Użytkownicy mogą przeglądać pli- Dostępność i wymagania systemowe
logiami sieciowymi, projektowaniu zgodnie ki powiązane widoczne w pasku narzędzi Re- Po załadowaniu i uruchomieniu wersje be-
z wytycznymi W3C, użyteczności i dostęp- lated Files i za pomocą funkcji Code Naviga- ta oprogramowania Dreamweaver,Fireworks
ności serwisów WWW. tor wprowadzać zmiany w kodzie, które uka- i Soundbooth będą aktywne przez 48 godzin.
www.janmedia.pl zują się w różnych częściach dokumentu po Po tym czasie dostęp do nich będą mieli tyl-
Adobe otworzy Flasha jednokrotnym naciśnięciu przycisku aktu- ko klienci posiadający pakiet CS3. Będą oni
Adobe poinformował o rozpoczęciu prac alizacji. Zaktualizowana wersja oprogramo- mogli, korzystając z numerów seryjnych swo-
nad stworzeniem, w ramach projektu Open wania Dreamweaver jest również wyposażo- ich pakietów CS3, odblokować wersje beta
Screen Project, spójnego środowiska dla na w nowy tryb Live View, oparty na modu- i bezpłatnie ich używać do chwili udostęp-
gamy urządzeń elektronicznych. W tym le renderingu typu open source pod nazwą We- nienia następnej wersji pakietu Creative Su-
celu korporacja ma udostępnić specyfika-
bkit. Tryb ten pozwala użytkownikom prze- ite. Dostęp do wersji beta pozwoli użytkow-
cję formatu Flash, zarówno .swf, jak i .flv/.f4v
oraz usunąć wszystkie restrykcje licencyjne. glądać na bieżąco treści umieszczone w śro- nikom przekazywać za pośrednictwem ser-
W przyszłości taki sam los ma też spotkać AIR. dowisku rzeczywistym bez potrzeby wycho- wisu Adobe Labs ich sugestie dotyczące
Warto zaznaczyć, że Adobe już jakiś czas temu dzenia z programu Dreamweaver w celu przyszłego rozwoju produktu. Wersje beta
umożliwił deweloperom tworzenie narzędzi obejrzenia tych treści z poziomu przeglądar- programów Dreamweaver i Fireworks działa-
zapisujących we Flashu. Do ich odtworzenia ki. Funkcja ta umożliwia również użytkow- ją pod kontrolą różnych systemów operacyj-
konieczne było jednak posiadanie Flash Play-
nikom zamrażanie kodu w języku JavaScript nych, w tym systemu Microsoft Windows XP
era. Teraz mają być one dostępne na każdym
urządzeniu. Poza specyfikacją samego Flasha, w celu debugowania stron interaktywnych, z pakietem Service Pack 2, systemu Windows
Adobe planuje otwarcie specyfikacji proto- a także przeglądanie treści we Flash'u i inte- Vista i systemu Mac OS X w wersji 10.4.11
kołów Adobe Flash Cast i Action Message rakcje z nimi. Nowości w wersji beta progra- lub nowszej zainstalowanego na kompute-
Format oraz API niezbędnego do wdrażania mu Fireworks obejmują nowy interfejs użyt- rach Macintosh z procesorami PowerPC G5
Flash Playera na różnych platformach. Otwar-
kownika, który jest obecnie zgodny z inny- lub Intel. Wersja beta programu Soundbo-
cie specyfikacji Flasha wydaje się wyzwaniem
rzuconym w stronę platformy Microsoftu do mi aplikacjami wchodzącymi w skład pakie- oth działa pod kontrolą wszystkich wymie-
wyświetlania i tworzenia bogatych graficznie tu Creative Suite. Ułatwia to użytkownikom nionych systemów poza systemami zainsta-
multimedialnych treści internetowych Silver- przełączanie się między aplikacjami, które lowanymi na komputerach Macintosh z pro-
light. Adobe ma nadzieję, że przyczyni się to mają teraz taki sam wygląd i sposób obsłu- cesorami PowerPC. Wersje beta można już
do jego popularyzacji na miarę wydanego gi. Ponadto wersja beta programu Fireworks pobrać z serwisu Adobe Labs pod adresem
w 1993 roku PDF, który w krótkim czasie stał
pozwala użytkownikom eksportować zapro- www.labs.adobe.com.
się otwartym standardem zapisu dokumen-
tów elektronicznych, a także wkrótce standar- jektowane kompozycje w postaci zapewnia-
dem ISO 32000. jących dużą wierność obrazu, interaktyw-
www.readwriteweb.com nych i bezpiecznych dokumentów w forma-

10 FLEX
Aktualności

3dflash.pl onAIR w Warszawie


6 czerwca w Centrum Olimpijskim w War-
szawie, odbyła się konferencja onAIR. Jest
tworzy adobe.com.pl to cykl wykładów w języku angielskim,
dotyczących technologii Adobe AIR. W

P
omysł na projekt systemu społeczno- no dodawać produktów do systemu Allegro tym roku impreza odbywa się w 11 krajach
ściowego dla użytkowników progra- i naszego. Oczywiście nie zabraknie tutoriali Europy (Warszawa była 8 z kolei).
Na tym trwającym cały dzień, dostępnym
mów z rodziny Adobe, powstał już rok z zakresu użytkowania produktów Adobe. nieodpłatnie dla wszystkich wydarzeniu,
temu, gdy uzyskaliśmy domenę adobe.com.pl. Poza tym dobrą informacją dla użytkowni- można było posłuchać znakomitych ewan-
Przez ten okres pracownicy naszej agencji ków powinna być możliwość umieszczania gelistów oraz specjalistów z Adobe takich
tworzyli wzór największego systemu pod w galerii plików JPG z własnymi pracami, jak: Mike Chambers, Serge Jespers, Kevin
technologią Flex. Ze względu na ilość modu- podobnie jak w serwisie digart. Ponadto roz- Hoyt, czy Daniel Dura. Poza zdobyciem
ogromu wiedzy przekazanej na wykładach,
łów jakie będzie serwis posiadał, agencja mu- szerzyliśmy funkcjonalność do plików SWF
można było w czasie przerwy porozmawiać
siała rozwiązać szereg problemów technicz- i PDF. Jeszcze jedną funkcjonalnością będzie z prelegentami, zadać nurtujące pytania i
nych, związanych z połączeniami modułów moduł odpowiedzialny za odczyt nowych wymienić się wiedzą. Można było też odpo-
ze sobą, a także połączeniami z bazami da- wiadomości i informacji z serwisów flab.pl cząć przy kawie, przekąskach, a nawet XBo-
nych. W pewnym momencie cały projekt sta- oraz magazynu 3DFX (www.3dfxmag.pl). x’ach, które dostarczył organizator. Dodat-
nął pod znakiem zapytania ze względu na re- Jedną z głównych zalet tego modułu będzie kową atrakcją było losowanie nagród w
postaci oprogramowania Adobe. Ilość
alizacje serwisu Flextech firmy Janmedia, ale dodawanie własnych źródeł np. z serwisów
uczestników, którzy wzięli udział w warsz-
zorientowaliśmy się, że nie będzie on tak roz- wp.pl czy Onet.pl. tatach świadczy o dużym zainteresowaniu
budowany jak nasz projekt, dlatego nie za- technologią AIR w Polsce.
trzymaliśmy prac nad adobe.com.pl. Trochę o technologiach Więcej o onAIR na http://onair.adobe.com/
Cały system będzie bazował zarówno na narzę-
FlexChallenge – let’s flex
Co serwis będzie oferował dziach komercyjnych, jak i Open Source. Naj-
what’s possibile
Przede wszystkim dzięki implementacji naj- ważniejsze to: Jesteś programistą Flex? A może właśnie
nowszych technologii Flex użytkownicy bę- Całość video-konwersji oraz wyświetla- zacząłeś swoją przygodę z AIR? Bez względu
dą mogli dodawać swoje video i videotuto- nia będzie realizowane przez Adobe Flash na płeć, wiek, doświadczenie czy wykonywa-
riale w jakości dotąd niespotykanej, nawet Media Server 3. Połączenia z bazą będą re- ny zawód zapraszamy do wzięcia udziału we
do 480i (720x480), czyli dwukrotnie więcej alizowane poprzez darmowy amfphp i we- FlexChallenge. Jeżeli chcesz pokazać światu
swoje prace, podejmij wyzwanie! Adobe
niż obecne na Youtube. Ale to nie wszystko. borb. Ze względu na to że moduł animiacji
Flex oraz Adobe AIR to nowoczesne techno-
Ze względu na to, że najnowszy Flash Player we Flex 3 nie jest dla nas najlepszy, dodta- logie pozwalające tworzyć bogate wizual-
9.0.124.0 ma możliwość odtwarzania plików kowym silnikiem napędowym będzie także nie aplikacje (RIA), które są zorientowanie na
MOV kodowanych kodekiem h264 i dźwię- darmowy Tweener. Pozostałe elementy stwo- środowisko internetowe oraz desktopowe.
ku kodekiem AAC+, wilekość pliku będzie rzone zostały we Flex w połączeniu z plika- FlexChallenge to cykl ogólnopolskich zawo-
dów w wytwarzaniu aplikacji RIA, umożli-
porównywalna z wielkością plików na Youtu- mi PHP, które są silnikiem pozyskiwania in-
wiających rywalizację z najlepszymi, zapre-
be. Kolejnym modułem będzie personaliza- formacji z róznych serwisów poprzez meto- zentowanie i doskonalenie swoich umiejęt-
cja profilów o swoje prace, ciekawe informa- dy parsowania. ności, a tym samym promocję utalentowa-
cje, linki do stron, własny avatar, ponadto nych osób tworzących w technologiach Flex
wszystkie elmenety zdjęciowe będzie można Dla kogo jest adobe.com.pl? i AIR. Konkurs wystartował 6 czerwca br., a
obrabiać poprzez wbudowany edytor plików Serwis będzie prosty i zrozumiały dla wszyst- kończy się jesienią. Skład sędziowski ocenia-
jący zgłoszone prace stanowią doświadczo-
zdjęciowych. Za pomocą edytora będzie moż- kich. Miejsce dla siebie znajdą tam zaawan-
ne osoby związane bezpośrednio z wytwa-
na skalować, obcinać ,zmieniać kolorystykę, sowani użytkownicy programów Adobe oraz rzaniem aplikacji RIA oraz uznani na świe-
czy też dodawać np. loga do swoich zdjęć. początkujący. Ważną rolę w tym aspekcie od- cie ewangeliści oraz inżynierowie technolo-
Ponadto, system będzie posiadał forum, ser- grywa layout tworzony przez naszego grafi- gii Adobe. Nagrody rzeczowe, które można
wis ze zleceniami gdzie freelancerzy będą mo- ka Monikę Onsowicz. Połączenie zaawan- wygrać w konkursie są bardzo atrakcyjne
gli zabiegać o pozyskanie projektów, a praco- sowanych funkcji z intuicyjną i przyjemną – komputery MacBook, iPody, oprogramo-
wanie Adobe oraz niespodzianki od sponso-
dawcy będą mogli umieszczać zlecenia. Ko- w odbiorze dla użytkowników aplikacją by-
rów i patronów medialnych. Głównym spon-
lejnym modułem będzie miejsce, gdzie bę- ło dużym wyzwaniem dla grafików i progra- sorem oraz patronem zawodów jest polski
dzie można oferować stałą prace.Będzie moż- mistów. oddział firmy Adobe Systems. Organizato-
liwość tworzenia grup Adobe i dopisywania rem zawodów jest polska grupa użytkow-
się kolejnych osób do już stworzonych. Bę- Termin zakończenia prac ników technologii Flex oraz AIR – FlexTech,
której sponsorem głównym jest międzyna-
dzie też mozliwość komunikacji pomiędzy Wersji finalnej na pewno jeszcze jakiś czas
rodowa firma informatyczna Janmedia Inte-
osobami w danej grupie, a także umieszcza- nie będzie, ale wersja testowa jest już od 7 ractive. Zawody trwają! Zajrzyj na oficjalną
nie przez użytkowników informacji o spotka- lipca. stronę konkursu i zgłoś swój udział!
niach i seminariach. Sklepom sprzedających W dniu zamknięcia magazynu SDJ Extra http://www.flexchallenge.com
oprogramowanie Adobe będziemy oferowali skończone było 90% serwisu. Licząc z wszyst-
system typu Ceneo. Będziemy też zamiesz- kimi silnikami i kodami napisaliśmy około
czać pełne opisy technologiczne tych progra- trzech milonów linii kodu. Zapraszamy do od-
mów. Planujemy także powiązanie tego mo- wiedzenia serwisu adobe.com.pl.
dułu z sklepami Allegro, aby osoby odpowie-
dzialne za administracje nie musiały osob-

www.sdjournal.org 11
ADOBE FLEX

Pierwsza
aplikacja we Flex
Przełom w budowie dynamicznych witryn WWW to wprowadzenie technologii
Flash, która zniosła wiele ograniczeń i pozwoliła na rozwój prawdziwych
multimedialnych projektów Internetowych. Po jednorazowym załadowaniu
wykonanej witryny, użytkownik korzystał z pełni funkcjonalnego GUI
niewymagającego ponawiania zapytań do serwera i wysyłania odpowiedzi.
Wprowadzenie
Dowiesz się... Powinieneś wiedzieć... do technologii Flex
• O technologii Flex i środowisku Flex Builder 3; • Wymagana jest podstawowa wiedza z zakresu Obszarem zastosowania Flex jest wspomaganie
• Nauczysz się korzystać z klasy HttpService programowania oraz języka XML. budowy aplikacji w zakresie tworzenia warstwy
oraz komponentu Datagrid. • Wiedza na temat aplikacji internetowych. prezentacji. Flex skoncentrowany jest na dostar-
• Samodzielnie wykonasz program wyświetlają- czaniu rozwiązań wspierających budowę graficz-
cy dane z pliku XML. nego interfejsu użytkownika. Pisząc o Flexie sto-
suję pewne uogólnienie dla kompleksowego roz-
wiązania, w skład którego wchodzi Flex Software
wych, wykorzystujących dynamicznie generowany Development Kit (Flex SDK) oraz zaawansowa-
jednoekranowy interfejs użytkownika. Debiut pro- ne środowisko developerskie Flex Builder. SDK to
Poziom trudności duktu został poprzedzony wprowadzeniem nowe- rozwiązanie darmowe, oferujące m.in. kompilator
go terminu dla projektów Internetowych – RIA działający z linii poleceń. Siłą SDK jest wykorzy-
(Rich Internet Application), co w dosłownym tłu- stanie tandemu: języka MXML wraz z obiektowo
maczeniu brzmi bogata aplikacja internetowa. Po- zorientowanym językiem ActionScript 3, dobrze

O
bszar zastosowań Flash zaskoczył sa- jęcie oznacza nowoczesne dynamiczne aplikacje in- znanym wszystkim użytkownikom Flash.
mych producentów. Narzędzie prze- ternetowe, w których wyeliminowano uciążliwość MXML jest opartym o XML językiem cha-
znaczone do tworzenia multimedial- standardowych technologii opartych o HTML. rakteryzującym się stosunkowo prostą składnią.
nej animacji opartej na wektorach stało się jednym Aplikacje wykonane w oparciu o założenia RIA Znacznikowa budowa szczególnie przypadnie do
z wiodących rozwiązań wykorzystywanych do charakteryzują się jednoekranową prezentacją da- gustu tradycyjnym webmasterom oraz początku-
projektowania witryn internetowych. nych (znaną z rozwiązań desktopowych), brakiem jącym programistom. MXML umożliwia łatwe
Model budowy projektów w oparciu o listwę konieczności przeładowywania zawartości ekranu generowanie i zarządzanie komponentami wizu-
czasową i sceny, stworzony z myślą o animacji, zo- podczas pracy oraz przyjaznym, zawierającym ele- alnymi, które można następnie wywoływać, zmie-
stał zaadaptowany na potrzeby WWW. Często- menty multimedialne interfejsem. niać właściwości i dodawać efekty.
kroć budowa witryny wykonanej we Flash skła-
dała się ze scen umieszczonych na listwie czaso-
wej, po których użytkownik przesuwał się nawi-
gując po menu. W późniejszych wersjach Flash
wykorzystywano kilka niezależnych dokumen-
tów SWF ładowanych dynamicznie do główne-
go pliku SWF.
Tworzenie bardziej zaawansowanych aplikacji
w środowisku przeznaczonym pierwotnie do two-
rzenia animacji zaczęło być coraz trudniejsze i co-
raz mniej wydajne. Problem dostrzegli projektan-
ci z firmy Marcomedia (obecnie Adobe) i posta-
nowili, że należy postawić jasną granicę pomię-
dzy rozwiązaniami wspomagającymi tworzenie
dynamicznych aplikacji WWW, a rozwiązaniami
wspomagającymi pracę grafików. Owocem tej de-
cyzji stał się Flex.
Czy Flex jest następcą Flash? Odpowiedź brzmi:
nie. Jest to osobny produkt z rodziny Adobe, umoż-
liwiający budowę nowoczesnych projektów webo- Rysunek 1. Zrzut ekranu po uruchomieniu Flex Builder 3

12 FLEX
Język znacznikowy ma jednak pewne ograniczenia np. brak możliwo-
ści przetwarzania wprowadzonych danych, zapętlania, stosowania instruk-
cji warunkowych. Wszystkie wymienione braki wypełnia ActionScript, któ-
ry umożliwia stosowane dynamicznych interakcji pomiędzy komponenta-

Listing 1. Dzięki klasie HTTPService otrzymujemy dane z pliku XML


w postaci odpowiedzi HTTP

<?xml version="1.0" encoding="utf-8"?>


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
ayout="absolute">
<mx:HTTPService id="adresyDane" url=”adresy.xml” />
</mx:Application>

Listing 2. Wywołanie przez creatioComplete funkcji send()


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" creationComplete="adr
esyDane.send()">
<mx:HTTPService id="adresyDane" url="adresy.xml"/>
</mx:Application>

Listing 3. Kompontent DataGrid wyświetla dane znajdujące się


w obiekcie w tabeli
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" creationComplete="adr
esyDane.send()">
<mx:HTTPService id="adresy" url="adresy.xml" />
<mx:DataGrid x=”50” y=”50” width=”850”/>
</mx:Applicat ion>

Listing 4. Aby wyświetlić dane, musimy odwołać się do obiektu


lastResult
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml”
layout="absolute" creationComplete="adr
esyDane.send()">
<mx:HTTPService id="adresyDane" url="adresy.xml" />
<mx:DataGrid x=”50” y=”50” width=”850” "{adresyDane.lastRes
ult.adresy.stock}" />
</mx:Application>

Listing 5. Dodajemy nagłówki w kolumnach


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" creationComplete="adr
esyDane.send()">
<mx:HTTPService id="adresyDane" url=" adresy.xml"/>
<mx:DataGrid x="21" y="10" width="850” dataProvider="{adresy
Dane.lastResult.adresy.osoba}">
<mx:columns>
<mx:DataGridColumn dataField="imie"
headerText="Imię"/>
<mx:DataGridColumn dataField="nazwisko"
headerText="Nazwisko"/>
<mx:DataGridColumn dataField="adres"
headerText="Adres zamieszkania"/>
<mx:DataGridColumn dataField="tel"
headerText="Telefon kontaktowy"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>

www.sdjournal.org
ADOBE FLEX

mi, np. możemy przetworzyć dane wprowadzo- Pierwszy projekt bardzo proste i logiczne. Uzupełniamy nasz
ne przez użytkownika w polach tekstowych, wy- Wspólnie wykonamy projekt prostej aplikacji, któ- kod źródłowy tak jak na Listingu 2. Wywołanie
konać obliczenia itd. Budowa Flex pozwala na bar- ra w przystępny sposób wyświetli nam zawartość funkcji send() przekazuje dane z pliku XML
dzo intuicyjne łączenie obu języków, dlatego praca pliku adresy.xml. Celem wykonania projektu jest do Flex w postaci obiektu, który zostaje ob-
z dokumentem jest łatwa, a budowa projektu spój- zaprezentowanie składni języka MXML oraz pro- służony przez klasę HTTPService. Po otrzyma-
na. Kod źródłowy aplikacji wykonanych we Flex stoty tworzenia aplikacji we Flex. niu danych HTTPService umieszcza je w obiek-
przetwarzany jest do postaci kodu ActionScript, Aby utworzyć aplikację, musimy stworzyć no- cie lastResult. Za każdym razem, kiedy dane
a następnie kompilowany do postaci pliku SWF. wy projekt, w którym Flex utworzy niezbędną zostaną zmienione obiekt lastResult zostanie
W skład SDK wchodzą również: biblioteka goto- strukturę katalogów i plików. W tym celu wybie- zaktualizowany.
wych klas - Flex Class Library oraz Flex Data ramy menu File>New>Flex Project. W polu Pro- Nadszedł czas, aby wyświetlić pobrane da-
Service umożliwiający łączenie warstwy prezen- jectname wpisujemy nazwę naszego projektu np. ne. W tym miejscu skorzystamy z komponen-
tacji z warstwą biznesową. PierwszaAplikacjaFlex. Inne opcje pozostawiamy tu DataGrid, który wyświetla dane znajdują-
Flex Data Sevice nie umożliwia bezpośred- z domyślnymi wartościami i klikamy przycisk Fi- ce się w obiekcie w tabeli. Uzupełnijmy zatem
niego dostępu do baz danych. Pełni rolę pośredni- nish. Po chwili nasz projekt zostanie załadowa- nasz kod, dodając komponent wraz z atrybuta-
ka umożliwiającego np. wywołanie na serwerze ny. Jak widać na Rysunku 1. w panelu Flex Na- mi definiującymi szerokość pola (width) oraz
kodu Java, .Net, PHP, ASP czy ColdFusion, powo- vigator, stworzona została odpowiednia struktu- pozycje w poziomie (x) i pionie (y) (Listing 3.).
dującego pobranie danych z bazy, a następnie ich ra. W głównym oknie projektu znajdują się dwie Następnie musimy przekazać dane, które zo-
przekazanie do warstwy prezentacji. zakładki: Source, w której możemy edytować kod stały przechwycone przez HTTPService do pola
Wraz z pojawieniem się technologii Flex, Adobe źródłowy naszej aplikacji oraz Design, z której do- DataGrid, w tym przypadku HTTPService peł-
zaoferowało dedykowane rozwiązanie wspomaga- stęp mamy do edytora graficznego. Skupimy się na ni rolę dostawcy danych, które chcemy wyświe-
jące pracę developerów - Flex Builder. Produkt jest edycji kodu źródłowego, dlatego przejdźmy do za- tlić. Aby wyświetlić dane, musimy odwołać się
zaawansowanym graficznym środowiskiem typu kładki Source. do obiektu lastResult (Listing 4.).
RAD opartym o dobrze znany programistom Ja- Jak widać, po stworzeniu projektu, utworzony W zasadzie nasza aplikacja jest już gotowa,
va - Eclipse. został szkielet dokumentu z otwierającym i zamy- dodajmy jednak przyjazne użytkownikowi na-
Oprócz znanych z Eclipse narzędzi wspoma- kającym znacznikiem Application. główki poszczególnych kolumn w tabeli wg Li-
gających tworzenie aplikacji, Flex Builder oferu- Istnieje kilka możliwości uzyskana dostępu stingu 5.
je graficzny edytor pozwalający na wizualną kre- do zawartości pliku XML. Wykorzystamy kla- Nasz projekt jest gotowy. Pozostaje jedynie
ację projektu. Wszystkie niezbędne komponenty sę HTTPService, dzięki której Flex otrzyma da- skompilować i uruchomić program. W tym ce-
jak przyciski, pola tekstowe, elementy menu, moż- ne z pliku XML w postaci odpowiedzi HTTP. lu z menu wybieramy Run>Run PierwszaApli-
na w prosty sposób przeciągnąć myszką i umieścić W tym miejscu warto przypomnieć, że progra- kacjaFlex lub wciskamy skrót klawiszowy [Ctrl]
w oknie projektu. Celowo pomijam opis samego mowanie we Flex jest zorientowane obiektowo + [F11]. Po chwili w oknie domyślnej przeglą-
środowiska Flex Builder oraz opis procesu insta- i każdemu zdarzeniu przyporządkowana jest darki ukaże się nasz program wyświetlający da-
lacji. W poniższym opisie wykorzystałem najnow- odpowiednia akcja. Zdarzeniem może być np. ne adresowe z pliku adresy.xml (na DVD).
szą, trzecią odsłonę Flex Buildera. Do dzieła! Za- załadowanie aplikacji, kliknięcie przycisku lub
czynamy przygodę z Flex! wpisanie tekstu. Podsumowanie
Pomiędzy głównymi znacznikami aplikacji Tworzenie aplikacji we Flex nie jest trudne. Jak
wprowadzamy znacznik <HTTPService> opa- łatwo zauważyć, ilość linii kodu potrzebnych
trzony wymaganym atrybutem id, przyjmij- do wyświetlenia pliku XML jest minimalna.
my id=”adresy”. Kolejny atrybut URL definiu- Poznaliśmy składnię języka MXML, a samo-
je ścieżkę dostępu do pliku oraz jego nazwę, po- dzielne wykonanie projektu przybliżyło moż-
dajmy ścieżkę do katalogu gdzie umieściliśmy liwości klasy HTTPService oraz komponent
nasz plik adresy.xml. Nasz kod powinien wyglą- DataGrid.
dać jak na Listingu 1. Mam nadzieję, że ten artykuł stanie się dla
Jak wspomniałem wcześniej, aby nastąpi- Was początkiem dalszej przygody z Flex, tech-
ła akcja, musi wystąpić zdarzenie, które ją wy- nologią, która zmienia oblicze Internetu.
woła. Samo użycie klasy HTTPService do po-
łączenia z plikiem XML nie jest rozpoznawa- Propozycja dalszej literatury
ne jako zdarzenie, dlatego musimy zdefinio- Niestety brakuje polskojęzycznych podręczni-
wać inne zdarzenie. Użycie creatioComplete ków do nauki Flex, dlatego konieczne jest sko-
w głównym znaczniku Application spowo- rzystanie z anglojęzycznej literatury. Szczegól-
duje, że fakt ukończenia ładowania aplikacji nie dwie pozycje warte są polecenia:
zwrócony zostanie jako zdarzenie mogące wy-
wołać odpowiednią funkcję. W naszym przy- • Flex 3: A Beginner's Guide By Michele E. Da-
padku użyjemy funkcji send(), która zosta- vis, Jon A. Phillips;
nie wywołana w momencie załadowania apli- • The Essential Guide to Flex 3 By Charles E
Rysunek 2. Widok panelu Flex Navigator
kacji. Brzmi to nieco zawile, ale w istocie jest Brown.

KRYSTIAN RAJSKI
Autor na co dzień pracuje jako Software Test Engi-
neer w firmie ADVA Optical Networking.
Prywatnie interesuje się programowaniem aplikacji
webowych. Związany z grupą ProgInn.
Rysunek 3. Widok gotowego projektu Kontakt: krajski@p-innovations.com

14 FLEX
Od formularza do RIA

Od formularza do RIA
Adobe Form Guides

Budowa aplikacji w technologii Flex niekoniecznie musi odbywać się


w narzędziu Flex Builder. Dla pewnego typu aplikacji łatwiejsze może być
użycie narzędzia Adobe Guide Builder.

Pierwszy formularz
Dowiesz się... Powinieneś wiedzieć... Na początku stworzymy prosty formularz
• Jak przy pomocy narzędzia Adobe LiveCycle • Czym jest plik dokumentu PDF i do czego słu- kontaktowy na podstawie jednego z goto-
Designer ES szybko stworzyć formularz PDF ży program Adobe Acrobat; wych szablonów Designera. W tym celu uru-
aby zebrać dane; • Czym są formularze elektroniczne. chom zainstalowany program Adobe Live-
• Jak na podstawie przygotowanego formularza Cycle Designer ES i wykonaj poniższe pole-
utworzyć Form Guide. cenia:

• Z menu górnego File wybierz opcję New;


wymi, bezpieczeństwem dokumentów oraz • W oknie Asystenta New Form Assistant
ich automatycznym generowaniem. Adobe na pierwszej stronie Getting Started wy-
Poziom trudności tworząc Designera, postanowiło wyjść na- bierz opcję Based on a Template i naciśnij
przeciw oczekiwaniom różnych grup pro- przycisk Next;
jektantów. • Na stronie drugiej Document Setup z listy
Zwykli użytkownicy, którzy potrzebują w Select a template wybierz szablon pod na-

W
poniższym artykule postaram prosty i szybki sposób zebrać potrzebne infor- zwą Contact Information i naciśnij przy-
się przedstawić, jak prosto stwo- macje, pracę z Designerem mogą rozpocząć od cisk Next;
rzyć elektroniczny formularz, po- wyboru jednego z kilku gotowych, prekonfi- • Wpisz nazwę firmy lub pozostaw przy-
mocny w zbieraniu danych, który następnie gurowanych szablonów formularzy, a następ- kładową, a następnie kliknij przycisk
można równie łatwo zamienić w interfejs bę- nie za pomocą Asystenta Tworzenia Formula- Next;
dący bogatą aplikacją internetową w forma- rzy odpowiednio je przystosować do własnych • Wskaż ścieżkę do pliku graficznego logo,
cie SWF. potrzeb. które będzie zamieszczone w prawym,
Graficy i webdesignerzy, którzy tworzą zop- górnym rogu formularza lub pozostaw
Narzędzie tymalizowane interfejsy formularzy w celu uła- standardowe i naciśnij przycisk Next;
tworzenia formularzy twienia użytkownikom wprowadzania danych, • Wprowadź dane teleadresowe na kolej-
Zapewne większość z czytelników miała do pracę z Designerem mogą rozpocząć od projek- nych podstronach (Address, Contact), za-
czynienia z oprogramowaniem Adobe Acro- towania układu strony lub zaimportowania ist- twierdzając je przyciskiem Next;
bat i formatem dokumentów PDF oraz dar- niejących już projektów z programów InDesign • Na ostatniej stronie Form Return Setup
mowym czytnikiem Adobe Reader. Możli- lub Illustrator. wpisz swój adres e–mail i naciśnij przy-
we, że wielu czytelników tworzyło już wła- Programistów oraz projektantów baz da- cisk Finish;
sne interaktywne formularze PDF w progra- nych, którzy szczególnie skupiają swoją uwagę • Zapisz stworzony formularz jako plik
mie Acrobat. na właściwej organizacji i strukturze danych PDF (menu File) i wybierz opcję Save.
Jednakże Acrobat nie jest głównym narzę- ucieszy zapewne fakt, że Designer umożliwia
dziem do projektowania formularzy. W tym zaimportowanie pliku w postaci XML lub pli- Właśnie udało Ci się stworzyć formularz słu-
artykule przedstawię sposób tworzenia inte- ku schematu XSD, aby na ich podstawie au- żący zbieraniu informacji kontaktowych od
raktywnych formularzy w narzędziu specjal- tomatycznie wygenerować odpowiednie po- użytkowników.
nie do tego celu przeznaczonym i w pełni ten la formularza. Możesz podejrzeć jego działanie, wybierając
proces wspierającym – Adobe LiveCycle De- Każda z grup projektantów może rozpocząć zakładkę Preview PDF (Rysunek 1.).
signer ES. pracę z Designerem w odpowiedni dla siebie
Adobe LiveCycle Designer ES to narzędzie sposób, zgodny z upodobaniami. Zbieranie danych
z rodziny rozwiązań serwerowych Adobe Li- Wersja testowa programu Adobe LiveCyc- za pomocą formularza
veCycle Enterprise Suite opartych o platfor- le Designer ES jest dostępna pod adresem: Przygotowany w Designerze formularz możesz
mę J2EE, łączących obsługę formularzy elek- http://www.adobe.com/go/trylivecycle_desi- dystrybuować do użytkowników, by przy jego
tronicznych, zarządzanie procesami bizneso- gner. pomocy kolekcjonować dane. Użytkownicy wy-

www.sdjournal.org 15
ADOBE FLEX

pełniają formularz danymi w programie Adobe Można je tworzyć poprzez narzędzie LiveCyc- cej popularną technologię Flash. Ma to na ce-
Acrobat lub darmowym Adobe Reader i po je- le Designer ES, a do zbierania danych i prezen- lu, z punktu widzenia użytkownika, jeszcze
go wypełnieniu, za pomocą przycisku Submit tacji on-line wymagana jest usługa renderowa- łatwiejsze wprowadzanie danych do formu-
by Email, odsyłają formularz z powrotem do nia formularzy modułu serwerowego LiveCyc- larzy, bogatszych wizualnie i o większej uży-
Ciebie. Warto wspomnieć, że odsyłany jest je- le Forms ES. teczności.
dynie kawałek dokumentu PDF – reprezenta- Jedyne narzędzie, którego potrzebuje użyt- Nowa technologia Adobe Form Guides dia-
cja zebranych danych w pliku XML. Zawartość kownik końcowy formularza to przeglądar- metralnie zmienia sposób dostarczania i odbie-
pliku może przedstawiać się jak na Listingu 1. ka internetowa z zainstalowanym Flash Play- rania informacji.
erem. Form Guides mogą być alternatywnym spo-
Formularze RIA – nowa technolo- Form Guides to połączenie siły technolo- sobem na wprowadzanie danych do istnieją-
gia Adobe o nazwie Form Guides gii LiveCycle z technologią RIA, zaawanso- cych już formularzy PDF. Użytkownik wy-
To kolejna generacja w ewolucji interaktyw- wanych interfejsów użytkownika dostępną w pełniając formularz w technologii Form Gu-
nych interfejsów formularzy elektronicznych. Adobe Flex, a także animacji wykorzystują- ides nie widzi całej struktury formularza, a je-
dynie prowadzony jest przez interaktywny in-
Listing 1. Zawartość pliku Xml z formularza wypełnionego danymi, który jest odsyłany przez terfejs z szeregiem pytań i użyteczną pomo-
klienta cą, podczas gdy zbierane w tle dane wpisy-
wane są do formularza PDF. Podsumowując,
<form1> Form Guide jest rodzajem asystenta wypełnia-
<Date>2008–05–23</Date> nia formularzy.
<EmployeeName>Tomasz Lichota</EmployeeName>
<Address>ul. Prusa 2</Address> Tworzenie Form Guide
<StateProv>mazowieckie</StateProv> Każdy z Form Guide jest renderowany przez
<ZipCode>00–493</ZipCode> moduł serwerowy LiveCycle Forms ES. W
<SSNumber>00000001</SSNumber> tym celu należy zainstalować Adobe LiveCyc-
<HomePhone>1234556677</HomePhone> le Enterprise Suite.
<CellPhone>999100100</CellPhone> Wersja próbna dostępna jest pod adresem:
<Comments>brak</Comments> http://www.adobe.com/go/trylivecycle, a infor-
</form1> macje dotyczące instalacji znaleźć można pod
adresem: http://www.adobe.com/go/learn_lc_in-
stall.
Zajmijmy się teraz procesem tworzenia i
personalizowania wyglądu Form Guide dla
stworzonego wcześniej formularza kontakto-
wego. Aby utworzyć Form Guide, wykorzy-
stując przygotowany do tego wcześniej for-
mularz kontaktowy, postępuj według poniż-
szych kroków:

• W programie LiveCycle Designer ES


otwórz zapisany wcześniej plik PDF for-
mularza kontaktowego;
• Z menu górnego Tools wybierz opcję Cre-
ate or Edit Form Guide;
• W oknie narzędzia tworzenia i edycji
Form Guide o nazwie Guide Builder, w za-
kładce Edit Guide i w oknie po lewej stro-
nie, kliknij prawym przyciskiem myszy i z
menu wybierz opcję Add Panel;
• W tej samej zakładce Edit Guide, wybierz
opcję Add or Bind Fields (Rysunek 2.);
• Z części okna po prawej stronie o na-
zwie Form Objects, przytrzymując kla-
Rysunek 1. Okno programu LiveCycle Designer ES z nowo utworzonym formularzem kontaktowym wisz [Shift], zaznacz i przeciągnij my-

W Sieci
• Wersja próbna narzędzia Adobe LiveCycle Designer ES dostępna jest pod adresem:
http://www.adobe.com/go/trylivecycle_designer;
• Wersja próbna programu Adobe Acrobat 8 Professional dostępna jest pod adresem:
http://www.adobe.com/go/acrobatpro_trial;
• Wersja próbna rozwiązania serwerowego Adobe LiveCycle Enterprise Suite dostępna jet pod
adresem: http://www.adobe.com/go/trylivecycle;
• Strona produktu – Adobe LiveCycle Enterprise Suite znajduje się pod adresem:
http://www.adobe.com/products/livecycle/. Rysunek 2. Okno Guide Buildera z widoczną opcją
Add or Bind Fields wiązania pól formularza

16 FLEX
Od formularza do RIA

szą wszystkie obiekty z sekcji #subform


– Header do górnego panelu o nazwie
New Panel po lewej stronie oraz z Body
do nowo dodanego panelu New Panel
części okna po lewej. Obiekty z tych
sekcji powinny teraz znajdować się tak-
że w okienku po lewej stronie i być po-
wiązane z panelami Form Guide, co sy-
gnalizuje ikonka łańcucha przy każdym
z nich.
Nazwy paneli, nazwy sekcji oraz Form
Guide można zmienić według uznania
(Rysunek 3.);
• W zakładce Customize Appearance mo-
żesz spersonalizować wygląd Form Guide,
ustawiając m.in. takie parametry jak kolor
tła paneli, kolor i wygląd czcionek, wygląd
przycisków, itp.
Możesz dowolnie eksperymentować z
opcjami w celu uzyskania zadowalającego
efektu;
• Aby podejrzeć utworzony Form Guide,
kliknij zakładkę Preview, która spowoduje
Rysunek 3. Okno narzędzia Guide Builder z widocznymi powiązaniami pól formularza i tworzonego Form Guide otwarcie przeglądarki internetowej i wy-
świetlenie pliku HTML z osadzonym we-
wnątrz plikiem Flash (Rysunek 4.);
• W celu zatwierdzenia wszystkich wpro-
wadzonych ustawień kliknij przycisk Ap-
ply, a następnie zamknij narzędzie Guide
Builder przyciskiem Close;
• Zapisz wprowadzone w formularzu zmia-
ny.

Co dalej?
Tak stworzony oraz spersonalizowany formu-
larz kontaktowy z interfejsem Form Guide go-
towy jest do zamieszczenia na serwerze i wyko-
rzystania w procesie renderowania modułu Li-
veCycle Forms ES.
Posłuży on nam do zbierania danych od użyt-
kowników, którzy dysponując jedynie przeglą-
darką z zainstalowanym Flash Playerem, będą
mogli wypełniać przygotowany przez nas inte-
raktywny formularz w prosty i przyjazny użyt-
kownikowi sposób.
Więcej informacji na temat Form Guides
znaleźć można pod adresem:
http://www.adobe.com/go/learn_lc_fgGetStart.

TOMASZ LICHOTA
Zajmuję się wsparciem klientów wykorzystujących
Rysunek 4. Przykładowy wygląd Form Guide stworzonego w programie LiveCycle Designer ES w technologie formularzy elektronicznych.
narzędziu Guide Builder na podstawie pliku PDF formularza kontaktowego http://www.adobe.pl

Tabela 1. Programy do tworzenia formularzy Form Guides


Program: Zastosowanie:
Adobe Acrobat 8 Professional z programem LiveCycle Desi- Tworzenie, konwersja i edycja elektronicznych dokumentów w formacie PDF, tworzenie
gner 8.0 interaktywnych formularzy PDF opartych na XML i wspierających specyfikację XFA 2.5
Adobe LiveCycle Designer ES (8.1) Tworzenie interaktywnych formularzy PDF opartych na XML, możliwość tworzenia
wzbogaconych formularzy RIA bazujących na technologii Adobe Flex i Flash o nazwie
Form Guides. Designer 8.1 wspiera specyfikację XFA w wersji 2.6

www.sdjournal.org 17
ADOBE FLEX

Flex i AIR
Tworzenie aplikacji w oparciu o środowisko Adobe AIR
z wykorzystaniem Adobe Flex.
Z AIR korzystają obecnie takie firmy jak AOL czy eBay, a po niedawno
ogłoszonym przez Adobe Open Screen Project, możemy się go spodziewać
także na urządzeniach przenośnych jak np. telefony komórkowe, PDA i MID
(ang. Mobile Internet Device).

śniejszym zainstalowaniu AIR update for Flash


Dowiesz się... Powinieneś wiedzieć... CS3 Professional) lub ściągnąć samo AIR SDK
• Jakie funkcje oferuje Adobe AIR. • Powinieneś znać podstawy ActionScript i Flex. (lub Flex 3 SDK) i tworzyć aplikację za pomocą
edytora tekstowego (lub IDE np. FlashDevelop).
Opiszę jednak najprostszą, i jak dla mnie najwy-
da także większy dostęp do naszego systemu, godniejszą, metodę – czyli Flex Builder 3.
w porównaniu do aplikacji Flash/Flex. Może- Po ściągnięciu i zainstalowaniu Flex Builder
Poziom trudności my manipulować schowkiem, ustawiać ikony 3, powinien nam się ukazać widok podobny do
w tray'u (Windows) lub docku (MacOS X), za- tego na Rysunku 1.
rządzać DRM, przeglądać i edytować zawartość Nasze środowisko podzielone jest na trzy ko-
dysku czy uzyskać dostęp do lokalnej bazy da- lumny, które można dowolnie reorganizować.

F
lex i AIR ze swoją multimedialnością, ła- nych SQLite. Możemy więc połączyć estetykę Po lewej znajduje się Flex Navigator, służący do
twością w tworzeniu i dostępnością mo- i multimedialność Flash z możliwościami apli- zarządzania plikami w naszym projekcie, oraz
że być prawdziwą konkurencją dla Ja- kacji desktopowej. Outline, pokazujący drzewko elementów aktyw-
vy. Oparcie o otwarte standardy daje nam nie- nego pliku w edytorze, który znajduje się w środ-
zliczoną ilość narzędzi i dodatków, tworzo- Jak zacząć? kowej kolumnie. Pod edytorem widzimy zakład-
nych przez niezależnych programistów z całe- Aby stworzyć naszą aplikację AIR, możemy użyć kę Problems, która informuje o ostrzeżeniach
go świata. Należy tutaj dodać, że standardowe jednego z wielu narzędzi (zarówno autorstwa i błędach w projekcie. W prawej kolumnie znaj-
IDE dla Flex/AIR, to nic innego jak zmodyfi- Adobe, jak i osób trzecich). Wydaje się, że naj- duje się pomoc kontekstowa. Klikając kompo-
kowane, tworzone i używane przez wielką spo- prostszym wyjściem jest zainstalowanie testo- nent czy obiekt w edytorze i naciskając [F1], zo-
łeczność Eclipse. wej (60–dniowej) wersji Flex Builder 3 (samo- baczymy tematy pomocy adekwatne do zazna-
dzielnej paczki lub wtyczki do Eclipse). Oczy- czenia. Kolejną zakładką jest Konsola, w której
Co daje AIR? wiście możemy użyć Adobe Flash CS3 (po wcze- widzimy błędy, ostrzeżenia oraz wyjście funkcji
Aplikacje AIR możemy uruchamiać na pra-
wie dowolnym systemie operacyjnym. Aktual-
Listing 1. Dostęp do schowka
nie stabilne wersje tego środowiska są dostęp-
ne dla systemów Windows i MacOS X (wer-
sja dla Linux jest jeszcze w fazie beta). Instala- import flash.desktop.*;
cję naszego produktu możemy uprościć do mi- public function copy(text:String):void {
nimum, wykorzystując małą wklejkę we Flash, // Wyczyszczenie aktualnego schowka
która dzięki częściowej integracji Flash Play- Clipboard.generalClipboard.clear();
er’a z systemem, ogranicza użytkownika do wy- // Ustawienie naszych danych
konania 3–4 kroków. Jedną z głównych części Clipboard.generalClipboard.setData(ClipboardFormats.TEXT_FORMAT, text);
AIR jest silnik renderujący WebKit (będący ser- }
cem przeglądarek Safari i KHTML oraz jest uży- public function paste():String{
ty w telefonach S60 Nokii i Apple iPhone) ce- // Odczytujemy tylko tekstowy schowek
chujący się wysoką kompatybilnością ze stan- if(Clipboard.generalClipboard.hasFormat(ClipboardFormats.TEXT_FORMAT)) {
dardami (m.in. CSS 3) oraz wydajnością w po- // Zwracamy zawartość rzutowaną jako String
równaniu z innymi silnikami (np. Mozilla Gec- return String(Clipboard.generalClipboard.getData(ClipboardFormats.TEXT_FORMAT));
ko). To dzięki niemu możemy użyć naszej zna- } else {
jomości HTML i JavaScript do tworzenia apli- return null;
kacji czy integrować usługi typu Google Maps }
lub biblioteki takie jak jQuery, Prototype.js, }
Dojo. Aplikacja uruchomiona w AIR posia-

18 FLEX
Flex i AIR

trace() podczas sesji debugowania. Ostatnia za- my na menu File>New>Flex Project. Ukaże nam talogów. Katalog bin–debug zawierać będzie na-
kładka to Debugger, który w tym widoku (wido- się okno dialogowe New Flex Project, w którym szą zbudowaną aplikację w wersji do debugowa-
ki zmieniamy klikając przycisk w prawym gór- wpisujemy nazwę projektu, lokalizację, w której nia, wewnątrz katalogu libs umieszczamy do-
nym rogu) jest ograniczony do minimum. będziemy przechowywać nasze pliki oraz zazna- datkowe biblioteki (jeśli z nich korzystamy). Ka-
czamy Desktop application w Application type. Na talog src zawiera teraz dwa pliki dla nas najbar-
Pierwsza aplikacja razie nie potrzebujemy zmieniać żadnych do- dziej istotne. Są to: <nazwa_aplikacji>–app.xml
Gdy już oswoimy się ze środowiskiem, może- datkowych opcji, więc klikamy Finish. Po chwi- opisujący nazwę, identyfikator czy wersję naszej
my stworzyć nasz pierwszy projekt AIR. Klika- li zostanie wygenerowane kilka plików oraz ka- aplikacji, jak i wygląd początkowego okna oraz
skojarzenia z plikami (jeśli np. aplikacja posia-
da własny format pliku). Drugim ważnym pli-
Przedrostki ścieżek do pliku kiem jest <nazwa_aplikacji>.mxml, zawierający
nasze główne okno. Należy zwrócić uwagę na je-
• app:/ dla plików umieszczonych w folderze aplikacji;
• app–storage:/ dla plików w wydzielonym folderze danych aplikacji; go format. Jest to specjalny XML opisujący wy-
• file:/// dla plików rozmieszczonych w dowolnym miejscu na dysku. gląd oraz zachowanie naszej aplikacji, który mo-
że zawierać wewnątrz funkcje ActionScript,
style CSS czy osadzone w aplikacji zasoby ty-
Listing 2. Przeciągnij i upuść pu grafika czy animacja. Pliki MXML możemy
edytować tekstowo lub graficznie. Przełączamy
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" się pomiędzy tymi trybami za pomocą przyci-
nativeDragEnter="onDragIn(event)" nativeDragDrop="onDrag(event)"> sków Source i Design, znajdującymi się na górze
<mx:Script> edytora. W graficznym trybie edycji dochodzi
<![CDATA[ nam kilka paneli. Components (przełączany na
import flash.desktop.*; zmianę z Outline) to paleta dostępnych kom-
ponentów, które dodajemy do projektu, prze-
public function onDragIn(event:NativeDragEvent):void{ ciągając na okno edycji. Po prawej stronie po-
// Zaakceptowanie dowolnego obiektu jawia się kolumna zawierająca panel States, za-
NativeDragManager.acceptDragDrop(this); wierający zdefiniowane stany aplikacji oraz pa-
} nel Flex Properties, pozwalający łatwo zmieniać
parametry zaznaczonego komponentu. W tym
public function onDrag(event:NativeDragEvent):void { momencie możemy uruchomić naszą podsta-
// Ustawienie domyslnej akcji wową aplikację naciskając [Ctrl]+[F11] (lub sa-
NativeDragManager.dropAction = NativeDragActions.COPY; mo [F11], jeśli chcemy otworzyć sesję debugo-
// Zakładamy że przeciągnięto plik wania). Gdy zamierzamy udostępnić naszą apli-
var dropfiles:Array = event.clipboard.getData( ClipboardFormats.FILE_LIST_FORMAT) as kację, musimy najpierw stworzyć paczkę AIR.
Array; Aby tego dokonać, wybieramy z menu Project>
// Wyliczamy wszystkie przeciągnięte pliki Export Release Build. W pierwszym oknie mo-
for each (var file:File in dropfiles){ żemy zmienić nazwę pliku paczki lub umożli-
trace(file.nativePath); wić podgląd źródła. Po kliknięciu Next wybiera-
} my opcję Export and sign an AIR file with a di-
} gital certificate, tworzymy nowy certyfikat (je-
]]> śli jeszcze takowego nie stworzyliśmy), klikając
</mx:Script> Create. Następnie wybieramy utworzony certy-
fikat i podajemy do niego hasło, po czym klika-
Listing 3. Obsługa plików my Finish. Utworzony plik *.air możemy swo-
// Funkcja obsługująca zakończenie operacji bodnie rozprowadzać.
public function onComplete(event:Event):void {
trace('Plik usunięty'); Podstawowa
} integracja z systemem
Podczas codziennej pracy przy komputerze
// Funkcja obsługująca błąd wejścia/wyjścia przyzwyczailiśmy się do kopiowania, wklejania
public function onIoerror(event:IOErrorEvent):void { pomiędzy aplikacjami czy technologii przecią-
trace('Błąd wejścia/wyjścia podczas usuwania pliku'); gnij i upuść. Aplikacje pracujące w przeglądar-
} ce nie posiadają takich możliwości lub są one

public function delFile():void {


// Stworzenie tymczasowego pliku
var file:File = File.createTempFile();
// Ustawienie funkcji obsługujących zdarzenia
file.addEventListener(Event.COMPLETE, onComplete);
file.addEventListener(IOErrorEvent.IO_ERROR, onIoerror);
// Asynchroniczne usunięcie pliku
file.deleteFileAsync();
}
Rysunek 1. Flex Builder 3 po uruchomieniu

www.sdjournal.org 19
ADOBE FLEX

ograniczone. AIR zdejmuje z nas te ogranicze- my do dyspozycji także zdarzenia informujące dze. Wystarczy podać folder początkowy
nia. Obsługi schowka dokonujemy za pomocą o postępie operacji w trybie asynchronicznym. w atrybucie directory i obsługiwać zdarzenia
klasy Clipboard (automatycznie inicjowanej) Są to outputProgress (postęp danych zapisy- directoryChange i fileChoose.
oraz statycznych stałych w ClipboardFormats wanych) oraz progress (postęp odczytu pliku).
i ClipboardTransferMode. Najczęściej stosowa- Przykład zastosowania mamy na Listingu 4. Kontrolka HTML
nymi metodami są getData() oraz setData(), Komponenty wyświetlające zawartość na- Osadzony w AIR silnik WebKit daje nam
ich przykładowe użycie mamy na Listingu 1. szego dysku także są bardzo proste w obsłu- nie tylko możliwość wyświetlania zawarto-
Kolejną techniką jest przeciągnij i upuść. Jej ob-
sługa jest wykonywana poprzez kilka zdarzeń: Listing 4. Asynchroniczny zapis do pliku
nativeDragEnter, nativeDragDrop,
nativeDragStart, nativeDragUpdate, public function writeToFile():void {
nativeDragOver, nativeDragExit i var file:File = File.createTempFile();
nativeDragComplete. var fileStream:FileStream = new FileStream();
Najważniejsze są dwa pierwsze. Najpierw // Otwarcie strumienia pliku asynchronicznie
definiujemy funkcje obsługujące te zdarzenia fileStream.openAsync(file, FileMode.WRITE);
w naszej aplikacji, a następnie piszemy funkcje fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onOutputProgress);
obsługujące (Listing 2.). // Zapisanie 1024kB losowych danych
Zależnie od typu przeciąganego obiektu mo- for (var i:int = 0; i < 1024*1024; i++) {
żemy zezwalać lub zabraniać upuszczania we- fileStream.writeByte(Math.round(Math.random()*255));
wnątrz funkcji onDragIn(). Tak przeciągnięty }
plik możemy odczytać z systemu plików. }

Lokalny system plików public function onOutputProgress(event:ProgressEvent):void {


Jedną z najważniejszych funkcji aplikacji są od- trace('Pozostało '+event.target.bytesPending+' bajtów');
czyt, zapis oraz modyfikacja plików znajdują- }
cych się na dysku. Oprócz tych podstawowych
metod AIR oferuje zaawansowane komponen- Listing 5. Operacje na DOM
ty do wyświetlania zawartości folderu w róż- <mx:Script>
nych stylach. Może to być siatka ikon, drzew- <![CDATA[
ko, szczegółowa lista czy lista rozwijana. Dostęp public function navigate():void {
do pliku uzyskujemy za pomocą klasy File oraz // Ustawienie wartości input-a z zapytaniem
odpowiednio sformatowanej ścieżki. W zależ- html.domWindow.document.getElementsByName('q')[0].value = 'adobe air';
ności gdzie znajduje się plik, mamy trzy przed- // Wysłanie formularza
rostki do wyboru (przedrostki ścieżek do pliku html.domWindow.document.getElementsByName('f')[0].submit();
opisane są w ramce). }
Rozdzielenie katalogów uzyskujemy ukośni- ]]>
kiem [/]. W systemach rodziny Windows moż- </mx:Script>
na także użyć backslasha [\]. Dostęp do plików <mx:Button x="10" y="10" label="Button" click="navigate()"/>
może być synchroniczny lub asynchroniczny. <mx:HTML location="http://www.google.pl" left="10" right="10" top="40" bottom="10"
Przy trybie synchronicznym, aplikacja zatrzy- id="html"/>
ma swoje działanie do czasu zakończenia ope-
racji na pliku. Jest to dosyć klasyczne podejście, Listing 6. Przekazywanie zdarzeń DOM do aplikacji
jednak przy większych operacjach może być <mx:Script>
irytujące dla użytkownika. Dlatego lepiej uży- <![CDATA[
wać trybu asynchronicznego i dodając funkcje public function setupListeners():void {
obsługi zdarzeń complete oraz ioError kontro- // Znalezienie wszystkich odnośników
lować postęp jak na Listingu 3. var linki = html.domWindow.document.getElementsByTagName('a');
Strumieniowy odczyt i zapis do pliku wyko- for(var i:int = 0; i < linki.length; i++) {
nujemy za pomocą klasy FileStream. Możemy // Ustawienie własnej funkcji reagującej na kliknięcie
odczytywać/zapisywać dane w różnych forma- linki[i].addEventListener("click", onClick);
tach (bardzo przydatne przy plikach binarnych) }
jak bajt, słowo, liczba całkowita, obiekt zseriali- }
zowany w formacie AMF czy ciąg znaków. Ma-
public function onClick(event:Object) {
// Wyświetlenie adresu docelowego
Przydatne adresy trace('Kliknięto link do '+event.target.href);
• http://www.adobe.com/products/air/ // Anulowanie domyślnej akcji (przejście do adresu)
strona domowa Adobe AIR event.preventDefault();
• http://livedocs.adobe.com/flex/3/langref/ }
index.html – pełna dokumentacja Flex ]]>
wraz z AIR
</mx:Script>
• http://www.onflex.org/ – blog Teda Pa-
tricka, jednego z najlepszych specjali- <mx:HTML location="http://www.google.pl" left="10" right="10" top="40" bottom="10"
stów Flex id="html" complete="setupListeners()"/>

20 FLEX
Flex i AIR

ści serwisów WWW, ale także integrację Ac- staniem tej kontrolki są np. historie rozmów my od manipulacji DOM oraz wywoływania
tionScript z DOM i JavaScript. Nasza aplika- w komunikatorach czy różnego rodzaju logi, metod JavaScript (Listing 5.).
cja może reagować na zdarzenia pochodzące gdzie pisanie własnego ItemRenderera wy- Obiekt domWindow jest odpowiednikiem
z DOM lub wyświetlana strona może wywo- magałoby za dużo pracy. Oczywiście idąc da- obiektu window w JavaScript. Posiada wszystkie
ływać funkcje i modyfikować zmienne zawar- lej możemy integrować usługi typu Google funkcje oraz własności obsługiwane przez We-
te w naszej aplikacji. Najprostszym wykorzy- Maps, ale to już wyższa szkoła jazdy. Zacznij- bKit. Idąc w drugą stronę, możemy przekazać
logikę otwartej strony do naszej aplikacji tak,
Listing 7. Zaokrąglone rogi w CSS3 jak na Listingu 6.
Oprócz znakomitego silnika JavaScript (na-
<mx:HTML left="10" right="10" top="40" bottom="10" id="html"> zwanego JavaScriptCore) mamy także do dys-
<mx:htmlText> pozycji częściową obsługę CSS3, np. zaokrąglo-
<![CDATA[ ne rogi (Listing 7.).
<div style="width: 100px; height: 50px; background: #FFBF02; -webkit-border- Przenosząc usługę z sieci na desktop, może-
radius: 5;">Test</div> my to robić stopniowo, na początku integru-
]]> jąc ją w naszej aplikacji. Ze względu na swo-
</mx:htmlText> je możliwości dobrze jest pamiętać o istnie-
</mx:HTML> niu tego komponentu przy tworzeniu kolej-
nych projektów.
Listing 8. Obsługa bazy SQLite
<mx:Script> Baza danych SQLite
<![CDATA[ Zazwyczaj każda aplikacja zapisuje i odczy-
var connection:SQLConnection = new SQLConnection(); tuje pewne dane na dysku. Możemy to ro-
var query:SQLStatement = new SQLStatement(); bić poprzez wcześniej opisaną klasę File
i FileStream lub znanym z Flash SharedObject.
public function connect():void { Gdy operujemy jednak na danych tabelarycz-
// Ustawienie obsługi zdarzeń nych z pewnymi relacjami, najlepiej składować
connection.addEventListener(SQLEvent.OPEN, onOpen); je w bazie danych. Adobe AIR zawiera osadzo-
query.addEventListener(SQLEvent.RESULT, onResult); ną bazę danych SQLite, która zyskała uznanie
// Przypisanie połączenia do zapytania w wielu aplikacjach ze względu na swoje ma-
query.sqlConnection = connection; łe rozmiary oraz wydajność. Baza jest transak-
cyjna (obsługuje rozpoczynanie, zatwierdza-
// Stworzenie tymczasowego pliku nie oraz cofanie transakcji) i odpytujemy ją
var dbFile:File = File.createTempFile(); za pomocą języka SQL. Obsługa bazy danych
// Otwarcie bazy danych jest asynchroniczna, nie blokuje więc naszej
connection.open(dbFile); aplikacji nawet przy większych zapytaniach.
} Podstawowymi klasami są SQLConnection,
SQLStatement oraz SQLResult. Przykład użycia
public function execute():void { mamy na Listingu 8.
query.text = taQuery.text; Zwrócony wynik może zostać zbindowany
query.execute(); jako dataSource np. do DataGrid czy List. Do-
} datkowo możemy zarządzać schematami tabel
czy wyzwalaczami, ale to bardziej zaawansowa-
public function onOpen(event:SQLEvent):void { ne funkcje.
btnExecute.enabled = true;
} Na koniec
Jak widzimy, AIR jest naprawdę potężne
public function onResult(event:SQLEvent):void { i w moim odczuciu przyjemniejsze w pro-
// Pobranie wyniku gramowaniu niż Java. Poruszyłem tylko ma-
var result:SQLResult = query.getResult(); łą część możliwości tego środowiska. Dobrym
if (result != null) { źródłem wiedzy jest Internet, który jest pełen
var numRows:int = result.data.length; blogów oraz forów na temat AIR. Także Ado-
for (var i:int = 0; i < numRows; i++) { be w swoim Developer Center zbiera wielką
var row:Object = result.data[i]; bazę wiedzy dotyczącej Flex czy AIR. Pole-
// Manipulacja danymi z rekordu cam zainteresowanie się tą technologią, zwa-
} żywszy jej bardzo szybki rozwój i rosnącą po-
} pularność.
}
]]> WOJTEK SIUDZIŃSKI
</mx:Script> Autor jest programistą w firmie Kreativ sp. z o.o.
<mx:Button x="10" y="10" label="Połącz" click="connect()"/> Programuje w PHP, JavaScript oraz Adobe Flex
<mx:TextArea x="10" y="40" width="635" height="123" id="taQuery"/> z wykorzystaniem AIR. W czasie wolnym programu-
<mx:Button x="10" y="171" label="Wykonaj" id="btnExecute" click="execute()" je dla własnej przyjemności. Prowadzi blog tech-
enabled="false"/> niczny http://blog.suda.pl
Kontakt z autorem: admin@suda.pl

www.sdjournal.org 21
ADOBE FLEX

Adobe AIR
Powrót na desktop

Do niedawna flashowe aplikacje działające na pulpicie były rzadkością.


Było to spowodowane w głównej mierze problemami z instalowaniem
i dostarczaniem aplikacji w formie gotowej do uruchomienia na komputerze
klienta. Adobe stworzyło narzędzie, które umożliwia produkcję przyjemnie
wyglądających aplikacji okienkowych. Tak z projektu Apollo powstał AIR.
lepiej zacząć od programu typu Hello World.
Dowiesz się: Powinieneś wiedzieć: Otwieramy FlexBuildera, z menu wybieramy
• Jak szybko, łatwo i przyjemnie tworzyć apli- • Powinieneś znać podstawy posługiwania się File>New>Flex Project. Nazywamy projekt np.:
kacje okienkowe wykorzystując Flex Buildera programem Flex Builder, podstawy języka opi- helloAir. W panelu Application type wybieramy
i Adobe AIR. su danych MXML oraz programowania w Ac- opcję Desktop application (runs in Adobe AIR).
tionScript 3.0. Klikamy przycisk Finish i gotowe. Jak widać,
w okienku Flex Navigatora pojawił się nowy
projekt z ikonką folderu i logo AIR. Struktura
dardowych, odtwarzanych w oknie naszej prze- stworzonych katalogów jest niemal identycz-
glądarki. Głębszą eksplorację AIR najlepiej za- na jak w przypadku standardowego projektu
Poziom trudności cząć od zapoznania się z dokumentacją załączo- Flexowego, jedynie brakuje katalogu html-tem-
ną do tych klas (tabela z listą klas znajduje się na plate, za to pojawił się dodatkowy plik helloAir-
płycie dołączonej do magazynu). app.xml. Jest to plik odpowiedzialny za opcje
Wiele klas dostępnych z poziomu SWF'ów systemowe docelowego projektu, takie jak ikon-

A
dobe AIR to nie tylko narzędzie umoż- w przeglądarce zyskało na nowej funkcjonalno- ka aplikacji, tytuł głównego okienka, opis pro-
liwiające produkcję aplikacji okienko- ści. Z AIR’em do Flexa doszło także kilka no- gramu w instalatorze itd. Opcje konfiguracyjne
wych wykorzystujące Flexa, z powodze- wych komponentów takich jak: posiadają w tym samym pliku komentarze, któ-
niem można w nim tworzyć wykorzystując tech- re pomagają zidentyfikować, do czego dany pa-
nologie Flash, HTML, JavaScript czy Ajax. AIR to • FileSystemEnumerationMode , rametr jest wykorzystywany.
skrót od Adobe Integrated Runtime i wywodzi się • FileEvent , Gdy otworzymy plik helloAir.mxml – główny
z projektu o kodowej nazwie Apollo. AIR działa • FileSystemComboBox , plik źródła aplikacji zobaczymy, że różni się on
nie tylko na Windowsie, ale także na Mac OS X, • FileSystemDataGrid , od standardowego pliku projektu Flex tym, że
czy Linuxie. Przeniesienie na pulpit FlashPlayera • FileSystemEnumerationMode , główny tag xml-owy to nie <mx:Application>
to niejedyna zaleta AIR (bo to już było możliwe, • FileSystemHistoryButton , tylko <mx:WindowedApplication>. Aby prze-
używając projektorów FlashPlayera), rozbudowa- • FileSystemList , testować, czy projekt został prawidłowo wy-
nie funkcji dostępnych w AIR jest nieporówny- • FileSystemDisplayMode , generowany, klikamy zieloną ikonkę Run hel-
walnie większe od FP działającego w przeglądarce, • FileSystemTree , loAir i voila. Otworzy nam się zwykła aplika-
do najważniejszych zalet należą: tworzenie okie- • HTML , cja desktopowa z tytułem okienka helloAir (to
nek wykorzystujących API systemowe, wsparcie • Window, WindowedApplication . między innymi właśnie ten tytuł okna moż-
dla plików PDF, dostęp do schowka systemowego, na zmienić w pliku helloAir-app.xml). Właśnie
operacje drag&drop, operacje wejścia/wyjścia na Do dzieła stworzyliśmy pierwszą aplikację desktopową
plikach, SQLite, wsparcie dla XSLT, możliwość w AIR. Jeśli chcemy przenieść wcześniejszą Fle-
umieszczenia aplikacji w tray'u systemowym, au- Instalacja xowo-webową aplikację do AIR, to wystarczy
tostart aplikacji z systemem oraz wiele, wiele in- Aby zacząć bawić się AIR’em we Flexie, na- skopiować wszystko, co zawiera się wewnątrz
nych, których ilość znacznie przekracza ramy te- leży ściągnąć i zainstalować środowisko uru- taga <mx:Application> i wkleić do nowego
go artykułu. Właśnie ze względu na stopień roz- chomieniowe AIR dostępne pod adresem projektu. Oczywiście, jeśli korzystaliśmy z ja-
budowania AIR ograniczymy się tylko do kilku http://www.adobe.com/go/getair. kichkolwiek klas, bibliotek czy plików to także
ciekawszych cech tego środowiska. Instalacja nie powinna nastręczać kłopotów należy je dołączyć do projektu AIR’owego.
i każdy powinien sobie z nią poradzić bez pro-
Nowa funkcjonalność w AIR blemów. Od ogółu do szczegółu
Aby mieć pełny przegląd możliwości AIR, na-
leży przyjrzeć się nowym klasom, jakie wraz Hello World Detekcja połączenia z Internetem
z nim udostępnia nam Adobe, i które odróżnia- Jak chyba każdy początek przygody z nowym Pomimo tego, że AIR służy do budowania apli-
ją aplikacje tworzone w tej technologii od stan- środowiskiem, językiem programowania naj- kacji desktopowych, to dalej mają to być Rich In-

22 FLEX
Adobe AIR

ternet Applications. Właśnie cała potęga AIR to stęp do katalogu z obiektami na pulpicie. Me- aplikacji, sytuacja jest analogiczna dla pozosta-
możliwość łatwego połączenia aplikacji deskto- toda getDirectoryListing zwraca tablicę ele- łych systemów. Przykładem takiej ścieżki zapi-
powych z Internetem. Aby przeprowadzić jaką- mentów w danym katalogu, w tym przypad- sywanego i odczytywanego pliku może być
kolwiek interakcję aplikacji z siecią przydałoby ku znajdujących się na pulpicie. W pętli ite- np.: C:\Documents and Settings\Szymek\Dane
się najpierw dowiedzieć, czy istnieje taka moż- racyjnej sprawdzamy, czy obiekt nie jest lini- aplikacji\fileIOAsync\Local Store\test.txt. Do-
liwość. Najprostszym sposobem na wykonanie kiem symbolicznym i jeśli tak to listujemy go stęp do katalogu danych aplikacji można także
tego jest sprawdzenie połączenia z witryną, np.: do okna konsoli Flex Buildera (pod warun- uzyskać za pomocą prefixu ścieżki app-storage:
http://www.google.com. Wykorzystamy do tego kiem, że testujemy aplikacje debugerem – od- / podobnie app:/ dla katalogu aplikacji, czy file:
klasę URLMonitor z paczki air.net monitoru- powiednik okienka output znanego doskona- /// dla pełnej ścieżki pliku. Linię:
jącą status połączenia z Internetem. le Flash developerom). Równie dobrze istnie-
Jak widzimy na Listingu 1. zaraz po zaini- je możliwość połączenia tej listy z komponen- f = File.applicationStorageDirectory.re
cjowaniu aplikacji wywoływana jest funk- tem TextArea . Zmienną len reprezentują- solvePath(fileName);
cja init(). Tworzymy tam instancję klasy cą długość tablicy elementów w tego typu pę-
URLMonitor, która jako parametr przyjmuje tlach iteracyjnych można by pominąć, ale dla- można więc z powodzeniem zastąpić zapisem
obiekt URLRequest, to on jest wykorzystywa- tego, że wartość ta jest obliczana przy każdym (zakomentowany kod):
ny do przesyłania zapytań do domeny www.go- kroku pętli, ze względów wydajnościowych,
ogle.com. Dodaliśmy także funkcję nasłuchu- dobrze jest zachować tą wartość w zmiennej. f = new File();
jącą zdarzeń zmiany statusu w obiekcie mo- Założyłem, że chcemy wykonać kopię katalo- f.url = 'app-storage:/'+fileName;
nitor. Zaraz po uruchomieniu aplikacji wi- gu test (i że taki katalog istnieje) pod nazwą test
dzimy (o ile mamy połączenie z Internetem), kopia. Metoda resolvePath zwraca ścieżkę do i działanie aplikacji nie zmieniłoby się, jest
że tekst komponentu label o identyfikatorze nowo tworzonego katalogu na pulpicie i wyko- to inny zapis tego samego działania. Po klik-
stat zmienił się na Status połączenia z interne- nujemy operację kopiowania aktualnego ele- nięciu przycisku Zapis wywoływana jest
tem : true. W celu przetestowania, czy wszyst- mentu właśnie do tego nowego katalogu. funkcja saveFile . Dla sprawdzenia i wy-
ko działa jak należy, można wyłączyć na chwilę Innym przykładem użytecznych opera- krycia ewentualnych wyjątków i błędów ca-
kartę sieciową lub fizycznie odłączyć kabel sie- cji jest zapis i odczyt pliku. Na Listingu 3. ła operacja zapisu jest zamknięta w bloku
ciowy od komputera i obserwować tekst w apli- przedstawiony jest najprostszy przykład za- try … catch … finally. Blok try ... catch
kacji. Właściwość available (a razem z nią tekst pisu i odczytu do pliku tekstowego. Stworzy- … finally jest przykładem bardzo dobrej
na ekranie) powinna się zmieniać z true na fal- liśmy dwa pola tekstowe: jedno do edycji da- praktyki przy wykrywaniu błędów i wyjąt-
se i odwrotnie. Do monitorowania połączenia nych do zapisania (writeTxt) i drugie do wy- ków (nie tylko w języku ActionScript , ale
można wykorzystać połączenia nie tylko na świetlania danych pobranych z pliku (read- w większości języków programowania).
standardowym porcie WWW (80) i protokole Txt). Po uruchomieniu aplikacji wywoływana Dzięki stosowaniu tej techniki mamy du-
HTTP, ale także wykorzystując gniazda i klasę jest metoda init(), gdzie inicjujemy uchwyt żo większą kontrolę nad wykonywanym ko-
SocketMonitor. do pliku i strumień do wysyłania i odbiera- dem i obsługujemy błędy, które niekoniecz-
nia danych. Katalog danych aplikacji w syste- nie muszą spowodować zawieszenie apli-
Operacje na katalogach i plikach mie Windows XP dostępny jest pod ścieżką kacji, ale mogą umożliwić dalsze wykony-
To, czego naprawdę brakowało np. w Projekto- C:\Documents and Settings\{UŻYTKOWNIK}\ wanie programu pomimo tego, że niektó-
rach SWF'a to dostęp do systemu plików. Co Dane aplikacji\{NAZWA APLIKACJI}\Local re operacje nie zostały zakończone sukce-
ciekawsze, mamy dostęp nie tylko do katalo- Store\ gdzie w miejscu {UŻYTKOWNIK} jest sem. Jeśli nie przygotujemy naszej aplika-
gu aplikacji, ale także do standardowego kata- aktualnie zalogowany do systemu użytkownik, cji na ewentualne błędy, to przeciętny użyt-
logu danych aplikacji desktopowych, do plików a w miejscu {NAZWA APLIKACJI} jest nazwa kownik naszej aplikacji w momencie wystą-
na pulpicie, do plików dokumentów, itp. Więk-
szość operacji na plikach umożliwiają klasy
z paczki flash.filesystem (File, FileMode,
FileStream). Najpierw spróbujmy wylistować
wszystkie elementy pulpitu i wykonać kopię
jednego z katalogów.
Do zainicjowania operacji wylistowania
i kopiowania użyliśmy przycisku wywołujące-
go funkcję dirOpen. Klasa File posiada właści-
wości, które pozwalają dostać się do kilku zna-
czących miejsc w systemowej strukturze kata-
logów:

• katalogu aplikacji – applicationDirectory ;


• katalogu danych aplikacji – applicationS
torageDirectory ;
• katalogu dokumentów –
documentsDirectory ;
• pulpitu – desktopDirectory ;
• katalogu domowego użytkownika –
userDirectory.

W tym przykładzie (Listing 2.) użyliśmy wła-


ściwości desktopDirectory, aby uzyskać do- Rysunek 1. Natywne okna

www.sdjournal.org 23
ADOBE FLEX

pienia pierwszego z nich najczęściej porzu- cji tego okna z poziomu ActionScript. Z me- komponentu tworzymy instancję komponentu
ci jej użytkowanie i nigdy więcej jej nie uru- nu File> New wybieramy opcję MXML Compo- Label o nazwie infoText (Listing 4.).
chomi. Wykorzystaliśmy także klasę Alert nent. W polu Filename wpisujemy nazwę kom- Na listingu 5. przedstawiono kod aplikacji wy-
do wizualizacji błędów, tak przy zapisie, jak ponentu, który chcemy stworzyć (ja nazwałem korzystującej wcześniej stworzony komponent.
i odczycie pliku. Operacja zapisu, a tak- komponent BeautyWindow), a w ComboBoxie Naciśnięcie przycisku uruchamia funkcję
że odczytu jest banalnie prosta, otwiera- Based on wybieramy klasę Window. W kodzie createNewWindow(), która tworzy nowy kom-
my strumień, wybierając przy tym tryb do-
stępu do pliku (z dostępnych predefinio- Listing 1. Detekcja połączenia z Internetem
wanych stałych klasy FileMode - READ /
WRITE / APPEND / UPDATE), zapisujemy/ <?xml version="1.0" encoding="utf-8"?>
odczytujemy dane, zamykamy strumień do <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
pliku. Możliwe są też operacje asynchro- initialize="init()">
niczne przy dostępie do plików (takie moż- <mx:Script>
liwości daje klasa FileStream – meto- <![CDATA[
da openAsync ), wtedy należy jednak usta- import air.net.URLMonitor;
wić funkcje nasłuchujące na odpowiednich import flash.net.URLRequest;
zdarzeniach wysyłanych przez obiekt (me- import flash.events.StatusEvent;
todą addEventListener). Jak widać na Li- private var monitor:URLMonitor;
stingu 3. proces odczytu pliku został wy-
konany właśnie asynchronicznie. Dzię- private function init():void {
ki ustawieniu nasłuchiwaczy zdarzeń monitor = new URLMonitor(new URLRequest('http://www.google.com'));
(Event.COMPLETE , ProgressEvent.PROGRESS , monitor.addEventListener(StatusEvent.STATUS, onStatusChanged);
IOErrorEvent.IO _ ERROR ) wiemy dokładnie monitor.start();
co się dzieje podczas wykonywania aplika- }
cji. Do wyświetlania informacji o aktualnie private function onStatusChanged(e:StatusEvent):void {
wykonywanych operacjach wykorzystali- stat.text = "Status połączenia z internetem : " + monitor.available;
śmy globalną funkcję trace(). Listę wszyst- }
kich zdarzeń wysyłanych przez obiekt
przy operacjach asynchronicznych moż- ]]>
na znaleźć w manualu klasy FileStream . </mx:Script>
Dzięki ustawieniu wyzwalacza na zdarze- <mx:Label horizontalCenter="0" verticalCenter="0" id="stat"/>
niu IOErrorEvent.IO _ ERROR dla funkcji </mx:WindowedApplication>
onError wiemy, kiedy wystąpił błąd odczy-
tu (jest to kolejna metoda obsługi wyjąt- Listing 2. Wylistowanie i kopiowanie katalogów na pulpicie
ków w języku ActionScript). Jeśli z katalo- <?xml version="1.0" encoding="utf-8"?>
gu danych aplikacji usuniemy plik (lub przy <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
pierwszym uruchomieniu zanim zapiszemy width="376" height="327">
plik, spróbujemy go odczytać) dostaniemy <mx:Script>
informację (w konsoli Flex Buildera) podob- <![CDATA[
ną do poniższej: import flash.filesystem.File;

Błąd odczytu: kod błędu: 3003, treść błędu: private function dirOpen():void {
Error #3003: File or directory does not var elems:Array = File.desktopDirectory.getDirectoryListing();
exist. file: C:\Documents and Settings\ var f:File;
Szymek\Dane aplikacji\fileIOAsync\Local var len:uint = elems.length;
Store\test.txt for ( var i:uint = 0; i < len; i++ ){
var n:String = elems[i].name;
Oczywiście w docelowej aplikacji, w której if (!elems[i].isSymbolicLink) {
wykorzystujemy zapis/odczyt do plików nale- trace( n );
ży poinformować użytkownika o wystąpieniu }
błędu (na przykład przy pomocy klasy Alert) if( n == 'test' ) {
wykorzystując kod błędu (event.errorID) f = File.desktopDirectory.resolvePath( n+' kopia');
oraz instrukcję warunkową switch … case elems[i].copyTo( f );
lub w jakikolwiek inny sposób. Jednym ze spo- }
sobów informowania użytkownika o napotka- }
nych błędach, czy innych zdarzeniach celem }
podjęcia kolejnych działań, są okienka. ]]>
</mx:Script>
Okienka <mx:Button label="Button" horizontalCenter="0" verticalCenter="0"
Możliwość dynamicznego tworzenia okien to click="dirOpen()"/>
kolejna wielka zaleta AIR. Najprostszym przy- </mx:WindowedApplication>
kładem dynamicznego tworzenia okienek, jest
stworzenie nowego komponentu bazującego na
komponencie Window oraz utworzenie instan-

24 FLEX
Adobe AIR

ponent typu BeautyWindow i otwiera okno.


Listing 3. Zapis i odczyt pliku Ustawiamy tytuł okna i przypisujemy do pola
<?xml version="1.0" encoding="utf-8"?> infoText tekst identyfikujący okienko. Zmien-
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" ną nr typu uint (typu oznaczającego całkowi-
width="680" height="445" initialize="init()"> tą liczbę bez znaku) wykorzystaliśmy do nume-
<mx:Script> rowania okien – dlatego po stworzeniu nowe-
<![CDATA[ go okna inkrementujemy (zwiększamy o 1) je-
import flash.filesystem.File; go wartość dla uzyskania numerów kolejnych
import flash.filesystem.FileMode; okien. Należy pamiętać, że właściwość title
import flash.filesystem.FileStream; należy do bazowych właściwości klasy Window,
import mx.controls.Alert; dlatego moglibyśmy ją przypisać przed otwo-
rzeniem okna, ale już komponent infoText na-
private var fileName:String = "test.txt"; leży do interfejsu samego okienka. W związ-
private var f:File; ku z tym, jeśli przesuniemy otwarcie okienka
private var fs:FileStream; dwie linijki w dół, po przypisaniu tekstu do po-
private function init():void { la infoText to wystąpi błąd wykonywania nu-
f = File.applicationStorageDirectory.resolvePath(fileName); mer 1009 (nie można się dostać do właściwo-
//f = new File(); ści lub metody obiektu typu null). Pomimo
//f.url = 'app-storage:/'+fileName; tego, że przy wyświetlaniu zmiennej nr moż-
fs = new FileStream(); na by pominąć wywołanie metody toString()
} wykonującej rzutowanie zmiennej numerycz-
private function saveFile():void { nej na typ String – tekst (rzutowanie by by-
try { ło wykonywane automatycznie), to bardzo do-
fs.open(f, FileMode.WRITE); brym nawykiem jest pamiętanie o kontroli ty-
fs.writeUTFBytes(writeTxt.text); pów w językach programowania. Wielu po-
} catch (e:Error) { czątkujących programistów (niezależnie od ję-
Alert.show('Błąd nr ' + e.errorID + "\nTreść błędu:\n" + e.message, zyka programowania) bardzo często zapomi-
'Błąd'); na o typach zmiennych, których używa i przez
} finally { to sama komplikuje sobie przygodę z progra-
fs.close(); mowaniem poprzez błędy z tego wynikają-
} ce, dlatego należy się pilnować i zwracać na
} to uwagę. Jak widać po uruchomieniu apli-
kacji, podczas kolejnego naciskania przycisku
private function readFile():void { tworzone są nowe okna z kolejnymi numera-
fs.addEventListener(Event.COMPLETE, onComplete); mi. Jeśli do kodu Listingu 4. dodamy do taga
fs.addEventListener(ProgressEvent.PROGRESS, onProgress); Window właściwości transparent="true" oraz
fs.addEventListener(IOErrorEvent.IO_ERROR, onError); systemChrome="none" to otrzymamy okien-
fs.openAsync(f, FileMode.READ); ko o przezroczystych rogach. Zmiana właści-
} wości systemChrome ze standard (wartość do-
myślna) na none jest konieczna, ponieważ stan-
private function onError(event:IOErrorEvent):void { dardowe okienka nie zakładają posiadania prze-
trace( 'Błąd odczytu: kod błędu: '+event.errorID+', treść błędu: zroczystości.
'+event.text ); Jednak to nie wszystko, co można wycią-
} gnąć z AIR odnośnie okien. Są dwa podej-
ścia do tworzenia okien, jedna – bazująca na
private function onProgress(event:ProgressEvent):void { komponentach została już przedstawiona po-
trace( 'czytam plik: przeczytano ' + event.bytesLoaded+' z wyżej. Nic nie stoi oczywiście na przeszko-
'+event.bytesTotal + ' bajtów' ); dzie, aby tworzyć kodem języka ActionScript
} obiekty np.: TextArea i dołączać je do okien,
ale jest to sposób moim zdaniem mniej intu-
private function onComplete(event:Event):void { icyjny przy tym podejściu komponentowym.
trace( 'zakończono' ); Jest jeszcze jedna metoda bazująca całkowicie
readTxt.text = fs.readUTFBytes(f.size); na ActionScripcie, a konkretniej na klasach
fs.close(); NativeWindow i NativeWindowInitOptions. Ba-
} zując na przykładzie z Listingu 5. dodajmy no-
]]> wy przycisk do głównego okna naszej aplikacji:
</mx:Script>
<mx:TextArea id="writeTxt" x="29" y="83" width="291" height="263" text="Ala ma <mx:Button label="Nowe natywne okno"
kota"/> horizontalCenter="0" verticalCenter="30"
<mx:TextArea id="readTxt" x="361" y="83" width="291" height="263"/> click="createNewActionscriptWindow()"/>
<mx:Button x="264" y="381" label="Zapis" click="saveFile()"/>
<mx:Button x="361" y="381" label="Odczyt" click="readFile()"/> oraz funkcję tworzącą nowe okno (Listing 6.).
</mx:WindowedApplication> Jest to metoda trochę bardziej zaawansowa-
na od strony programistycznej, ale dająca du-

www.sdjournal.org 25
ADOBE FLEX

żo więcej możliwości. Uruchamiając aplikację cja readFile ), ale bezpośrednio ciało funk- Na początku należy zaopatrzyć się w stosowną
i klikając przycisk Nowe natywne okno powinno cji. Takie przypisywanie funkcji niczym się ikonkę zależnie od zastosowania w rozmiarze
pojawić się okno jak na Rysunku 1. praktycznie nie różni w działaniu, ma jed- 16x16 lub 128x128 pikseli, w przykładzie z Li-
Pomimo tego, że to co stworzyliśmy wcale nak jedną poważną wadę w przypadku, gdy- stingu 7. są to pliki AIRApp_16.png i AIRApp_
nie wygląda jak standardowe okno, to jest to byśmy chcieli ponownie wywołać tę funkcję 128.png umieszczone w katalogu icons.
w rzeczywistości pełnowartościowe okno apli- w innym miejscu kodu. Musielibyśmy po- Jak widać na listingu, w tagu Windowed
kacji. W związku z tym, że konstruktor klasy nownie pisać ciało funkcji, a nie tylko przy- Application mamy ustawione wyzwalacze na-
Window przyjmuje jeden wymagany parametr pisać uchwyt do niej. Sposób, którego użyli- słuchujące na dwóch zdarzeniach, na moment
(typu NativeWindowInitOptions) odpowiada- śmy, można więc używać pod warunkiem, inicjalizacji aplikacji (initialize – funk-
jący za parametry inicjujące okno trzeba naj- że nie chcemy nigdzie indziej wykorzysty- cja init) i na chwilę przed zamknięciem apli-
pierw stworzyć instancję tej klasy – zmienną wać danej funkcji. Ze względu na przejrzy- kacji (closing – funkcja hideApp). Założy-
options. Dla uzyskania przezroczystości nale- stość kodu dobrze też jest, jeśli nie ma go za łem, że chcemy wrzucić aplikację do tray’a za-
żało, podobnie jak przy modelu komponento- dużo (jedna do dwóch operacji). raz po uruchomieniu, ale nic nie stoi na prze-
wym, ustawić właściwości systemChrome na no- szkodzie, żeby to zrobić dopiero w momen-
ne oraz transparent na true. Gdybyśmy uży- Tray systemowy i menu cie kliknięcia przycisku zamykającego, czy
wali standardowych okien, moglibyśmy usta- AIR umożliwia także budowanie aplikacji dzia- w dowolnym innym momencie działania apli-
wić także takie właściwości jak, maximizable, łających w tle. Można umieścić aplikację w za- kacji. Na początku tworzymy obiekt Loader,
minimizable, resizable itp., ale skoro wszyst- sobniku systemowym (w Windowsie – ikonki umożliwiający w dalszej części załadowanie
ko rysujemy kodem to o takie elementy jak mak- aplikacji obok zegarka systemowego) jednocze- pliku ikonki do zasobnika systemowego. Na-
symalizacja czy minimalizacja okna także trze- śnie usuwając aplikację z paska zadań, ale przy- stępnym krokiem jest stworzenie menu do-
ba się zatroszczyć samodzielnie. W systemach kład z Listingu 6. będzie działał także pod syste- stępnego pod prawym przyciskiem myszy nad
z rodziny OS X, w których operacja maksymali- mem typu OS X – opis jednak będzie dotyczył ikonką w tray'u – klasą odpowiednią do tego
zacja okien jest tożsama z operacją zmiany roz- tylko systemu z rodziny Windows. jest NativeMenu. Dodaliśmy tam dwa elemen-
miaru, aby zapobiec maksymalizacji okna obie Przykład jest trochę dłuższy od poprzed- ty, jeden do ponownego otwarcia okna aplika-
właściwości (maximizable i resizable) trzeba nich, ale tylko z pozoru jest bardziej skompli- cji i drugi do całkowitego zamknięcia aplika-
ustawić na false. Proponuję przetestować apli- kowany. Budując tego typu aplikację, mamy cji, funkcje wykonujące odpowiednio showApp
kację, zmieniając różne właściwości obiektu do rozwiązania trzy problemy: i closeApp. Klasa NativeApplication umoż-
options. Jedną z ciekawszych z nich jest wła- liwia sprawdzenie, czy system pozwala na
ściwość type, która jak sama nazwa wskazuje • przechwycenie zdarzenia zamykania apli- umieszczenie aplikacji w tray'u za pomocą
pozwalająca na uzyskanie różnych typów okien kacji (kliknięcie standardowego przycisku właściwości supportsSystemTrayIcon, dlate-
często spotykanych w systemie, i tak wartości zamykającego okienko); go wszystkie operacje dotyczące tray'a zostały
tego parametru mogą być wybrane z predefi- • ukrycie aplikacji w trayu (w tym załadowa- wykonane pod warunkiem, że jest taka moż-
niowanych stałych klasy NativeWindowType: nie ikonki); liwość (analogicznie dla supportsDockIcon).
• dodanie menu umożliwiającego ponowne Gdybyśmy nie sprawdzili tego, a system nie
• NativeWindowType.NORMAL – Najczęściej otworzenie aplikacji. miałby takiej możliwości, to podczas wyko-
spotykane okna – pokazujące się na pasku
zadań w systemie Windows a w systemie Listing 4. Nowy komponent okienkowy – BeautyWindow
OS X w menu okien;
• NativeWindowType.LIGHTWEIGHT – Lekkie <?xml version="1.0" encoding="utf-8"?>
okienko – przy tej opcji nie można korzy- <mx:Window xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="400"
stać z systemowego chromu okien (sys- height="300">
temChrome = „none”); <mx:Label horizontalCenter="0" verticalCenter="0" id="infoText"/>
• NativeWindowType.UTILITY – Okien- </mx:Window>
ko narzędziowe – jest to trochę bardziej
okrojona wersja okna typu NativeWindow Listing 5. Dynamiczne tworzenie okienek z użyciem komponentów
Type.NORMAL . <?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
W momencie, gdy mamy już przygotowa- <mx:Script>
ne opcje inicjacyjne, tworzymy okno, a ja- <![CDATA[
ko parametr konstruktora podajemy właśnie private var nr:uint = 1;
zmienną options. Ustawiamy tytuł okna, private function createNewWindow():void {
wymiary oraz dodajemy do okna kilka za- var newWindow:BeautyWindow = new BeautyWindow();
okrąglonych prostokątów. W przeciwień- newWindow.open(true);
stwie do sytuacji, w której skorzystalibyśmy newWindow.title = "Moje okienko nr " + nr.toString();
z systemowego chromu okien, musimy tak- newWindow.infoText.text = "To jest nowo stworzone okienko numer " +
że dodać obsługę przesuwania okna i zamy- nr.toString();
kania go – przesuwanie po kliknięciu mysz- nr++;
ką i zamykanie po naciśnięciu przycisku na }
klawiaturze. Przedstawiony sposób jest tro- ]]>
chę bardziej zwięzłą wersją przypisywania </mx:Script>
wyzwalaczy na zdarzeniach w stosunku do <mx:Button label="Nowe okno" verticalCenter="0" horizontalCenter="0" click="create
poprzednich przykładów. Jako funkcję na- NewWindow()"/>
słuchującą na zdarzeniu nie przypisujemy </mx:WindowedApplication>
uchwytu do funkcji (patrz Listing 3., funk-

26 FLEX
Adobe AIR

nywania operacji wystąpiłby błąd wykonywa- my ją do właściwej aplikacji (iconLoadComple- my samo okno aplikacji z paska zadań (instan-
nia. Właściwość klasy NativeApplication te). Zmienna systray odpowiada już za właści- cja nativeApplication dalej będzie urucho-
o nazwie nativeApplication to instancja kla- wą ikonkę umieszczoną w tray'u, przypisuje- miona w systemie). W momencie wybrania
sy NativeApplication w modelu Singletona my do niej dymek pokazujący się po najecha- z menu aplikacji opcji Otwórz (funkcja showApp)
i właśnie do niej należy się odwoływać, jeśli niu na tę ikonkę i wcześniej stworzone menu. ponownie pokazujemy okno programu. Metoda
chcemy uzyskać uchwyt do aktualnie urucho- Sposób postępowania w przypadku DockIcon activate() uaktywnia okienko – ustawia na
mionej aplikacji. Aby zapobiec automatyczne- jest analogiczny jak przy SystemTrayIcon. Po- nim focus. Właściwe kończenie działania apli-
mu zamykaniu aplikacji w momencie zamyka- został jeszcze jeden problem do rozwiązania, kacji wykonamy w funkcji closeApp wywoła-
nia wszystkich okien aplikacji (domyślnie tak pokazywanie i ukrywanie aplikacji. Funkcja nej po kliknięciu wcześniej stworzonego menu
się właśnie dzieje) należy zmienić właściwość hideApp jest wywoływana na chwilę przed za- (opcja Zamknij), gdzie usuwamy ikonkę aplika-
autoExit instancji klasy NativeApplication mknięciem aplikacji, zazwyczaj używa się tego cji i kończymy jej działanie.
na false. W tym konkretnym przykładzie jest zdarzenia (closing) do posprzątania po sobie,
to działanie na wyrost, ponieważ zapobiegnie- czyli zapisanie zmian przed zamknięciem itp. Coś większego
my automatycznemu zamykaniu aplikacji Zapobiegniemy jednak zamykaniu programu Znając już kilka elementów składowych środo-
w trochę inny sposób. Wywołujemy załadowa- ,używając do tego metody preventDefault() wiska AIR, spróbujmy stworzyć trochę bardziej
nie obrazu ikonki i po załadowaniu przypisuje- zdarzenia wywołującego funkcję, tylko ukryje- skomplikowaną aplikację. W związku z natło-
kiem niechcianej informacji w Internecie co-
Listing 6. Dynamiczne tworzenie okienek z użyciem kodu ActionScript raz większą popularność zyskują czytniki RSS,
na potrzeby tego artykułu napiszemy aplikację
private function createNewActionscriptWindow():void { wykorzystującą dane w formacie RSS z witry-
//tworzymy opcje uruchomieniowe okna ny http://foto.moon.pl, czyli coś dla miłośników
var options:NativeWindowInitOptions = new NativeWindowInitOptions(); fotografii. Kanał RSS podaje informacje o naj-
options.transparent = true; nowszych zdjęciach w serwisie. W skład źró-
options.systemChrome = "none"; dła aplikacji wchodzą dwa pliki: główny plik
projektu – FotoMoonRss.mxml oraz plik kom-
//tworzymy okienko ponentu okna powiadamiającego – NoticeWin-
var newWindow:NativeWindow = new NativeWindow(options); dow.mxml. Kodu jest oczywiście zdecydowanie
newWindow.title = "Tytuł okna"; więcej w stosunku do poprzednich aplikacji,
newWindow.width = 300; ale większość to właśnie przykład wykorzysta-
newWindow.height = 300; nia wcześniej przedstawionych elementów.
Wykorzystane zostały także dwa pliki
//dodajemy do okna elementy graficzne: images/icon_128.png oraz images/
var client:Sprite = new Sprite(); icon_128_red.png jako ikonki w zasobniku
var rectSize:int = 40; systemowym. Plik icon_128.png odpowiada
var rectSpace:int = 4; za pomyślne połączenie z witryną oraz icon_
with(client.graphics){ 128_red.png jest tą samą ikonką tylko w kolo-
lineStyle(1,0,1); rze czerwonym – reprezentuje ona brak po-
beginFill(0xff0000,.5); łączenia z serwisem. Celowo nie wykorzysta-
for(var i:int = 0; i <= 5; i++){ łem w ogóle layoutu głównego pliku aplikacji,
for (var j:int = 0; j <= 5; j++){ aby pokazać jak można wykorzystać kompo-
drawRoundRect(i*(rectSize+rectSpace),j*(rectSize+rectSpace),rectS nent mx:Window do wyświetlania danych i po-
ize,rectSize,10,10); wiadomień. Działanie elementów, które były
} wykorzystane we wcześniejszych przykładach
} nie będzie ponownie tłumaczone. Analizę ko-
endFill(); du zacznijmy od początku – jak w większości
} przykładów aplikacja rozpoczyna swoją pracę
// dodajemy do okna grafikę od funkcji init(). Tworzymy instancję kla-
newWindow.stage.addChild(client); sy URLMonitor o nazwie monitor do sprawdza-
/* nia połączenia z witryną http://foto.moon.pl/
(z tej witryny będziemy pobierać dane, dla-
jeśli nie używamy systemowego wyglądu okien (systemChrome="none") tego ta domena jest bardziej odpowiednia w
to dodajemy zdarzenia pozwalające zamknąć i przesuwać okno odróżnieniu od http://www.google.com, jak to
*/ miało miejsce na Listingu 1.). Do cykliczne-
if(options.systemChrome == NativeWindowSystemChrome.NONE){ go sprawdzania czy są nowe zdjęcia w serwi-
newWindow.stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:Event): sie, została wykorzystana klasa Timer, spraw-
void{e.target.stage.nativeWindow.close();}); dzająca co 10 sekund dane w kanale RSS,
newWindow.stage.addEventListener(MouseEvent.MOUSE_DOWN, wywołując funkcję loadData(). Ładujemy
function(e:Event):void{e.target.stage.nativeWindow.startMove();}) obie ikonki – po załadowaniu zmieniając
} właściwości odpowiednio iconLoaded oraz
//pokazujemy nowe okno errorIconLoaded na true, oraz dodajemy wy-
newWindow.activate(); zwalacz zdarzeń dla obiektu httpRequest
} (obiekt wykorzystywany do wysyłaniu za-
pytań i odbierający dane z RSS-a), zmienia-
jąc jednocześnie ikonkę przy błędzie połą-

www.sdjournal.org 27
ADOBE FLEX

czenia. Następnie minimalizujemy aplikację


do zasobnika systemowego i tworzymy no- Listing 7. Umieszczanie aplikacji w zasobniku systemowym
we okienko powiadamiające (nowo stworzo-
nego typu NoticeWindow). Tonacja całego ser- <?xml version="1.0" encoding="utf-8"?>
wisu jest w szarych kolorach, dlatego za naj- <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
odpowiedniejszy typ tworzonego okna uzna- initialize="init()" closing="hideApp(event)">
łem NativeWindowType.UTILITY pozbawiony <mx:Script>
chromu systemowego i z przezroczystością. <![CDATA[
Pokazywane okno będzie zawsze na wierz-
chu (alwaysInFront = true) oraz nie moż- private function init():void {
na będzie zmieniać jego rozmiarów. Zaraz po var icon:Loader = new Loader();
otworzeniu okna przesuwamy je do prawego var iconMenu:NativeMenu = new NativeMenu();
dolnego rogu pulpitu oraz ukrywamy głów- var showCommand:NativeMenuItem = iconMenu.addItem(new NativeMenuItem("Otw
ne okno aplikacji (które tak naprawdę oprócz órz"));
kodu aplikacji żadnych elementów interfejsu var exitCommand:NativeMenuItem = iconMenu.addItem(new NativeMenuItem("Zam
użytkownika nie zawiera). Jak już wspomnia- knij"));
no wcześniej, obiekt którego używamy do exitCommand.addEventListener(Event.SELECT, closeApp);
transmisji danych jest httpRequest, który jest showCommand.addEventListener(Event.SELECT, showApp);
instancją klasy HTTPService. Dane, które do
nas przyjdą po wysłaniu zapytania HTTP zosta- NativeApplication.nativeApplication.autoExit = false;
ną zrzutowane na obiekt (resultFormat="o-
bject"), a metoda, która zostanie wykonana if (NativeApplication.supportsSystemTrayIcon) { // Windows
po odebraniu danych to onDataLoaded (re- icon.contentLoaderInfo.addEventListener(Event.COMPLETE,
sult="onDataLoaded(event)"). Przyjrzyjmy iconLoadComplete);
się funkcji onDataLoaded, jako parametr icon.load(new URLRequest("icons/AIRApp_16.png"));
przyjmuje ona zdarzenie wywołujące var systray:SystemTrayIcon = NativeApplication.nativeApplication.icon
(event), jest to uchwyt właśnie do kompo- as SystemTrayIcon;
nentu httpRequest. Dzięki temu, że da- systray.tooltip = "Ukryta aplikacja";
ne zostały zrzutowane na obiekty możemy systray.menu = iconMenu;
się odwoływać do tych danych (event.re- }
sult) tak, jakby to były właściwości obiektu if (NativeApplication.supportsDockIcon){ // OS X
httpRequest. Kolejne tagi i atrybuty xml-owe icon.contentLoaderInfo.addEventListener(Event.COMPLETE,iconLoadComple
z drzewa RSS są rzutowane na kolejne podo- te);
biekty, dla przykładu odpowiednikiem <rss icon.load(new URLRequest("icons/AIRApp_128.png"));
…><channel><title> jest event.result.rss var dock:DockIcon = NativeApplication.nativeApplication.icon as
.channel.title i dla pozostałych elementów DockIcon;
sytuacja jest analogiczna. Silnik do obsługi dock.menu = iconMenu;
XML w ActionScripcie 3 został napisany cał- }
kowicie od nowa, dzięki temu nie ma już pro- }
blemów (co się zdarzało we wcześniejszych
wersjach Flasha) z parsowaniem kilku mega- private function closeApp(event:Event):void {
bajtowych plików XML. NativeApplication.nativeApplication.icon.bitmaps = [];
Przejdźmy teraz do Listingu 9. Zastosowali- NativeApplication.nativeApplication.exit();
śmy tutaj trochę bardziej zaawansowany kod. }
Jak widać wszystkie właściwości komponen-
tu są ustawione jako prywatne – np.: private private function hideApp(event:Event):void {
var _alphaTimer:Timer; itd. Aby móc się nativeWindow.visible = false;
dostać do tych właściwości z zewnątrz (np.: event.preventDefault();
z głównego okna aplikacji) zostały dodane }
tzw. settery i gettery – funkcje przypisujące
i pobierające wartości właściwości prywat- private function showApp(event:Event):void {
nych – to takie pewnego rodzaju bramki bez- nativeWindow.visible = true;
pieczeństwa, jest to bardzo ważne, jeśli chce- nativeWindow.activate();
my programować zgodnie z ogólnie przyjęty- }
mi kanonami sztuki programowania obiek-
towego. Takie bramki dają nam dużo więk- private function iconLoadComplete(event:Event):void {
szą stabilność i kontrolę nad kodem aplikacji NativeApplication.nativeApplication.icon.bitmaps = [event.target.content.
(możemy na przykład w tym miejscu spraw- bitmapData];
dzić, czy właściwość jest przypisana w spo- }
sób prawidłowy). Jeśli przypisujemy do cze- ]]>
goś liczbę sekund, to czy jest ona zawarta </mx:Script>
w przedziale od 0 do 60 i jeśli wykracza po- </mx:WindowedApplication>
za zakres to ustawić wartość maksymalną do-
stępną – 60 lub minimalną dostępną – 0).

28 FLEX
Adobe AIR

Listing 8a. Kod aplikacji RSS – okno główne – plik FotoMoonRss.mxml

<?xml version="1.0" encoding="utf-8"?> createWindow();


<mx:WindowedApplication xmlns:mx="http://www.adobe.com/ }
2006/mxml" layout="absolute" private function hideAppInTray():void {
initialize="init()"> var iconMenu:NativeMenu = new NativeMenu();
var showCommand:NativeMenuItem =
<mx:Script> iconMenu.addItem(new NativeMenuItem("O
<![CDATA[ twórz"));
import mx.controls.Image; var exitCommand:NativeMenuItem =
import air.net.URLMonitor; iconMenu.addItem(new NativeMenuItem("Za
import flash.display.Loader; mknij"));
import flash.display.NativeMenu; exitCommand.addEventListener(Event.SELECT,
import flash.display.NativeMenuItem; closeApp);
import flash.display.NativeWindow; showCommand.addEventListener(Event.SELECT,
import flash.display.NativeWindowInitOptions; showApp);
import flash.display.NativeWindowType; if (NativeApplication.supportsSystemTrayIcon) {
import flash.events.StatusEvent; var systray:SystemTrayIcon = NativeAppli
import flash.net.URLRequest; cation.nativeApplication.icon as
import flash.utils.Timer; SystemTrayIcon;
import mx.rpc.events.FaultEvent; systray.tooltip = "Foto moon pl - RSS";
import mx.rpc.events.ResultEvent; systray.menu = iconMenu;
import mx.rpc.soap.LoadEvent; }
if (NativeApplication.supportsDockIcon){
private var lastID:String = ''; var dock:DockIcon = NativeApplication.nativeApp
private var actID:String = ''; lication.icon as DockIcon;
private var monitor:URLMonitor; dock.menu = iconMenu;
private var timer:Timer; }
private var nw:NoticeWindow; }
private var win:NativeWindow; private function createWindow():void {
private var errorIconLoader:Loader; nw = new NoticeWindow();
private var errorIconLoaded:Boolean = false; nw.type = NativeWindowType.UTILITY;
private var iconLoader:Loader; nw.alwaysInFront = true;
private var iconLoaded:Boolean = false; nw.maximizable = false;
nw.resizable = false;
private function init():void { nw.minimizable = false;
monitor = new URLMonitor(new URLRequest('http: nw.open();
//foto.moon.pl')); nw.move(Screen.mainScreen.bounds.width - nw.wid
monitor.addEventListener(StatusEvent.STATUS, th,Screen.mainScreen.bounds.height -
netStatusChanged); nw.height - 100);
monitor.start(); nativeWindow.close(); // zamykamy główne okno
timer = new Timer(10000); aplikacji
timer.addEventListener(TimerEvent.TIMER }
, function(event:TimerEvent): private function closeApp(event:Event):void {
void{loadData();}); NativeApplication.nativeApplication.icon.bitmaps
timer.start(); = [];
iconLoader = new Loader(); NativeApplication.nativeApplication.exit();
iconLoader.contentLoaderInfo.addEventListener(Eve }
nt.COMPLETE, function(event:Event):void private function showApp(event:Event):void {
{iconLoaded = true;}); nw.visible = true;
iconLoader.load(new URLRequest("images/icon_ }
128.png")); private function netStatusChanged(event:StatusEvent):
errorIconLoader = new Loader(); void {
errorIconLoader.contentLoaderInfo.addEventListener changeIcon();
(Event.COMPLETE, function(event:Event): if( monitor.available ) {
void {errorIconLoaded = true;}); loadData();
errorIconLoader.load(new URLRequest("images/icon_ }
128_red.png")); }
httpRequest.addEventListener(FaultEvent.FA private function changeIcon():void {
ULT, function(event:Event):void if( monitor.available && iconLoaded ) {
{changeIcon();}); NativeApplication.nativeApplication.icon.bitmaps =
hideAppInTray(); [iconLoader.content];

www.sdjournal.org 29
ADOBE FLEX

Listing 8b. Kod aplikacji RSS – okno główne – plik FotoMoonRss.mxml

} else if( !monitor.available && errorIconLoaded if( nw.lastID != rss.channel.item[0].guid ) { //


) { sprawdzenie czy zostało dodane nowe
NativeApplication.nativeApplication.icon.bitmaps = zdjecie
[errorIconLoader.content]; nw.lastID = rss.channel.item[0].guid.toString
} ();
} nw.items = rss.channel.item;
private function loadData():void { }
if( monitor.available ) { }
httpRequest.send();
} ]]>
}
private function onDataLoaded(event:ResultEvent): </mx:Script>
void { <mx:HTTPService id="httpRequest" resultFormat="object"
var rss:Object = event.result.rss; result="onDataLoaded(event)"
if( nw.logotype.source == null ) { // pierwsze showBusyCursor="false" url="http://
załadowanie foto.moon.pl/rss/zdjecia"/>
nw.logotype.source = rss.channel.image.url; </mx:WindowedApplication>
}

Listing 9a. Kod aplikacji RSS – okno powiadamiające – plik NoticeWindow.mxml

<?xml version="1.0" encoding="utf-8"?> _currentIndex--;


<mx:Window xmlns:mx="http://www.adobe.com/2006/mxml" loadPhoto();
layout="absolute" width="198" checkButtons();
height="262" backgroundColor="#FFFFFF" }
systemChrome="none" transparent="true" }
closing="beforeClose(event)"> private function showPrev():void {
<mx:Script> if( _currentIndex != _lastIndex ) {
<![CDATA[ _currentIndex++;
loadPhoto();
import mx.collections.ArrayCollection; checkButtons();
}
private var _alphaTimer:Timer; }
private var _closeTimer:Timer; private function loadPhoto():void {
private var _lastID:String = ''; if( !visible ) {
private var _currentIndex:uint = 0; visible = true;
private var _lastIndex:uint = 0; }
private var _items:ArrayCollection; var item:Object = _items[_currentIndex];
box.toolTip = (item.title != null ) ? "Tytuł: \n"
public function set items(items:ArrayCollection): + item.title : '';
void { image.source = item.thumbnail.url;
_items = items; image.addEventListener(MouseEvent.CLICK,onPhotoC
_lastIndex = _items.length - 1; lick);
_currentIndex = 0; autor.text = "Autor: " + item.author;
checkButtons(); opis.text = (_currentIndex + 1).toString()+'/'+(_
loadPhoto(); lastIndex+1).toString();
} }
public function set lastID(ID:String):void { private function onPhotoClick(event:MouseEvent):void
_lastID = ID; {
} navigateToURL(new URLRequest(_items[_
public function get lastID():String { currentIndex].link));
return _lastID; }
} private function checkButtons():void {
private function beforeClose(event:Event):void { nextBtn.enabled = ( _currentIndex == 0 ) ? false
visible = false; : true;
event.preventDefault(); prevBtn.enabled = ( _lastIndex == _currentIndex )
} ? false : true;
private function showNext():void { }
if( _currentIndex != 0 ) { override public function set visible(value:Boolean):

30 FLEX
Adobe AIR

Listing 9b. Kod aplikacji RSS – okno powiadamiające – plik NoticeWindow.mxml

void { }
if( _alphaTimer == null ) { }
_alphaTimer = new Timer(10); private function showAlpha(e:TimerEvent):void {
_alphaTimer.addEventListener(TimerEvent.TIMER, if( alpha < .99 ) {
showAlpha); alpha += .01;
_closeTimer = new Timer(10); _alphaTimer.start();
_closeTimer.addEventListener(TimerEvent.TIMER, } else {
hideAlpha); alpha = 1;
} _alphaTimer.stop();
if( value && alpha != 1 ) { }
super.visible = true; }
_alphaTimer.start(); ]]>
_closeTimer.stop(); </mx:Script>
} else if( !value && alpha != 0 ){ <mx:Image horizontalCenter="0" top="10" id="logotype"/>
_closeTimer.start(); <mx:Button label="»" width="41" click="showPrev()"
_alphaTimer.stop(); id="prevBtn" right="10" bottom="10"/>
} <mx:Button label="«" width="41" click="showNext()"
} id="nextBtn" bottom="10" left="10"/>
private function hideAlpha(e:TimerEvent):void { <mx:VBox horizontalAlign="center" verticalAlign="middle"
if( alpha > .05 ) { id="box" top="67" bottom="40" left="10"
alpha -= .05; right="10" >
_closeTimer.start(); <mx:Image id="image"/>
} else { </mx:VBox>
_closeTimer.stop(); <mx:Label bottom="8" horizontalCenter="0" id="opis"/>
alpha = 0; <mx:Label horizontalCenter="0" top="41" id="autor"/>
super.visible = false; </mx:Window>

Najprostszym przykładem wykorzystania właściwego wywołania ukrycia okna użyliśmy Podsumowanie


tych pośredniczących funkcji jest ustawienie słowa kluczowego super odnoszącego się wła- Eksplorując zasoby sieci, czy dokumentację
właściwości _lastID poprzez funkcje get/ śnie do tzw. superklasy – klasy rodzica, po któ- AIR, często zadawałem sobie pytanie: ciekawe,
set lastID() – jest to zmienna wykorzysta- rej dziedziczymy (w tym przypadku Window). czy jest to możliwe w AIR. Z czasem, odnajdując
na do identyfikacji ostatnio dodanego zdjęcia. Nawigacja po kolejnych elementach kanału kolejne odpowiedzi, okazało się, że w większo-
Dla właściwości _items jest przypisany tylko (poprzednich i następnych zdjęciach) została ści przypadków odpowiedź na tego typu pyta-
setter, więc z zewnątrz (poza kodem kompo- zrealizowana w sposób wykorzystujący index nia jest twierdząca. Dlatego odnoszę wraże-
nentu) nie można jej odczytać, można ją tyl- aktualnego elementu (_currentIndex) kolek- nie, że to dopiero początek wielkiej przygo-
ko przypisać. Ciekawym przykładem wyko- cji tablicy _items. Jak pamiętamy z Listingu dy z AIR’em (biorąc pod uwagę fakt, że AIR
rzystania takiego settera jest pokazywanie 8. w momencie załadowania nowych danych jest aktualnie w wersji 1.0.1, a prace nad Fle-
i ukrywanie okna z danymi aplikacji – usta- do kolekcji _items, przypisane zostają dane xem 4 trwają).
wienie właściwości visible. Zamiast standar- z kanału RSS. Zaraz po przypisaniu ustawiamy
dowego momentalnego pokazania i ukrycia aktualny index na 0, sprawdzamy czy możli-
aplikacji dodaliśmy przejście, które płynnie wa jest nawigacja po elementach (poprzednie,
zmienia widoczność okienka. Wykorzystali- następne zdjęcie) oraz ładujemy najnowsze
śmy do tego właściwość alpha, odpowiada- z nich. W funkcji loadPhoto na samym po- SZYMON KOSYDOR
jącą za przezroczystość okna, którą zmienia- czątku sprawdzamy, czy okienko interfejsu Chief Technology Officer Internet Designers
my w przedziale od 0 do 1, pokazując lub od aplikacji jest aktualnie widoczne – dzięki te- (www.id.pl)
1 do 0 ukrywając okno. Mamy tutaj kolejny mu użytkownik zostanie automatycznie po- Geek technologiczny w pełnym wymiarze. Absol-
przykład wykorzystania klasy Timer powodu- wiadomiony (poprzez pokazanie się okien- went Politechniki Wrocławskiej na kierunku Fizyki
jący zmianę właściwości alpha okna co jakiś ka aplikacji) o nowo dodanym zdjęciu do ser- Technicznej specjalność Fotonika.
odstęp czasu. Wnikliwsi czytelnicy z pewno- wisu, bez konieczności ręcznego otwierania Od 2001 roku związany z Internet Designers
ścią zauważyli dodatkowy parametr override okienka aplikacji. Dodaliśmy także obsługę (www.id.pl). Obecnie zajmuje stanowisko szefa
w deklaracji funkcji przypisującej. Użyliśmy zdarzenia wywołanego przez kliknięcie zdję- sekcji wdrożeń i rozwoju technologicznego (Chief
tego słowa dlatego, że zmieniamy standardo- cia (onPhotoClick) – powodującego przej- Technology Officer).
wą funkcję przypisującą, która należy do ba- ście do witryny z pełną wersją aktualnie wi- „Moje zainteresowania technologiczne to przede
zowych właściwości klasy Window (po której docznego elementu (zdjęcia). W kodzie apli- wszystkim flash, php i łączenie różnych technologii.
dziedziczymy tworząc aktualny komponent). kacji nie przewidzieliśmy sytuacji, w której Od kilku lat programuję praktycznie tylko obiek-
Nie jest właściwością należącą do tego pokole- najnowsze zdjęcie zostanie usunięte z serwi- towo głównie we Flashu, PHP, a także w technolo-
nia obiektu (do komponentu NoticeWindow) su – w takim przypadku poprzednie zdjęcie gii Flex. Napisałem własnego cms’a w PHP5 + AJAX
tylko do bazowej klasy Window. Bez tego sło- zostanie wyświetlone jako pierwsze, ale roz- z całkiem pokaźną na dziś listą wdrożeń. Po godzi-
wa kluczowego override aplikacja nie skom- wiązanie tego problemu pozostawiam czytel- nach: wspinaczka, rower, fotografia.”
pilowała by się poprawnie. W funkcji tej, dla nikowi jako formę treningu. Kontakt z autorem: szymon.kosydor@id.pl

www.sdjournal.org 31
ADOBE FLEX

Aplikacje wykorzystujące
mapy w Adobe Flex
Popularność serwisów wykorzystujących mapy jako jeden z głównych
elementów interfejsu użytkownika ciągle wzrasta. Od pierwszej wersji API
map Google powstało wiele doskonałych aplikacji opartych o tego typu
rozwiązania. Z punktu widzenia programisty, tematyka ta staje się coraz
bardziej atrakcyjna, a używane technologie są coraz doskonalsze.
zwalające na mierzenie odległości pomię-
Dowiesz się... Powinieneś wiedzieć... dzy kolejnymi punktami przez nas wyzna-
• Jakiego typu aplikacje możemy stworzyć za • Wymagane są: podstawowa wiedza z zakre- czonymi. Odległości pomiędzy punktami
pomocą tego typu rozwiązań; su użycia Web Services oraz tworzenia aplika- przedstawione są jako kolejne elementy
• Jakich bibliotek możemy użyć wraz z platfor- cji opartych o zewnętrzne dane (mashups), jak wykresu;
mą Adobe Flex; i podstawowa umiejętność pracy ze środowi- • HomeLocator jest przykładem aplikacji po-
• Jak stworzyć przykładowe elementy projektu skiem Flex. zwalającej na zestawienie w ciekawy spo-
opartego o Flex i Yahoo Maps. sób informacji o sprzedawanych domach,
jak i ich lokalizacji geograficznej. Aby za-
poznać się z tym przykładem, należy od-
oraz środowisku Flex. Spektrum zastosowań wiedzić stronę http://www.asfusion.com/
biznesowych tego typu rozwiązań może być apps/homelocator/. Całość została zaopa-
Poziom trudności bardzo szerokie. Jeżeli puścimy wodze fanta- trzona w intuicyjny i przyjazny interfejs;
zji projektując aplikację, a dodatkowo skorzy- • TrailTracer to aplikacja służąca do tworze-
stamy z usług agregujących dane gromadzone nia i współdzielenia spersonalizowanych
we wszelkiego rodzaju serwisach, aby pobrać map. Znajdziemy ją pod adresem http://

M
amy możliwość korzystania z kil- dodatkowe dane, możemy zbudować aplikację www.trailtracer.com/;
ku środowisk klienckich (AJAX, realizującą dowolne zadania. Ciekawymi reali- • Oobgolf Course Finder jest narzędziem do
Flash, Flex lub w przyszłości Silver- zacjami są np.: przeglądania informacji o wprowadzonych
light), jak i interfejsów aplikacji (API). Głów- do bazy serwisu polach golfowych. Serwis
nymi dostarczycielami technologii są Google • Aplikacja do mierzenia własnego postępu można pochwalić za jakość wykonania
Maps, Yahoo Maps oraz Microsoft Live Search podczas biegania lub jeżdżenia na rowe- aplikacji, jak i ilość oraz dokładne poło-
Maps.Dlaczego warto połączyć te technologie rze. Gotowe rozwiązanie możemy znaleźć żenie przeglądanych miejsc. Znajdziemy
z platformą Adobe Flex? Odpowiedź na to py- pod adresem http://www.traxmeet.com/ go pod adresem http://www.oobgolf.com/
tanie można podzielić na kilka punktów. Po traxmeet/TraxmeetPlayer.html?performan- courses/finder/;
pierwsze – łatwiejsza komunikacja z API do- ceid=12726591&josso_ assertion_id=1E- • Często stosowanym rozwiązaniem jest
starczycieli map. Z reguły odbywa się ona za 32082B39AA1FA4. Pozwala nam na re- geolokalizacja punktów sprzedaży danej
pomocą Web Services SOAP lub REST, które gularne mierzenie poczynanych przez nas sieci, tak aby klienci mogli znaleźć najle-
z kolei są mocno osadzone w środowisku Flex. postępów poprzez integrację z danymi po- piej im odpowiadający. Przykładowe roz-
Po drugie – możemy stworzyć rozbudowany bieranymi z GPS, a następnie dokładną ich wiązanie zastosowała firma Rolex. Roz-
interfejs korzystający z dużego modelu danych. analizę; wiązanie znajdziemy pod adresem http:
Często przy wykorzystaniu technologi AJAX • Aplikacja, która umożliwia naniesienie na //www.rolex.com /en/inside–rolex /sales–
musimy wybrać, ze względu na optymalizację, mapę zdjęć oraz danych geolokalizacyj- service/find–a–rolex–dealer/index.jsp.
jedno lub drugie. Korzystając zaś z Flexa – nie nych odczytanych z urządzeń zapisują-
musimy rezygnować z ciekawych rozwiązań, cych pozycję GPS. Całość pozwala np. na Osobiście jako konsultant i programista Ado-
wręcz przeciwnie – możemy często dopieścić odtworzenie odbytej przez nas wycieczki, be Flex wykonałem kilka ciekawych projek-
nawet bardzo skomplikowaną aplikację cieka- dodatkowo nanosząc wprowadzone przez tów wykorzystując mechanizm map. Najbar-
wym i nietuzinkowym interfejsem. Po trzecie nas dane. Następnie możemy rozesłać dziej interesującym z nich jest aplikacja po-
– Flex będąc zbudowanym na Flashu, jest z na- tak przygotowaną mapę do znajomych. zwalająca na śledzenie w czasie rzeczywi-
tury środowiskiem graficznym. Oznacza to, że Projekt znajdziemy pod adresem http:// stym oraz przeglądanie danych historycznych
możemy w łatwy sposób łączyć elementy wizu- mapmypix.com/; o włamaniach. Jest to ciągle rozwijany projekt,
alne z wybraną technologią map. • Prosty, ale ciekawy przykład znajdziemy jednak udowodnił on, że Flex jest doskonale
Istnieje już kilka ciekawych projektów apli- również pod na stronie http://www.earth- sprawdzającym się narzędziem do takich za-
kacji internetowych RIA opartych na mapach measurements.com/. Jest to rozwiązanie po- stosowań. Aplikacja opiera się na danych kil-

32 FLEX
Tworzenie aplikacji wykorzystujących mapy w Adobe Flex

kuset do kilkunastu tysięcy obiektów, a do


tego obserwacja zgłoszonych zdarzeń w za- Listing 1. Zastosowanie biblioteki Yahoo Map
<mx:Application
bezpieczanych budynkach może odbywać się
w czasie rzeczywistym. Całość została zaopa- xmlns:mx="http://www.adobe.com/2006/mxml"
trzona w ciekawy i przyjemny dla użytkow- layout="absolute"
nika interfejs. Pozwala on na zmianę parame- creationComplete="onCreationComplete()">
trów aktualnie przeglądanych wydarzeń oraz <mx:Script>
ich filtrowanie. Projekt jest wykonywany na
zlecenie firmy ochroniarskiej pragnącej narzę- <![CDATA[
dzia pozwalającego na szybkie i przejrzyste za- import mx.events.ResizeEvent;
poznanie się i analizowanie danych o przestęp- import com.yahoo.maps.api.YahooMap;
stwach (Rysunek 1.). import com.yahoo.maps.api.YahooMapEvent;
Bardzo ciekawe możliwości daje połączenie import com.yahoo.maps.api.core.location.Address;
platformy Flex, map oraz technologii zdalne- import com.yahoo.maps.webservices.geocoder.GeocoderResult;
go dostępu i wymiany wiadomości BlazeDS import com.yahoo.maps.webservices.geocoder.events.GeocoderEvent;
lub LiveCycle DS (technologie umożliwiają-
ce budowę aplikacji korzystających z logiki private var _yahooMap:YahooMap;
biznesowej serwerów Java w czasie rzeczywi- private var _address:Address;
stym). Możliwości biznesowe takich rozwią- private function onCreationComplete():void
zań są bardzo obiecujące. Przykładowo, po- {
zwalają one na współdzielenie w czasie rze- var appid:String = Application.application.parameters.appid;
czywistym map przez kilku użytkowników,
np. podczas telekonferencji. Tak wykonaną _yahooMap = new YahooMap();
prostą aplikację wraz ze źródłem oraz instruk- _yahooMap.addEventListener(YahooMapEvent.MAP_INITIALIZE,
cjami wykonania znajdziemy pod adresem handleMapInitialize);
http://coenraets.org/blog/2008/04/yahoo–maps– _yahooMap.init(appid,mapContainer.width,mapContainer.height);
collaboration–using–flex–and–blazeds/. Zain-
teresowanych tematyką koniecznie odsyłam mapContainer.addChild(_yahooMap);
do zapoznania się z przedstawionym rozwią- mapContainer.addEventListener(ResizeEvent.RESIZE, onMapContainerResize);
zaniem.
_yahooMap.addPanControl();
Flex i API gotowych bibliotek _yahooMap.addZoomWidget();
Jak wspomnieliśmy we wstępie podczas projek- _yahooMap.addTypeWidget();
towania i wykonywania aplikacji do dyspozycji _yahooMap.addScaleBar();
mamy kilka rozwiązań, jak i gotowych do uży- }
cia bibliotek. Podczas pracy z platformą Flex
najlepiej jest skorzystać z: private function handleMapInitialize(event:YahooMapEvent):void {
// Tu dodajemy isntrukcje wykonywane po zainicjalizowaniu mapy,
• Yahoo Maps (http://developer.yahoo.com/ // np. wyszukiwanie i dodawanie punktów na mapie
maps/). Rozwiązanie jest wygodne, do-
starczone zostało API dla ActionScript _address = new Address("warszawa");
w wersjach 2 oraz 3, AJAX i Simple API _address.addEventListener(GeocoderEvent.GEOCODER_SUCCESS,
(usługa niewymagająca umiejętności pro- onGeocodeSuccess);
gramowania). Całość jest dobrze udoku- _address.geocode();
mentowana, posiada wiele przykłado- }
wych zastosowań, jak i instrukcji krok po
kroku. Projekt jest również bardzo czyn- private function onGeocodeSuccess(event:GeocoderEvent):void
nie wspierany przez środowisko. Wszela- {
kie pytania możemy zadawać na oficjal- var result:GeocoderResult = _address.geocoderResultSet.firstResult;
nym forum http://tech.groups.yahoo.com/
group/yws–maps/; _yahooMap.zoomLevel = result.zoomLevel;
• UMap firmy Advanced Flash Compo- _yahooMap.centerLatLon = result.latlon;
nents (http://www.afcomponents.com/
components/umap_as3/). Dostarczone }
API dla ActionScript 3.0 oferuje wie-
le ciekawych funkcji. Rozwiązaniu te- private function onMapContainerResize(event:ResizeEvent):void {
mu warto jest się przyjrzeć bliżej, pro- _yahooMap.setSize(mapContainer.width,mapContainer.height);
ducent oferuje kilka instrukcji wprowa- }
dzających do swojego produktu. Ten pro- ]]>
jekt również posiada mocne wsparcie śro-
dowiska, forum znajdziemy pod adre- </mx:Script>
sem http://www.afcomponents.com/forum/ <mx:UIComponent id="mapContainer" width="100%" height="100%"/>
viewforum.php?f=20. Standardowo użyte </mx:Application>
mapy mają trochę niższą jakość niż wy-

www.sdjournal.org 33
ADOBE FLEX

mienione powyżej Yahoo Maps, ich głów- Script 3.0 mamy do dyspozycji wiele przydat- gę wraz z mapami. Rezultat może być na-
nym dostarczycielem jest serwis http:// nych Web Services, m.in.: prawdę ciekawy;
openstreetmap.com/ (możemy go jednak • Yahoo! Travel (http://developer.yahoo.com/
zamienić np. na Google Maps); • Yahoo! Weather (http://developer.yahoo.com/ travel/). REST API pozwala nam na dostęp
• Modest Maps weather/). Umożliwia on połączenie map do danych zawierających informacje o wy-
(http://www.modestmaps.com/). Zespół pro- z danymi pogodowymi dla zadanej lo- cieczkach, ciekawych miejscach, możli-
gramistów tworzy rozwiązanie w opar- kacji. Przykładowo prognoza pogody wych połączeniach lotniczych czy miej-
ciu o licencję BSD, dając nam do dyspozy- dla Krakowa znajduje się pod adresem scach hotelowych. Aplikacja stworzona
cji API ActionScriptowe w wersji 2 oraz 3, http://weather.yahooapis.com/forecastrss?p w oparciu o takie rozwiązanie może udo-
jak i dla języka Python. Do wyboru mamy =PLXX0012; stępnić użytkownikom nowe, przyjazne
kilku dostarczycieli map, możemy skorzy- • Yahoo! Traffic (http://developer.yahoo.com/ podejście do tej tematyki.
stać z zasobów Open Street Map, NASA, traffic/). REST API daje nam możliwość
Blue Marble, Google, Yahoo oraz Micro- dostępu do bieżących danych o natężeniu Możemy również użyć gotowych biblio-
softu. Projekt nie jest rozwijany tak pręż- ruchu ulicznego w żądanej lokalizacji; tek stworzonych pod ActionScript 3.0 uła-
nie jak wcześniejsze i nie posiada tak silne- • Yahoo! HotJobs twiających korzystanie z udostępnionych
go wsparcia jak one. (http://developer.yahoo.com/hotjobs/). Dzię- przez Yahoo serwisów. Biblioteka ta to
ki faktowi, że ogłoszenia pracy w serwi- Yahoo! Astra Web Library. Aby się z nią
Najlepszym rozwiązaniem z naszego punk- sie Yahoo możemy przeglądać wyszu- zapoznać, należy odwiedzić stronę http://
tu widzenia są Yahoo Maps. Poza obsługą sa- kując m.in. po nazwach miast, możliwe developer.yahoo.com/flash/astra–webapis/. Dzię-
mych map bezpośrednio z poziomu Action- jest stworzenie aplikacji łączącej tę usłu- ki niej mamy uproszczony dostęp np. do
Yahoo! Weather.

Yahoo Maps ActionScript 3.0 API


Stronę projektu znajdziemy pod adresem http:
//developer.yahoo.com/flash/maps/index.html.
Jak już wcześniej wspomnieliśmy, znajdzie-
my tu dostęp do bardzo dobrej dokumenta-
cji API (http://developer.yahoo.com/flash/maps/
classreference/index.html), wprowadzenie do bi-
blioteki (http://developer.yahoo.com/flash/maps/
using.html) oraz liczne przykłady użycia jej róż-
nych elementów (http://developer.yahoo.com/
flash/maps/examples.html).
Aby móc skorzystać z biblioteki, instalu-
jemy środowisko Flex (do pobrania z http:
//www.adobe.com/products/flex lub z płyty
dołączonej do magazynu). Ze strony http://
developer.yahoo.com/flash/maps/index.html po-
bieramy aktualną wersję komponentu Yahoo
Maps for ActionScript 3.0. W pliku .zip znaj-
dziemy m.in. skompilowaną bibliotekę Yaho-
oMap.swc (w katalogu Build). Plik ten umiesz-
Rysunek 1. Przykład własnej aplikacji – mapa z danymi o włamaniach do budynków czamy w katalogu libs tworzonych we Flex Bu-
ilderze aplikacji. Aby móc w pełni korzystać
Listing 2. Modyfikacja funkcji onGeocodeSuccess() z serwisu Yahoo Maps, będziemy potrzebo-
wać jeszcze swój klucz API, potrzebny pod-
private function onGeocodeSuccess(event:GeocoderEvent):void czas inicjalizacji mapy. Aby go otrzymać, re-
{ jestrujemy naszą aplikację pod adresem http:
var result:GeocoderResult = _address.geocoderResultSet.firstResult; //developer.yahoo.com/wsregapp/index.php.
Przejdźmy teraz do najprostszego przykładu
_yahooMap.zoomLevel = result.zoomLevel; zastosowania komponentu (Listing 1.). Aby
_yahooMap.centerLatLon = result.latlon; móc umieścić obiekt mapy w naszym projek-
cie, musimy umieścić go jako element kompo-
for (var i:int = 0; i < 10; i++)
{
var latlon:LatLon = new LatLon(result.latlon.lat + Math.random() * 0.1,
result.latlon.lon + Math.random() * 0.1);
var marker:SimpleMarker = new SimpleMarker();
marker.latlon = latlon;

_yahooMap.markerManager.addMarker(marker);
}
} Rysunek 2. Wskaźnik graficzny stworzony w
programie Flash

34 FLEX
Tworzenie aplikacji wykorzystujących mapy w Adobe Flex

nentu UIComponent. Dzieje się tak, ponieważ .MAP_INITIALIZE, handleMapInitialize); – wyświetla aktualną skalę mapy oraz Zoom
dostarczone przez Yahoo rozwiązanie dzie- _yahooMap.init(appid,mapContainer.width, Widget – pozwala na zmianę przybliżenia:
dziczy bezpośrednio po Sprite. Przeanali- mapContainer.height);
zujmy przykład z Listingu 1. Po zakończeniu _yahooMap.addPanControl();
tworzenia aplikacji wywoływana jest funkcja Kolejne linijki to: dodanie obiektu do wspo- _yahooMap.addZoomWidget();
onCreationComplete(). W niej przechwytu- mnianego UIComponent oraz nasłuchiwanie _yahooMap.addTypeWidget();
jemy parametr przekazany do Flexa zawiera- zdarzenia zmiany rozmiarów komponen- _yahooMap.addScaleBar();
jący nasz klucz API: tu kontenera mapy oraz, w wypadku wystą-
pienia zdarzenia, wywołanie odpowiedniej Po zakończeniu inicjalizacji mapy możemy
var appid:String = Application.application. funkcji: wykonać dodawanie do niej elementów, np.
parameters.appid; wskaźników na mapie (Marker) czy usta-
mapContainer.addChild( _ yahooMap); lić punkt centralny, na który ustawi się no-
Następnie tworzymy obiekt YahooMap, doda- mapContainer.addEventListener(ResizeEvent wo załadowana mapa. W naszym prostym
jemy jako odbiorcę zdarzenia zakończenia ini- .RESIZE, onMapContainerResize); przykładzie wykorzystaliśmy bardzo przy-
cjalizacji tego komponentu funkcję handleMap datny element biblioteki Yahoo Map, ja-
Initialize()oraz wywołujemy metodę inicja- Następne linijki umożliwiają dodanie do ką jest mechanizm dekodujący zapytanie
lizującą mapę, przekazując jej nasz klucz oraz obiektu mapy odpowiednich elementów uła- (w postaci obiektu Adress) do konkretnej lo-
rozmiar okna, w którym jest wyświetlana: twiających korzystanie z mapy, są to m.in.: kalizacji geograficznej zawierającej dokład-
Pan Control – element umożliwiający prze- ne współrzędne oraz zalecany poziom zbli-
_ yahooMap = new YahooMap(); ciąganie mapy, Type Control – przełącza- żenia. Zwracany w wyniku zapytania obiekt
_yahooMap.addEventListener(YahooMapEvent nie pomiędzy typami widoków, Scale Bar (GeocoderResult) zawiera również inne da-

Listing 3. Tworzenie CustomMarker.as

package this.adress = customAdress;


{ this.imageURL = customImageURL;
import com.yahoo.maps.api.markers.Marker;
this.marker = new FlashMarker();
import flash.display.Loader; this.marker.filters = [this.dropShadowFilter];
import flash.display.MovieClip; this.addChild(this.marker);
import flash.events.MouseEvent;
import flash.filters.BitmapFilterQuality; this.toolTip = this.drawToolTip();
import flash.filters.DropShadowFilter; this.addChild(this.toolTip);
import flash.net.URLRequest; }
import flash.text.TextField;
import flash.text.TextFormat; private function onMouseOver(event:MouseEvent):void
{
public class CustomMarker extends Marker this.promoteToTop();
{
private var dropShadowFilter:DropShadowFilter = new if(this.toolTip) this.toolTip.visible = true;
DropShadowFilter(0, 0, 0, 1, 12, 12, }
1.5, 3);
private function onMouseOut(event:MouseEvent):void
private var marker:MovieClip; {
private var toolTip:MovieClip; if(this.toolTip) this.toolTip.visible = false;
}
private var adress:String;
private var imageURL:String; private function drawToolTip():MovieClip
{
public function CustomMarker(customName:String, var toolTipMC:MovieClip = new MovieClip();
customAdress:String, customImageURL: toolTipMC.graphics.beginFill(0x3c3c3c, 0.66);
String) toolTipMC.graphics.drawRoundRect(–80, –155, 160, 125,
{ 10, 10);
super(); toolTipMC.graphics.endFill();
toolTipMC.visible = false;
this.addEventListener(MouseEvent.MOUSE_OVER,
this.onMouseOver); var name:TextField = new TextField();
this.addEventListener(MouseEvent.MOUSE_OUT, name.width = 160;
this.onMouseOut); name.height = 20;
this.addEventListener(MouseEvent.ROLL_OUT, name.x = –80;
this.onMouseOut); name.y = –150;
name.text = this.name;
this.name = customName;

www.sdjournal.org 35
ADOBE FLEX

ne, np. nazwę państwa, miasta, hrabstwa Jak widzimy zastosowanie komponentu Załóżmy, że na potrzeby projektu musimy
(w Polsce – powiatu), kod kraju, kod pocz- YahooMap jest bardzo proste, a jego stosowanie stworzyć wskaźniki graficzne według projektu
towy itp. Możemy oczywiście wykonać za- logiczne. graficznego, który nam dostarczono. Najprost-
pytanie o wiele elementów naraz. Pamiętaj- szy sposób, w jakim możemy tego dokonać to
my jednak, wykonywane są one asynchro- Dodanie wskaźników do mapy wykonać odpowiednie grafiki w programie
nicznie, co wymusza na nas kontrolę odbie- Wizualizacja danych w aplikacjach wykorzy- Flash, wyeksportować je do plików SWF, które
ranych danych. Przyjrzyjmy się zawartości stujących mapy odbywa się poprzez zastoso- to z kolei możemy wprowadzić do naszej aplika-
funkcji handleMapInitialize(): wanie wskaźników (Markers), które zosta- cji. Zacznijmy więc od początku – tworząc grafi-
ją umieszczone w odpowiadających im po- kę. Przykład zamieszczony jest na Rysunku 2.
_address = new Address("warszawa"); zycjach. W dalszej części omówimy umiesz- Wygodne jest stworzenie wskaźników w
_address.addEventListener(GeocoderEvent. czanie prostych wskaźników, jak i stworzenie aplikacji Flash, bo tworzonym elementom
GEOCODER_SUCCESS, własnych oparte na stworzonych przez nas ele- możemy automatycznie przyporządkować
onGeocodeSuccess); mentach graficznych. punkt odniesienia. Jest to o tyle ważne, że
_address.geocode(); Zarządzaniem wskaźnikami zajmuje się nie musimy później pamiętać o przesunięciu
klasa MarkerManager. Przy użyciu kompo- wskaźników. Sytuacja taka zdarzyłaby się przy
Tworzymy obiekt Adress, przekazując do nie- nentu YahooMap, używając standardowej kla- użyciu np. grafik .png, które są pozycjonowa-
go treść zapytania. Następnie, jako odbiorcę sy map, biblioteka sama stworzy dla nas odpo- ne w swoim górnym lewym rogu. Aby tego
zdarzenia powodzenia zapytania, ustalamy wiedni obiekt. Następnie będziemy mogli do uniknąć, musimy korzystać ze specjalnej kla-
funkcję onGeocodeSuccess(). Kolejna linijka niego dodawać wskaźniki, upewniając się, tyl- sy, CustomImageMarker.
wykonuje zapytanie. Przejdźmy więc do funk- ko aby miały one poprawne dane geograficzne. Mając przygotowany wskaźnik w posta-
cji odbierającej wymienione zdarzenie. Po ode- Jako wskaźników użyjemy prostych obiektów ci pliku .swf, przygotujemy klasę dziedziczą-
braniu rezultatu w postaci zdarzenia, na jego SimpleMarker. Są one wbudowane w omawia- cą po Movie Clip, który będzie go zawierać.
podstawie ustalamy poziom zbliżenia mapy ną bibliotekę. Rozszerzmy więc poprzedni Obrany tu przeze mnie sposób dobrze ilustru-
oraz jest punkt centralny (obiekt LatLon): przykład. Dodamy wokół punktu centralne- je, jak możemy szybko osiągnąć pożądany re-
go kilka losowo umieszczonych wskaźników. zultat. Przy użyciu wielu różnych wskaźni-
var result:GeocoderResult = _ address.geoco Aby to zrobić, musimy najpierw mieć zwró- ków najlepiej jest stworzyć we Flashu odpo-
derResultSet.firstResult; coną treść zapytania GeoCoderResult. Mody- wiedni plik zawierający, który je zawiera, i na-
_yahooMap.zoomLevel = result.zoomLevel; fikujemy funkcję onGeocodeSuccess(). pisać metody, które będą zwracały nam od-
_yahooMap.centerLatLon = result.latlon; Jest to maksymalnie uproszczony przykład, powiednie obiekty. Całość eksportujemy do
mający zobrazować zasadę działania tego me- Flexa za pomocą narzędzia Flex Component
Ostatnią funkcją jest onMapContainerResize(). chanizmu. Aby stworzyć własny wskaźnik, roz- Kit for Flash (http://www.adobe.com/go/flex3_
Jak już wcześniej wspomnieliśmy, wywoływa- szerzamy klasę Marker. Klasa ta posiada już kil- cs3_swfkit). Wracając do omawianego przy-
na ona jest automatycznie po zmianie rozmia- ka przydatnych dla nas właściwości, jak np. ad- kładu, napiszmy klasę Movie Clip zawierający
ru komponentu zawierającego mapę. Aby za- res, własne dane geograficzne, referencję do plik Flash (Listing 4.). Mając gotowy do uży-
pewnić poprawne wyświetlanie mapy, musimy obiektu mapy, na której jest umieszczony, naj- cia symbol graficzny, możemy stworzyć wła-
upewnić się, że nowe wartości zostaną przeka- większy i najmniejszy poziom zbliżenia, przy sny wskaźnik. Załóżmy, że chcemy wykorzy-
zane jej obiektowi1. Spowoduje to przerysowanie którym wskaźnik jest widoczny, a także cha- stać przygotowaną grafikę, a klient dodatko-
elementów składowych (mapa, wskaźniki, ele- rakterystyczny identyfikator grupy wskaźni- wo żąda od nas wyświetlenia dymku z infor-
menty interfejsu mapy). W naszym przykładzie ków. Jeżeli chcemy przyporządkować wskaź- macją o danej lokalizacji, zawierającego dodat-
sytuacja ta wystąpi w momencie zmiany rozmia- niki do takiej grupy, będziemy mogli pobierać kowo pewną ikonkę. Tworzymy plik Custom-
rów okna przeglądarki. Zadanie to jest realizowa- tablicę zawierającą referencję do wszystkich jej Marker.as (Listing 3.).
ne wywołaniem odpowiedniej metody: elementów z poziomu obiektu MarkerManager. Omówmy ten przykład. Do konstruktora
Przyda się to np. w sytuacji, gdy chcemy szyb- wskaźnika przekazujemy jego nazwę, pewien
_yahooMap.setSize(mapContainer.width,mapCon ko ustawić danej grupie pewne właściwości, np. adres (pojawi się on w dymku), oraz adres URL
tainer.height); ich widoczność. obrazka, który chcemy załadować. Nasłuchiwa-

Listing 4. Załączenie pliku swf Listing 5. Modyfikacja funkcji onGeocodeSuccess

package private function onGeocodeSuccess


{ (event:GeocoderEvent):void
import flash.display.MovieClip; {
var result:GeocoderResult = _address.geocoderResultSet.firstResult;
[Embed("Marker.swf", symbol="MarkerRed")]
public class FlashMarker extends _yahooMap.zoomLevel = result.zoomLevel;
MovieClip _yahooMap.centerLatLon = result.latlon;
{
public function FlashMarker() var customMarker:CustomMarker =
{ new CustomMarker
super(); ("Przyklad", "Warszawa, Centrum", "icon.jpg");
} customMarker.latlon = result.latlon;

} _yahooMap.markerManager.addMarker(customMarker);
} }

36 FLEX
Tworzenie aplikacji wykorzystujących mapy w Adobe Flex

nie zdarzeń związanych z ruchem myszki po- Możliwości bilioteki • Rysowania tzw. Geodesic Polyline, są to spe-
zwoli na pokazanie lub ukrycie podpowiedzi. Yahoo Maps Actionscript 3.0 API cyficzne krzywe, często wykorzystywane
Stworzony wcześniej FlashMarker dodajemy Większość elementów biblioteki zosta- przy aplikacjach wykorzystujących mapy;
do naszego wskaźnika poprzez (dodajemy do ła doskonale omówiona na stronie http: • Rysowania na mapach własnych kształ-
niego również cień): //developer.yahoo.com/flash/maps/examples.html. tów, są one przechowywane w specjalnej
Przedstawione tam przykłady zawierają pod- warstwie;
this.marker = new FlashMarker(); gląd źródła, możemy więc zapoznać się krok po • Korzystania z serwisu Yahoo! Local Se-
this.marker.filters = kroku z kolejnymi funkcjami tego API. Wstęp- arch. Umożliwia on znajdowanie obiek-
[this.dropShadowFilter]; nie zapoznaliśmy się z możliwością zadawania tów zainteresowań w bazie serwisu Yahoo!
this.addChild(this.marker); zapytań o adres, pozycjonowaniem wskaźni- i umieszczania ich na prezentowanej ma-
ków, a także z tworzeniem własnych obiektów pie;
Funkcja drawToolTip() powinna być dosko- służących do wyświetlania danych. Przejrze- • Zbudowania serwisu w oparciu o biblio-
nale zrozumiała dla osób na co dzień korzy- nie przykładów ze wspomnianej strony pozwo- tekę Yahoo Maps oraz ASTRA Web API –
stających z aplikacji Flash i języka Action- li nam na zrozumienie zasad: korzystającej z danych meteorologicz-
Script. Ręcznie rysujemy w niej dymek, do- nych.
dajemy i formatujemy tekst, który ma się • Obsługi kolejnych zdarzeń komponentu
w nim ukazać a także ładujemy i wyświetla- YahooMap ; Zakończenie
my żądany obrazek. Powróćmy do głównego • Rysowania polilinii w przedstawianych Podczas wykonywania tego typu aplikacji pa-
pliku naszej aplikacji i zmodyfikujmy funkcję mapach (jest to o tyle łatwe, że kolejne miętajmy o pewnych ograniczeniach technicz-
onGeocodeSuccess() (Listing 5.). Wynik na- wierzchołki możemy definiować za pomo- nych – spotkamy się z nimi na pewno w apli-
szej pracy możemy zobaczyć na Rysunku 3. cą współrzędnych geograficznych); kacji opierającej się o setki lub tysiące punktów
na mapach. Tworzenie zapytań o ich współ-
rzędne geograficzne przy każdym urucho-
mieniu aplikacji jest dalece niepraktyczne. Za-
miast tego upewnijmy się, że dane o punktach
przechowywane przez nas w bazie będą miały
również współrzędne. Możemy tego dokonać,
zapisując każdy punkt w bazie, wywoławszy
wcześniej odpowiedni Web Service, np. Geo-
coding API udostępnione przez Yahoo (http://
developer.yahoo.com/maps/rest/V1/geocode.html).
Co ważne – posiada on limit 5000 zapytań
na dobę.
Zapoznaliśmy się z możliwościami użycia bi-
blioteki Yahoo Maps Actioncript 3.0 API.
Wykorzystując ją (lub inne wcześniej wspo-
mniane), możemy budować bardzo ciekawe
serwisy, których funkcjonalności były wcze-
śniej trudne do osiągnięcia klasycznymi tech-
nikami. Platforma Flex umożliwia nam bar-
Rysunek 3. Wskaźnik na mapie dzo łatwą komunikację z dziesiątkami Web Se-
rvices na świecie, przy wykorzystaniu serwisów
typu Yahoo! Pipes (urzeczywistnienia zasady
Web As Platform). Nawet trywialne przykłady
zastosowania przy użyciu tej technologii, mo-
gą być ciekawie przedstawione – np. ile hoteli
znajduje się w promieniu pięć minut jazdy tak-
sówką od centralnego punktu odwiedzanych
przeze mnie miast?

WOJCIECH PTAK
Od 2 lat konsultant i programista Adobe Flex oraz
Adobe Integrated Runtime (AIR) (przez rok obejmo-
wał to stanowisko w norweskiej firmie Making Wa-
ves). Wykonał w całości m.in. aplikację Kalkulator
Energetyczny Vattenfall, która została wyróżnio-
na w międzynarodowym konkursie Webby Awards
2008. Aktualnie pracuje dla takich klientów jak Adi-
das, Heineken, Coca–Cola, Schweppes czy British
Telecom, dostarczając kompleksowe aplikacje B2B
Rysunek 4. Aplikacja Flex z ASTRA Web Services oparte o Adobe Flex oraz AIR.

www.sdjournal.org 37
ADOBE FLEX

Flex na Javie
Historia Adobe Flex sięga marca 2004 roku, kiedy pojawiło się pierwsze wydanie
tego zbioru technik wytwarzania tzw. bogatych aplikacji internetowych (Rich
Internet Application – RIA). Bazuje on na platformie Flash. Pierwsze wydanie
(Macromedia) zawierało SDK, IDE oraz aplikację Flex Data Services zbudowaną
za pomocą J2EE. W 2005 roku firma Macromedia została przejęta przez Adobe
i Flex Data Services przemianowano na LiveCycle Data Services.

rego możemy pobrać ze strony domowej pro-


Dowiesz się... Powinieneś wiedzieć... jektu Adobe Flex lub z płyty DVD. Dostępna
• W jaki sposób tworzyć aplikacje RIA, na przy- • W jaki sposób korzystać z SQL (także z pozio- jest wersja 60-dniowa, którą możemy wyko-
kładzie forum, wykorzystując różne technolo- mu Javy). Znać podstawy JSP, RIA, Flex. rzystywać do celów niekomercyjnych. Przygo-
gie Internetowe, a w szczególności Javę, a tak- towano także specjalną edycję dla studentów.
że SQL, JSP oraz Flex. W przypadku użytkowników Linuksa, poja-
wiło się światełko w tunelu – wydana zosta-
ła wersja alfa Flex Buildera, którą można po-
(znane użytkownikom Flasha) oraz odpowied- brać i zainstalować jako wtyczkę do Eclipse.
nie pliki .html, w których osadzone będą pliki Flex Builder nie jest niezbędny, jednak przy-
Poziom trudności .swf. Po uruchomieniu strony w przeglądarce, daje się, jeśli chcemy nasze aplikacje budować
zostanie załadowany odtwarzacz Flasha, który w sposób graficzny. Jeśli nie, wystarczy zwy-
można uruchomić bez włączania strony, a włą- kły notatnik, bo kompilację i tak przerzucimy
czając jedynie plik .swf. I voila! Możemy cieszyć na nasz serwer, o którym za chwilę.

W
lutym 2008 roku ukazała się trze- się naszą aplikacją. Instalacja przebiega bezproblemowo. Kli-
cia wersja Flex SDK wydana na O Flexie można by dużo mówić. Nie będę kamy jedynie przycisk Dalej, w odpowiednim
Mozilla Public License. Jednak na jednak dłużej owijał w bawełnę i powiem krót- miejscu akceptujemy licencję i czekamy na za-
licencji ogólnej wciąż prawa pozostają Adobe ko – stwórzmy coś! kończenie kopiowania plików. Po zakończonej
Flash Player, który pozwala uruchamiać apli- instalacji, w menu Start czeka na nas Flex Buil-
kacje flashowe oraz flexowe i Flex Builder, czy- Instalujemy i konfigurujemy der. Uruchamiamy go i naszym oczom ukazu-
li IDE (używane do budowania aplikacji flexo- Przygotujmy sobie środowisko pracy. Co ro- je się GUI znane z Eclipse, zatem osoby, któ-
wych) oparte o Eclipse. bimy? Programujemy we Fleksie. Do tego ce- re miały już wcześniej do czynienia z tym śro-
We Flexie wykorzystano MXML, czyli lu będziemy potrzebowali Flex Buildera, któ- dowiskiem, bez problemu się w nim odnajdą.
XML’owy język służący do opisu interfejsu
użytkownika, XMLHttpRequest, czyli obiekt
służący do wykonywania zapytań do serwe-
rów, ActionScript, czyli język programowania
bazujący na specyfikacji ECMAScript.
Alternatywnymi technologiami są: Open-
Laszlo, AJAX, XUL, JavaFX, Silverlight.
Ogólny schemat wytwarzania i działania
aplikacji flexowych jest bardzo prosty. Tworząc
nowy projekt, przygotowujemy pliki .mxml,
w których opisujemy cały interfejs użytkowni-
ka, zaczynając od tego, jakie obiekty będą na
nim widoczne, poprzez obsługę zdarzeń, a koń-
cząc na skryptach, pozwalających dynamicznie
zmieniać stany tejże aplikacji. Następnie mo-
żemy dorzucić jakieś pliki, w których zakodu-
jemy kilka klas za pomocą ActionScriptu, czy
Javy lub pliki .xml, które będą przechowywać
różne dane. Po zakończeniu prac programi-
stycznych, przychodzi czas na kompilację. IDE
wygeneruje nam plik lub zestaw plików .swf Rysunek 1. Okno rejestracji

38 FLEX
Flex na Javie

Jeśli jednak masz pewne problemy, to nie oba- my przydatne narzędzia, na dole konsolę in- db\flexdemodb.script, który zawiera komplet-
wiaj się – poprowadzę Cię za rękę. formująca o błędach itp. Jeśli natomiast cho- ny opis bazy danych. Wszystkie operacje na
W artykule wykorzystamy także język Java, dzi o FDS-Tomcat, najważniejsze, co musimy tej bazie danych w trakcie działania serwera
zatem warto doinstalować wtyczkę pozwala- wiedzieć jest to, że przy uruchomieniu ser- wykonywane są w pamięci, a dopiero podczas
jącą na programowanie w tymże języku za po- wera wczytywany jest m.in. plik fds-tomca\ poprawnego zamknięcia serwera, zmodyfiko-
mocą Flex Buildera. Aby to zrobić, klikamy
kolejno Help>Software Updates>Find and In- Listing 1. Pierwsza aplikacja
stall. W oknie, które się pojawi, zaznaczamy
opcję Search for new features to install, klikamy <?xml version="1.0" encoding="utf-8"?>
przycisk Next i na liście zaznaczamy pozycję <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
The Eclipse Project Updates. Gdy otrzymamy li- <mx:ApplicationControlBar x="239" y="36" dock="true" height="60">
stę pakietów, które możemy zainstalować, od- <mx:Label text="FlexForum" fontSize=”25”/>
szukujemy najnowszą wersję Eclipse Java De- </mx:ApplicationControlBar>
velopment Tools i przystępujemy do jej insta- </mx:Application>
lacji. Zaopatrzmy się także w specjalnie przy-
gotowany i skonfigurowany serwer FDS-Tom- Listing 2. Dodajemy stopkę
cat, który pobrać można z Internetu (link
w ramce). Rozpakujmy go najlepiej na dysk C, <?xml version="1.0" encoding="utf-8"?>
po czym (korzystając z konsoli), przejdźmy <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
do folderu C:\fds-tomcat\bin i wpiszmy pole- <mx:ApplicationControlBar x="239" y="36" dock="true" height="60">
cenie catalina run. Musimy pamiętać o tym, <mx:Label text="FlexForum" fontSize=”25”/>
że potrzebna jest zdefiniowana zmienna śro- </mx:ApplicationControlBar>
dowiskowa JAVA_HOME. Można ją zdefiniować <mx:Label text="(C) 2008" horizontalCenter="0" bottom="0"/>
albo za pomocą narzędzi systemowych, albo </mx:Application>
zdefiniować ją tymczasowo, nieco modyfi-
kując polecenie: JAVA_HOME=dysk:\sciezka\ Listing 3. FlexForum.mxml
do\javy\ catalina run. Okno konsoli mo- <?xml version="1.0" encoding="utf-8"?>
żemy zminimalizować, ale nie należy go za- <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
mykać. FDS-Tomcat bez problemu działa tak- <mx:states>
że na Linuksie (na moim laptopie czas startu <mx:State name="logged">
serwera pod Linuksem był blisko dwukrotnie <mx:RemoveChild target="{lpBox}"/>
krótszy!), a uruchamiany jest analogicznie jak <mx:RemoveChild target="{registerButton}"/>
na innych platformach, pamiętając o zmien- <mx:RemoveChild target="{loginButton}"/>
nej JAVA_HOME – JAVA_HOME=/sciezka/do/ <mx:AddChild relativeTo="{lrBox}" position="lastChild">
javy/ ./catalina.sh run, uprzednio na- <mx:LinkButton id="logoutButton" label="Logout" click="logout()"/>
dając prawa wykonania pliku poprzez po- </mx:AddChild>
lecenie chmod +x catalina.sh. W syste- </mx:State>
mie Windows, Java znajduje się domyślnie </mx:states>
w C:\Program Files\Java\jre-numer-wersji\, <mx:Script source="as/FlexForum.as"/>
natomiast w moim Linuksie (Ubuntu) pod <mx:ApplicationControlBar x="0" y="0" dock="true" height="65">
ścieżką /usr/share/java-numer-wersji/. Może- <mx:Canvas width="100%" height="100%" horizontalScrollPolicy="off" verticalScrollPo
my także skorzystać z ręcznie postawionego licy="off">
Tomcata oraz jakiejś bazy danych SQL (np. <mx:Image source="logo.png" scaleContent="true" width="100%" height="100%"/>
MySQL) zamiast z FDS-Tomcata, który nie <mx:VBox verticalCenter="0" right="0">
jest dość stabilny i bezpieczny do codzienne- <mx:HBox id="lpBox" width="100%" height="100%">
go użytku, natomiast do celów edukacyjnych <mx:Label text="Login"/>
nadaje się znakomicie. Instalację i konfigura- <mx:TextInput id="loginTextInput" width="80"/>
cję pozostawiam drogi czytelniku Tobie – wy- <mx:Label text="Password"/>
starczy zajrzeć do dokumentacji wyżej wy- <mx:TextInput id="passwordTextInput" width="80"/>
mienionych projektów. Uwaga dla tych, któ- </mx:HBox>
rzy zdecydują się samodzielnie ustawić ser- <mx:HBox id="lrBox" width="100%" height="100%">
wer: domyślnie skonfigurowany Tomcat nie <mx:Spacer width="100%"/>
skompiluje plików .mxml, a FDS-Tomcat tak. <mx:LinkButton id="loginButton" label="Login" click="login()"/>
W artykule proces kompilacji został pominię- <mx:LinkButton id="registerButton" label="Register" click="showRegisterPopUp()"/>
ty i przerzucony właśnie na FDS-Tomcat, tak- <mx:Spacer width="100%"/>
że w przypadku korzystania z czystego Tom- </mx:HBox>
cata należy go albo przekonfigurować, albo </mx:VBox>
we Flex Builderze skompilować plik .mxml do </mx:Canvas>
pliku .swf i umieścić go w odpowiednim kata- </mx:ApplicationControlBar>
logu, do którego Tomcat sięgnie wyświetlając <mx:Label text="(C) 2008" horizontalCenter="0" bottom="0"/>
strony internetowe. <mx:HTTPService id="srv" url="http://localhost:8600/FlexForum/Login.jsp"
To tyle, jeśli chodzi o przygotowania. Śro- method="POST" result="srvResult(event)"/>
dowisko jest podzielone na trzy główne czę- </mx:Application>
ści – w środkowej piszemy kod, po bokach ma-

www.sdjournal.org 39
ADOBE FLEX

wane dane zapisywane są ponownie w tym


samym pliku. Baza ta nie jest w żaden spo- Listing 4. Register.mxml
sób szyfrowana, jest to plik napisany w czy- <?xml version="1.0" encoding="utf-8"?>
stym SQL. <mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal"
Pora zabrać się do pracy. Zaczynamy od title="Register" close="PopUpManager.removePopUp(this)"
stworzenia nowego projektu. W tym ce- showCloseButton="true" x="{this.parentApplication.width/
lu klikamy File>New>Flex Project. Nazwijmy 2 - this.width/2}" y="{this.parentApplication.height/2 -
go FlexForum. Możemy teraz zmienić ścież- this.height/2}">
kę, pod którą przechowywane będą pliki źró- <mx:Script source="../as/Register.as"/>
dłowe (i wynikowe). Wprowadźmy więc: <mx:Form width="100%" height="100%">
C:\fds-tomcat\webapps\ROOT\FlexForum. <mx:FormItem label="Login">
Mamy także możliwość wyboru typu aplikacji <mx:TextInput id="login"/>
– webowa, oparta na Flash Player albo deskto- </mx:FormItem>
powa, oparta na Adobe Air. W naszym przy- <mx:FormItem label="Password">
padku decydujemy się na aplikację webową <mx:TextInput id="password" displayAsPassword="true"/>
i klikamy Next. Następnie wybieramy miejsce, </mx:FormItem>
w którym przechowywane będą skompilowa-
ne pliki. Zostawmy to pole puste, tak aby pli- <mx:FormItem label="E-Mail">
ki te pojawiały się w katalogu głównym naszej <mx:TextInput id="email"/>
aplikacji. Idąc dalej, wybieramy folder dla ko- </mx:FormItem>
dów źródłowych, które także powinny znajdo- <mx:FormItem label="Gender">
wać się w katalogu głównym, więc zostawmy <mx:HBox width="100%" height="100%">
także to pole puste. Klikamy Finish. Wyłącz- <mx:RadioButtonGroup/>
my automatyczne budowanie projektu (gdyż <mx:RadioButton id="male" label="Male" groupName="" selected="true"/>
zadba o to serwer FDS-Tomcat), odznaczając <mx:RadioButton id="female" label="Female" groupName=""/>
opcję Project>Build Automatically. </mx:HBox>
</mx:FormItem>
Kodujemy
Zauważmy, że w głównej części okna pojawia <mx:FormItem>
się niebieski obszar, a nad nim przyciski Sour- <mx:HBox width="100%" height="100%">
ce oraz Design, dzięki czemu możemy swobod- <mx:Button label="Register" click="register()"/>
nie przełączać się między trybami programo- <mx:Button label="Cancel" click="hideRegisterPopUp()"/>
wania a projektowania. Będąc w trybie pro- </mx:HBox>
jektowania, po lewej stronie znajduje się za- </mx:FormItem>
kładka Components, z której możemy przecią- </mx:Form>
gać kontrolki do naszej aplikacji oraz zmieniać
ich właściwości za pomocą elementów znajdu- <mx:HTTPService id="srv" url="http://localhost:8600/FlexForum/Register.jsp"
jących się na zakładce Flex Proporties po pra- method="POST" result="srvResult(event)"/>
wej stronie. </mx:TitleWindow>
Dodajmy więc do naszej aplikacji kontro-
lkę ApplicationControlBar (znajduje się ona Listing 5. FlexForum.as
w sekcji Layout) i ustawmy jej właściwość Dock import mx.managers.PopUpManager;
na true, a Height na 60. Teraz do Application- import mx.rpc.events.ResultEvent;
ControlBar dodajmy komponent Label (sek- import views.Register;
cja Controls), a właściwość Text ustawiamy na public function login() : void {
FlexForum. Przełączmy się teraz do trybu So- var p : Object = new Object();
urce (patrz Listing 1.). Jego pierwsza nagłów- p.login = loginTextInput.text;
kowa linia pozostaje bez zmian, gdyż jest do p.password = passwordTextInput.text;
dokument typu XML. Ciekawsze natomiast srv.send(p);
}
public function logout() : void {
W Sieci this.currentState='';
}
• http://www.adobe.com – Strona domo- public function showRegisterPopUp() : void {
wa firmy Adobe
PopUpManager.createPopUp(this, views.Register, true);
• http://www.adobe.com/products/flex/
Flex Builder }
• http://www.flex.org – Strona społeczno- public function srvResult(event : ResultEvent) : void {
ści Flexa var tmp : String = event.result.login;
• http://www.riadocs.com – Artykuły i do- if (tmp == "Success")
kumenty na temat RIA
this.currentState = 'logged';
• http://livedocs.adobe.com/flex/3/html/
else if (tmp == "Failure")
index.html – Pomoc do Adobe Flex 3
• http://coenraets.org/download/fds-tom- PopUpManager.createPopUp(this, views.LoginFail, true);
cat.zip – FDS-Tomcat }

40 FLEX
Flex na Javie

są kolejne linie. Najpierw tworzymy obiekt od przycisku Design. W pliku Register.mxml ActionScript
typu <mx:Application>, a w nim dwa kolej- przygotowujemy kontrolki pozwalające na Plik FlexForum.as będzie zawierał odpowied-
ne obiekty – <mx:ApplicationControlBar>, rejestracje – Listing 4. Efekt widoczny jest nie skrypty. Na razie umieścimy w nim funk-
które zawierają w sobie <mx:Label>. Za- na Rysunku 1. cje, zawarte na Listingu 5.
uważmy, że wszystkie te obiekty znajdują Obiekt HTTPService pozwala na wysyłanie W funkcji login przygotowujemy parame-
się w klasie mx. Każdy obiekt opisywany jest zapytań do zdalnego serwera (w naszym przy- try, które przekażemy metodą POST do na-
przez pewne parametry. Pamiętamy, że usta- padku jest to localhost). Odwołujemy się tu- szego pliku Java Server Page. Parametry two-
wiliśmy wartość dock naszego Application- taj do Register.jsp, który pobierając odpowied- rzymy poprzez przygotowanie obiektu ty-
ControlBar na true i jest to widoczne w ko- nie parametry przekazane metodą POST, po- pu Object, a następnie odwołujemy się do
dzie źródłowym aplikacji. Możemy teraz za- zwoli na rejestrację korzystając z przygotowa- niego przy pomocy odpowiedniej referencji
pisać projekt oraz uruchomić go wpisując nych przez nas w Javie klas. (w naszym przypadku r), podając po kropce
w przeglądarce adres: http://localhost:8600/
FlexForum/FlexForum.mxml. Pamiętajmy, że
wielkość liter ma znaczenie. Pierwsze załado-
wanie (po każdej modyfikacji kodu źródłowe-
go lub restarcie serwera) potrwa odrobinę dłu-
żej ze względu na konieczność rekompilacji.
W tym momencie serwer sam skompiluje plik
uwzględniając wszystkie wcześniej przygoto-
wane opcje konfiguracyjne.
Teraz, w trybie Source, poniżej Applica-
tionControlBar dodajmy kolejny Label, tak
by nasz kod prezentował się jak na Listingu
2., a poprzedni Label wzbogaćmy o parametr
fontSize=”25”. Ustalamy, jaki tekst ma zo-
stać wyświetlony, w jakiej odległości od hory-
zontalnego środka oraz w jakiej odległości od
dołu. Ostatnie dwa parametry pozwalają na
dynamiczne (w zależności od rozmiaru okna)
ustalenie się położenia etykiety (ang. label). Po
zapisaniu pliku przełączamy się do trybu De-
sign i zauważamy, że u dołu aplikacji pojawiła Rysunek 3. Efekt po zalogowaniu.
się nasza stopka. Efekt dynamicznego dostoso-
wania położenia można uzyskać także w tym Listing 6. Register.as
trybie poprzez zaznaczenie interesującego nas
obiektu i ustaleniu odpowiednich właściwości import mx.managers.PopUpManager;
w sekcji Layout na zakładce Flex Proporties. Za- import mx.rpc.events.ResultEvent;
pisujemy projekt i w przeglądarce odświeża- public function hideRegisterPopUp() : void {
my stronę. PopUpManager.removePopUp(this)
Jak widzimy, mamy do dyspozycji dwa tryby }
tworzenia aplikacji. W zależności od potrzeb, public function register() : void {
jeden z nich będzie wygodniejszy, od drugiego. var params : Object = new Object();
Przejdźmy do konkretów. Klikając prawym params.login = login.text;
przyciskiem na projekt, utwórzmy dwa folde- params.password = password.text;
ry – views i as. W pierwszym z nich utwórz- params.email = email.text;
my nowy MXML Component o nazwie Regi- params.gender = (male.selected ? "male" : "female");
ster.mxml, (pola width i height zostawiamy srv.send(params);
puste, natomiast w polu Based on wybiera- }
my TitleWindow), a w drugim nowy Action- public function srvResult(event : ResultEvent) : void {
Script File o nazwie FlexForum.as i o nazwie var tmp : String = event.result.registration;
Register.as. Otoczmy wszystko, co znajdu- if (tmp == "Success") {
je się w ApplicationControlBar, za pomocą hideRegisterPopUp();
<mx:Canvas> i dodajmy kilka dodatkowych this.parentApplication.currentState = 'logged';
elementów jak skrypt, kontenery czy spacery. } else if (tmp == "Failure")
Kod powinien prezentować się tak, jak na Li- PopUpManager.createPopUp(this, views.RegisterFail, true);
stingu 3. Proponuję zająć się tym w trybie So- }
urce, gdyż ze względu na ilość kontenerów,
ciężko będzie nam wszystko odpowiednio Listing 7. Uwidaczniamy naszą klasę
poukładać. Jeżeli jednak zdecydujesz się mo- <destination id="forum">
dyfikować tę aplikację w trybie Design, aby <properties>
wiedzieć, w którym kontenerze umieszczasz <source>flex.Forum.Forum</source>
obiekt, wygodnie jest włączyć opcję Show </properties>
Surrounding Containers za pomocą klawisza </destination>
[F4] lub klikając na drugą ikonkę na prawo

www.sdjournal.org 41
ADOBE FLEX

nazwę parametru. Nazwę tę ustalamy sobie sa- cja otrzyma zwrotne dane po wysłaniu zapy- to wszystko, co znajduje się pomiędzy znacz-
mi. W pliku FlexForum.mxml przy tworzeniu tania do zdalnego serwera. W event.result nikami <login> i </login>. W zależności od
obiektu HTTPService, ustaliliśmy, iż parametr znajduje się cały dokument XML utworzony tego jaka wartość tam wystąpi, zostaną wywo-
result wskazuje na funkcję srvResult(event za pomocą kodu zawartego w pliku Login.jsp. łane odpowiednie instrukcje.
: ResultEvent) : void, zatem musimy ją Dokument ten będzie wyglądał przy udanym Ostatni plik – Register.as – ma wyglądać
także umieścić w naszym skrypcie. Funkcja logowaniu tak: <login>Success</login>. Po- tak, jak na Listingu 6.
ta jest wywoływana zawsze, gdy nasza aplika- przez odwołanie event.result.login zyskujemy Podobnie w przypadku plików Register.as
i Register.mxml mamy funkcję, która przygo-
Listing 8. Forum.java towuje parametry do zapytania wysyłanego
do zdalnego serwera oraz funkcję, która prze-
package flex.Forum; twarza dane otrzymane z tegoż serwera. Dzia-
import java.sql.Connection; ła ona na podobnej zasadzie jak w poprzednim
import java.sql.PreparedStatement; przypadku.
import javax.servlet.http.HttpServlet;
public class Forum extends HttpServlet { Java
public boolean login(String login, String password) { Zajmijmy się teraz Javą. Klikamy: File>New>
// TODO Other i wybieramy Java Project. Nazwijmy go
return true; Forum, wybierzmy przycisk Next, w kolejnym
} oknie dialogowym zmieniamy domyślny fol-
public boolean logout(String login) { der dla plików wynikowych, klikając przycisk
//TODO Browse. W oknie dialogowym wybieramy z li-
return true; sty nazwę projektu (Forum), klikamy Create
} New Folder..., gdzie zaznaczamy opcję Link
public boolean register(String login, String password, String email, String gender) to folder in the file system, po rozwinięciu sek-
{ cji Advanced. W pole, które się pojawiło, wpi-
Connection c = null; sujemy ścieżkę na C:\fds-tomcat\webapps\
PreparedStatement ps = null; ROOT\WEB-INF\classes. Ok, Ok, Finish.
try { Folder C:\fds-tomcat\webapps\ROOT\WEB-
c = ConnectionHelper.getConnection(); INF\classes\flex\Forum musi istnieć.
ps = c.prepareStatement("INSERT INTO user (login, password, email, gender, type) Od razu utwórzmy w naszym nowym pro-
VALUES (?, ?, ?, ?, ?)"); jekcie klasę o nazwie Forum, podając dla niej
ps.setString(1, login); nazwę pakietu flex.Forum. Zostaliśmy także
ps.setString(2, password); przełączeni do perspektywy Java. Możemy
ps.setString(3, email); łatwo przełączać się między perspektywami,
ps.setString(4, gender); korzystając z przycisków w menu, w prawym
ps.setString(5, "user"); górnym rogu okna Flex Buildera. Domyślna
ps.executeUpdate(); perspektywa dla projektów flexowych to Flex
} catch (Exception e) { Development.
e.printStackTrace(); Musimy teraz edytować plik C:\fds-tomcat\
} finally { webapps\ROOT\WEB-INF\flex\remoting-con-
ConnectionHelper.close(c); fig.xml, tak aby serwer wiedział, do której kla-
} sy będziemy się odwoływać. Wewnątrz sek-
return true; cji <service> (najlepiej przed jej zakończe-
} niem) musimy umiescić kod zamieszczony
} na Listingu 7.
Restartujemy serwer i wracamy do progra-
Listing 9. Register.jsp mowania. W pliku Forum.java umieszczamy
<%@ page import="flex.Forum.Forum" contentType="text/html"%> taki kod jak na Listingu 8.
<?xml version="1.0" encoding="utf-8"?> Tutaj przyda się odrobina wiedzy z zakresu
<% wykorzystania SQL z poziomu Javy. Zauważ-
Forum f = new Forum(); my, że funkcje zwracają wartości true/false.
if (f.register(request.getParameter("login"), request.getParameter("password"), Pozostaje nam jeszcze utworzyć dwa pli-
request.getParameter("email"), request.getParameter("gender")) ki w katalogu głównym naszej aplikacji inter-
== true) { netowej, czyli tam, gdzie umieszczone są pli-
%> ki .mxml. Tworzymy więc plik Register.jsp oraz
<registration>Success</registration> Login.jsp. Zawartość tych plików przedstawio-
<% no odpowiednio na Listingach 9. i 10.
} else { Aby zrozumieć o co tutaj chodzi, trze-
%> ba znać podstawy JSP. Wytłumaczę jednak
<registration>Failure</registration> wszystko w miarę zwięźle. Odwołując się do
<% serwera poprzez adres http://localhost:8600/
} FlexForum/Login.jsp serwer Tomcat zacznie
%> wykonywać instrukcje zawarte w tym pli-
ku. Pomiędzy symbolami <% i %> mamy Ja-

42 FLEX
Flex na Javie

vę, natomiast poza nimi jest XML. W pierw- SQL wać posty użytkowników. Na pewno warto
szej linii umieszczamy informację o impor- Ostatnią rzeczą, jaką musimy przygotować, to umieścić tam (oprócz treści postu) datę je-
towanych klasach. Zaznaczamy, że będzie- tabele w bazie danych. W katalogu głównym go umieszczenia na forum, nazwę autora itp.
my korzystać z klasy Forum, która znajduje się FDS-Tomcat, jest folder db, który zawiera plik Wymaga to umieszczenia dodatkowych funk-
w pakiecie flex.Forum. Następnie definiuje- flexdemodb.script. Plik ten powinien mieć za- cji w klasie Forum oraz przygotowania odpo-
my typ dokumentu XML, a później przecho- wartość jak na Listingu 11. wiednich plików .jsp, a także plików .mxml,
dzimy już do właściwego kodu. Zaczynamy które będą opisywały np. okno edycji posta.
od utworzenia obiektu klasy Forum, po czym Zostawiam Cię Następnie powinieneś zrobić pobieranie
na rzecz tego obiektu wywołujemy funkcję Odpowiednie funkcje w plikach .java będą od- tematów/postów z bazy danych i wyświetlanie
login() z odpowiednimi parametrami. Pa- woływać się do utworzonej tutaj tabeli, doda- ich w swojej aplikacji. Tutaj wystarczy również
rametry te to obiekty klasy String, wydoby- jąc do niej rekordy, modyfikując je, usuwając nowa funkcja w klasie Forum oraz dodatkowy
te z obiektu request. Obiekt request posia- itp. Aplikacja utworzona w ramach tego ar- plik .jsp, który będzie zawierał dokument XML
da wszystkie potrzebne informacje dotyczące tykułu nie pozwala na wszystkie te operacje, z odpowiednimi informacjami. Plik ten zosta-
klienta, który wysyła zapytanie. Możemy wy- jednak możesz na własną rękę w odpowied- nie przeanalizowany w naszej fleksowej aplika-
dobyć z niego takie dane jak adres IP, typ prze- ni sposób ją później rozwinąć. W przypad- cji podobnie, jak analizowane są pliki Register.jsp
glądarki itp., ale w tym przypadku interesu- ku logowania, rekord zostanie zmodyfikowa- i Login.jsp. Tematy i posty wydobyte z tegoż pli-
ją nas jedynie parametry, które zostały prze- ny w taki sposób, że pole LOGGED przybie- ku można umieścić np. w komponencie <mx:
kazane przez użytkownika. Piszemy więc np. rze wartość true, a w polu IP zapisany zosta- Tree> lub napisać własny komponent wyświe-
request.getParameter("login"), gdzie login, nie adres IP klienta. Jest to bardzo proste za- tlający te informacje według własnego uznania,
to parametr utworzony w pliku FlexForum.as bezpieczenie pozwalające na pozostanie za- tzw. renderer. To wszystko pozostawiam jednak
w funkcji login() poprzez instrukcję p.login logowanym przez jakiś czas, ale które uchro- Tobie jako pracę domową. Pokazałem Ci jak za-
= loginTextInput.text;. ni nas częściowo przed tym, że ktoś inny pod- cząć, a Ty dokończ to tak, jak zechcesz. Sposo-
Sprawdzamy także, jaki wynik da nam wy- szyje się pod innego zalogowanego użytkowni- bów jest naprawdę wiele. Do dzieła!
wołanie tej funkcji. Jeśli uda się zalogować, ka. Jeżeli chcemy zrobić to profesjonalnie, na-
z pewnością będzie to true. Warunkowo więc leży skorzystać z zarządzania sesjami z pozio- Jutro
kończymy kod, zapisując w naszym doku- mu JSP. Podobnie wygląda to w przypadku Tworząc naszą aplikację, nie wykorzystaliśmy
mencie XML znacznik <login>Success</ aplikacji PHP. w pełni wszystkich możliwości Flexa, gdyż moż-
login>, po czym znów otwieramy blok kodu, Końcowy efekt (uwzględniając logowanie) liwości te są nieograniczone, a objętość tego arty-
a następnie wykonujemy blok else gdzie, je- widzimy na Rysunku 3. Brakuje jedynie wy- kułu nie jest duża. Jeżeli chcesz poszerzyć swo-
śli coś poszło źle, znów zakończymy kod Javy świetlania postów. ją wiedzę w tym zakresie, koniecznie odwiedź
i zapiszemy w dokumencie <login>Failure</ Pozostawiam Ci także, Czytelniku, przy- strony, których adresy znajdziesz w tabelce.
login>. gotowanie tabeli, która będzie przechowy- Co przyniesie przyszłość? Adobe poinfor-
mowała, że Flex 4.0 (znany pod nazwą kodową
Listing 10. login.jsp Gumbo) ukaże się w roku 2009. W chwili pi-
sania tego tekstu nie są znane jeszcze dokładne
<%@ page import="flex.Forum.Forum" contentType="text/html"%> plany, ale pojawiło się już kilka ogólników. I tak
<?xml version="1.0" encoding="utf-8"?> oto w kolejnej wersji Flexa mają pojawić się ta-
<% kie elementy jak:
Forum f = new Forum();
if (f.login(request.getParameter("login"), request.getParameter("password")) == • Design in Mind (projektuj w myślach)
false) { – framework pozwalający na poszerza-
%> nie współpracy pomiędzy developerami
<login>Success</login> a designerami;
<% • Accelerated Development (przyspieszone
} else { rozwijanie) – pozwoli przejść od koncep-
%> cji do realiów bardzo szybko;
<login>Failure</login> • Horizontal Platform Improvements (ulep-
<% szenia platformy) – wydajność kompila-
} tora, uwydatnienie języka, komponenty
%> BiDi, uwydatnienie tekstu;
• Broadening Horizons (poszerzanie hory-
Listing 11. flexdemodb.script zontów) – znalezienie sposobów na uczy-
nienie frameworka lżejszym, poprawa ob-
CREATE SCHEMA PUBLIC AUTHORIZATION DBA sługi MXML.
CREATE MEMORY TABLE USER(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT
NULL PRIMARY KEY,LOGIN VARCHAR(40),PASSWORD VARCHAR(128),EMAIL Pierwsza beta ukaże się z końcem 2008 roku,
VARCHAR(65),GENDER VARCHAR(6),TYPE VARCHAR(9),LOGGED BOOLEAN,IP a wersja finalna w 2009 roku.
VARCHAR(15))
ALTER TABLE USER ALTER COLUMN ID RESTART WITH 12 ROGER ZACHARCZYK
CREATE USER SA PASSWORD "" Autor jest stałym współpracownikiem Software-
GRANT DBA TO SA Wydawnictwo. Interesuje się głównie programowa-
SET WRITE_DELAY 20 niem (C/C++, Java, PHP, AJAX). Jest zwolennikiem
SET SCHEMA PUBLIC ruchu Open Source.
Kontakt z autorem: roger.zacharczyk@gmail.com

www.sdjournal.org 43
ADOBE FLEX

Flex.Security.allowSecure
Communication('*');
Na początku chcielibyśmy krótko opisać możliwe sposoby wymiany
informacji pomiędzy serwerem, a użytkownikiem, dostępne dla języka
ActionScript 3.0 z dodatkowym wykorzystaniem gotowych komponentów
środowiska Flex 3.

zostały one opisane w artykule pt. Flex i php


Dowiesz się.. Powinieneś wiedzieć... – wykorzystanie web services i technologii flash
• O systemie zabezpieczeń języka ActionScript 3; • Wymagana jest podstawowa wiedza z zakresu remoting.
• zabezpieczeniach komunikacji; wymiany danych backend–frontend. Chciałbym jednakże pokrótce opisać wyko-
• nowych crossdomains; rzystanie klasy flash.net.URLLoader po stronie
• oraz dlaczego warto używać Flash Media Se- Flexa do komunikacji z backendem w PHP. Po
rver. stronie serwera będzie znajdował się wystawio-
ny gateway nasłuchujący naszych żądań, który
przyjmować będzie argumenty zarówno z ta-
Podsumowując wcześniejsze zagadnienia, blicy $_GET jak i $_POST. Adres gateway'a
wspomnimy również o możliwości kradzie- ustalimy na: http://example.com/gateway.php.
Poziom trudności ży własności intelektualnej, mechanizmach Założę również, że na żądanie ?action=
DRM, zaprezentujemy za i przeciw zabezpie- getDummyData dostanę zwrot w postaci
czaniu plików SWF oraz przyjrzymy się kilku XML:
prostym metodom śledzenia prób fałszowania

P
o krótce scharakteryzujemy dostępne komunikacji klient–serwer. <?xml version="1.0" encoding="utf–8"?>
metody – ich zalety i wady – jak rów- <return><row attr1=”hello” /><row>world</
nież porównamy wydajność wymie- Różne źródła danych row></return>
nionych rozwiązań, takich jak: flashvars, Podczas projektowania nawet najprostszych
<mx:WebService>, <mx:RemoteObject>, <mx: aplikacji działających po stronie klienta, szyb- Na Listingu 3. przedstawię fragment ko-
HTTPService>, URLLoader. Zastanowimy się ko nadchodzi potrzeba parametryzowania du w ActionScript, który wyśle przykłado-
też nad różnymi formatami danych. aplikacji, dostarczania jej dynamicznych źró- we dane i odbierze zwrot. Dla uproszcze-
Dalszą część artykułu poświęcimy bezpie- deł danych, uzyskania obustronnej komunika- nia przykładu nie dodałem obsługi zdarzenia
czeństwu w obrębie flash playera (sandboxy cji. Runtime Flash udostępnia nam kilka możli- IOErrorEvent.IO _ ERROR oraz nie przepro-
i crossdomain) oraz sposobom ochrony przesy- wości, by zrealizować te potrzeby. wadziłem walidacji zwrotu, co jest niezbędne
łanych informacji. Opisywane przez nas me- Pierwszą i najprostszą metodą na dostar- w komercyjnych projektach.
tody zabezpieczenia komunikacji poparte są czenie do naszej aplikacji (pisanej na przy- Chciałbym jeszcze zaznaczyć, iż Flex po-
wieloma projektami i doświadczeniem au- kład we Flexie) zmiennych jest posłużenie się zwala również na bezpośrednią komunika-
torów z zakresu architektury środowisk bac- obiektem flashvars. Do osadzenia projektu cję na bardzo niskim poziomie jakim są gniaz-
kendowych, frontendowych i co najważniejsze na stronie HTML użyję biblioteki JavaScript da (ang. sockets). Wyróżnić można dwa rodza-
– ich integracji. Poruszymy tak oczywiste roz- SWFObject2 (http://code.google.com/p/swfobject) je połączeń – poprzez XMLSocket, który wy-
wiązania, jak sesja po stronie serwera, znaczni- – patrz Listing 1. musza posługiwanie się dokumentami XML
ki czasu, sumy kontrolne zapytań oraz ciekaw- Już ten prosty sposób daje nam możliwość oraz klasę Socket, która pozwala na binarny
sze podejście do tematu jak choćby wykorzy- dynamicznego generowania zmiennych wraz przesył danych.
stanie FMS 3, czy generowanie dynamicznych z wartościami, które na Listingu 2. zostaną od- Chciałbym jeszcze wymienić trzy sposo-
plików SWF po stronie serwera zawierających czytane z poziomu Flexa: by komunikowania się ze światem zewnętrz-
klucze czasowe. Podobnym jednostronnym sposobem ko- nym. Pierwszy z nich to wykorzystanie kla-
Zbliżając się do końca artykułu, w ostatnich munikacji jest sczytywanie parametrów prze- sy ExternalInterface. Pozwala ona na wy-
paragrafach postaramy się przybliżyć i opisać kazanych w URL–u. Flashvarsy są wygodne je- woływanie funkcji osadzonych w skryptach
najczęstsze sposoby łamania zabezpieczeń dla śli chodzi o jakieś małe zmienne, kluczowe do JavaScript, które mogą towarzyszyć aplika-
plików SWF i ich komunikacji ze światem ze- prawidłowego zainicjalizowania aplikacji – na cji Flex osadzonej na stronie HTML. Dodat-
wnętrznym. Poczynając od wtyczki DataTam- przykład adres webservice'u. kowo dzięki tej klasie możemy umożliwić ko-
per dla Firefox, przez komercyjne sniffery oraz Jeżeli chodzi o bardziej zaawansowane tech- munikację w drugą stronę – JavaScript może
dekompilery. niki komunikacji jak webservice i flash remoting wywołać wystawione funkcje z aplikacji Fle-

44 FLEX
Flex.Security.allowSecureCommunication(‘*’);

xowej. Natomiast drugi to używanie Local- w grę – np. 8 i 9) osadzonymi na danej stro- identycznie jak cookies w przeglądarce. Tech-
Connection do komunikacji z innymi plika- nie HTML. Trzecim sposobem są SharedO- nika ta pozwala na zapisywanie dowolnych in-
mi SWF (również różne ich wersje wchodzą bjects, które na pierwszy rzut oka wyglądają formacji po stronie użytkownika, do których
można się odwoływać podczas bieżącej sesji
lub dowolnej następnej. Podczas czyszczenia
ciasteczek w przeglądarce SharedObject nie
ulegają usunięciu. W odróżnieniu od popu-
larnych ciasteczek, nie wygasają, ich wielkość
domyślnie może wynosić do 100 KB każdy,
klient może ustawić maksymalną dostępną
wielkość obiektu SharedObject. Potrafią one
przechowywać proste natywne typy danych
oraz co ważne nie są transmitowane do serwe-
ra podczas innej formy komunikacji w przeci-
wieństwie do ciasteczek.
Zachęcam również do zapoznania się z Ry-
sunkiem 1., który obrazuje wydajność róż-
nych sposobów komunikacji. Każdy z dostęp-
nych sposobów ma swoje wady i zalety – we-
dług mnie nie ma jednego najlepszego. Każdy
projekt używający komunikacji backend–fron-
tend wymaga indywidualnego przeanalizowa-
Rysunek 1. Porównanie wydajności metod komunikacji. http://www.jamesward.org/census/ nia i dobrania optymalnej formy integracji.
Podczas fazy projektowej biorę pod uwagę:
Listing 1. Osadzenie aplikacji poprzez SWFObject2
• czy istnieje już gotowe API po stronie
<script type="text/javascript"> backendu,
• czy aplikacja we Flexie/Flashu będzie je-
var flashvars = { }; dynym klientem,
flashvars.name1 = "hello"; • czy chcę mieć możliwość buforowania
flashvars.name2 = "world"; zwrotów po stronie klienta – jest to bar-
dzo ważne w większych projektach,
var params = { }; • kwestię poufności wymienianych da-
params.menu = "false"; nych,
• rząd wielkości zwrotów,
var attributes = { }; • elastyczność zmian na wypadek zmian
w specyfikacji,
swfobject.embedSWF( "aplikacyjka.swf", "myContent", "300", "120", "9.0.0","expressI • wydajność konkretnej technologii.
nstall.swf", flashvars, params, attributes );
</script> Zabezpieczanie komunikacji
Na samym wstępie należy jasno powiedzieć,
Listing 2. Wczytanie flashvars
że nie ma bezwzględnie bezpiecznej formy
komunikacji z aplikacji klienckiej do serwe-
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initFlash ra. Jednakże już najprostsze formy uwierzy-
Vars()"> telniania i komplikowania wymiany danych
<mx:Script><![CDATA[ w bardzo dużym stopniu skomplikują ży-
[Bindable] cie osobom, które próbowałyby ją fałszować.
public var myName1:String; Z własnego doświadczenia mogę powiedzieć,
[Bindable] aby zwracać szczególną uwagę na aspekt bez-
public var myName2:String; pieczeństwa w grach online i wszelkiego ty-
pu konkursach internetowych. Należy rów-
private function initFlashVars():void { nież cały czas mieć na uwadze, iż aplikacja
myName1 = Application.application.parameters.name1; kliencka z łatwością może być zdekompilo-
myName2 = Application.application.parameters.name2; wana, a cały ruch Internetowy, który generu-
} je – podsłuchany. Naturalne jest dla mnie nie-
]]></mx:Script> zapisywanie poufnych danych po stronie apli-
kacji klienckiej, takiego typu jak użytkownik
<mx:HBox> i hasło do bazy danych. Owszem istnieje taka
<mx:Label text="Name1: {myName1}"/> możliwość by z poziomu Flexa/ActionScriptu
<mx:Label text="Name2: {myName2}"/> bezpośrednio łączyć się do bazy danych, lecz
</mx:HBox> dla mnie jest to zupełne nieporozumienie.
</mx:Application> Pierwsza bardzo prosta technika zabez-
pieczania komunikacji polega na wysyłaniu
sumy kontrolnej dotyczącej danej paczki.

www.sdjournal.org 45
ADOBE FLEX

Dla przykładu w pewnym momencie z Fle- ustawiając czas ważności klucza na przy- komunikacji z wczytanym plikiem – jest to
xa wychodzi dowolną metodą ciąg danych kładowe pięć minut. konieczne, by z poziomu Flash 9 komuniko-
zmienna1=wartosc1, zmienna2=wartosc2, wać się z Flash 8.
zmienna3=wartosc3, checksum=123456. Niech Na Listingu 4. pokażę krótki sposób na wy- Dodatkowym sposobem na zabezpieczenie
cheksum będzie wartością funkcji MD5 obliczo- generowanie SWF za pomocą biblioteki aplikacji klienckiej jest technika obfuskacji wy-
nej na podstawie wartości1 oraz wartości2. MING. nikowego SWF. Można do tego celu znaleźć
Takie samo obliczenie checksum może się wy- By następnie na Listingu 5. z poziomu Ac- darmowe programy w sieci, które w ogrom-
konać po stronie backendu celem weryfikacji tionScriptu we Flexie odebrać klucz. Proszę nym stopniu utrudniają dekompilację skompi-
źródła pochodzenia danych. Oczywiście func- zwrócić uwagę na użycie LocalConnection do lowanych kodów z Flexa do postaci SWF.
kja hashująca może być o wiele bardziej skom-
plikowana lub złożona z wielu dostępnych na- Listing 3. Zastosowanie URLLoader
raz. Jest to metoda bardzo prosta, a zarazem
całkiem efektywna i niewymagająca duże- package {
go nakładu pracy programisty frontendowego import flash.display.Sprite;
oraz backendowego. import flash.events.Event;
Równie prostym sposobem na weryfikację import flash.net.URLLoader;
źródła pochodzenia danych jest dostarczanie import flash.net.URLRequest;
znaczników czasu podczas wysyłania zapy- import flash.net.URLRequestMethod;
tań – polecam, aby i one były w formie zako- import flash.net.URLVariables;
dowanej. Weryfikacja po stronie serwera mo-
że polegać na sprawdzaniu, czy każdy nowy public class myClass extends Sprite {
znacznik jest większy od poprzedniego. Ko- public function myClass( ) {
lejnym elementem, który jest możliwy do we- var request:URLRequest = new URLRequest( "http://example.com/gateway.php?ac
ryfikacji przy tej metodzie, jest sprawdzanie tion=getDummyData" );
czy zapytania przychodzą w racjonalnych od- request.method = URLRequestMethod.POST;
stępach czasowych stosownych do profilu na- request.data = new URLVariables( );
szej aplikacji. request.data.myVariable1 = 'raz dwa trzy';
Następnym elementem wartym uwagi,
jest stosowanie nieintuicyjnych nazw me- var loader:URLLoader = new URLLoader( );
tod. Jednakże należy się poważnie zastano- loader.addEventListener(Event.COMPLETE, onComplete );
wić nad stosowaniem tej techniki, gdyż może loader.load(request);
ona przysporzyć wiele kłopotów przy robie- }
niu poprawek w aplikacji po dłuższej prze- private function onComplete( event:Event ):void {
rwie lub też na samym etapie debugowania var dataXML:XML = XML( event.target.data );
aplikacji. }
Jeśli istnieje możliwość stosowania mecha- }
nizmu sesyjnego po stronie serwera, jest to }
bardzo naturalne rozwiązanie towarzyszące
wszystkim metodom wymagającym autory- Listing 4. Użycie MING w PHP
zacji. Mankamenty takiego rozwiązania mogą
się pojawić podczas uploadu plików ze strony <?php
Flexa, co można zawsze rozwiązać dosyłając $secretKey = '123456';
identyfikator sesyjny podczas uploadu, który $m = new SWFMovie( );
pozwoli na manualne ustawienie sesji po stro- $m–>add( new SWFAction( "key = '$secretKey';
nie backendu. var sending_lc:LocalConnection = new LocalConnection( );
Bardziej wyrafinowane rozwiązanie za- sending_lc.send( 'lc_name', 'setKey', key );" ) );
bezpieczające komunikację polegać będzie header( 'Content–type: application/x–shockwave–flash' );
na pobieraniu przez Flexa dynamicznie wy- $m–>output( );
generowanego pliku SWF po stronie backen- ?>
du i wykorzystywaniu informacji w nim za-
wartych do dalszego wysyłania danych. Do Listing 5. Obiór klucza we Flexie
tego celu posłużyć może biblioteka MING
w PHP – http://php.net/ming .Idea jest nastę- var l = new Loader( );
pująca: l.load( new URLRequest( 'http://example.com/gateway.php?getSecretKeySwf' ) );

• Flex wysyła zapytanie o wygenerowanie var receivingLC:LocalConnection = new LocalConnection();


dynamicznego SWF–a. receivingLC.client = this;
• Backend generuje bardzo lekki (1kb) plik receivingLC.connect('lc_name');
SWF zawierający unikalny klucz.
• Flex ładuje wygenerowany plik i wyko- function setKey( key ) {
nuje właściwe zapytanie dodając wartość trace( 'dostalem klucz z wczytanego swfa skompilowanego do wersji 8: ', key
pobranego klucza. );
• Backend weryfikuje zgodność kluczy }
podczas obsługi zapytania, dodatkowo

46 FLEX
Flex.Security.allowSecureCommunication(‘*’);

Warto również, po stronie backendu, po- nia żądania na adres http://example.com/gate- wrażliwego kodu, uruchomi aplikację lokal-
kusić się o sprawdzanie adresu URL z którego way.php?action=someAction i zwracana jest nie, jego zapytania będą przychodziły z inne-
przychodzą żądania. Jest to dobry sposób na odpowiedź w formie XML, a całość nie jest go URL’a niż backend powinien się spodzie-
wstępną weryfikację prawdziwości generowa- w żaden sposób zabezpieczona, wówczas za- wać – chyba, że użytkownik będzie na tyle
nych zapytań. danie podmiany danych jest wręcz banalne. dociekliwy, by podmienić nagłówki preparu-
Sytuacja nieznacznie się komplikuje, gdy jąc właściwy adres URL.
Podsłuchiwanie i komunikacja odbywa się za pomocą FlashRe- Stosowanie więcej niż jednego zabezpie-
próby fałszowania komunikacji moting, na przykład wykorzystując AMFPHP. czenia przesyłu danych zdecydowanie odstra-
Zapewne jedną z pierwszych rzeczy, któ- Jednakże i tutaj dla wprawnego oka, dokład- szy większą część osób, które bądź to dla za-
rą zrobi osoba zainteresowana fałszowaniem ne przeanalizowanie RAW_POST_DATA pozwo- bawy, bądź dla konkretnego efektu będą pró-
komunikacji, będzie sprawdzenie, w jaki spo- li na wyłuskanie nazw metod i argumentów. bowały ją zafałszować.
sób ona się odbywa. Najprostszym sposobem Takie informację przydadzą się do napisania
na to jest zainstalowanie wtyczki DataTamper własnej klasy po stronie ActionScript, która FlashMediaServer 3
dostępnej dla przeglądarki Firefox – widok na zasymuluje oryginalną, wykorzystaną w apli- Popularność materiałów wideo w sieci
Rysunku 2. kacji klienckiej. WWW rośnie lawinowo z roku na rok. Nie
W interesujących nas momentach w okien- Kolejnym krokiem, na jaki zapewne zdecy- możemy przejść obojętnie obok faktu, że tak
ku wtyczki widać wszystkie zapytania GET, duje się włamywacz, będzie dekompilacja pli- duża popularność była możliwa tylko dzięki
POST jak również ich treść oraz cookies, któ- ku SWF. Jeżeli będzie on w stanie odnaleźć prostemu, szybkiemu, a zarazem przyjazne-
re również mogą zawierać ciekawe rzeczy jak interesujący go fragment kodu i skutecznie mu dla użytkownika systemowi dostępu do
choćby identyfikator sesyjny. Kolejnym eta- go podmieni, wówczas po kompilacji takie- materiałów video. Pomimo wieloletniej obec-
pem będzie sprawdzenie jak została osadzo- go projektu aplikacja kliencka w krytycznym ności odtwarzaczy multimedialnych na ryn-
na aplikacja, a co za tym idzie odszukanie momencie wyśle sfałszowane dane. Oczywi- ku, takich jak Windows Media Player–Mi-
ewentualnych flashvars. Uzbrojony w ta- ście, to czy backend przyjmie takie zapytanie, crosoftu, czy Quicktime'a firmy Apple, nic
ką wiedzę użytkownik może przystąpić do zależy od tego, czy jakkolwiek będziemy we- nie przyspieszyło rewolucji tak jak format
działania. Jeśli użyto najprostszej formy wy- ryfikować wierzytelność zapytań. Jeśli użyt- plików FLV od Adobe. Jednak wraz ze wzro-
miany danych na przykład w postaci wysyła- kownik po dekompilacji i udanej zamianie stem popularności formatu FLV, pojawił się
problem nieautoryzowanego przechwytywa-
Listing 6. Standardowy plik crossdomain.xml nia plików audio i video (na przykład płatnej
zawartości serwisu internetowego). Istnieje
<cross–domain–policy> wiele sposobów przechwycenia video z pliku
<allow–access–from domain="www.przykladowa_strona.com"> FLV. Rozpoczynając od nasłuchiwania zapy-
</cross–domain–policy> tań HTTP, poprzez wyciąganie pliku z kata-
logu pamięci podręcznej przeglądarki, aż do
Listing 7. Nagłówek odpowiedzi dla pliku crossdomain.xml poklatkowego zapisywania video przez klasę
flash.display.BitmapData.
HTTP/1.1 200 OK Między innymi dlatego też powstał Flash
X–Permitted–Cross–Domain–Policies: none Media Server, który miał być odpowiedzią
Adobe na wyższy poziom ochrony zawartości,
oraz zapotrzebowanie na prawdziwe strumie-
niowanie plików.
Wymiana danych pomiędzy użytkowni-
kiem a serwerem odbywa się domyślnie przez
protokół RTMP (ang. Real Time Messaging Pro-
tocle) autorstwa Adobe. Dotychczas możliwe
było szyfrowanie zawartości przez SSL (ang.
Secure Socket Layer) wykorzystywane przez
protokół RTMPS, jednak od wersji trzeciej
serwera, twórcy zawartości dostali dodatko-
wo nowy protokół RTMPE (ang. Encrypted Re-
al Time Messaging Protocole), który nie wyma-
ga użycia certyfikatów. Dzięki 128 bitowemu
kodowaniu zawartości strumienia i zwiększo-
nej wydajności protokół ten stanie się zapew-
ne popularniejszy od znacznie wolniejsze-
go RTMPS. Dzięki strumieniowemu przesy-
łaniu danych nasze pliki nie są przechowy-
wane w pamięci podręcznej przeglądarki,
a w chronionym obszarze pamięci wewnątrz
Flash Playera, co eliminuje większość zagro-
żeń związanych z popularnymi programami
do przechwytywania plików video.
Flash Media Server 3 oferuje również moż-
liwość zapewnienia bezpieczeństwa naszej
Rysunek 2. Wtyczka DataTamper dla Firefox aplikacji poprzez dopuszczanie jedynie tych

www.sdjournal.org 47
ADOBE FLEX

plików, które pochodzą z autoryzowanego rzyć wszystkich reguł zabezpieczających, je- ror, informujący nas o braku możliwości do-
źródła. Za każdym razem, kiedy plik SWF żeli planujemy niewielką stronę internetową stępu do danych. Oczywiście nie zawsze ma-
zostaje wysłany do klienta, jego kopia rezy- bądź aplikację. Im większy projekt tym więk- my możliwość umieszczenia pliku crossdo-
duje na serwerze. W razie wykrycia różnic sze potrzeby zapewnienia mu bezpieczeń- main.xml w dowolnym miejscu. W tym wy-
w strukturze pliku, serwer odrzuci zapytanie stwa oraz umożliwienia swobodnego dostę- padku z pomocą przychodzi nam metoda
klienta o żądany plik. Oczywiście oprócz te- pu danych zewnętrznych, takich jak doku- flash.system.SecurityloadPolicyFile() ,
go mamy możliwość autoryzacji użytkowni- menty, pliki video i audio, a także w niektó- która pozwala nam określić dokładne położe-
ka przez sumy kontrolne MD5, unikalne klu- rych przypadkach pliki SWF innych autorów, nie pliku. Niestety możliwość wczytania do-
cze, czy przekazanie użytkownika i hasła. znajdujące się w domenach innych niż nasza wolnej ilości plików crossdomain.xml, zwięk-
Te aspekty zostały poruszone we wcześniej- aplikacja. sza ryzyko ingerencji w nasz obszar bezpie-
szej części artykułu, tak więc nie będę ich tu- Domyślnie, plik SWF może wczytywać je- czeństwa, poprzez wczytanie innych pli-
taj rozwijał. dynie te pliki, które znajdują się w tej samej ków crossdomain w trakcie działania nasze-
Dlaczego zatem rozwiązanie to nie stało domenie co nasza aplikacja. Jednak bardzo go programu. Aby zabezpieczyć się przed
się bardzo popularne? Otóż dość poważnym często, w szczególności przy tworzeniu du- taką możliwością, możemy wybrać jedną
problemem okazała się cena, która nierzad- żych serwisów, pojawia się konieczność wy- z dwóch opcji:
ko przewyższała możliwości finansowe nie- świetlania zawartości dostarczanej z innych
których serwisów, szczególnie w sytuacji, serwerów. Aby możliwe było wczytywanie • Zmodyfkować plik crossdomain.xml do-
kiedy ilość połączeń i transfer danych podle- plików znajdujących się w innej domenie, dając do niego znacznik <site–control>
gały ograniczeniom. W odpowiedzi na brak niezbędny jest plik XML o nazwie crossdoma- zawierający atrybut permitted–cross–
taniego rozwiązania powstał serwer RED5. in.xml . Informacje w nim zawarte pozwalają domain–policies .
Rozwiązanie Open Source przedstawiane ja- określić, między innymi, jakie domeny i ad- • Używając nagłówka odpowiedzi HTTP
ko alternatywa dla FMS. Obecnie prowadzo- resy IP mają prawo do pobierania zawartości X–permitted–Cross–Domain–Policies ,
ne są prace nad rozwojem do wersji 1.0 (obec- z serwera, na którym ów plik się znajduje. jak przedstawiono na Listingu 7.
na to 0.7.0), tak więc widać, że determinacja Plik crossdomain przedstawiony na Listin-
twórców w rozwoju tego projektu nie słabnie gu 6. pozwala na wczytanie danych każdemu Pomimo, iż znacznik meta–policy zo-
(więcej na http://osflash.org). plikowi SWF znajdującemu się w domenie stał wprowadzony stosunkowo niedawno,
Na szczęście FMS w wersji trzeciej nie po- przykladowa_strona.com. Jeżeli plik zostanie Adobe zaleca umieszczanie go we wszyst-
siada ograniczeń transferu i limitu jednocze- umieszczony w katalogu głównym domeny kich plikach master policy files, ponieważ ze
snych połączeń co znacząco zwiększa opła- nie musimy martwić się potrzebą wczytywa- względów bezpieczeństwa domyślna war-
calność tego rozwiązania, które oferuje do- nia go, ponieważ przy pierwszej próbie wczy- tość all zostanie zamieniona na none, co mo-
skonałe zabezpieczenia przy niewielkim na- tania danych z domeny, na której znajduje że spowodować utrudnienia w działaniu
kładzie środków, a także odciąża administra- się plik crossdomain.xml, SWF automatycz- już istniejących aplikacji, które korzystają
torów oraz twórców programów, którzy nie nie spróbuje go pobrać. Jeżeli operacja się nie z tych plików. Wszystkie powyższe operacje
muszą wymyślać setek sposobów na ochro- powiedzie, wynikiem będzie błąd SecurityEr- na pliku crossdomain.xml dotyczące znaczni-
nę plików znajdujących się na serwerze. Uży-
wając określenia Flash Media Server w tym
tekście, odnosiłem się do całej rodziny pro-
Opcje konfiguracji znacznika meta–policy w pliku
duktów oferowanych przez Adobe, które crossdomain.xml
pojawiły się wraz z premierą wersji trzeciej
• all –Domyślna konfiguracja. Wszystkie pliki crossdomain.xml są akceptowane.
(więcej na : http://www.adobe.com/products/ • by–content–type – Akceptowane są tylko pliki corssdomain, których nagłówek Content–
flashmediaserver/). Type to text/x–cross–main–policy . Tylko dla serwerów HTTP i HTTPS.
• by–ftp–filename – Akceptowane pliki, których adres URL kończy się na /crossdomain.xml.
Bezpieczeństwo Tylko dla serwerów FTP.
od strony developera • master–only – Jedynym możliwym plikiem crossdomain.xml, będzie tak zwany master poli-
cy file, czyli plik crossdomain.xmli znajdujący się w katalogu głównym domeny.
W pierwszej części artykułu zostały prze- • none – Żadne pliki crossdomain.xml nie są akceptowane. Jeżeli umieścimy takowy w kata-
analizowane dodatkowe metody zabezpie- logu głównym aplikacji, będzie on mógł zawierać jedynie znacznik meta–policy, wszystkie
czenia danych przesyłanych pomiędzy użyt- inne będą ignorowane.
kownikiem a serwerem. Czy oznacza to, że • none–this–response – dostepny tylko dla nagłówka odpowiedzi HTTP, uniemożliwiający in-
firma Adobe nie wyposażyła Flash Playera terpretację zwrotu jako pliku crossdomain. Dotyczy to tylko aktualnie przychodzącego na-
główka i nie wpływa na wczytywanie innych plików crossdomain.
w odpowiednie narzędzia bezpieczeństwa?
Wręcz przeciwnie. Wraz z pojawianiem się
kolejnej rewizji Flash Playera twórcy forma-
tu SWF starają się ulepszyć sposoby ochrony Listing 8. Przykładowy znacznik allow–http–request–headers–from
danych oraz maksymalnie ograniczyć możli-
wości nieautoryzowanego dostępu do działa- <allow–http–request–headers–from domain="www.przykladowa_strona.com" headers="Moj–
jącego programu. Naglowek"/>
Każdy plik SWF posiada swój własny ob-
szar bezpieczeństwa, w obrębie którego Listing 9. Przykładowy plik crossdomain dla połączeń typu Sachet
możemy poruszać się bez większych prze-
szkód przesyłając dane, nazywany powszech- <cross–domain–policy>
nie sandboxem (ang. Piaskownica). Podsta- <allow–access–from domain="www.przykladowa_strona.com" secure="true" to–
wowo zdefiniowana ilość możliwych ope- ports="3050"/>
racji jest ściśle ograniczona do niezbędne- </cross–domain–policy>
go minimum, tak abyśmy nie musieli two-

48 FLEX
Flex.Security.allowSecureCommunication(‘*’);

ka meta–policy dotyczą pliku master policy fi- zezwala na nawiązanie połączenia z portem na komunikację pomiędzy dwoma plikami
le, czyli znajdującego się w głównym katalo- czy przesłanie danych, jeżeli zapytanie nie SWF, znajdującymi się na komputerze użyt-
gu domeny. pochodzi z bezpiecznego protokołu HTTPS. kownika.
Flash Player od wersji 9 oferuje możliwość Dla połączeń HTTPS domyślną wartością jej Klasa LocalConnection umożliwia na na-
wysyłania własnych nagłówków HTTP. Jest true, Adobe zaś nie zaleca zmiany jej zamia- wiązanie połączenia pomiędzy dwoma uru-
to kolejna okazja, aby wydobyć informacje ny na false. chomionymi plikami SWF (nawet jeżeli znaj-
z naszej aplikacji. Aby temu zapobiec, moż- Kiedy jesteśmy już pewni, że zabezpie- dują się one w odrębnych oknach przeglądar-
liwości konfiguracji pliku crossdomain zosta- czyliśmy się przed nieautoryzowanymi pró- ki) i jest jedynym sposobem na komunikację
ły wzbogacone o znacznik allow–http–requ- bami pobierania zawartości naszego serwe- pomiędzy plikami SWF starszych wersji ob-
est–headers–from , który pozwala nam okre- ra, a zarazem zapewniliśmy bezproblemo- sługiwanych przez pierwszą wersję maszyny
ślić domenę, z której będą akceptowane przy- we działanie naszej aplikacji, powinniśmy za- wirtualnej AVM1. Jest to kolejna okazja do
chodzące nagłówki, oraz ich dokładny typ. pobiec próbom spenetrowania naszego ko- niepożądanego dostępu do aplikacji, jeżeli
Przykładowy wygląd tego znacznika przed- du przez inne pliki SWF, a także udostęp- nierozważnie będziemy rozporządzać prawa-
stawiono na Listingu 8. nić możliwość komunikacji naszego progra- mi dostępu do naszej aplikacji. Sposoby kon-
Wraz z pojawieniem się rewizji Flash Play- mu z innymi plikami SWF, jeżeli jest to wy- troli przesyłanych tą drogą informacji, działa-
era 9.0.115, nastąpiła zmiana w dostępie magane. Aby umożliwić bądź zablokować ją podobnie jak przy wczytywaniu zewnętrz-
do danych poprzez klasę Socket, służącą do wymianę informacji, tak zwany cross–scrip- nych plików SWF i składają się na nie metody
przesyłania binarnych danych na wskazanym ting, korzystamy przede wszystkim z meto- LocalConnection.allowDomain() oraz Loca
przez nas porcie. Dzięki niej mamy możli- dy flash.system.Security.allowDomain lConnection.allowInsecureDomain() .
wość napisania na przykład własnego klienta (). Pozwala ona na dostęp wczytanego pli- Pomimo wszystkich tych możliwości, oso-
pocztowego. Dotychczas do kontroli upraw- ku SWF do pliku wczytującego. Dla przy- by o dostatecznie dużej determinacji znaj-
nień dla tej klasy wystarczył plik crossdoma- kładu, jeżeli chcemy zareagować na zdarze- dą drogę dostępu do naszej aplikacji. Dlate-
in.xml, jednak ze względów bezpieczeństwa nie Event.RESIZE, nie będziemy w stanie te- go też ciągle staramy się wymyślać nowe, bar-
postanowiono odseparować te dwa typy połą- go zrobić, jeżeli główny plik aplikacji nie ze- dziej efektywne zabezpieczenia i utrudnie-
czeń. Obecnie, zanim zostanie nawiązane po- zwoli nam na dostęp. Oczywiście pojawia się nia dostępu osobom niepożądanym. Nawet
łączenie z serwerem (nawet jeżeli plik SWF problem, jeżeli w chwili kompilacji nie zna- pomimo nieudanych prób wstrzyknięcia ko-
należy do tej samej domeny) sprawdzana my dokładnego adresu IP lub domeny, z któ- du do naszego programu, nasze pliki SWF,
jest obecność pliku autoryzującego znajdu- rej będzie wczytywany plik SWF. W takiej sy- mogą zostać poddane próbie dekompilacji
jącego się domyślnie na porcie 843 (podob- tuacji możemy adres takiej domeny przeka- i późniejszej kompilacji ze zmodyfikowanym
nie jak plik crossdomain.xml domyślnie powi- zać w obiekcie flashvars podczas osadza- wewnątrz kodem. Obecnie dekompilacja pli-
nien znajdować się w katalogu głównym do- nia pliku SWF bądź wykorzystać informacje ków SWF powstałych przy użyciu Flex Fra-
meny), możliwe jest wysłanie ów pliku z do- z obiektu loaderInfo, aby przyznać dostęp mework nie jest jeszcze taka prosta, jednak
wolnego dostępnego portu, jednak podobnie adresowi przechowywanemu w zmiennej jest to tylko kwestią czasu, zanim powstanie
jak w wypadku połączeń przez HTTP musi- url. Niestety oba te rozwiązania niosą ze so- odpowiednie komercyjne rozwiązanie, gdyż
my wczytać plik samodzielnie poprzez me- bą wysokie ryzyko łatwej modyfikacji obu ad- dekompilacja plików SWF kompilowanych
todę loadPolicyFile(). Format pliku auto- resów, tak więc są tutaj bardziej przykładem, w środowisku IDE Flasha jest już możliwa.
ryzującego połączenia portów jest taki sam niż zalecanym rozwiązaniem. Na szczęście Dlatego też pamiętajmy, aby nasze aplikacje
jak pliku autoryzującego połączenia HTTP w większości przypadków znamy adres do- zawierały możliwie jak najmniej informacji,
i HTTPS, z jedną małą różnicą, którą przed- meny, która będzie chciała komunikować się które umożliwiłyby dostęp do danych nasze-
stawia Listing 9. z naszym plikiem SWF, tak więc dynamiczne go serwera, bądź ich modyfikację.
Znacznik to–ports określa port bądź za- przyznawanie dostępu plikom SWF, nie jest Stworzenie aplikacji całkowicie odpornej
kres portów, do których nasza aplikacja tutaj standardem. na ataki jest praktycznie niemożliwe, jed-
otrzyma dostęp. Podobnie do połączeń przez Podobnie do powyższej metody działa flas nak dzięki świadomemu i rozważnemu ko-
HTTP, połączenia poprzez porty również po- h.system.Security.allowInsecureDomain(), rzystaniu z reguł bezpieczeństwa i dostępu,
siadają możliwości kontrolowania, które pli- z tą różnicą jednak, że w tym wypadku zezwa- już z pomocą standardowych narzędzi jeste-
ki autoryzacyjne powinny być zaakceptowa- lamy na dostęp do plików SWF dostępnych śmy w stanie choć trochę utrudnić penetra-
ne. Znacznik meta–policy w tym wypadku przez HTTPS plikom SWF dostępnym przez cję stworzonej aplikacji. Dużo lepszym wy-
ma mniej możliwości konfiguracji. protokół HTTP. Oczywiście taką komunikację borem będzie spojrzenie do plików pomocy,
Zamykając temat plików autoryzacyjnych, otwieramy na własną odpowiedzialność, z peł- czy rozbudowanej dokumentacji udostępnia-
należy wspomnieć o jeszcze jednym elemen- ną świadomością faktu, że osłabiamy tym sa- nej przez Adobe, niż posługiwanie się asteri-
cie, który jest wspólny dla połączeń przez mym bezpieczeństwo naszej aplikacji. skiem (*) przy przyznawaniu praw dostępu
HTTP i porty. Atrybut secure dla znacznika Pomimo ścisłej kontroli domen, z których do danych na serwerze i aplikacji.
allow–access–from, jeżeli ustawiony na true, pliki SWF mogą komunikować się z naszym
<allow–access–from secure='true'>, nie programem, istnieje jeszcze jeden sposób
ŁUKASZ ZMYWACZYK
Development Team Leader w agencji T-SIGN STU-
Opcje konfiguracji znacznika meta–policy w pliku autoryzacyjnym DIOS.
dla połączeń przez klasę Socket Kontakt: L.Zmywaczyk@gmail.com

• all –Domyślna konfiguracja. Wszystkie pliki autoryzacyjne dla połączeń przez porty są ak-
ceptowane. JAKUB MATUSZEWSKI
• master–only – Jedynym możliwym plikiem będzie tak zwany socket master policy file, czyli Senior Flash Developer oraz Development Team Le-
plik crossdomain dostepny przez port 843. ader w agencji T–SIGN STUDIOS. Z ActionScriptem
• none – Żadne pliki autoryzacyjne dla portów nie są akceptowane. związany od 5 lat.
Kontakt: jacob@t–sign.com

www.sdjournal.org 49
ADOBE FLEX

Test Driven Development


Testuj kod zanim go napiszesz

Człowiek jest niewinny dopóty, dopóki nie udowodni mu się winy.


Analogicznie, aplikacja Flex nie zawiera błędów dopóty, dopóki się ich
nie znajdzie. Jak zatem zorientować na sukces proces produkcyjny takich
aplikacji?

Rational Unified Process), który ma korzenie


Dowiesz się... Powinieneś wiedzieć... w USDP (ang. Unified Software Development Pro-
• Co to jest TDD, dlaczego i kiedy warto używać • Jak pracuje się ze środowiskiem FlexBuilder 3. cess) i jest reprezentantem metodyk ciężkich. XP
tej techniki. jako uznana metodyka zwinna, zaczęła perma-
• Jak używać biblioteki FlexUnit. nentnie dążyć do skracania faz produkcyjnych,
i tak m.in. powstał pomysł na to, aby zautoma-
tyzować testowanie poprzez wprowadzenie te-
TDD a Flex stów jednostkowych (nazwa bierze się z testo-
Termin TDD pojawił się niedługo po ukuciu wania danej jednostki, jaką jest metoda – funk-
Poziom trudności i rozpowszechnieniu się terminu XP (ang. eXtre- cja lub klasa) oraz przeniesienie fazy testowa-
me Programming), jednej z bardziej popular- nia na początek fazy implementacji, a docelowo
nych metodyk lekkich (inaczej zwanych zwin- zmusić programistę, aby pisał przypadki testo-
nymi – ang. agile) wytwarzania oprogramowa- we przed napisaniem właściwego kodu aplikacji

T
echnologia Flex i język programowa- nia, które kładą nacisk na dostarczanie kliento- programowej. W skrócie, programista powinien
nia ActionScript wdzierają się do roz- wi artefaktów programowych, zamiast papiero- opisywać i precyzować na początku, czego ocze-
wiązań korporacyjnych na tyle szybko, wych tj. dokumentacji – która w XP ma formę kuje po działaniu przyszłego kodu, zanim zaj-
że coraz częściej zespoły wytwarzające oprogra- szczątkową w porównaniu m.in. do RUP (ang. mie się jego pisaniem. W porównaniu do trady-
mowanie w oparciu o Flex, stosują znane me-
todyki programowania, używane w innych
Listing 1. Przypadek testowy
środowiskach/technologiach wytwarzania od
dosyć dawna. Same przez siebie niejako nobi- public class SampleTest extends TestCase //przypadek testowy
litują one Flexa, pokazując, że jest on w stanie
podołać skomplikowanym wdrożeniom RIA, {
absorbującym duże zespoły projektowe i pro- public function SampleTest(methodName : String = null) {
dukcyjne. super(methodName);
Biorąc pod uwagę fakt kompleksowości apli- }
kacji Flex, która bierze się między innymi z du- public static function suite():TestSuite {
żej liczby możliwych ścieżek kolaboracji mię- var sampleTS:TestSuite = new TestSuite(); // zestaw testowy
dzy odrębnymi obszarami funkcjonalnymi sampleTS.addTestSuite(SampleTest);
– wydaje się, że nie powinno się zakładać z gó- accountTS.addTest(new SampleTest("testA"));
ry, że oprogramowanie danych funkcjonalno- return sampleTS;
ści w kontekście jednostkowych pakietów, klas, }
a ostatecznie wyrażeń behawioralnych będzie public function testA():void { // metoda testowa
pozbawione błędów. Dlatego poszukiwano var sample:Sample = new Sample();
sposobu na automatyzację wykrywania błędów assertEquals("Expecting zero", 0, sample.getBalance()); // asercja
w funkcjonowaniu aplikacji w możliwie naj- }
wcześniejszych fazach produkcyjnych, co jest
szczególnie ważne przy wytwarzaniu aplikacji override public function setUp():void {
zorientowanym na klienta, które zakłada pro- }
gresywną realizację funkcjonalności przy moż-
liwie najkrótszych iteracjach. Na takim tle po- override public function tearDown():void {
wstał pomysł na TDD (ang. Test Driven Develop- }
ment), czyli na wytwarzanie oprogramowania }
zorientowanego na testy.

50 FLEX
Test Driven Development

cyjnego procesu wytwarzania oprogramowania, pisać przede wszystkim, z łatwości zaadaptowa- wierać przeciążone dwie metody setUp() oraz
w którym testy (czy to weryfikacyjne, walidacyj- nia procesu produkcyjnego pod nią oraz z do- tearDown(), które służą do ustawiania warto-
ne, wydajnościowe, czy to ilościowe) są przepro- syć dużej liczby narzędzi wspierających jej sto- ści obiektów niezbędnych dla środowiska, w któ-
wadzane zazwyczaj w końcowych fazach proce- sowanie w praktyce. rym wykonuje się przypadek testowy przed wy-
su wytwarzania oprogramowania z domniema- Słuszność tej tezy potwierdza się również konaniem testu setUp() oraz po jego zakończe-
niem sukcesu, o którym była mowa wyżej, była w przypadku wytwarzania oprogramowania niu tearDown(). Metody te ułatwiają m.in. inicja-
to koncepcja nadzwyczaj rewolucyjna, ale jak się w oparciu o technologię Flex, dla której najbar- cję wspólnego zbioru obiektów dla więcej niż jed-
później okazało słuszna. Ze zdroworozsądkowego dziej popularnym w tej chwili frameworkiem nego przypadku testowego (patrz na Listing 1.).
punktu widzenia, wydawało się od razu, że pro- testów jednostkowych pozwalającym na stoso-
gramiści będą mieć większy zapał, aby pisać te- wanie idei TDD jest FlexUnit. Zestaw testowy (ang. test suite)
sty na początku fazy wdrożenia, niż w kolejnych Służy do grupowania przypadków testowych
fazach. Każdy z nas ma najwięcej zaangażowania Zanim zaczniemy oraz innych zestawów testowych. Agregacja wy-
na początku prac, najmniej na żmudnym końcu, Przed rozpoczęciem instalacji oraz stworze- branych testów w zestaw testowy jest niezbęd-
kiedy należy poprawiać i poprawiać, i nie zawsze niem przykładowych przypadków testowych, na dla możliwości zadeklarowania, jakie testy
wiadomo, gdzie się popełniło błąd. Kod tworzo- musimy zrozumieć podstawowe terminy me- mają się wykonać w danej sesji.
ny wedle ścisłych reguł umożliwiających auto- todyki TDD.
matyzację testowania oraz przypadków testo- Asercja (ang. assertion)
wych będzie łatwiejszy w pielęgnacji i rozbudo- Przypadek testowy (ang. test case) Predykat to wyrażenie behawioralne, któ-
wie. TDD nie jest metodyką testowania, ale uży- Przypadek testowy to najmniejsza jednostka te- re zwraca prawdę lub fałsz, umieszczamy go
wania testów w celu wytwarzania oprogramowa- stowa, która sprawdza poprawność wartości, ja- w pewnym miejscu w kodzie przypadku testo-
nia w sposób przyrostowy i zorientowany na me- ką zwraca test na wyjściu, biorąc pod uwagę war- wego. Wskazuje on, że programista zakłada, że
todyki lekkie. Owe używanie testów w procesie tość, która pojawia się na jego wejściu. Przypa- dany warunek jest prawdziwy. W przypadku,
produkcyjnym powinno mieć cykl zaprezento- dek testowy w kontekście elementów języka Ac-
wany na Rysunku 1. tionScript stanowi klasę, która dziedziczy po kla-
Utylitarność metodologii TDD bierze się nie sie TestCase i ma konstruktor, który wywołu-
tylko z faktu, niezaprzeczalnych atutów płyną- je za pomocą metody super() konstruktor kla-
cych z teorii, ale również, a być może należy na- sy bazowej. Klasa przypadku testowego może za-

Rysunek 2. Flex Builder 3

�����������

����
������������

Rysunek 3. Tworzenie nowego projektu

����������

������������������
������������

Rysunek 1. Cykl TDD Rysunek 4. Dodanie zewnętrznej biblioteki

www.sdjournal.org 51
ADOBE FLEX

gdy predykat jest fałszywy, (czyli niespełnio-


ne są warunki postawione przez programistę) Listing 2. Operator testu
asercja powoduje przerwanie wykonania pro- <?xml version="1.0" encoding="utf-8"?>
gramu. Asercja jest realizowana za pomocą me- <mx:Application
tod np. assertEquals (message, input – war- xmlns:mx="http://www.adobe.com/2006/mxml"
tość oczekiwana, output – wartość aktualna), xmlns:flexunit="flexunit.flexui.*"
które sprawdzają poprawność predykatów. creationComplete="onCreationComplete()">
<mx:Script>
Operator testu (ang. test runner) <![CDATA[
Jest to komponent uruchomieniowy zestawów private function onCreationComplete():void
testów bądź przypadków testowych. Ma on gra- {
ficzny interfejs oraz pozwala zaprezentować testRunner.test =CartTest.suite();
wykonywanie się zadeklarowanych przypad- testRunner.startTest();
ków testowych. Robimy to przypisując do pa- }
rametru test komponentu TestRunner zestaw ]]>
testowy. Uruchamia się go używając metody </mx:Script>
startTest() komponentu TestRunner. <flexunit:TestRunnerBase id="testRunner" width="100%" height="100%" /> // operator
Przykład znajduje się na Listingu 2. testu
</mx:Application>
No to zaczynamy!
Pierwsze co musimy zrobić to pobrać źródła bi- Listing 3. Klasa zawierająca przypadek testowy
blioteki FlexUnit. Znajdują się one pod adresem: package
http://labs.adobe.com/wiki/inde x.php/ {
ActionScript_3:resources:apis:libraries#FlexUnit. import flexunit.framework.TestCase;
Instalacja ogranicza się do rozpakowania ar- import flexunit.framework.TestSuite;
chiwum. Ja wypakowane pliki umieściłem
w katalogu: D:\Programowanie\flexDev\flex public class CartTest extends TestCase
Unit. Po rozpakowaniu archiwum w katalogu {
flexUnit znajdą się katalogi bin, docs i src oraz public function CartTest(methodName : String){
plik z licencją (license.txt). super(methodName);
}
Przykładowy projekt
Stworzymy klasę obsługującą prosty koszyk public static function suite():TestSuite{
w sklepie internetowym. Każdy, kto chociaż var cartTS:TestSuite = new TestSuite();
raz odwiedził taki sklep zauważy, że jest ona //tutaj umieścisz testy
trywialna i brakuje jej wielu niezbędnych funk- return cartTS;
cjonalności, jednak wystarczy do zrozumienia, }
jak tworzy się aplikacje za pomocą TDD. }
Do stworzenia przykładowej aplikacji wyko- }
rzystałem środowisko Flex Builder 3.
Do pobrania z https://www.adobe.com/ Listing 4. Klasa, którą będziemy testować
cfusion/tdrc/index.cfm?product=flex lub dostęp- package
ne na DVD. {
public class Cart
Utworzenie nowego projektu {
Z menu File wybieramy pozycję New/Flex Pro- public function Cart(){
ject. Otworzy się okno kreatora (Rysunek 3.), }
w pierwszym kroku należy nadać nazwę pro- }
jektowi, np. TDD Tests. }
Możesz też zmienić domyślny katalog, w któ-
rym będzie zapisany projekt, na jakiś dowolnie Listing 5. Test nr 1
wybrany odznaczając pozycję Use default loca- public function testNew():void{
tion. Pozostałe opcje pozostaw bez zmian i na- var cart:Cart = new Cart();
ciśnij Next. W kolejnym kroku ustaw katalog, assertEquals("Nic nie powinno być w koszyku", 0, cart.getQuantity());
gdzie będą zapisywane skompilowane pliki. Tu }

Listing 6. Metoda suite()


public static function suite():TestSuite{
var cartTS:TestSuite = new TestSuite();
cartTS.addTest(new CartTest("testNew"));

return cartTS;
}
Rysunek 5. Pierwszy błąd

52 FLEX
Test Driven Development

taj możesz nic nie zmieniać i przejść od razu Zawiera też jedną statyczną metodę suite(), a w tym konkretnym przypadku poda 0. Czyli
do kolejnego kroku (przyciskając Next). W tym która w wyniku swojego działania zwraca ze- masz już założenia do pierwszego testu.
kroku ustawimy ścieżki do zewnętrznych bi- staw testowy. W TDD piszesz najpierw test, a dopiero póź-
bliotek – czyli w tym przypadki do FlexUnit. niej testowaną metodę. Test umieść w funkcji
Wybierz zakładkę Library path i naciśnij przy- Utworzenie klasy koszyka testNew() w pliku CartTest.as (Listing 5.).
cisk Add SWC (Rysunek 4.). Wskaż plik flexu- Oczywiście musisz utworzyć jeszcze klasę, któ- Funkcja testująca tworzy nową zmienną kla-
nit.swc, znajduje się on w podkatalogu bin, kata- rą będziesz testować. Umieść ją w pliku Cart.as sy Cart oraz ustanawia nową asercję metodą
logu flexUnit. Teraz możesz już wcisnąć Finish Na początku będzie ona bardzo prosta jak na assertEquals(). Metoda ta ma trzy parametry:
– projekt został utworzony. Listingu 4.
assertEquals(„Nic nie powinno być w
Utworzenie pliku main.mxml Pierwszy test koszyku”, 0, cart.getQuantity());
Plik MXML dla tego przykładu znajduje się już Kiedy pierwszy raz wchodzisz do sklepu in-
w części opisującej operatora testu (test runner), ternetowego, Twój koszyk jest na początku pu- String Nic nie powinno być w koszyku to po pro-
Listing 2. W pliku tym przede wszystkim: sty. Jest to oczywiste, nie zdążyłeś jeszcze wy- stu komentarz dodany w celach informacyj-
brać niczego co chciałbyś kupić. Jednak, aby się nych. 0 to wartość, jaką powinna zwrócić testo-
• tworzymy nową przestrzeń nazw dla na- o tym przekonać potrzebna jest metoda, która wana metoda, a cart.getQuantity() to wła-
szej aplikacji, poda ilość towarów znajdujących się w koszyku, śnie testowana metoda.
• przypisujemy metodę onCreationComlete
do zdarzenia creationComplete ,
• umieszczamy instancję komponentu
TestRunnerBase .

Stworzenie nowej przestrzeni nazw:

xmlns:flexunit="flexunit.flexui.*"

Kod tworzy przestrzeń nazw flexunit, któ-


ra jest powiązana z pakietem flexunit.flexui.
Masz dostęp do tego pakietu, ponieważ doda-
łeś plik flexunit.swc do projektu.
Aby umieścić instancję komponentu Test
RunnerBase, wystarczy wpisać taką linijkę:

<flexunit:TestRunnerBase id="testRunner" />

Gdybyś inaczej nazwał przestrzeń nazw, rów-


nież ta linia wyglądałaby inaczej:

<jakas_nazwa:TestRunnerBase id="testRunner" />

Komponent TestRunnerBase to nasz operator


testu (ang. test runner), dlatego przypisaliśmy
mu odpowiednie ID.
Przejdźmy do metody onCreationComle Rysunek 6. Odwołanie do nieznanej metody
te(). Jest ona wywoływana przez zdarzenie
creationComplete i robi dwie rzeczy. Wczytu-
je testy do naszego operatora:

testRunner.test =CartTest.suite();

i uruchamia je:

testRunner.startTest();

Utworzenie zastawu testowego


Teraz utworzysz plik ActionScript o nazwie
CartTest.as, w którym będziesz umieszczać te-
sty – Listing 3.
Jak zauważyłeś nasza klasa (CartTest) roz-
szerza klasę TestCase z pakietu FlexUnit. Jej
konstruktor wywołuje konstruktor klasy ma-
cierzystej, wysyłając mu nazwę jakiejś metody:

super(methodName); Rysunek 7. Okno operatora testu

www.sdjournal.org 53
ADOBE FLEX

Metoda assertEquals() porównuje otrzy- Przejdź zatem do etapu 3 z Rysunku 1. i na- śmy wartości 0, a otrzymaliśmy NaN (Not
many wynik działania z zakładanym. pisz odpowiednią metodę w klasie Cart. Będzie a Number). Aby go poprawić, wystarczy nadać
Aby test został wykonany, musisz go jeszcze ona teraz wyglądała tak jak na Listingu 7. zmiennej _quantity wartość 0 podczas two-
dodać do zestawu. Dopisz poniższy kod do me- Utworzyłeś zmienną quantity i napisałeś rzenia nowej zmiennej tej klasy, czyli w kon-
tody suite() w pliku CartTest.as metodę getQuantity(), która zwraca jej war- struktorze:
tość. Skompiluj ponownie projekt. Powinieneś
cartTS.addTest(new CartTest("testNew")); otrzymać rezultat jak na Rysunku 7. public function Cart(){
Operator wykonał pierwszy test, który za- _quantity = 0;
Czyli dodajesz test (nową zmienną klasy kończył się niepowodzeniem. Oczekiwali- }
CartTest – tej, w której właśnie jesteś) do
zestawu za pomocą metody addTest(). Ja- Listing 8. Test ilości przedmiotów w koszyku
ko parametr dla konstruktora podajesz na-
zwę funkcji testującej (w konstruktorze: public function testAddNewItem():void{
super(methodName);). var cart:Cart = new Cart();
Teraz metoda suite() powinna wyglądać var newItem:Object = {id:731, name:"Książka", price:26.80};
tak jak na Listingu 6. cart.addItem(newItem);
Pierwszy etap projektowania aplikacji masz już assertEquals("Powinien być jeden przedmiot", 1, cart.getQuantity());
za sobą (Rysunek 1.). Aby przejść do następnego, }
skompiluj i uruchom aplikację [Ctrl] + [F11].
Powinieneś otrzymać raport o pierwszym Listing 9. Dodajemy nowy test
błędzie (Rysunek 5.). Przyczyną jest oczywi- public static function suite():TestSuite{
ście to, że nie zaimplementowałeś jeszcze testo- var cartTS:TestSuite = new TestSuite();
wanej metody (Rysunek 6.). cartTS.addTest(new CartTest("testNew"));
cartTS.addTest(new CartTest("testAddNewItem"));
return cartTS;
}

Listing 10. Wprowadzamy zmiany do pliku Cart.as


package
{
public class Cart
{
private var CartItems:Array = new Array();
public function Cart(){
Rysunek 8. Okno operatora testu – test zaliczony
}
public function getQuantity():Number{
return CartItems.length;
}
public function addItem(item:Object):void{
CartItems.push(item);
}
}
}

Listing 11. Testujemy i wprowadzamy nowe funkcjonalności


Rysunek 9. Wynik czwartego testu public function testAddItemAndCalc():void{
var cart:Cart = new Cart();

Listing 7. Piszemy metodę w klasie Cart var newItem:Object = {id:731, name:"Książka", price:26.80};
cart.addItem(newItem);
package newItem = {id:945, name:"Płyta", price:32.50};
cart.addItem(newItem);
{ assertEquals("Powinienny być dwa przedmioty", 2, cart.getQuantity());
public class Cart assertEquals("Wartość towarów w koszyku", 59.30, cart.getValue());
{ }
private var _quantity:Number;
public function Cart(){ Listing 12. Dodajemy kolejną metodę do klasy Cart
} public function getValue():Number{
public function getQuantity(): var val:Number = 0;
Number{ for(var i:int = 0; i<CartItems.length; i++){
return _quantity; val += CartItems[i].price;
} }
} return val;
} }

54 FLEX
Test Driven Development

Skompiluj projekt ponownie. Tym razem test Kolejną funkcjonalnością, jaką dodamy do Po kompilacji ponownie otrzymałeś błąd in-
powinien zostać zaliczony (Rysunek 8.). naszego koszyka, będzie podanie wartości na- formujący o braku metody w klasie Cart. Tym
Udało ci się przejść pełny cykl TDD, w wy- szych zakupów. Dodajmy też jeszcze jeden razem chodzi o metodę getDiscountValue().
niku czego napisałeś klasę poprawnie inicjali- przedmiot, aby sprawdzić czy poprawnie jest Obliczy ona cenę towarów po rabacie i zwróci
zującą koszyk. obliczana wartość całego zamówienia. Zacznie- jej wartość. Procent rabatu przekażemy do me-
my oczywiście od testu (Listing 11.). tody jako parametr (Listing 14).
Kolejne testy W tym teście wprowadziliśmy dwie asercje. Skoro funkcja jest gotowa, skompiluj projekt.
Teraz przydałoby się coś wrzucić do koszyka. Pierwsza sprawdza ilość towarów w koszyku, Powinieneś uzyskać efekt podobny do tego
Napiszmy więc test, który doda jakiś towar do a druga ich łączną wartość. Dodaj jeszcze test z Rysunku 9. Test zwrócił błąd:
koszyka i sprawdzi ile przedmiotów się w nim od zbioru, umieszczając kolejną linie w meto-
znajduje po tej operacji (Listing 8.). A następ- dzie suite(): Error: Wartość towarów po udzieleniu rabatu
nie dodajmy nowy test do zestawu wg Listingu 15% - expected:<50.41> but was:<50.405>
9. Oczywiście po kompilacji otrzymasz błąd: cartTS.addTest(new CartTest("testAddItemAnd
Calc")); Czyli rabat jest obliczony poprawnie, jednak
Error: Powinien być jeden przedmiot - cenę należy zaokrąglić do pełnych groszy. Za-
expected:<1> but was:<0> Po kompilacji otrzymasz znany już błąd o bra- tem musisz dodać odpowiednie obliczenia do
ku metody w klasie Cart , czyli należy ją dopi- naszej metody (Listing 15.).
Jest to spowodowane tym, że w klasie Cart sać wg Listingu 12. Skompiluj projekt jeszcze raz. Teraz wszyst-
nie ma jeszcze metody addItem(). Dopiszmy Po kompilacji testy powinny wykonać się po- ko powinno być już w porządku.
ją zatem. W tym momencie zauważysz też prawnie.
błąd w początkowych założeniach klasy Cart. Załóżmy, że projektowany przez nas sklep bę- Podsumowanie
Bardziej logiczne byłoby utworzenie tablicy, dzie udzielał rabatów niektórym klientom. Na- Na tym prostym przykładzie powinieneś zro-
gdzie będą zapisywane kolejne przedmioty. pisz zatem test, który sprawdza poprawność zumieć technikę TDD. Oczywiście w prak-
W takim przypadku nie będzie już potrzeb- obliczenia rabatu 15%, tak jak na Listingu 13. tyce będziesz ją wykorzystywał do progra-
na zmienna _ quantity, ponieważ zawsze mo- Dodaj go do zestawu dopisując linię: mowania bardziej skomplikowanych rze-
żemy odczytać długość takiej tablicy. Wpro- czy. Przekonałeś się, jak można programo-
wadź zatem zmiany do pliku Cart.as wg Li- cartTS.addTest(new CartTest("testPriceWithD wać od tyłu – najpierw sprawdzając wynik,
stingu 10. iscount")); a później pisząc i poprawiając kod generują-
Skompiluj projekt. Tym razem nie powinie- cy. Przy projektowaniu dużych i skompliko-
neś otrzymać żadnych błędów. do metody suite() w klasie CartTest . wanych aplikacji technika ta może okazać się
nieoceniona, skracając i upraszczając pracę
Listing 13. Test obliczeń rabatu programistów.

public function testPriceWithDiscount():void{ Słowniczek stosowanych terminów

var cart:Cart = new Cart(); • Test jednostkowy (ang. unit test) – to w pro-
var newItem:Object = {id:731, name:"Książka", price:26.80}; gramowaniu obiektowym, a w szczegól-
cart.addItem(newItem); ności programowaniu ekstremalnym kod,
newItem = {id:945, name:"Płyta", price:32.50}; który uruchamia fragment testowanego
cart.addItem(newItem); programu i porównuje jego wynik z oczeki-
assertEquals("Wartość towarów po udzieleniu rabatu 15%", 50.41, cart.getDiscountVa wanym;
lue(15)); • eXtreme programming (XP) – programo-
} wanie ekstremalne jest reprezentantem
zwinnych metodyk programowania (ang.
Listing 14. metoda getDiscountValue() obliczy cenę towarów po rabacie i zwróci jej wartość agile), która kładzie nacisk na dostar-
public function getDiscountValue(discount:Number):Number{ czanie klientowi funkcjonalności przy
szczątkowej formie dokumentacji;
var val:Number = getValue(); • Test Driven Development (TDD) – jest
val -= val * (discount/100); techniką wytwarzania oprogramowania
return val; w kontekście zwinnej metodyki XP zo-
} rientowaną na iteracje oraz przypadki te-
stowe. Podstawowa zasada – testuj kod
Listing 15. Szlifujemy metodę, tak by zaokrąglała cenę do pełnych groszy zanim go napiszesz;
public function getDiscountValue(discount:Number):Number{ • FlexUnit – jest frameworkiem testów
jednostkowych dla języka programowa-
var val:Number = getValue(); nia ActionScript 3.0 oraz środowiska
var roundVal:Number = 0; Flex.

val -= val * (discount/100);


roundVal = Math.round(val * 100)/100;
PAWEŁ CICHOŃ,
return roundVal; TOMASZ KULCZYCKI
} Janmedia Interactive
http://www.janmedia.pl/

www.sdjournal.org 55
ADOBE FLEX

Adobe Cairngorm
Framework architektoniczny dla Adobe Flex

Niezaprzeczalnymi faktami potwierdzającymi to, że aplikacje Internetowe


będą miały coraz większe znaczenie, a dla nas programistów wiedza na ich
temat będzie coraz bardziej potrzebna, są działania największych graczy
rynku Internetowego.

• Możemy programować równolegle z wielo-


Dowiesz się... Powinieneś wiedzieć... ma programistami, mając jasny podział ról
• O najpopularniejszym frameworku MVC dla • Wymagana jest znajomość zasady działania i odpowiedzialności, wykorzystując usta-
platformy Adobe Flex. wzorca MVC. loną komunikację między warstwami na-
• Jaka jest jego zasada działania. • Wiedza na temat wzorców projektowych i za- szego projektu.
• Jak wykonać przykładowy projekt wykorzy- sad programowania obiektowego.
stując Adobe Cairngorm. Cairngorm jest z natury lekkim framewor-
kiem (obciążenie klasami tego frameworka
jest stosunkowo nieduże). Idee będące jego
netową! Rezultat, który otrzymujemy jest za- filarem zostały nakreślone już w 2002 roku
skakujący w porównaniu, do pracy jaką wło- przez zespół Macromedii. Miały one za za-
Poziom trudności żyliśmy w jego stworzenie. Jest to jedna z za- danie zastosowanie sprawdzonych wzorców
sad tworzenia współczesnego oprogramowa- projektowych języka Java (Core J2EE Pat-
nia Internetowego. Prędkość i poziom funk- tern Catalog) we współczesnym Flash MX.
cjonalności z jaką możemy stworzyć gotowy Duży wpływ na projekt mieli programi-

P
o pierwszych sukcesach Adobe Flex, produkt stały się najważniejszymi wartościa- ści iteration::two, Steven Webster oraz Ali-
Microsoft prężnie zaczął rozwijać mi biznesowymi. star McLeod, którzy obecnie należą do ze-
swój najnowszy produkt – Silverlight, Jednak co się wydarzy, gdy zaczniemy się społu Adobe Consulting oficjalnie tworzą-
a Sun oficjalnie ogłosił stworzenie konku- mierzyć z kolejnymi modyfikacjami funkcjo- cego ten produkt. Opierając się na silnych
rencyjnej technologii JavaFX. Spośród nich, nalności, graficy zarzucą nas nowymi elemen- podstawach programistycznych, Cairngorm
omawiana platforma jest najbardziej dojrza- tami interfejsu, a technologia połączenia z ser- był rozwijany wewnątrz firmy Adobe i zo-
łą i rozbudowaną. Jako programista i konsul- werem, jak i komunikat z niego otrzymywany stał publicznie zaprezentowany jako pro-
tant korzystający na co dzień z Adobe Flex gruntowanie się zmieni? Co będzie, gdy zajdzie jekt typu Open Source w listopadzie 2004 ro-
wierzę, że jej nazwa ukrywa w sobie cechę się potrzeba dodania kolejnych elementów apli- ku podczas konferencji Macromedia MAX
tego środowiska (flex – ang. giętki). Jest ono kacji? Gdy do zespołu dołączy nowy programi- 2004 w Nowym Orleanie. Wówczas była to
przyjazne osobom w nim pracującym, za- sta? Odpowiedź jest prosta – jakość pracy w ze- wersja oznaczona numerem 0.95. Aktual-
wsze gotowe na zmiany w projekcie, zarów- spole będzie współzależna od jakości dotych- nie Cairngorm jest rozbudowywany przez
no graficzne, jak i funkcjonalne. Flex w wer- czasowego kodu. Niestety wraz z wprowadza- zespół doświadczonych programistów i dzie-
sji 3 jest opublikowany na licencji Open Sour- niem zmian w projekcie, rozpoczyna się cha- li się na dwie wersje Standard oraz Enterpri-
ce, co oznacza, że środowisko jest rozszerzal- os. W takiej sytuacji z pomocą przychodzą fra- se, znajdując wykorzystanie zarówno w ty-
ne i stale udoskonalane. meworki architektoniczne. Dlaczego warto więc powych aplikacjach internetowych opartych
Projekty Flexowe z natury są aplikacjami podjąć wyzwanie wprowadzając tego typu roz- o Flex, jak i aplikacjach desktopowych wyko-
internetowymi wypełnionymi funkcjonalno- wiązania do projektów? Odpowiedzi można rzystujących Adobe AIR.
ściami, które mają za zadanie stworzenie wy- mnożyć, poniżej wymienię te najważniejsze: Cairngorm jest w pełni oparty o architektu-
soce interaktywnego, atrakcyjnego i przyja- rę MVC. Będąc całkowicie przygotowanym pod
znego interfejsu. Wykorzystując tę platfor- • Dostajemy do ręki gotowy i sprawdzony środowisko Flexa, pozwala on w pełni wykorzy-
mę, możemy dostarczać naszym klientom przepis na dobrze rozwarstwioną i prze- stać zalety, jakie ono niesie. Wykorzystuje zna-
produkty przynoszące nową jakość usług biz- myślaną aplikację, mogąc skupić się na pro- ne wzorce projektowe, które omówimy w kolej-
nesowych. gramowaniu elementów naszej aplikacji, nych częściach tego artykułu. Stworzenie apli-
Przepis jest prosty: potrzebujemy jakieś a nie na tym jak rozwiązać problem archi- kacji opartej o ten fremawork wymaga zrozu-
źródło danych, np. Web Service, kilka goto- tektury; mienia poszczególnych elementów go współ-
wych komponentów interfejsu użytkowni- • Nie chcemy spędzać kolejnych dni na tworzących. W tym artykule stworzymy pro-
ka, trochę ActionScriptu, aby wszystko zwią- wprowadzaniu nawet najprostszych stą aplikację wyświetlającą książki, wchodzące
zać razem i mamy działającą aplikację inter- zmian do naszej aplikacji; w skład pewnej podręcznej biblioteczki.

56 FLEX
Cairngorm

Struktura aplikacji tów strony serwera (obiektów platform Ja- istniejące już klasy, np. bardzo często zda-
opartej o Cairngorm va, ColdFusion, PHP, Ruby lub .Net). Imple- rza się użycie obiektów opartych o kolekcję
Przedstawiona na Rysunku 1. struktura, opiera mentując ten interfejs, możemy rozszerzać ArrayCollection. Przykładowa implementa-
się o podzielenie elementów na główne składo-
we naszej aplikacji. Całość zostanie omówiona Listing 1. Implementacja oparta na wzorcu Value Object
w poszczególnych częściach tego artykułu.
package com.wjptak.samplelibrary.vo
Zarządzanie danymi aplikacji {
Podczas tworzenia aplikacji, do pobrania import com.adobe.cairngorm.vo.IValueObject;
i prezentowania danych korzystamy z war-
stwy pośredniej, znanej jako warswa bizne- [Bindable]
sowa (ang. Business Tier). Dane przechowywa- public class BookVO implements IValueObject
ne w relacyjnych bazach danych muszą zostać {
zamienione na konkretne obiekty. Dodatko- public var title:String;
wo spoczywa na nas zadanie podtrzymania public var author:String;
ich spójności. public var publisher:String;
Z pomocą programistom przychodzą róż- public var yearPublished:Number;
ne rozwiązania, np. JavaBeans, Hiberna- }
te, ADO.NET czy nHibernate. Jako progra- }
miści aplikacji internetowych RIA jesteśmy
zwolnieni z tego zadania, możemy skupić Listing 2. Implementacja Model Locator
się na odpowiednim przemyśleniu i zastoso- package com.wjptak.samplelibrary.model
waniu odpowiedniego modelu danych war- {
stwy biznesowej i przedstawieniu go za po- import com.adobe.cairngorm.CairngormError;
mocą warstwy prezentacji. Cairngorm opie- import com.adobe.cairngorm.CairngormMessageCodes;
ra się na dwóch wzorcach projektowych uży- import com.adobe.cairngorm.model.IModelLocator;
tych do zarządzania informacją przechowy-
waną w naszej aplikacji: Model Locator oraz import mx.collections.ArrayCollection;
Value Object.
Dane dostarczone nam przez zewnętrzne [Bindable]
źródło przechowywane są w postaci obiektów public class LibraryModelLocator implements IModelLocator
implementujących interfejs IValueObject. {
W naszym przykładzie klasa ta będzie bardzo private static var modelLocator:LibraryModelLocator;
prosta – będziemy mieć tu kilka właściwości
tj. tytuł, autor, wydawnictwo i datę wydania. public static function getInstance():LibraryModelLocator
Całość obejmiemy metatagiem [Bindable], {
co pozwoli na skorzystanie z mechanizmu if(modelLocator == null) {
tzw. Data Bindingu. Ułatwia on prezentowa- modelLocator = new LibraryModelLocator();
nie modelu, automatycznie odświeżając ko- }
lekcję tych obiektów, ściągając z nas obowią-
zek odświeżania elementów aplikacji. Mecha- return modelLocator;
nizm działa w dwie strony (zmienny wpro- }
wadzane w elementach interfejsu automa-
tycznie zostaną naniesione na odpowiadają- public function LibraryModelLocator():void {
ce obiekty modelu). Jest to jedna z cech Fle- if(modelLocator != null) {
xa, która bardzo ułatwia pracę nad aplika- throw new CairngormError(
cjami RIA. Możemy tu również skorzystać CairngormMessageCodes.SINGLETON_EXCEPTION, "ModelLocator"
z mechanizmu Remote Class, który pozwo- );
li nam na bezpośrednie zmapowanie obiek- }

modelLocator = this;
}

// DANE NASZEGO MODELU ==============================

public var books:ArrayCollection;


public var applicationState:Number = 0;

// STALE OKRESLAJACE MOZLIWE STANY WIDOKU ===========


public static const VIEW_DATA:Number = 0;
public static const ENTRY_DATA:Number = 1;
}
}
Rysunek1. Struktura Projektu

www.sdjournal.org 57
ADOBE FLEX

cja oparta na wzorcu Value Object przedsta- Rozwiązanie to posiada zarówno zalety, jak go wzorca w naszej aplikacji jest następująca
wiona jest na Listingu 1. i wady – w związku z kontrowersjami, jakie (Listing 2.).
Konstrukcja pliku jest dość prosta, więc budzi wśród programistów prawdopodob- W katalogu model możemy umieścić rów-
przejdźmy dalej. Do przechowywania pre- nie w następnych wersjach frameworka zosta- nież inne klasy rozszerzające funkcjonalność
zentowanych informacji, jak i wszelkich nie zamienione na inne. Zaletą tego rozwią- naszego modelu, w miarę jak stopień skom-
danych dotyczących naszej aplikacji, jak zania jest prosty dostęp do danych przecho- plikowania aplikacji wzrasta. Charaktery-
np. stanów komponentów widoku, uży- wywanych w naszej aplikacji, natomiast wią- styczna implementacja wzorca Singleton
wamy obiektu implementującego interfejs że się to ze złamaniem kilku zasad obiekto- wynika z cechy ActionScript 3.0, jaką jest
IModelLocator. Model Locator jest wzorcem wości (do Singletona nie możemy zastoso- nieudostępnienie prywatnych konstrukto-
projektowym opartym o wzorzec Singleton. wać zasad polimorfizmu). Implementacja te- rów. Dostęp do obiektu mamy więc za pomo-
cą wywołania metody LibraryModelLocator
Listing 3. Tworzenie pliku business/Services.mxml .getInstance().
Możemy zauważyć, że dane w na-
<cairngorm:ServiceLocator szej aplikacji przechowujemy w kolekcji
xmlns:cairngorm="com.adobe.cairngorm.business.*" ArrayCollection. Umożliwia ona zastoso-
xmlns:mx="http://www.adobe.com/2006/mxml"> wanie mechanizmu wspomnianego wcze-
śniej – Data Bindingu, co ułatwi nam znacz-
<mx:HTTPService id="BookAssets" nie prezentowanie przechowywanych w niej
url="data/sample_books.xml" obiektów.
makeObjectsBindable="true"
showBusyCursor="true" Komunikacja z zasobami danych
resultFormat="e4x" /> Ideą każdej aplikacji RIA jest przedstawienie
w interaktywny sposób pewnych danych użyt-
</cairngorm:ServiceLocator> kownikowi. Chociaż kod jest w całości wyko-
nywany po stronie klienta, źródło danych znaj-
duje się najczęściej na serwerze, na którym by-
Listing 4. Tworzenie klasy Business Delegate w katalogu business
ła umieszczona również aplikacja. Flex daje
package com.wjptak.samplelibrary.business nam bardzo duże możliwości połączenia z do-
{ wolnymi współczesnymi językami serwerowy-
import com.adobe.cairngorm.business.ServiceLocator; mi przy wykorzystaniu kilku mechanizmów,
m.in. HTTPService – pliki XML oraz komu-
import mx.rpc.AsyncToken; nikaty w formie JSON, Web Service – za-
import mx.rpc.IResponder; równo REST, jak i SOAP oraz RemoteObject
– najsilniejsze rozwiązania przesyłające obiek-
public class GetBasicDataDelegate ty w ich natywnej formie. Cairngorm wystę-
{ puje w wersjach Standard oraz Enterprise. Ta
druga rozszerza funkcjonalność frameworka
private var responder : IResponder; o klasy wspomagające mechanizmy Remote
private var service : Object; Object, szczególnie mowa tu o LiveCycle
Data Services.
public function GetBasicDataDelegate( responder : IResponder ) Aplikacja oparta o Cairngorm jako central-
{ ne miejsce przechowujące dostęp do możli-
this.service = ServiceLocator.getInstance().getHTTPService( "BookAssets" ); wych do użycia serwisów wykorzystuje wzo-
this.responder = responder; rzec Service Locator. Jest to klasa oparta na
} Singletonie, której implementacja w tworzo-
nej aplikacji sprowadza się do stworzenia na-
public function getData():void stępującego pliku business/Services.mxml (Li-
{ sting 3.).
var call:AsyncToken = service.send(); W naszym przykładzie aplikacja będzie ko-
call.addResponder( this.responder ); rzystać z danych umieszczonych w pliku .xml
} na serwerze w katalogu <katalog_aplikacji>/
data/, wykorzystując w tym celu komponent
} HTTPService. Dodatkowo zaznaczyliśmy, aby
} automatycznie wymuszać mechanizm Data
Binding–u na tworzonych obiektach (make-
ObjectsBindable=“true“), pokazać podczas
pobierania pliku kursor oczekiwania (shwoBu-
syCursor=“true“) oraz zwrócić dane w forma-
������������� ������ cie E4X (resultFormat=“e4x“). W przypadku
����� ������� ����� �����
��������� ���������� potrzeby skorzystania z innych lub większej ilo-
ści serwisów modyfikujemy odpowiednio omó-
wiony plik.
Użycie konkretnego serwisu odbywa się
Rysunek 2. Przepływ zdarzenia w aplikacji opartej o Cairngorm przez odpowiednio przygotowany mechanizm,

58 FLEX
Cairngorm

oparty o zdarzenia, który zostanie omówiony ną wcześniej implementację wzorca Business nać poprzez bezpośrednie przekazanie pożąda-
w dalszej części. Cairngorm do wywołania kon- Delegate oraz określony odpowiednio serwis nego widoku, np.:
kretnego serwisu używa klas wzorca Business w pliku Services.mxml. Za dobrą praktykę uwa-
Delegate. Spełniają one potrójne zadanie – lo- ża się oddzielenie Responder od ICommand – new SwitchViewEvent( LibraryModelLoca
kalizują poprzez Service Locator odpowied- tak aby wszystkie klasy wzorca Command mia- tor.ENTRY_DATA ).dispatch();
ni serwis, wywołują go oraz przesyłają wynik ły zbliżoną konstrukcję.
zapytania do odpowiedniego obiektu rozsze- Przepływ zdarzenia w aplikacji opartej o Ca- Dokładnie będzie to pokazane podczas oma-
rzającego klasę Responder. W naszym przykła- irngorm jest taki jak na Rysunku 2. wiania elementów warstwy prezentacji.
dzie odwołujemy się do pliku sample_books.xml Jako prosty przykład posłużą nam klasy Zwróćmy uwagę, że użycie tego mechani-
poprzez HTTPService. Aby z niego skorzy- służące do zmiany aktualnie wyświetlane- zmu jest bardzo proste. Nie musimy pisać kil-
stać, tworzymy odpowiednią klasę Business go interfejsu naszej aplikacji. Klasa rozsze- ku linijek, załatwiamy wszystko w jednej. In-
Delegate w katalogu business, co widać na Li- rzająca Cairngorm Event jest taka jak na Li- ny element omawianej klasy, na który należy
stingu 4. stingu 5. zwrócić uwagę, to stała określająca typ zda-
Do konstruktora tej klasy przekazujemy re- Konstruktor tej klasy został tak zaprojekto- rzenia. Zastosowanie tu pełnej ścieżki klasy
ferencję do obiektu opartego o Responder. Na- wany, że rozgłoszenie zdarzenia możemy wyko- pozwala uniknąć sytuacji, gdy budując dużą
stępnie chcąc wywołać dany serwis, korzysta-
my z metody getData(). Analogicznie wygląda Listing 5. Klasa rozszerzająca Cairngorm Event
zapytanie, mającego na celu przesłanie danych
do serwera np. zapisu do bazy danych. W takim package com.wjptak.samplelibrary.events
przypadku wywołujemy odpowiednią metodę {
obiektu service, przekazując jako parametry import com.adobe.cairngorm.control.CairngormEvent;
przesyłane dane. import flash.events.Event;

Warstwa kontrolera public class SwitchViewEvent extends CairngormEvent


aplikacji opartej o Cairngorm {
Aplikacje tworzone w oparciu o omawiany fra- public static const SWITCH_VIEW:String = "com.wjptak.samplelibrary.events.Switc
mework wykorzystują wzorzec Service to hView";
Worker. Cairngorm jest oparty o to rozwiązanie.
Na pierwszy rzut oka konstrukcja, z której przyj- public var view:Number;
dzie nam skorzystać, może wydawać się zagma-
twana. Aby lepiej zrozumieć tę ideę, przybliżmy public function SwitchViewEvent( newView:Number )
klasy wchodzące w skład frameworka: {
super( SwitchViewEvent.SWITCH_VIEW );
• CairgnormEvent – dziedziczy po Event . view = newView;
Aby zbudować poprawną komunikację }
opartą o zdarzenia, na której opiera się Ca-
irngorm, wykorzystujemy obiekty budo- override public function clone():Event
wane w oparciu o tą właśnie klasę; {
• CairngormEventDispatcher – centralny return new SwitchViewEvent( view );
punkt komunikacji opartej na zdarzeniach. }
Jest oparty na Singletonie, podobnie jak }
omówiony wcześniej Model Locator. Słu- }
ży do rozgłaszania zdarzeń zbudowanych
w oparciu o CairngormEvent ;
Listing 6. Klasa implementująca wzorzec Command
• FrontController – przyporządkowuje
stworzone przez nas klasy rozszerzające package com.wjptak.samplelibrary.commands
CairngormEvent do odpowiadających im {
klasom wzorca Command ; import com.adobe.cairngorm.commands.ICommand;
• ICommand – Budując klasy korzystające ze import com.adobe.cairngorm.control.CairngormEvent;
wzorca Command , musimy zaimplemento- import com.wjptak.samplelibrary.events.SwitchViewEvent;
wać ten interfejs. Wymaga to od nas opra- import com.wjptak.samplelibrary.model.LibraryModelLocator;
cowania odpowiedniej metody execute(),
która jest przyporządkowana poprzez public class SwitchViewCommand implements ICommand
FrontController do odpowiedniego zda- {
rzenia CairngormEvent .
public function execute(eventParam:CairngormEvent):void
Podczas fazy analizy projektowanej aplika- {
cji tworzymy diagramy przypadków uży- var event:SwitchViewEvent = eventParam as SwitchViewEvent;
cia. Następnie, stosując Cairngorm, każdy LibraryModelLocator.getInstance().applicatio
przypadek użycia zamieniamy na parę klas nState = event.view;
CairngormEvent – ICommand . Jeżeli wymaga }
on komunikacji z serwerem, musimy rozsze- }
rzyć klasę implementującą ICommand poprzez }
Responder, a dodatkowo stworzyć omówio-

www.sdjournal.org 59
ADOBE FLEX

aplikację zaczniemy duplikować nazwy ty- sujemy w konstruktorze, jakie zdarzenie bę- obraźmy sobie także inną sytuację – synchro-
pów zdarzeń. dzie rozgłoszone i w odpowiednim miejscu niczne pobieranie danych z serwera. Zastoso-
Jak już wspomniałem, potrzebna jest metody execute() należy wykonać metodę wanie tego mechanizmu znacznie upraszcza
nam również klasa implementująca wzorzec executeNextCommand(). W tworzonym przez naszą pracę.
Command. Dla pokazanego tu zdarzenia będzie nas przykładzie możemy pomyśleć o rozwiąza- Już wcześniej wspomnieliśmy o potrzebie
ona wyglądać tak jak na Listingu 6. niu dodającym do naszej kolekcji książek nowe zaprogramowania przypadków użycia komu-
Możliwe jest automatyczne stworzenie ta- egzemplarze, a następnie automatycznie prze- nikujących się z warstwami serwerowymi. Aby
kiej klasy rozgłaszającej kolejne zdarzenie łączającym widok (Listing 7.). przybliżyć mechanizm stosowany przez Cairn-
po wykonaniu swojego zadania. W tym ce- Zauważmy, że takie rozwiązanie upraszcza gorm, przeanalizujmy Rysunek 3.
lu należy zbudować ją poprzez rozszerze- zaprogramowanie skomplikowanych interak- To, co jest tu dla nas nowe to implemen-
nie klasy SequenceCommand. Następnie dopi- cji, gdzie musimy wykonać wiele operacji. Wy- tacja wzorca Command oraz Responder. Kla-
sa Business Delegate została już omówio-
Listing 7. Dodawanie do biblioteki nowych książek na – jak pamiętamy, aby wywołać żądany ser-
wis, musimy do jej konstruktora przekazać re-
package com.wjptak.samplelibrary.commands ferencję do obiektu Respondera, odpowiadają-
{ cego za zapis otrzymanego wyniku do nasze-
import com.adobe.cairngorm.commands.ICommand; go Modelu.
import com.adobe.cairngorm.commands.SequenceCommand; W związku z tym, przykładowe rozwiąza-
import com.adobe.cairngorm.control.CairngormEvent; nie wygląda następująco – najpierw przyjrzyj-
import com.wjptak.samplelibrary.events.AddElementEvent; my się klasie Command, znajdującej się podob-
import com.wjptak.samplelibrary.events.SwitchViewEvent; nie, jak i poprzednie w katalogu commands
import com.wjptak.samplelibrary.model.LibraryModelLocator; (Listing 8.).
import com.wjptak.samplelibrary.vo.BookVO; Jak widzimy, rozwiązanie jest niezwy-
kle przejrzyste. Przypatrzmy się więc ko-
public class AddElementCommand extends SequenceCommand implements ICommand lejnej klasie, tj. Responder. W poprzednich
{ wersjach frameworka zalecało się tworzenie
public function AddElementCommand() dwóch rodzajów implementujących wzo-
{ rzec Command – jednej do zwykłych wywo-
this.nextEvent = new SwitchViewEvent( LibraryModelLocator.VIEW_DATA ); łań zmiany widoku, innych wykorzystują-
} cych również metody Respondera służących
do komunikacji poza aplikacją. We współ-
override public function execute( eventParam:CairngormEvent ):void czesnym podejściu rozdziela się te role, two-
{ rząc osobną klasę. Powoduje to spójne podej-
var event:AddElementEvent = eventParam as AddElementEvent; ście do klas wzorca Command. Spójrzmy więc
na przykład z tworzonej przez nas aplikacji
var bookVO:BookVO = new BookVO(); (Listing 9.).
bookVO.title = event.title; Implementacja interfejsu IResponder wią-
bookVO.author = event.author; że się z zaprogramowaniem dwóch metod:
bookVO.publisher = event.publisher; result() oraz fault(). Nasz przykład po po-
bookVO.yearPublished = event.yearPublished; prawnym przesłaniu żądanego pliku odczytuje
kolejne wpisy w nim zawarte, przy użyciu me-
LibraryModelLocator.getInstance().books.addItem( bookVO ); chanizmu E4X. Przykładowy wpis wygląda na-
stępująco:
executeNextCommand();
} <book id="1" title="Adobe Flex 2 Training
} From the source" author="Team work"
} publisher="Adobe Press"
yearPublished="2007"/>

Następnie tworzy odpowiednie obiekty wzor-


ca Value Object , dodając je równocześnie do
kolekcji przechowywanej w modelu. Jak może-
��������������� ������� my się domyślić – niejednokrotnie wcześniej
mechanizm Data Bindingu samoczynnie spo-
woduje zaktualizowanie odpowiednich ele-
��������
�������� mentów interfejsu użytkownika. W razie nie-
������� powodzenia w przesłaniu pliku, aplikacja po-
wiadomi nas komunikatem.

����� ����� ���������


Warstwa prezentacji
Nasza aplikacja umożliwia zarówno wprowa-
dzenie danych, jak i ich wyświetlanie w postaci
tabeli. Dla potrzeb tego przykładu zastosujemy
Rysunek 3. Mechanizm zdarzeń – komunikacja z serwem komponent ViewStack. Umożliwia on proste

60 FLEX
Cairngorm

przełączenie pomiędzy stanami aplikacji. Do Jak pamiętamy ze wcześniejszego przykła- do kolekcji w naszym modelu, a następ-
tego w naszym modelu służą te linie: du, wywołuje ono odpowiednią implemen- nie samoczynnie wywołuje zmianę ekranu,
tację wzorca Command , która zapisuje obiekt na ekran prezentujący dane. Komponent
public var applicationState:Number = 0;
publicstaticconst VIEW_DATA:Number = 0; Listing 8. Implementacja wzorca Command
publicstaticconst ENTRY_DATA:Number = 1;
package com.wjptak.samplelibrary.commands
Stwórzmy więc komponent odpowiadający za {
prezentację danych. Wykorzystamy tu kilku- import com.adobe.cairngorm.commands.ICommand;
krotnie wcześniej wspomniany mechanizm import com.adobe.cairngorm.control.CairngormEvent;
Data Bindingu, dzięki czemu stanie się on w import com.wjptak.samplelibrary.business.GetBasicDataDelegate;
pełni zrozumiały. Skorzystamy również ze
stworzonych wcześniej klas. Przykładowy plik public class GetBasicDataCommand implements ICommand
MXML, view/MainView.mxml, znajduje się na {
Listingu 10. public function execute( eventParam:CairngormEvent ):void
Przypatrzmy się kolejnym elementom tego {
pliku. Do wyświetlania stanów aplikacji (wy- var delegate:GetBasicDataDelegate = new GetBasicDataDelegate( new
świetlanie lub wprowadzanie danych) służy GetBasicDataResponder() );
komponent View Stack. Jedna z jego właści- delegate.getData();
wości wykorzystuje Data Binding, co możemy }
w kodzie MXML rozpoznać po klamrowych }
nawiasach {}: }

selectedIndex="{model.applicationState}"
Listing 9. Implementacja wzorca Responder

Widzimy już jak wykorzystać siłę tego roz- package com.wjptak.samplelibrary.commands


wiązania w połączeniu z resztą aplikacji {
opartej o Cairngorm. Innym ważnym ele- import com.wjptak.samplelibrary.model.LibraryModelLocator;
mentem jest komponent DataGrid , służą- import com.wjptak.samplelibrary.vo.BookVO;
cy do tabelarycznego przedstawienia kolek-
cji, którą tworzyliśmy w kolejnych krokach. import mx.controls.Alert;
Przekazujemy jej, w podobny sposób referen- import mx.rpc.IResponder;
cję do kolekcji:
public class GetBasicDataResponder implements IResponder
dataProvider="{model.books}" {
public function GetBasicDataResponder()
Tworząc odpowiednie kolumny, informujemy, {
z jakich pól przekazanych w kolekcji obiektów super();
mogą one odczytać swoje dane. Całość odby- }
wa się automatycznie, co w połączeniu z tech-
nologią Data Binding znacznie przyspiesza na- public function result(data:Object):void
szą pracę. W ekranie wyświetlającym kolekcję {
obiektów BookVO znajduje się również przy- var result:XML = data.result as XML;
cisk, którego kliknięcie powoduje wykona-
nie odpowiedniej funkcji, która rozgłasza od- for each (var book:XML in result.book )
powiednie zdarzenie, przełączajac wyświetla- {
ny ekran: var bookVO:BookVO = new BookVO();
bookVO.title = book.@title;
new SwitchViewEvent( LibraryModelLoca bookVO.author = book.@author;
tor.ENTRY_DATA ).dispatch(); bookVO.publisher = book.@publisher;
bookVO.yearPublished = book.@yearPublished;
Ekran wprowadzania danych składa się
z formularza, którego pola muszą pomyślnie LibraryModelLocator.getInstance().books.addItem( bookVO );
przejść walidację. Warunki, jakie muszą speł- }
nić poszczególne pola, określiliśmy w następu- }
jący sposób (Listing 12.).
Po kliknięciu przycisku i spełnieniu warun- public function fault(info:Object):void
ków walidacji rozgłaszane jest odpowiednie {
zdarzenie, do którego przekazujemy dane z for- Alert.show("Blad podczas pobierania pliku z danymi", "Blad!!");
mularza: }

new AddElementEvent( bookTitle.text, }


bookAuthor.text, bookPublisher.text, }
bookYearPublished.value ).dispatch();

www.sdjournal.org 61
ADOBE FLEX

Listing 10. Tworzenie pliku widoku, view/MainView.mxml

<mx:Canvas sortableColumns="true">
xmlns:mx="http://www.adobe.com/2006/mxml" <mx:columns>
width="640" height="480"> <mx:DataGridColumn dataField="title"
headerText="Tytul" />
<mx:Script> <mx:DataGridColumn dataField="author"
<![CDATA[ headerText="Autor" />
import com.wjptak.samplelibrary.events.AddElementEvent; <mx:DataGridColumn dataField="publisher"
import com.wjptak.samplelibrary.events.SwitchViewEv headerText="Wydawca" />
ent; <mx:DataGridColumn dataField="yearPublished"
import com.wjptak.samplelibrary.model.LibraryModelLo headerText="Rok wydania" />
cator; </mx:columns>
import mx.events.ValidationResultEvent; </mx:DataGrid>

[Bindable] private var model:LibraryModelLocator = <mx:Button


LibraryModelLocator.getInstance(); label="Wprowadz pozycje"
click="switchToDataEntryScreen()" />
private function addElement():void </mx:Panel>
{
if( vTitle.validate().type == ValidationResultEven <mx:Panel
t.VALID && title="Wprowadzanie nowej pozycji w bibliotece"
vAuthor.validate().type == ValidationResultEven width="100%" height="100%">
t.VALID && <mx:Form
vPublisher.validate().type == ValidationResultE defaultButton="{processBtn}"
vent.VALID ) width="100%" height="100%">
{ <mx:FormHeading
new AddElementEvent( bookTitle.text, label="Wypelnij dane i nacisnij przycisk 'Dodaj'"
bookAuthor.text, bookPublisher.text, textAlign="center"
bookYearPublished.value ).dispatch(); width="100%"/>
} <mx:FormItem
} label="Tytul"
required="true">
private function switchToDataEntryScreen():void <mx:TextInput id="bookTitle" width="150"/>
{ </mx:FormItem>
new SwitchViewEvent( LibraryModelLocator.ENTRY_ <mx:FormItem
DATA ).dispatch(); label="Autor"
} required="true">
]]> <mx:TextInput id="bookAuthor" width="150"/>
</mx:Script> </mx:FormItem>
<mx:FormItem
<mx:StringValidator id="vTitle" source="{bookTitle}" label="Wydawnictwo">
property="text" minLength="4" <mx:TextInput id="bookPublisher"
maxLength="40" required="true" /> width="150"/>
<mx:StringValidator id="vAuthor" source="{bookAuthor}" </mx:FormItem>
property="text" minLength="4" <mx:FormItem
maxLength="40" required="true" /> label="Rok wydania">
<mx:StringValidator id="vPublisher" <mx:NumericStepper id="bookYearPublished"
source="{bookPublisher}" property="text" minimum="1990" maximum="2008"
minLength="4" maxLength="40" stepSize="1" />
required="false" /> </mx:FormItem>
<mx:FormItem>
<mx:ViewStack <mx:Button id="processBtn"
selectedIndex="{model.applicationState}" label="Dodaj"
width="100%" height="100%"> click="addElement()" />
</mx:FormItem>
<mx:Panel </mx:Form>
title="Pozycje w bibliotece"
width="100%" height="100%"> </mx:Panel>

<mx:DataGrid </mx:ViewStack>
dataProvider="{model.books}"
width="100%" height="100%" </mx:Canvas>

62 FLEX
Cairngorm

DataGrid automatycznie zaktualizuje wy- A kolejne elementy jako komponenty MXML: • Zmiana modelu może odbyć się tylko
świetlane dane. poprzez obiekty Command i Responder.
<business:Services id="services" /> Elementy widoku powinny bąbelko-
Główny plik aplikacji <control:LibraryController id="controller" /> wać zdarzenia w górę, gdzie odpowied-
Aplikacje Flex budowane w oparciu o Cairn- <view:MainViewwidth="100%" height="100%" /> nie funkcje wywołują odpowiadające
gorm zakładają charakterystyczne przygoto- im CairngormEventy. Złamanie tej za-
wanie głównego pliku aplikacji. Musimy tu Aplikacja została ukończona. Możemy teraz sady powoduje naruszenie zasad wzorca
zainicjalizować poszczególne elementy fra- skompilować projekt. MVC, jak i powoduje zaśmiecenie kodu
meworka – Model Locator, Service Locator, aplikacji;
Front Controller i główny plik widoku. Dobre praktyki • Dla każdego przypadku użycia opraco-
W tym pliku możemy zainicjalizować rów- Zasady pomagające tworzyć aplikacje w opar- wujemy jedną klasę Command oraz jed-
nież pierwsze zdarzenia jak np. pobranie da- ciu o Cairngorma można by mnożyć, jednak ną CairngormEvent . W razie potrzeby
nych początkowych. należy wymienić kilka, które na pewno okażą komunikacji dodajemy po jednej klasie
Przykład stworzony dla opracowywanej przez się przydatne. Delegate i Responder oraz modyfikujemy
nas aplikacji pozwoli zrozumieć zasady nakre- odpowiednio plik Services.mxml;
ślone przez Cairngorm. Spójrzmy na Listing 11. • Nie należy używać wzorców View Helper • Dobrą praktyką jest używanie wzorca
Model Locator inicjalizujemy poprzez: oraz View Locator. Nie są one potrzebne, Factory do parsowania danych otrzyma-
gdy poznamy pełne możliwości platformy, nych z serwera. Jest to przydatne z kilku
[Bindable] private var model: zostały oficjalnie usunięte z frameworka. powodów, m.in. uproszczenia pozosta-
LibraryModelLocator = LibraryModelLocato Dodatkowo, zwiększylibyśmy znacznie łych klas, jak i lepszego zoptymalizowania
r.getInstance(); narzut plików ActionScript; kodu pliku wzorca Factory. Odczujemy
to szczególnie przy użyciu wielu różnych
Listing 11. Tworzenie głównego pliku aplikacji źródeł danych w jednej aplikacji przesyła-
jących duże ilości danych;
<mx:Application • Tylko obiekty klas Business Delegate
xmlns:mx="http://www.adobe.com/2006/mxml" mają dostęp do danych w formatach po-
xmlns:business="com.wjptak.samplelibrary.business.*" średnich jak np. JSON, natomiast tylko
xmlns:control="com.wjptak.samplelibrary.control.*" Responder powinien otrzymywać wstęp-
xmlns:view="com.wjptak.samplelibrary.view.*" nie przygotowane dane i zamieniać je na
layout="absolute" konkretne obiekty Value Object ;
creationComplete="this.onCreationComplete()"> • Obiekty Command nie mogą zawierać ja-
kichkolwiek implementacji komunikacji,
<mx:Script> zadanie to należy do Service Locatora
<![CDATA[ i obiektów Business Delegate .
import com.wjptak.samplelibrary.events.GetBasicDataEvent;
import com.wjptak.samplelibrary.model.LibraryModelLocator; Zakończenie
Zapoznaliśmy się z frameworkiem Cairn-
[Bindable] private var model:LibraryModelLocator = LibraryModelLocator.getIn gorm, najszerzej stosowanym w środowisku
stance(); Adobe Flex, rozwijanym wewnątrz tej samej
firmy.
private function onCreationComplete():void { W przyszłości będzie on zapewne coraz bar-
new GetBasicDataEvent().dispatch(); dziej zoptymalizowany, co pozwoli na dostar-
} czenie nowych funkcjonalności, m.in. do two-
]]> rzenia aplikacji typu Enterprise. Stosowanie
</mx:Script> tego typu rozwiązań pozwoli nam uporząd-
kować nie nasz kod, ułatwi wprowadzanie
<business:Services id="services" /> ciągłych zmian, a także wspomoże równole-
głą pracę wielu programistów. Polecam bliż-
<control:LibraryController id="controller" /> sze zapoznanie się z opisanym powyżej fra-
meworkiem.
<view:MainView
width="100%" height="100%" />
WOJCIECH PTAK
</mx:Application> Od 2 lat konsultant i programista Adobe Flex
oraz Adobe Integrated Runtime (AIR) (przez rok
Listing 12. Wyróżniony fragment Listingu 10. obejmował to stanowisko w norweskiej firmie
Making Waves). Wykonał w całości m.in. aplika-
<mx:StringValidator id="vTitle" source="{bookTitle}" property="text" minLength="4" cję Kalkulator Energetyczny Vattenfall, która zo-
maxLength="40" required="true" />; stała wyróżniona w międzynarodowym konkur-
<mx:StringValidator id="vAuthor" source="{bookAuthor}" property="text" minLength="4" sie Webby Awards 2008. Aktualnie pracuje dla
maxLength="40" required="true" />; takich klientów jak Adidas, Heineken, Coca–Co-
<mx:StringValidator id="vPublisher" source="{bookPublisher}" property="text" la, Schweppes czy British Telecom, dostarczając
minLength="4" maxLength="40" required="false" />. kompleksowe aplikacje B2B oparte o Adobe Flex
oraz AIR.

www.sdjournal.org 63
ADOBE FLEX

Dostęp do danych
z aplikacji Flex
Adobe LiveCycle Data Services w praktyce
Dostęp do danych i logiki biznesowej znajdującej się na serwerze jest
nieodłączną częścią zdecydowanej większości aplikacji internetowych.
W zależności od wybranej technologii, jest to zadanie mniej lub bardziej
skomplikowane. W tym artykule chciałbym pokazać, że w przypadku
aplikacji Flex jest to wyjątkowo proste.
fig.xml i poniżej default–channels dodajemy de-
Dowiesz się... Powinieneś wiedzieć... klarację punktu docelowego (destination) – Li-
• Jak wywoływać metody obiektów Javy bezpo- • Powinieneś znać podstawy tworzenia aplikacji sting 2.
średnio z Flexa. w technologii Flex; Deklaracja informuje LiveCycle Data Se-
• Powinieneś znać podstawy Java Enterprise rvices, że chcemy wywoływać metody klasy
Edition. hello.HelloWorld (element source) i nadajemy
jej identyfikator HelloWorld (atrybut id). Ele-
ment scope określa zakres dostępności obiek-
po zakończeniu jesteśmy gotowi do skorzysta- tu podobnie jak znacznik <jsp:useBean>
nia z usług, które nam udostępnia. Podstawo- z tą różnicą, że dostępne są wartości request,
Poziom trudności we usługi to: session i application (bez page). Oprócz po-
wyższej deklaracji po stronie serwera nie po-
• RPC Service, w której skład wchodzi Re- trzebujemy nic więcej. Spójrzmy na przykła-
mote Object, czyli zestaw usług umoż- dową aplikację kliencką.

B
udowana aplikacja zazwyczaj będzie liwiających zdalne wywołania metod Tworzymy główny plik aplikacji Ma-
prezentowała i modyfikowała dane obiektów Javy (POJO, EJB, itp.) bezpo- in.mxml. Jeśli korzystamy z Flex Buildera,
z relacyjnej bazy danych (bezpośrednio średnio z Flexa; podczas tworzenia projektu należy zaznaczyć
lub przez rozwiązania typu ORM (ang. Object • Messaging Service – mechanizm przesyła- wykorzystanie LiveCycle Data Services jak na
– Relational Mapping)) lub z zewnętrznych sys- nia komunikatów wraz z adapterem JMS; Rysunku 1.
temów firmy. • Data Management Service – alternatywny
Standardowo Flex SDK dostarcza trzech me- sposób dostępu do danych, opierający się
chanizmów dostępu do danych: na zarządzanych kolekcjach danych.

• HTTPService; Przyjrzyjmy się bliżej mechanizmowi Remo-


• WebService; te Object. Najłatwiej zaprezentować to na ni-
• Remote Object. żej opisanym przykładzie. Zakładając, że Live-
Cycle Data Services jest już zainstalowane (na
Pierwsze dwa mechanizmy opierają się na czas tworzenia aplikacji najwygodniej jest ko-
zwykłych wywołaniach HTTP i mogą być rzystać z rozpakowanego archiwum WAR; da-
wykorzystane z dowolną technologią serwe- lej katalog instalacji będzie nazywany {LCDS_
rową. Remote Object umożliwia proste i wy- HOME}), a serwer aplikacji uruchomiony, za-
dajne wywołania zdalnych metod, jednakże cznijmy od standardowego HelloWorld – klasy
wymaga dodatkowego komponentu po stro- Javy, która udostępni nam metodę sayHello
nie serwera. Komponent ten, o nazwie Ado- z jednym parametrem (Listing 1.).
be LiveCycle Data Services ES (wcześniej Flex Aby móc wywołać tę metodę z Flexa, nie jest
Data Services) oraz jego dodatkowe funkcjo- potrzebny żaden dodatkowy kod. Wystarczy
nalności i praktyczne zastosowanie są tema- umieścić powyższą klasę w CLASSPATH naszego
tem poniższego artykułu. serwera aplikacji i poinformować LiveCycle Da-
Od strony technicznej LiveCycle Data Servi- ta Services, że będziemy chcieli z niej korzystać.
ces jest aplikacją J2EE. Instalacja na serwerze W tym celu otwieramy plik konfiguracyjny
sprowadza się do wdrożenia archiwum WAR; {LCDS_HOME}/WEB–INF/flex/remoting–con-

64 FLEX
Dostęp do danych z aplikacji Flex

W następnym kroku podajemy ścieżkę do


{LCDS_HOME}.
Do pliku Main.mxml dodajemy deklarację
Remote Object (Listing 3.), która określa, że:

• Identyfikatorem, który będziemy wyko-


rzystywać w aplikacji klienckiej jest hello-
World.
• Punktem docelowym (destination) po stro-
nie serwera jest HelloWorld, czyli wartość
atrybutu id w pliku remoting–config.xml.
• Zdarzenia result i fault będą obsługiwa-
ne przez metody success i failure , które
dodamy w następnym kroku.

Listing 4. prezentuje fragment skryptu do ob-


sługi zdarzeń.
W przypadku powodzenia wyświetla-
my wynik, w przypadku błędu – komunikat
o przyczynach.
Do zakończenia przykładu brakuje nam je-
dynie wywołania metody zdalnego obiektu.
Wykonamy to w reakcji na zdarzenie klik-
nięcia przycisku, jednocześnie przekazu-
jąc jako parametr zawartość pola tekstowe-
go (Listing 5.).
Rysunek 1. Zaznaczamy LiveCycle Data Services we Flex Builder Warto zauważyć jak proste jest samo wy-
wołanie: helloWorld.sayHello(). Mimo iż
obiekt, który będzie wykonywał główną logikę
jest na zdalnym serwerze, programista traktu-
je go jak lokalny obiekt ActionScriptu. Resztę
wykonuje za nas komponent Remote Object

Listing 1. Przykładowa klasa Javy z metodą


do zdalnego wywołania

package hello;
public class HelloWorld
{
public String sayHello(String
name)
{
return "Hello " + name + "!";
}
}
Rysunek 2. Aplikacja po skompilowaniu i uruchomieniu
Listing 2. Deklaracja punktu docelowego
HelloWorld
<destination id="HelloWorld">
<properties>
<source>hello.HelloWorld</
source>
<scope>request</scope>
</properties>
</destination>

Listing 3. Deklaracja Remote Object

<mx:RemoteObject id="helloWorld"
destination="HelloWorld"
result="success(event)"
fault="failure(event);"/>

Rysunek 3. Wynik wywolania

www.sdjournal.org 65
ADOBE FLEX

z Flex SDK i LiveCycle Data Services. Po go metody send przekazywane są parametry domyślnego kanału wykorzystywanego przy
skompilowaniu i uruchomieniu aplikacja po- pierwotnego wywołania. Następnie nazwa zdalnych wywołaniach (Listing 7.).
winna wyglądać tak jak na Rysunku 2. zdalnej metody i parametry zostają opakowa- W definicji kanału znajduje się URL servle-
Naciśnięcie przycisku powinno wywo- ne w komunikat RemotingMessage i wysła- tu, który odpowiada za odbieranie komuni-
łać metodę i wyświetlić komunikat zwróco- ne przez odpowiedni kanał komunikacyjny. katów od klienta, wywoływanie odpowied-
ny przez metodę obiektu HelloWorld w Javie Czym jest kanał? Jest to sposób przesyłania nich metod i serializację zwracanych wyni-
(Rysunek 3.). komunikatów, np. przez zwykły HTTP lub ków. Tajmniczy skrót AMF oznacza Action
Przyjrzyjmy się teraz szczegółom powyż- specjalny protokół RTMP. Definicje dostęp- Message Format – binarny format przekazy-
szego wywołania zdalnej metody. Gdy po nych kanałów znajdują się w pliku {LCDS_ wania danych, który zapewnia mały rozmiar
stronie Flexa wywołujemy metodę na rzecz HOME}/WEB–INF/flex/services–config.xml, komunikatu i bardzo szybką serializację i de-
instancji klasy RemoteObject, tworzony jest m.in.: kanał my–amf (Listing 6.), a w pli- serializację obiektów. Oprócz wygody uży-
obiekt mx.rpc.remoting.Operation i do je- ku remoting–config.xml występuje deklaracja cia mechanizmu Remote Object, to właśnie
AMF jest jego główną zaletą, która powodu-
Listing 4. Skrypt do obsługi zdarzeń związanych z wywołaniem Remote Object je, że komunikacja jest znacznie wydajniej-
sza niż przy użyciu XML (jak w HTTPServi-
<mx:Script> ce i WebService).
<![CDATA[ Wykorzystanie Remote Object, nie ograni-
import mx.controls.Alert; cza się do przekazywania parametrów typu
import mx.rpc.events.FaultEvent; String. Możliwe jest przekazywanie i zwra-
import mx.rpc.events.ResultEvent; canie obiektów dowolnego typu, a zasady
konwersji typów między Javą i ActionScrip-
public function success(event:ResultEvent):void tem sa określone w dokumentacji LiveCycle
{ Data Services.
Alert.show(event.result.toString()); Za tworzenie instancji obiektów po stro-
} nie serwera odpowiada tzw. fabryka, czyli
implementacja interfejsu flex.messaging.Fle-
public function failure(event:FaultEvent):void xFactory. Domyślna fabryka w LiveCycle Da-
{ ta Services tworzy obiekty za pomocą opera-
Alert.show(event.fault.faultDetail, event.fault.faultString); tora new. Jeśli chcemy korzystać z komponen-
} tów EJB lub obiektów zarządzanych przez
]]> Springa, wystarczy podać nazwę fabryki
</mx:Script> w deklaracji punktu docelowego; w kodzie
fabryki znajdują się odpowiednie instruk-
Listing 5. Interfejs użytkownika do wywołania zdalnej metody
cje tworzenia obiektu (np. zamiast new – lo-
okup lub getBean).
<mx:TextInput id="nameInput" x="10" y="10"/> Na koniec warto poruszyć kwestię licen-
<mx:Button x="180" y="10" label="sayHello" cjonowania. Adobe LiveCycle Data Services
click="helloWorld.sayHello(nameInput.text);"/> ES jest produktem komercyjnym, dostępnym
w sprzedaży u dystrybutorów Adobe. Jed-
Listing 6. Definicja kanału my–amf w services–config.xml nak do mniejszych zastosowań istnieje wersja
Express Edition, która oferuje pełną funkcjo-
<channel–definition id="my–amf" class="mx.messaging.channels.AMFChannel"> nalność z jednym ograniczeniem: może być
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" instalowana wyłącznie na serwerach z jed-
class="flex.messaging.endpoints.AMFEndpoint"/> nym procesorem, gdzie dwa rdzenie liczą się
<properties> jako jeden procesor. Z drugiej strony, w celu
<polling–enabled>false</polling–enabled> popularyzacji technologii Flex, Adobe udo-
</properties> stępniło podzbiór funkcjonalności LiveCyc-
</channel–definition> le Data Services w otwartym projekcie Bla-
zeDS. Używając BlazeDS koncepcja Remote
Listing 7.Ustawienie domyślnego kanału w remoting–config.xml Object, pozostaje taka sama, a licencja typu
Open Source pozwala na zastosowanie przy
<default–channels> budowie aplikacji dowolnej wielkości bez
<channel ref="my–amf"/> opłat licencyjnych.
</default–channels>

BARTŁOMIEJ SOIN
W Sieci: Specjalista w zakresie technologii Flex i LiveCycle
w polskim oddziale Adobe. Wolny czas spędza na
• http://www.adobe.com/products/livecycle/dataservices – Adobe LiveCycle Data Services ES; aktywnym wypoczynku (kolarstwo górskie, wspi-
• http://opensource.adobe.com/blazeds – BlazeDS;
naczka, snowboard), zgłębianiu tajników foto-
• http://www.adobe.com/devnet/flex – Flex Developer Center.
grafii i rozpoznawaniu najnowszych technologii
internetowych.

66 FLEX
Flex i PHP

Flex i PHP
Wykorzystanie technologii Web Services i Flash Remoting do
komunikacji klient – serwer
Adobe Flex zapewnia rozbudowane możliwości tworzenia aplikacji RIA.
Jednak wciąż są to aplikacje wykonywane po stronie klienta, więc w celu
stworzenia w pełni funkcjonalnej aplikacji internetowej konieczne jest
zapewnienie odpowiedniego kanału komunikacyjnego pozwalającego na
wymianę informacji pomiędzy klientem i serwerem.
Pierwszym argumentem jest nazwa udostęp-
Dowiesz się... Powinieneś wiedzieć... nianej metody – musi ona być dokładnie taka
• Jak za pomocą języka PHP tworzyć usługi in- • Czytelnik powinien znać podstawy technolo- sama jak nazwa wcześniej utworzonej funk-
ternetowe. gii SOAP. cji. Kolejnym argumentem jest lista przyjmo-
• Jak w języku ActionScript tworzyć aplikacje wy- • Znać podstawy języka ActionScript i PHP. wanych parametrów. W naszym przypadku
korzystujące usługi SOAP oraz Flash Remoting. • Znać podstawy systemu obsługi zdarzeń w ję- funkcja nie przyjmuje żadnych argumentów,
zyku ActionScript. więc jako wartość przekazujemy pustą tablicę.
Analogicznie, jako wartość trzeciego argumen-
tu należy podać listę zwracanych wartości okre-
Następnie należy utworzyć instancję serwe- ślonych jako pary nazwa – typ. Przykładowa
ra SOAP: funkcja zwraca tekst, dlatego też jako typ po-
Poziom trudności dajemy xsd:string. Listę wszystkich dostęp-
$server = new soap_server(); nych typów danych można znaleźć w specyfi-
kacji protokołu SOAP. Ostatni argument okre-
Aby możliwe było wykorzystanie tworzonej śla przestrzeń nazw, w jakiej znajdzie się opisy-

W
artykule przedstawione zostaną usługi w aplikacji Flex, konieczne jest skonfi- wana metoda.
możliwości wykorzystania techno- gurowanie serwera tak aby generował odpo- Ostatnią czynnością jest przekazanie otrzy-
logii PHP. Przedstawię dwie meto- wiedni plik WSDL (Web Services Definition manego zapytania do serwera SOAP w celu wy-
dy pozwalające na komunikację aplikacji Flex Language), który jest odpowiedzialny za opi- wołania metody:
z serwerem PHP – Web Services i Flash Remoting. sanie usługi:
$HTTP_RAW_POST_DATA = isset( $HTTP_RAW_POST_
Web Services $server–>configureWSDL( 'sample', 'http: DATA ) ? $HTTP_RAW_POST_DATA : '';
W przypadku usług internetowych dane pomię- //localhost' ); $server–>service( $HTTP_RAW_POST_DATA );
dzy klientem i serwerem przesyłane są w forma-
cie XML. Dzięki temu stworzenie takich usług Jako pierwszy argument metody należy podać Mając już przygotowaną usługę interne-
na serwerze nie ograniczy ich wykorzystania tyl- nazwę, która będzie identyfikować opisywa- tową udostępniającą przygotowane meto-
ko do aplikacji Flex. Większość popularnych ję- ną usługę. Drugi argument określa przestrzeń dy, możemy przystąpić do utworzenia aplika-
zyków programowania posiada odpowiednie bi- nazw, w której będą się znajdować metody udo- cji klienta. W tym celu wykorzystamy klasę
blioteki wspierające obsługę Web Services. stępniane przez usługę. Kolejnym etapem jest mx.rpc.soap.WebService. Tworząc instancję
Dla języka PHP powstało kilka takich biblio- utworzenie pierwszej metody. Będzie ona od- tej klasy, należy podać adres, pod którym jest
tek. Na potrzeby niniejszego artykułu przedsta- powiedzialna za odesłanie do klienta komuni- udostępniana usługa. W naszym przypadku
wiona zostanie jedna z nich – NuSOAP. Najwięk- katu powitalnego (Listing 1.). będzie to adres utworzonego wcześniej skryp-
szą zaletę wspomnianej biblioteki stanowi fakt, Ważną czynnością jest teraz zarejestrowanie tu PHP.
iż nie wymaga ona żadnych dodatkowych roz- utworzonej metody tak, by możliwe było jej
szerzeń PHP. W rezultacie więc można jej uży- udostępnienie klientom oraz wygenerowanie var webService:WebService = new WebService(
wać nawet na bardzo ograniczonych serwerach. odpowiedniego opisu WSDL (Listing 2.). "http://localhost/ws/sample.php" );
Po pobraniu biblioteki i umieszczeniu jej na
serwerze możemy przejść do tworzenia usługi.
W pierwszej kolejności stworzymy usłu-
W Sieci
gę, której jedynym zadaniem jest odesłanie do • NuSOAP – http://sourceforge.net/projects/nusoap/;
klienta prostego powitania. Pierwszym etapem • Programming with NuSOAP using WSDL – http://www.scottnichol.com;
jest dołączenie biblioteki NuSOAP: • AMFPHP – http://www.amfphp.org;
• Flex and ActionScript with AMFPHP – http://www.sephiroth.it.
require_once('nusoap/nusoap.php');

www.sdjournal.org 67
ADOBE FLEX

Następnie należy podać adres, pod którym


dostępny jest opis WSDL podanej usługi. Bi- Listing 1. Metoda zwracająca do klienta wiadomość powitalną
blioteka NuSOAP generuje plik opisu automa- function welcome()
tycznie i jest on dostępny pod tym samym ad- {
resem co sama usługa. Należy jedynie dodać do return "Welcome client!";
niego argument wsdl: }

webService.wsdl = "http://localhost/ws/ Listing 2. Kod odpowiedzialny za rejestrację metody zdalnej


sample.php?wsdl"; $server–>register(
'welcome',
Zanim możliwe będzie wywołanie metod array(),
usługi, konieczne jest wcześniejsze załadowa- array( 'return' => 'xsd:string' ),
nie opisu WSDL. W tym celu należy wywołać 'http://localhost'
metodę loadWSDL: );

webService.loadWSDL(); Listing 3. Kod odpowiedzialny za wywołanie metody welcome


function onWsdlLoad( event:LoadEvent ):void
Ładowanie opisu usługi odbywa się asynchro- {
nicznie, dlatego też, aby wywołać metodę usługi webService.welcome.addEventListener( ResultEvent.RESULT, onWelcome );
zaraz po jego załadowaniu, konieczne jest zareje- webService.welcome.addEventListener( FaultEvent.FAULT, onFault );
strowanie metody obsługującej odpowiednie zda- webService.welcome();
rzenie: }

webService.addEventListener( LoadEvent.LOAD, Listing 4. Funkcja odpowiedzialna za odebranie wyniku działania zdalnej metody welcome
onWsdlLoad ); function onWelcome( event:ResultEvent ):void
{
Również wywoływanie metod udostępnia- trace( event.result.toString() );
nych przez usługę internetową odbywa się }
asynchronicznie. Aby wykonać kod korzystają-
cy z wyniku otrzymanego po wykonaniu wywo- Listing 5. Funkcja obsługi błędów
ływanej metody, należy ponownie skorzystać function onFault( event:FaultEvent ):void
z mechanizmu obsługi zdarzeń (Listing 3.). {
Na koniec wystarczy już tylko utworzyć trace( event.fault.getStackTrace() );
funkcję, która zostanie wykonana w momencie }
otrzymania od usługi wyniku działania wywo-
łanej wcześniej metody (Listing 4.). Listing 6. Metoda usługi odpowiedzialna za obliczenie sumy argumentów
Warto również zadbać o właściwą obsłu- function sum( $a, $b )
gę błędów, które mogą się pojawić chociażby {
w przypadku wystąpienia problemów z połą- return $a + $b;
czeniem (Listing 5.). }
W ten sposób udało się nam utworzyć usłu-
gę internetową oraz aplikację klienta. Oczywi- Listing 7. Kod odpowiedzialny za rejestrację metody zdalnej
ście przykład ten jest bardzo uproszczony, jed- $server–>register(
nakże ogólny schemat postępowania pozostaje 'sum',
dokładnie taki sam, nawet w przypadku zdecy- array( 'a' => 'xsd:int', 'b' => 'xsd:int' ),
dowanie bardziej złożonych aplikacji. array( 'return' => 'xsd:int' ),
Dotychczas nasza usługa udostępniała tyl- 'http://localhost'
ko jedną metodę, która nie wymagała podania );]
żadnych argumentów, dlatego teraz zajmiemy
się dodaniem kolejnej metody, która w wyni- Listing 8. Kod wywołujący zdalną metodę sum wraz z obsługą zdarzenia informującego o
ku działania będzie zwracać wartość otrzyma- otrzymaniu wyniku jej wykonania
ną po zsumowaniu dwóch liczb. W tym celu function onWsdlLoad( event:LoadEvent ):void
do utworzonego wcześniej pliku PHP dołączy- {
my jej implementację (Listing 6.). webService.sum.addEventListener( ResultEvent.RESULT, onSum );
Następnie, tak jak miało to miejsce w przy- webService.sum.addEventListener( FaultEvent.FAULT, onFault );
padku metody welcome, musimy dokonać jej
rejestracji (Listing 7.). webService.sum( 5, 3 );
Ze względu na to, iż metoda sum przyjmuje }
dwa argumenty, musimy podać ich listę. Jest
to konieczne do wygenerowania prawidłowego private function onSum( event:ResultEvent ):void
opisu usługi. Lista ta ma taką samą postać jak {
lista zwracanych wartości, jednak w tym przy- trace( event.result.toString() );
padku ich typ to xsd:int. Przejdźmy teraz do }
modyfikacji aplikacji klienta, tak aby wywoły-

68 FLEX
Flex i PHP

wała ona nowo utworzoną metodę (Listing 8.). jej wywołania przekazane zostały dwie liczby. Analizując przedstawione wyżej przykłady
Jak widać poza zmianą nazwy metody, podczas Jako wynik otrzymamy ich sumę. można się przekonać, że zapewnienie komu-
nikacji klienta Flex z serwerem PHP za pomo-
cą Web Services jest łatwe i nie powinno spra-
wiać większych problemów. Zaletą wykorzysta-
nia takiego rozwiązania jest przenośność, która
objawia się w możliwości użycia jednego proto-
kołu komunikacji w wielu aplikacjach klienc-
kich, tworzonych za pomocą różnych języków
programowania. Niestety, zaleta ta jest również
po części wadą. Informacje przesyłane za pomo-
cą protokołu SOAP zapisane są w formie XML.
Jak wiadomo, jest to format tekstowy, co ma du-
ży wpływ na wielkość przesyłanych danych. Mo-
że się okazać, że w przypadku ograniczonej pręd-
kości łącz lub limitów transferów wykorzystanie
usług internetowych będzie niemożliwe.

Flash Remoting
Flash Remoting jest technologią opracowaną przez
firmę Macromedia, a obecnie rozwijaną przez
Adobe. Służy ona do wymiany danych pomiędzy
klientami napisanymi w języku ActionScript a ser-
werem obsługującym format AMF (ang. Action-
Script Message Format). Wspomniana technologia
Rysunek 1. Service Browser dostarczany wraz z biblioteką AMFPHP pozwala na szybkie testowanie jest w dużym stopniu oparta na wspomnianym
tworzonych usług wcześniej protokole SOAP, jednak w przypadku
AMF dane przesyłane są w formie binarnej.
Listing 15. Kod źródłowy usługi Flash Remoting wykorzystującej AMFPHP Tworzenie usług Flash Remoting za pomocą
PHP możliwe jest dzięki bibliotece AMFPHP. Jest
<?php ona cały czas rozwijana, aktualnie trwają prace nad
include_once( AMFPHP_BASE . "shared/util/MethodTable.php" ); wersją 2.0. Po skopiowaniu plików źródłowych na
class Sample serwer można przystąpić do tworzenia usług, któ-
{ re umieszczamy w katalogu amfphp/services.
function welcome() W przypadku AMFPHP usługi tworzone są
{ w formie klas zawierających udostępniane me-
return "Welcome client!"; tody. Aby ułatwić porównanie obu technolo-
} gii, utworzymy dwie metody, które będą dzia-
łać dokładnie tak samo, jak to miało miejsce
function sum( $a, $b ) w poprzednim przykładzie.
{ Na początek należy do skryptu tworzonej
return $a + $b; usługi dołączyć klasę MethodTable dostarcza-
} ną wraz z biblioteką AMFPHP:
}
?> include_once( AMFPHP_BASE . "shared/util/
MethodTable.php" );
Listing 9. Funkcja odpowiedzialna za odebranie wyniku wykonania zdalnej metody welcome
function onWelcomeResult( message:String ):void Następnie tworzymy klasę, która będzie repre-
{ zentować naszą usługę. Zawiera ona dwie me-
trace( message ); tody, które były już wykorzystywane wcześniej
} (Listing 15.).
Poważną zaletą wykorzystania biblioteki AMFPHP
Listing 10. Funkcja obsługi błędów jest to, iż nie musimy zajmować się tworzeniem
function onFault( fault:Object ):void opisu usługi ani nawet w żaden sposób rejestro-
{ wać udostępnianych metod. Wszystko odbywa się
trace( “Flash Remoting error!” ); automatycznie, co bardzo ułatwia pracę i pozwala
} uniknąć ewentualnych błędów. Dodatkowym atu-
tem AMFPHP jest to, iż nie narzuca ona konieczno-
Listing 11. Funkcja odpowiedzialna za odebranie wyniku wykonania zdalnej metody sum ści aktualizacji informacji o udostępnianych meto-
function onSumResult( result:Number ):void dach podczas dokonywania zmian dotyczących li-
{ sty argumentów czy też zwracanych wartości.
trace( result ); Autorzy AMFPHP przygotowali również na-
} rzędzie ułatwiające testowanie utworzonych
usług bez potrzeby tworzenia testowych apli-

www.sdjournal.org 69
ADOBE FLEX

kacji. Service Browser przedstawia listę dostęp- ocenioną pomocą w codziennej pracy (patrz: stywane są klasy flash.net.NetConnection
nych usług oraz ich metod umożliwiając jed- Rysunek 1.). oraz flash.net.Responder. Pierwsza z nich
nocześnie podanie argumentów i sprawdzenie Tworzenie klienta usług Flash Remoting jest w odpowiada za obsługę połączenia z usługą, dru-
wyniku działania. Narzędzie to dostępne jest w pewnym stopniu podobne do tworzenia klien- ga natomiast zajmuje się obsługą wywołania
katalogu amfphp/browser/index.html i jest nie- tów Web Services. W tym przypadku wykorzy- udostępnionej metody. W pierwszej kolejności

Listing 12. Kod źródłowy klienta Web Services

// File: SoapClient.as webService.welcome();


package
{ webService.sum.addEventListener(
import mx.core.Application; ResultEvent.RESULT, onSum );
import mx.rpc.events.FaultEvent; webService.sum.addEventListener( FaultEvent.FAULT,
import mx.rpc.events.ResultEvent; onFault );
import mx.rpc.soap.LoadEvent;
import mx.rpc.soap.WebService; webService.sum( 5, 3 );
}
public class SoapClient extends Application
{ private function onWelcome( event:ResultEvent ):void
private var webService:WebService; {
trace( event.result.toString() );
public function SoapClient() }
{
super(); private function onSum( event:ResultEvent ):void
{
webService = new WebService( "http://localhost/ws/ trace( event.result.toString() );
sample.php" ); }

webService.wsdl = "http://localhost/ws/ private function onFault( event:FaultEvent ):void


sample.php?wsdl"; {
webService.addEventListener( trace( event.fault.getStackTrace() );
LoadEvent.LOAD, onWsdlLoad ); }
}
webService.loadWSDL(); }
}
<!– File: SoapClientView.mxml –>
private function onWsdlLoad( event:LoadEvent ):void <?xml version="1.0" encoding="utf–8"?>
{ <SoapClient
webService.welcome.addEventListener( xmlns="*"
ResultEvent.RESULT, onWelcome ); xmlns:mx="http://www.adobe.com/2006/mxml"
webService.welcome.addEventListener( layout="absolute">
FaultEvent.FAULT, onFault ); </SoapClient>

Listing 13. Kod źródłowy usługi Web Services wykorzystującej bibliotekę NuSOAP
<?php 'http://localhost'
require_once( 'nusoap/nusoap.php' ); );

$server = new soap_server(); function welcome()

$server–>configureWSDL( 'sample', 'http://localhost' ); {


return "Welcome client!";
$server–>register( }
'welcome',
array(), function sum( $a, $b )
array('return' => 'xsd:string'), {
'http://localhost'); return $a + $b;
}
$server–>register( $HTTP_RAW_POST_DATA = isset( $HTTP_RAW_POST_DATA ) ? $HTTP_
'sum', RAW_POST_DATA : '';
array( 'a' => "xsd:int", 'b' => 'xsd:int' ), $server–>service( $HTTP_RAW_POST_DATA );
array('return' => 'xsd:int'), ?>

70 FLEX
Flex i PHP

należy utworzyć instancję klasę NetConnection otrzymywać wynik bezpośrednio w formie ar- zdalnej należy wykonać metodę call clasy
i nawiązać połączenie z bramą AMFPHP, która gumentu (Listing 9.). NetConnection.
odpowiada za dostęp do usług: Natomiast funkcja obsługi błędów została
przedstawiona na Listingu 10. connection.call( "Sample.welcome", responder );
var connection:NetConnection = new NetConnec W celu wywołania metody konieczne jest
tion(); utworzenie instancji klasy Responder. Odpo- Nazwa wywoływanej metody zdalnej jest prze-
connection.connect( "http://localhost/amfphp/ wiada ona za przekazanie wyniku do odpo- kazywana w formie NazwaUsługi.NazwaMetody.
gateway.php" ); wiedniej funkcji lub też poinformowania o wy- W przypadku wykorzystania AMFPHP nazwa
stąpieniu błędu: usługi odnosi się do klasy, w której zdefinio-
Wykorzystanie Flash Remoting pozwala unik- wana została wykonywana metoda. Drugi ar-
nąć konieczności ładowania opisu usługi, dzię- var responder:Responder = new Responder( on- gument to wcześniej utworzony obiekt odpo-
ki czemu możemy przystąpić do wywoływa- WelcomeResult, onFault ); wiedzialny za obsługę tego wywołania meto-
nia usług. dy zdalnej.
Najpierw zajmiemy się przygotowaniem Jako pierwszy argument podajemy referencję Przejdziemy teraz do drugiej metody udostęp-
funkcji odpowiedzialnej za odebranie wyniku do funkcji, która jest odpowiedzialna za ode- nianej przez naszą usługę. W jej przypadku ko-
wykonania wywoływanej metody. Na początek branie wyniku działania wywoływanej metody, nieczne jest przekazanie dwóch argumentów, któ-
zajmiemy się metodą welcome. W przypadku natomiast drugi argument to referencja do me- re w wyniku jej działania zostaną zsumowane:
wykorzystania Flash Remoting funkcja ta będzie tody obsługi błędu. W celu wykonania metody
var responder:Responder = new Responder( on-
SumResult, onFault );
Listing 14. Kod źródłowy kompletnej aplikacji klienta Flash Remoting
connection.call( "Sample.sum", responder, 4, 5 );
// File: SoapClient.as
package W tej sytuacji metoda onSumResult odpowie-
{ dzialna za odebranie wyniku działania me-
import flash.net.NetConnection; tody zdalnej będzie się różnic od metody
import flash.net.Responder; onWelcomeResult tylko typem przyjmowane-
import mx.core.Application; go argumentu (Listing 11.).
public class AmfClient extends Application
{ Podsumowanie
private var connection:NetConnection; Zapewnienie komunikacji na linii klient – ser-
wer jest możliwe na wiele różnych sposobów.
public function AmfClient() Jednak wykorzystanie Web Services i Flash Re-
{ moting w dużym stopniu ułatwia i przyspiesza
connection = new NetConnection(); związane z tym prace. Warto tutaj nadmienić,
connection.connect( "http://localhost/amfphp/gateway.php" ); iż obie technologie umożliwiają przesyłanie
złożonych obiektów, zagadnienie to jednak wy-
var responder:Responder = new Responder( onWelcomeResult, onFault ); kracza poza ramy niniejszego artykułu.
connection.call( "Sample.welcome", responder ); W przypadku Web Service dane przesyłane są
responder = new Responder( onSumResult, onFault ); w formacie XML, co ma duży wpływ na szyb-
connection.call( "Sample.sum", responder, 4, 5 ); kość i ilość przesyłanych informacji. Jednak
} dzięki wykorzystaniu protokołu SOAP, usługi
private function onWelcomeResult( message:String ):void te będą również dostępne dla aplikacji tworzo-
{ nych w innych językach programowania.
trace( message ); Flash Remoting przesyła dane w formie binar-
} nej, co w znacznym stopniu przyspiesza trans-
private function onSumResult( result:Number ):void misję. Niestety protokół AMF ogranicza wyko-
{ rzystanie tych usług do aplikacji utworzonych
trace( result ); w języku ActionScript.
}

private function onFault( event:Object ):void JAKUB WĘGRZYN


{ Pracuje na stanowisku Technical Unit Manager w fir-
trace( "Flash Remoting error!" ); mie Gamelion, wchodzącej w skład Grupy BLStream.
} Jakub kieruje komórką odpowiedzialną za progra-
} mowanie gier opartych na technologii Flash. Gru-
} pa BLStream powstała, by efektywniej wykorzysty-
wać potencjał dwóch, szybko rozwijających się pro-
<!– File: AmfClientView.mxml –> ducentów oprogramowania – BLStream i Game-
<?xml version="1.0" encoding="utf–8"?> lion. Firmy wchodzące w skład grupy specjalizują się
<AmfClient w wytwarzaniu oprogramowania dla klientów kor-
xmlns="*" poracyjnych, w rozwiązaniach mobilnych oraz pro-
xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> dukcji i testowaniu gier.
</AmfClient> Kontakt z autorem: jakub.wegrzyn@game–lion.com

www.sdjournal.org 71
ADOBE FLEX

ActionScript 3.0
Podstawowe wzorce projektowe oraz idiomy kodowania.

Można śmiało założyć, że każdy średnio doświadczony programista


przynajmniej raz spotkał się z pojęciem wzorców projektowych. W dużym
uproszczeniu można powiedzieć, iż wzorce są zestawem standardowych
rozwiązań najczęściej spotykanych problemów natury architekturalnej,
związanych z organizacją i tworzeniem oprogramowania.
na Listingu 1. Osoby, które miały już wcze-
Dowiesz się... Powinieneś wiedzieć... śniej do czynienia z tym wzorcem w innych
• W jaki sposób implementować podstawowe • Czytelnik powinien znać podstawy programo- językach programowania, zapewne zauwa-
wzorce projektowe w języku ActionScript 3. wania w języku ActionScript. żą w przedstawionej implementacji pewien
• Jak radzić sobie z ograniczeniami w Action- • Znać podstawowe koncepcje związane z pro- zasadniczy problem – brak zabezpieczenia
Script 3. gramowaniem zorientowanym obiektowo przed tworzeniem wielu egzemplarzy kla-
(OOP – ang. Object Oriented Programming). sy. Dla przykładu, w języku C++ wystarczy
w tym celu zadeklarować konstruktor klasy
Singleton jako prywatny lub chroniony. Jed-
gramistów rozpoczyna właśnie od niego swo- nak podczas prac nad językiem ActionScript
ją przygodę ze wzorcami. Wykorzystuje się 3, w celu spełnienia standardów określo-
Poziom trudności go w celu zagwarantowania tego, iż klasa bę- nych w specyfikacji ECMAScript, zrezygno-
dzie posiadać tylko jeden egzemplarz. Do- wano z możliwości tworzenia prywatnych
datkowym zadaniem Singeltonu jest zapew- konstruktorów. Na szczęście można rozwią-
nienie globalnego dostępu do wspomniane- zać ten problem na kilka sposobów. Jednym

W
spomniane rozwiązania zostały po go egzemplarza. z nich jest wykorzystanie prywatnych klas.
raz pierwszy skatalogowane i opi- Standardowa implementacja Singletonu W tym celu używa się pewnej sztuczki, po-
sane przez tzw. Bandę Czterech w języku ActionScript 3 jest przedstawiona legającej na zadeklarowaniu klasy poza zasię-
(ang. Gang of Four, w skrócie GoF) w książ-
ce Wzorce projektowe – elementy oprogramowa- Listing 1. Prosta implementacja wzorca Singleton w języku ActionScript
nia obiektowego wielokrotnego użytku. Pozy-
cja ta została wydana na polskim rynku przez package
wydawnictwo WNT w ramach serii Inżynieria {
Oprogramowania. W artykule tym przedsta- public class Singleton
wię sposoby implementacji oraz wykorzysta- {
nia kilku popularnych wzorców projektowych private static var instance:Singleton;
w odniesieniu do języka ActionScript.
Warto w tym miejscu podkreślić, iż ce- public function Singleton()
lem tego artykułu nie jest dokładne przed- {
stawienie wszystkich opracowanych do tej // Initialization code
pory wzorców, lecz przedstawienie pewnych }
przekrojowych problemów związanych z ich
implementacją w języku ActionScript 3.0. public static function getInstance():Singleton
W tym kontekście opisane zostaną tylko dwa {
popularne wzorce projektowe – Singleton oraz if ( !instance )
Metoda Wytwórcza, wraz z jednym idiomem {
językowym – Wyliczeniem. Osoby zaintereso- instance = new Singleton();
wane zgłębianiem wiedzy z tej dziedziny odsy- }
łam do literatury zamieszczonej w ramce.
return instance;
Singleton }
Singelton jest to chyba jeden z najbardziej roz- }
powszechnionych wzorców projektowych za- }
proponowanych przez GoF. Duża część pro-

72 FLEX
ActionScript 3.0

giem jakiejkolwiek przestrzeni nazw, co au- na tylko w obrębie tego samego pliku źródło- Oczywiście zaproponowane rozwiązanie
tomatycznie sprawia, że klasa ta jest dostęp- wego (Listing 2.). może być uznane za swojego rodzaju hak lub
nadużycie. Jednak z powodu braku możli-
Listing 2. Propozycja rozwiązania problemu prywatnego konstruktora za pomocą klasy
wości stosowania prywatnych konstrukto-
zadeklarowanej poza przestrzenią nazw rów konieczne jest poszukiwanie alterna-
tywnych rozwiązań. W przeciwnym wypad-
package ku pozostaje jedynie nadzieja na to, że oso-
{ by korzystające z tej klasy będą wiedziały, aby
public class Singleton samodzielnie nie tworzyć egzemplarzy klasy
{ Singleton, co należy uznać za jeszcze gorsze
private static var instance:Singleton; nadużycie.

public function Singleton( blocker:SingletonBlocker ) Typy wyliczeniowe (enum)


{ Wyliczenie jest to raczej idiom kodowania,
if ( blocker == null ) a nie klasyczny wzorzec projektowy, jednak-
{ że brak tej konstrukcji w języku ActionScript
throw new Error( "Cannot instantiate Singleton class!" ); 3 może być dosyć uciążliwy. Z tego powodu
} powstało kilka propozycji uzupełnienia tej
} luki. Przedstawienie ich wszystkich jest te-
matem na oddzielny artykuł, dlatego też sku-
public static function getInstance():Singleton pię się w tym miejscu na rozwiązaniu, któ-
{ re może spełnić większość wymagań stawia-
if ( !instance ) nych przez programistów chcących go wyko-
{ rzystać w swojej codziennej pracy.
instance = new Singleton( new SingletonBlocker() ); Najważniejszym problemem, z którym
} trzeba się zmierzyć jest zapewnienie kontro-
li typu tak, aby korzystanie ze zdefiniowane-
return instance; go wyliczenia było kontrolowane przez kom-
} pilator. Aby tego dokonać, należy zadeklaro-
} wać klasę, która będzie zawierała statyczne
} pola odpowiadające za poszczególne warto-
ści wyliczenia (Listing 3.).
class SingletonBlocker Przykładem wykorzystania takiego wyli-
{ czenia może być funkcja, której argumentem
} jest jego wartość, tak jak zostało to przedsta-
wione na Listingu 4.
Listing 3. Przykład implementacji wyliczenia umożliwiający wykorzystanie kontroli typu Kolejny raz można zauważyć pewien pro-
blem związany z wykorzystywaniem klasy
package{ reprezentującej typ wyliczeniowy niezgodnie
public class ShapeEnum z przeznaczeniem. Dokładniej chodzi tutaj
o problem prywatnego konstruktora. W ce-
{ lu zabezpieczenia właściwej kontroli typu
public function ShapeEnum() konieczne jest zapewnienie tego, iż egzem-
{ plarze tej klasy nie będą tworzone poza nią
public static const TRIANGLE:ShapeEnum = new ShapeEnum(); samą. Innymi słowy, chcemy mieć pewność,
public static const RECTANGLE:ShapeEnum = new ShapeEnum(); że jej instancje są tworzone tylko podczas ini-
public static const CIRCLE:ShapeEnum = new ShapeEnum(); cjalizacji statycznych stałych identyfikują-
cych wartości wyliczenia.
public function ShapeEnum() Tym razem zastosuję alternatywne rozwią-
{ zanie problemu prywatnego konstruktora.
} Wykorzystuje ono technikę nazywaną statycz-
} nym inicjalizatorem (static initializer). Techni-
} ka ta opiera się na dostarczeniu fragmentu ko-
} du, który jest wykonywany, zanim możliwość
tworzenia jej egzemplarzy zostanie udostęp-

Literatura
• Wzorce projektowe. Elementy oprogramowania obiektowego wielokrotnego użytku, Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, Wy-
dawnictwa Naukowo–Techniczne;
• Advanced ActionScript 3 with Design Patterns, Joey Lott, Danny Patterson, Adobe Press;
• ActionScript 3.0 Design Patterns: Object Oriented Programming Techniques, William Sanders, Chandima Cumaranatunge, Adobe Developer Library /
O’Reilly.

www.sdjournal.org 73
ADOBE FLEX

niona na zewnątrz klasy, ale już po inicjalizacji Object.toString, co ułatwi kontrolę wartości ked na true tuż po zainicjalizowaniu wszyst-
jej statycznych pól. wyliczenia za pomocą funkcji trace (Listing 5.). kich pól statycznych, co uniemożliwi wyko-
Dodatkowym elementem ułatwiającym korzy- Powyższy przykład wykorzystuje statycz- rzystanie klasy ShapeEnum poza przewidzia-
stanie z wyliczenia będzie przeciążenie metody ny inicjalizator do zmiany wartości pola loc- nym zakresem.
Zaprezentowana realizacja typu wyliczenio-
Listing 4. Przykład wykorzystania przedstawionej implementacji wyliczenia wego w ActionScript 3 na pewno nie jest ideal-
na. Jedną z jej wad jest konieczność tworzenia
function drawShape( shape:ShapeEnum ):void klasy dla każdego wyliczenia. Ponadto nie ofe-
{ ruje ona możliwości iterowania po kolejnych
switch ( shape ) wartościach, tak jak ma to miejsce w innych ję-
{ zykach programowania. Jednak zapewnienie
case ShapeEnum.TRIANGLE: silnej kontroli typu może być wystarczającym
// Draw triangle argumentem przemawiającym za wykorzysta-
break; niem tego rozwiązania.
case ShapeEnum.RECTANGLE:
// Draw rectangle Metoda Wytwórcza
break; (ang. Factory Method)
case ShapeEnum.CIRCLE: Jest to jeden z najprostszych wzorców pro-
// Draw circle jektowych. Metoda wytwórcza odpowiada za
break; utworzenie obiektów będących egzemplarza-
} mi klas implementujących wspólny interfejs.
} Kod wykorzystujący ten wzorzec zrzuca na
niego odpowiedzialność za wybór właściwej
Listing 5. Poprawiona implementacja wyliczenia wykorzystująca statyczny inicjalizator implementacji tego interfejsu.
package Na początek konieczne jest określenie in-
{ terfejsu produktu metody wytwórczej (Li-
public class ShapeEnum sting 6.). Następnie należy zdefiniować kla-
{ sy implementujące ten interfejs (Listing 7.).
public function ShapeEnum() Oczywiście jest to tylko mocno uproszczo-
{ ny kod mający za zadanie ułatwienie zrozu-
public static const TRIANGLE:ShapeEnum = new ShapeEnum( “Triangle” ); mienia specyfiki korzystania z metody wy-
public static const RECTANGLE:ShapeEnum = new ShapeEnum( “Rectangle” ); twórczej.
public static const CIRCLE:ShapeEnum = new ShapeEnum( “Circle” );
private static var locked:Boolean = false;
Listing 7. Definicje klas implementujących
{ interfejs produktu metody wytwórczej
locked = true;
} // File: Triangle.as
class Triangle implements Ishape
private var _name:String; {
public function draw():void
public function ShapeEnum( name:String ) {
{ // Draw triangle
if ( locked ) }
{ }
throw new Error( "Cannot instantiate ShapeEnum class!" );
} // File: Rectangle.as
class Rectangle implements Ishape
_name = name; {
} public function draw():void
{
public override function toString():String // Draw rectangle
{ }
return “ShapeEnum.” + _name; }
}
} // File: Circle.as
} class Circle implements Ishape
} {
public function draw():void
Listing 6. Przykładowy interfejs produktu metody wytwórczej {
interface Ishape // Draw circle
{ }
function draw():void; }
}

74 FLEX
ActionScript 3.0

W artykule przedstawimy odmianę wzor- Zaproponowana implementacja wzorca świadomości jego istnienia. Jego stosowa-
ca nazywaną Sparametryzowaną Metodą Wy- jest oczywiście prosta i ma jedynie wartość nie może być po prostu wynikiem własnych
twórczą. Główna zasada jej działania pole- czysto merytoryczną. Warto jednak zauwa- przemyśleń. Jednak faktem jest, że wzorzec
ga na utworzeniu metody przyjmującej jako żyć, że jej stosowanie pozwala na tworzenie ten jest bardzo praktyczny, a jednocześnie
argument wartość pozwalającą zidentyfiko- obiektów, których inicjalizacja wymaga wy- dzięki swojej prostocie jego użycie nie spra-
wać metodzie wytwórczej typ obiektu oczeki- konania większej ilości operacji w celu cho- wia większym problemów i nie wprowadza
wanego jako produkt. Oczywiście metoda wy- ciażby przygotowania dużej ilości danych. dodatkowych ograniczeń. Podobnym wzor-
twórcza może podejmować decyzję o wyborze Warto również zauważyć, że możliwe jest cem jest Fabryka Abstrakcyjna (ang. Abstract
konkretnej implementacji produktu na pod- rozszerzenie przedstawionej klasy w celu Factory), który zapewnia interfejs odpowie-
stawie dowolnych danych przewidzianych umożliwienia tworzenia dodatkowych obiek- dzialny za tworzenie rodzin powiązanych ze
przez programistę. W przykładzie zostanie tów. Przedstawia to Listing 9. sobą obiektów bez znajomości ich konkret-
wykorzystany typ wyliczeniowy przedstawio- Metoda wytwórcza jest popularnym wzor- nych implementacji. Jednak opis tego wzor-
ny w poprzedniej części artykułu (Listing 8.). cem, który często jest wykorzystywany bez ca wykracza poza łamy niniejszego artykułu,
dlatego też zachęcam do zapoznania się z lite-
Listing 8. Implementacja metody wytwórczej wykorzystując typ wyliczeniowy raturą opisującą wzorce projektowe.

class ShapeCreator Podsumowanie


{ Wzorce projektowe są nieocenionym na-
public function createShape( type:ShapeEnum ):Ishape rzędziem każdego programisty. Pomagają
{ w szybkim projektowaniu i tworzeniu opro-
switch ( shape ) gramowania, co w oczywisty sposób wpisuje
{ się w ideę RIA. Wzorce ułatwiają też komu-
case ShapeEnum.TRIANGLE: nikację pomiędzy programistami (na przy-
return new Triangle(); kład, posługując się ustandaryzowanym ję-
break; zykiem wzorców projektowych łatwiej pro-
case ShapeEnum.RECTANGLE: wadzić dyskusję o architekturze danego roz-
return new Rectangle(); wiązania). Niestety, język ActionScript 3.0
break; w pewnych kwestiach utrudnia ich imple-
case ShapeEnum.CIRCLE: mentację, wymuszając w ten sposób stoso-
return new Circle(); wanie sztuczek, które nie są powszechnie
break; znane.
default: Podobnie sytuacja wygląda w przypadku
throw new Error( “Unknown shape!” ); braku pewnych idiomów językowych, któ-
break; re są powszechnie stosowane w innych języ-
} kach programowania. Tutaj również progra-
} miści muszą się wykazywać pomysłowością
} i dociekliwością co niestety często jest nie-
możliwe w warunkach dużych ograniczeń
Listing 9. Rozszerzenie metody wytwórczej o nowy produkt czasowych.
W przedstawionym artykule podałem ze-
class AdvancedShapeCreator extends ShapeCreator staw gotowych rozwiązań nawiązujących do
{ popularnych wzorców projektowych i idio-
public function createShape( type:ShapeEnum ):Ishape mów kodowania. Mam nadzieję, że rozwią-
{ zania te pozwolą zaoszczędzić cenny czas
if ( type == ShapeEnum.STAR ) czytelników tworzących projekty w Action-
{ Script 3.
return new Star();
}
else
{ JAKUB WĘGRZYN
return super.createShape( type ); Pracuje na stanowisku Technical Unit Manager
} w firmie Gamelion, wchodzącej w skład Grupy
} BLStream. Jakub kieruje komórką odpowiedzial-
} ną za programowanie gier opartych na techno-
logii Flash. Grupa BLStream powstała, by efek-
tywniej wykorzystywać potencjał dwóch, szyb-
ko rozwijających się producentów oprogramo-
W Sieci wania – BLStream i Gamelion. Firmy wchodzą-
• ActionScript 3 Design Patterns – http://www.as3dp.com/; ce w skład grupy specjalizują się w wytwarzaniu
• Introduction to Design Patterns – http://www.moock.org/lectures/introToPatterns/; oprogramowania dla klientów korporacyjnych,
• Enums and ActionScript's Static Initializers – http://www.barneyb.com/barneyblog/; w rozwiązaniach mobilnych oraz produkcji i te-
• AS3: Singletons – http://www.gskinner.com/blog/; stowaniu gier.
• ActionScript 3 Singleton Redux – http://www.darronschall.com/weblog/.
Kontakt z autorem:
jakub.wegrzyn@game–lion.com

www.sdjournal.org 75
TIPS & TRICKS

Flex Tips & Tricks


Chciałbym odtworzyć plik MP3 we Flex. Jak to zrobić? własność selectedRanges, która jest tablicą obiektów zawierających dane
Do odtwarzania dźwięków, wykorzystujemy klasę Sound w połączeniu rangeStart oraz rangeEnd, na podstawie których można łatwo obliczyć
z URLRequest. Przykładowo: różnicę dni za pomocą ActionScript.

var snd:Sound = new Sound(new URLRequest("muzyka.mp3")); // Stała zawierająca ilość milisekund w jednym dniu
snd.play(); private const MS_PER_DAY:uint = 1000 * 60 * 60 * 24;
// Parametem jest jeden z obiektów
tablicy selectedRanges
Możemy także podać funkcji play() parametry takie jak miejsce, od które- private function calculateDays(item:Object):String {
go ma zacząć odtwarzać (w milisekundach) lub ilość powtórzeń: var tempDate:Date = new Date(item.rangeEnd – item.rangeStart);
return Math.round((tempDate.time / MS_PER_DAY) +
snd.play(1000, 3); // Odtwórz od pierwszej sekundy trzy razy 1).toString();
}

Mam tablicę zawierającą kilka rekordów, gdzie każdy z nich po-


siada dane takie jak imię, nazwisko czy datę urodzenia. Chciał- W jaki sposób formatować daty w kontrolce DateField?
bym je wyświetlać jako listę, a nie siatkę. Czy jest to możliwe? Do formatowania dat Flex posiada klasę DateFormatter, którą można
Oczywiście, Wystarczy użyć komponentu List (lub HorizontalList je- użyć za pomocą małej funkcji przypisanej jako labelFunction:
śli wolimy) i ustawić mu własność itemRenderer.
<mx:Script>
<mx:List itemRenderer="MyItemRenderer" x="0" y="0" width="300" <![CDATA[
height="300"> private function doLabel(item:Date):String {
<mx:dataProvider> return dateFormatter.format(item);
<mx:Array> }
<mx:Object name="Jan" surname="Kowalski" birthdate="1-2-1950" /> ]]>
<mx:Object name="Adam" surname="Marek" birthdate="4-7-1968" /> </mx:Script>
<mx:Object name="Marcin" surname="Iksiński" birthdate="8-12- <mx:DateFormatter id="dateFormatter" formatString="D MMM YYYY"/>
1989" /> <mx:DateField labelFunction="doLabel" />
</mx:Array>
</mx:dataProvider>
</mx:List> Jak zrobić aby zamienić
kolorowy obrazek w czarno-biały?
Do tego celu musimy użyć filtru ColorMatrixFilter i odpowiedniej ma-
Następnie tworzymy nowy komponent, w którym ustalamy sposób wy- trycy kolorów:
świetlania naszych danych:
<mx:Script>
<?xml version="1.0" encoding="utf-8"?> <![CDATA[
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" private var rLum:Number = 0.2225;
width="100%" height="40"> private var gLum:Number = 0.7169;
<mx:Label text="{data.name}" x="5" y="0" /> private var bLum:Number = 0.0606;
<mx:Label text="{data.surname}" x="5" y="15" /> [Bindable]
<mx:Label text="{data.birthdate}" x="5" y="30" /> private var bwMatrix:Array =
</mx:Canvas> [rLum, gLum, bLum, 0, 0, rLum,
gLum, bLum, 0, 0, rLum, gLum,
bLum, 0, 0, 0, 0, 0, 1, 0];
Renderer może być edytowany graficznie, więc ułatwia to nam jego pro- [Bindable]
jektowanie. [Embed('obrazek.jpg')]
private var image:Class;
Jak obliczyć ilość dni pomiędzy ]]> </mx:Script>
zaznaczonymi datami w kontrolce DateChooser? <mx:ColorMatrixFilter id="cmf" matrix="{bwMatrix}" />
Kontrolka DateChooser poza zaznaczeniem jednej daty, pozwala zaznaczyć <mx:Image source="{image}" filters="{[cmf]}" />
jeden lub więcej przedziałów dni. Dostęp do tych informacji mamy poprzez

76 FLEX
TIPS & TRICKS

Polecam poczytać o tym filtrze oraz pobawić się z wartościami matrycy. Jak ustawić ikonę w przycisku?
Daje to czasami ciekawe rezultaty. Ustawienie ikony wymaga poprzedniego je osadzenia w aplikacji lub za-
ładowania jej z zewnątrz. Osadzić ją możemy na dwa sposoby: poprzez
Jak wyświetlić dane XML wewnątrz komponentu DataGrid? ActionScript lub MXML według kodów poniżej.
Obsługa XML jest bardzo prosta we Flex. Wystarczy użyć klasy XML
oraz XMLListCollection w połączeniu z DataGrid. <mx:Script>
Mając przykładowy plik XML "dane.xml": <![CDATA[
[Bindable]
<?xml version="1.0" encoding="UTF-8" ?> [Embed(source="ikona.png")]
<osoby> private var Icon:Class;
<osoba> ]]>
<name>Jan</name> </mx:Script>
<surname>Kowalski</surname> <mx:Button label="[Embed(source='ikona.png')]" icon="{Icon}" />
<birthdate>1-2-1950</birthdate> <mx:Button label="@Embed('ikona.png')" icon="@Embed('ikona.png
</osoba> ')" />
<osoba>
<name>Adam</name>
<surname>Marek</surname> W jaki sposób wyświetlić
<birthdate>4-7-1968</birthdate> okno dialogowe z przyciskami Tak i Nie?
</osoba> Flex udostępnia klasę Alert, która może być zastosowana do tego celu:
<osoba>
<name>Marcin</name> <mx:Script>
<surname>Iksiński</surname> <![CDATA[
<birthdate>8-12-1989</birthdate> import mx.controls.Alert;
</osoba> private var alert:Alert;
</osoby> private function showAlert():void {
var text:String = "Czy na pewno chcesz wykonać tą jakże
ważną akcję?";
Wystarczy poniższy kod: var title:String = "Tytuł okienka";
alert = Alert.show(text, title, Alert.YES | Alert.NO);
<mx:XML id="myXML" source="dane.xml" /> }
<mx:XMLListCollection id="myXMLList" source="{myXML.osoba}" /> ]]>
<mx:DataGrid id="dataGrid" dataProvider="{myXMLList}" </mx:Script>
width="100%" rowCount= <mx:Button label="Alert.show()" click="showAlert();" />
"{myXMLList.length + 1}">
<mx:columns>
<mx:DataGridColumn id="nameCol" dataField="name" Niestety przyciski są w języku angielskim, więc jeśli chcemy mieć je
headerText="Imie" /> po polsku, musimy stworzyć własne okno dialogowe.
<mx:DataGridColumn id="surnameCol" dataField="surname"
headerText="Nazwisko" /> Jak zmienić format podpowiedzi w kontrolce Slider?
<mx:DataGridColumn Do tego celu musimy ustawić własność dataTipFormatFunction na na-
id="birthdateCol" dataField="birthdate" headerText="Data szą funkcję:
urodzenia" />
</mx:columns> <mx:Script>
</mx:DataGrid> <![CDATA[
private function formatFunction(item:Object):String {
return "Minimalna cena: " + item.toString() + "zł";
Czy mogę zmienić czas po jakim znika podpowiedź (ToolTip)? }
Tak. Wystarczy użyć klasy ToolTipManager: ]]>
</mx:Script>
<mx:Script> <mx:HSlider id="slider" width="200" liveDragging="true"
<![CDATA[ minimum="1" snapInterval="1"
import mx.managers.ToolTipManager; tickInterval="1" value="3" dataTipFormat
ToolTipManager.hideDelay = 2500; Function="formatFunction" />
]]> <mx:Label id="lbl" text="{slider.value}" />
</mx:Script>

<mx:Button id="button" label="Najedź na mnie" toolTip="Jestem Więcej przykładów w języku angielskim, można znaleźć na:
podpowiedzią która zniknie po 2,5s." /> http://blog.flexexamples.com/

www.sdjournal.org 77
Wywiad

Mike Chambers
dla SDJ Extra
Magazyn SDJ Extra zdołał przyłapać Mike'a Chambersa podczas konferencji
onAIR w Warszawie poświęconej środowisku wykonawczemu AIR 1.1,
gdzie omawiał nowości w odtwarzaczu Flash 10 oraz przybliżył swoją
wcześniejszą pracę przy Macromedia Generator.

Mike Chambers – Principal wypracowało nam metody wdrażania tych nak chcesz być bliżej użytkownika, wtedy
aplikacji. Było to coś, z czym musieliśmy Adobe AIR jest tym czego warto szukać.
Product Manager Developer uporać się dawno temu, ale nie mieliśmy ty-
Relations Flash Platform le zasobów ile byśmy sobie życzyli jako fir- SDJ: Jak wyglądają plany na rozwój AIR?
ma, dlatego połączyliśmy się z Adobe, co MC: Obecnie jesteśmy na etapie angloję-
spowodowało znaczne zwiększenie możli- zycznej wersji AIR 1.0. Pracę nad kolejną wer-
SDJ: Cześć Mike, mógłbyś opowiedzieć wości zespołu. Adobe wykonywał podob- sją rozpoczęliśmy w lutym i zbliżamy się do
nam trochę o sobie, swoim doświadcze- ną pracę z PDF, firma posiada know-how. In- wydania AIR 1.1. Automatycznie zaoferuje-
niu? W jaki sposób rozpocząłeś swoją pra- tegracja z Adobe była znakomitym momen- my wsparcie dla 10 języków. Następnie zaj-
cę w Adobe? tem na rozpoczęcie pracy nad AIR. miemy się pracą nad następną pełną wer-
MC: Nazywam się Mike Chambers i pracuję sją środowiska. W międzyczasie wprowadzi-
dla Adobe. Jestem Głównym Kierownikiem SDJ: Jakie ograniczenia technologiczne my wersję dla Linuxa, integrację odtwarza-
Projektu odpowiedzialnym za relacje pomię- przeglądarki musieliście rozważyć? cza Flash 10 i inne rzeczy.
dzy deweloperami. Jest to dosyć tajemnicza MC: Jeśli spojrzeć szczególnie na dwa ostat-
nazwa stanowiska, ale właściwie to pracuję nie lata, można zauważyć niesamowitą eks- SDJ: Możesz nam opowiedzieć trochę wię-
nad odtwarzaczem Flash i zespołami odpo- plozję aplikacji internetowych i aplikacji cej o przyszłości Flasha?
wiedzialnymi za środowisko AIR. Dbam o do- wdrażanych na przeglądarki. Jest wiele po- MC: Na razie wydaliśmy on-line wersję beta
bre stosunki i przepływ informacji pomiędzy wodów takich wdrożeń. Przeglądarki trochę Flash 10. Jest w niej wiele rożnych, świetnych
nami i deweloperami. Pracuję dla Adobe od dojrzały, także typ interakcji oferowany przez rozwiązań, takich jak wsparcie dla sprzęto-
około 8 lat. Pierwotnie związany byłem z Ma- AJAX okazał się niesamowicie prosty we wej akceleracji 3D i całkiem nowy silnik tek-
cromedią i zostałem zatrudniony z powodu wdrażaniu aplikacji internetowych, do któ- stu - obecny ma bardzo ograniczone możli-
mojej pracy nad Generatorem. Obecnie jest rych użytkownicy mogą uzyskać dostęp wła- wości edycyjne. Dysponujemy również pro-
to już stary produkt i trudno go gdziekolwiek ściwie zewsząd. Są też ograniczania, ponie- jektem o nazwie Pixel Bender (formalnie: Hy-
znaleźć, ale używałem go często w przypad- waż aplikacje są uruchamiane w przeglądar- dra), który pozwala użytkownikowi na budo-
ku Flasha i wdrażaniu rozwiązań Java. W ta- ce z wieloma różnymi dodatkowymi, wbu- wanie własnych bitmapowych filtrów tak,
ki oto sposób związałem się z Macromedią, dowanymi wtyczkami. Jeśli przypadkowo aby mógł je uruchomić natywnie w odtwa-
a dzisiaj Adobe. zamkniesz przeglądarkę, stracisz połączenie rzaczu Flash. To tylko niektóre z rozwiązań.
z aplikacją. Przeszkadza to, bo nie możesz Jest oczywiście jeszcze wiele innych udo-
SDJ: W jakich okolicznościach pojawił się prowadzić tego typu interakcji jaką prowa- godnień, na razie jesteśmy na etapie wersji
AIR? dzisz z innymi aplikacjami. Np. nie możesz beta, tak więc praca wre.
MC: Idea Flasha jako aplikacji desktopo- chwycić i przeciągnąć elementu z desktopu
wej jest czymś, co zaprzątało moją głowę do przeglądarki. Przeglądarka jest jak pudeł- SDJ: Wszystkie te rozwiązania wdraża-
już podczas pracy w Macromedii i przero- ko i nie ma zbyt dużego dostępu do twojego ne w odtwarzacz Flash 10 będą dostępne
dziło się w projekt nazywany Macromedia systemu plików. AIR stara się korzystać w jak także dla AIR?
Central. Było to trzy lata temu. Właściwie to najlepszy sposób z tych dwóch światów. Bu- MC: Zdecydowanie tak. Jądro AIR zbudowane
pracowałem z zespołem, który w tym cza- dujemy to środowisko na szczycie interne- jest na odtwarzaczu Flash, tak więc zsynchro-
sie przeprowadził pierwszą próbę zaimple- towych technologii. Jest to w miarę prosty nizujemy te rozwiązania w następnej wersji
mentowania Flasha na pulpit. Nie odnieśli- proces w sferze projektowania aplikacji i jej po AIR 1.1. Będzie ona miała całkowite wspar-
śmy wtedy sukcesu z wielu różnych powo- wdrażania, ale jednocześnie, zbliżamy się do cie dla wszystkich rozwiązań Flasha 10. Oczy-
dów, ale najważniejsze jest to, że wynieśli- integracji z pulpitem. Dzięki temu użytkow- wiście wyposażymy ją także w inne technolo-
śmy z tego projektu solidny kawał wiedzy nik może wchodzić w interakcję z aplikacją gie. To samo zrobimy z WebKit'em. Wykona-
i doświadczenia. Zdaliśmy sobie sprawę w taki sposób, jakby pracował w regularnym my update wersji WebKit, którą mamy w Ado-
z tego, że odtwarzacz Flash nie był wystar- programie. Nie oznacza to oczywiście śmier- be AIR i otrzyma ona wszystkie te świetne rze-
czająco szybki jak na nasze potrzeby. Mu- ci przeglądarek internetowych. Jest wiele po- czy, które pojawią się już niedługo.
sieliśmy więc go przyśpieszyć, spowodowa- wodów i sytuacji, w których chcemy używać
ło to wydanie Flasha 9 i ActionScript 3 oraz zwykłej przeglądarki internetowej, jeśli jed- SDJ: Mike, dziękuję za wywiad.

78 FLEX
Roczna prenumerata

tylko
180 ,-
Software Developer’s Journal (poprzednio Software 2.0)
jest miesięcznikiem głównie dla programistów, którzy li-
czą, że dostarczymy im gotowe rozwiązania, oszczędza-
jąc im czasu i pracy. Jesteśmy czytani przez tych, któ-
rzy chcą być na bieżąco informowani o najnowszych osią-
gnięciach w dziedzinie IT i nie chcą, żeby jakiekolwiek
istotne wydarzenia umknęły ich uwadze. Aby zadowolić
naszych czytelników, prezentujemy zarówno najnowsze
rozwiązania, jaki starsze, sprawdzone technologie.

Kontakt
1. Telefon 2. Online
+48 22 427 36 53 pren@software.com.pl
+48 22 427 36 79
3. Adres
Bokserska 1
2. Fax 02-682 Warszawa
+48 22 244 24 59 Polska
Zamówienie prenumeraty

Prosimy wypełniać czytelnie i przesyłać faksem na numer:


00 48 22 244 24 59
lub listownie na adres:
Software-Wydawnictwo Sp. z o. o.
ul. Bokserska 1
02-682 Warszawa
Polska
E-Mail: pren@software.com.pl
Przyjmujemy też zamównienia telefoniczne:
0048 22 427 36 53
0048 22 427 36 79

Jeżeli chcesz zapłacić kartą kredytową,


wejdź na stronę naszego sklepu internetowego www.buyitpress.com.

Imię i nazwisko ...............................................................................

Nazwa firmy.....................................................................................

Dokładny adres ..............................................................................

.........................................................................................................

Zadzwoń Telefon ............................................................................................

9
+48 22 427 36 7
E–mail .............................................................................................

lub ID kontrahenta ................................................................................

zamów Numer NIP firmy .............................................................................

mailowo! Fax (wraz z nr kierunkowym) .........................................................

□ automatyczne przedłużenie prenumeraty

Prenumerujesz
– zyskujesz
l oszczędność
pieniędzy Ilość Od
Ilość zama- numeru
l szybka dostawa Tytuł nume- wianych pisma Cena
rów prenume- lub mie-
l prezenty rat siąca

l bezpieczna płatność Software Developer’s


12
180*/

on–line Journal (1 płyta CD)


– dawniej Software 2.0
250
PLN

* cena prenumeraty rocznej dla osób prywatnych

You might also like