SDJExtra_31_2008_PL

84

description

Software Developers Jurnal

Transcript of SDJExtra_31_2008_PL

Page 1: SDJExtra_31_2008_PL
Page 2: SDJExtra_31_2008_PL
Page 3: SDJExtra_31_2008_PL
Page 4: SDJExtra_31_2008_PL

4 5

Le périodique hakin9 est publié par Software-Wydawnictwo Sp. z o.o.Bokserska, 02-682 Varsovie, PologneTél. +48 22 887 10 10, Fax. +48 22 887 10 11www.phpsolmag.org

Directeur de la publication : Jarosław Szumski

Imprimerie, photogravure : 101 Studio, Firma Tęgi Ekonomiczna 30/36, 93-426 ŁódźImprimé en Pologne/Printed in Poland

Abonnement (France métropolitaine, DOM/TOM) : 1 an (soit 6 numéros) 38 €

Dépôt légal : à parutionISSN : 1731-7037Distribution : MLP Parc d’activités de Chesnes, 55 bd de la Noirée BP 59 F - 38291 SAINT-QUENTIN-FALLAVIER CEDEX(c) 2005 Software-Wydawnictwo, tous les droits réservés

Magazyn SDJ Extra jest wydawany przez Software-Wydawnictwo Sp. z o.o. z siedzibą w Warszawie, 02-682, ul. Bokserska 1.

Dyrektor wydawniczy: Sylwia Małecka

Redaktor prowadzący: Anna Adamczyk [email protected]

Kierownik produkcji: Marta Kurpiewska [email protected]

Skład i łamanie: Tomasz Kostro [email protected]

Projekt okładki: Agnieszka Marchocka

Korekta: Mateusz Lipiński

Wyróżniony betatester: Leszek Sewastanowicz

Dział reklamy: [email protected]: Marzena Dmowska [email protected], tel. +48 22 427 36 79; +48 22 427 36 53

SPIS TREŚCI

06 Opis DVDKrystian RajskiKilka słów o tym co znajduje się na płycie, czyli o Flex SDK 3 i Flex Builder.

10 AktualnościNowinki ze świata Flex.

12 Pierwsza aplikacja we FlexKrystian RajskiKrystian uczy jak tworzyć aplikację wyświetlającą dane z pliku XML, mówi jak korzystać z klasy HttpService i komponenetu Datagird. Poznacie podstawowe informacje o technologii Flex i środowisku Flex Builder 3.

15 Od formularza do RIA – Adobe Form GuidesTomek LichotaTomek opowiada o tym jak przy pomocy narzędzia Adobe LiveCycle Designer ES szybko stworzyć formularz PDF, aby zebrać dane i jak na podstawie przygotowanego formularza utworzyć Form Guide.

18 Flex i AIRWojciech SiudzińskiWojtek opisuje jak zacząć pracę w Adobe AIR, prezentuje możli-wości tego środowiska i przykładowe użycie np. Technikę przecią-gnij i upuść, zaokrąglone rogi w CSS3 i kilka innych pożytecznych zastosowań.

22 Adobe AIR – Powrót na desktopSzymon KosydorArtykuł Szymona traktuje o tym jak łatwo i przyjemnie jest two-rzyć aplikacje okienkowe wykorzytując Flex Builder i Adobe AIR. Szymon m.in. podaje przepis na aplikację wykorzystującą dane w formacie RSS.

Kilka słów od pomysłodawców tego wydania

Mają Państwo przed sobą prawdziwy hit.Powodem powstania tego magazynu były: brak drukowanych publikacji w języku polskim na temat Flex, prawie nieograniczo-ne możliwości tego środowiska, o którym powinni dowiedzieć się i z niego korzystać wszyscy programiści pragnący tworzyć interaktywne i multimedialne projekty dla Internetu i na de-sktop, duże zainteresowanie tematyką (o czym świadczyć mo-że chociażby ilość osób biorących udział w warszawskiej edy-cji onAIR), nasza chęć rozpowszechniania wiedzy o technolo-giach przyszłości.Do współpracy przy SDJ Extra Flex zaprosiliśmy pasjonatów – osoby, które tworzą i rozwijają społeczność Flex, Flash i AIR, pi-szą blogi, udzielają rad na forach tematycznych oraz zawodow-ców, którzy codziennie w pracy korzystają z programistycznych rozwiązań Adobe.Tematy wybraliśmy w konsultacji z polską społecznością Flex, Tadeuszem Chełkowskim - Dyrektorem Technicznym z Adobe, beatatestermi wśród, których znajdują się programiści WWW, webdesignerzy, deweloperzy. Za pomoc wszystkim zaanga-żowanym w ten projekt serdecznie dziękujemy i wierzymy, że dzięki ich wsparciu oddajemy w Państwa ręce wartościowy me-rytorycznie magazyn.W numerze tym zetkniecie się Państwo z przekrojem tematów powiązanych z Flex. Znajdziecie tu przepis na stworzenie pierw-szej fleksowej aplikacji, oraz dowiecie się jak zabezpieczyć i te-stować oprogramowanie. Poznacie technikę pracy na frame-worku MVC dla Flex – Cairngormie. Poza tym przeczytacie arty-kuł o tworzeniu interaktywnych map Yahoo i o innowacyjnych formularzach Form Guides. Dowiecie się też o powiązaniach Flex z Java, PHP, AIR. Wszystko zostało opisane na konkretnych przykładach, a kody źródłowe, które mogą się przydać do ćwi-czeń udostępniamy na www.sdjournal.org. Na DVD zamieścili-ś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 sygnały, że są Państwo bardzo zainteresowani tą technologią, że szukacie materiałów, że chcecie się uczyć i pracować w RIA. Myślimy więc nad wydaniem regularnego, odrębnego tytułu w języku polskim o Flex, Flash i AIR. Do tego czasu tematykę Rich Internet Applications będziemy kontynuować w miesięcz-niku Software Developer’s Journal.

Życzymy przyjemnej lektury,

Anna AdamczykSoftware-WydawnictwoRafał MaciejewiczAdobe Systems

Page 5: SDJExtra_31_2008_PL

4 5

www.sdjournal.org

Rédacteur en chef : Marek Bettman [email protected]édacteurs : Aneta Cejmańska [email protected] Dudzic [email protected]éparation du CD : Aurox Core TeamMaquette : Anna Osiecka [email protected] : Agnieszka MarchockaTraduction : Iwona Czarnota, Aneta Lasota, Marie-Laure Perrotey, Grazyna WełnaBêta-testeurs : Thomas Bores, Tony Boucheau, Pascal Foulon, Pascal Miquet, Romain Lévy, Augustin Pascual, Julien Poulalion, Alain Ribault

Les personnes intéressées par la coopération sont priées de nous contacter : [email protected]

Abonnement : [email protected] : Marta Kurpiewska [email protected] : Monika Godlewska [email protected]é : [email protected]

Si vous êtes intéressé par l’achat de licence de publication de revues merci de contacter : Monika Godlewska [email protected] , tél : +48 (22) 887 12 66 fax : +48 (22) 887 10 11

La rédaction fait tout son possible pour s’assurer que les logiciels sont à jour, pourtant elle décline toute responsabilité pour leur utilisation. Elle ne fournit pas de support technique lié à l’installation ou l’utilisation des logiciels enregistrés sur le CD-ROM. Tous les logos et marques déposés sont la propriété de leurs propriétaires respectifs.

La rédaction utilise le système PAO Pour créer les diagrammes on a utilisé le programme

Le CD-ROM joint au magazine a été testé avec AntiVirenKit de la société G Data Software Sp. z o.o

AVERTISSEMENTLes techniques présentées dans les articles ne peuvent être utilisées qu'au sein des réseaux internes.La rédaction du magazine n'est pas responsable de l'utilisation incorrecte des techniques présentées.L'utilisation des techniques présentées peut provoquer la perte des données !

Nakład: 6 000 egz.

Dołączoną do magazynu płytę CD przetestowano programem AntiVirenKit firmy G DATA Software Sp. z o.o.

Redakcja dokłada wszelkich starań, by publikowane w piśmie i na towarzyszących mu nośnikach informacje i programy były poprawne, jednakże nie bierze odpowiedzialności za efekty wykorzystania ich; nie gwarantuje także poprawnego działania programów shareware, freeware i public domain.

Uszkodzone podczas wysyłki płyty wymienia redakcja.

Wszystkie znaki firmowe zawarte w piśmie są własności odpowiednich firm zostały użyte wyłącznie w celach informacyjnych.

Redakcja używa systemu automatycznego składu

Osoby zainteresowane współpracą prosimy o kontakt:[email protected]

Druk: 101 Studio, Drukarnia Tęgiul. Ekonomiczna 30/3691-426 Łódź

Wysokość nakładu obejmuje również dodruki. Redakcja nie udziela pomocy technicznej w instalowaniu i użytkowaniu programów zamieszczonych na płycie CD-ROM dostarczonej razem z pismem.

Sprzedaż aktualnych lub archiwalnych numerów pisma po innej cenie niż wydrukowana na okładce – bez zgody wydawcy – jest działaniem na jego szkodę i skutkuje odpowiedzialnością sądową.

32 Aplikacje wykorzystujące mapy w Adobe FlexWojciech PtakWojtek opisuje jakiego typu aplikacje możemy stworzyć za pomo-cą technologii Flex, jakich biblio-tek możemy używać wraz z tą plat-formą i jak stworzyć przykładowe elementy projektu opartego o Flex i Yahoo Maps.

38 Flex na JavieRoger ZacharczykRoger przedstawia w jaki sposób tworzyć aplikacje RIA na przykła-dzie forum internetowego, wyko-rzystując różne technologie internetowe, a w szczególności Javę oraz SQL, JSP, no i oczywiście Flex.

44 Flex.Security.allowSecureCommunication('*');Łukasz Zmywaczyk, Jakub MatuszewskiŁukasz i Jakub opisują sposoby wymiany informacji pomiędzy ser-werem a użytkownikiem, dostępne dla języka ActionScript 3.0 z dodatkowym wykorzystaniem gotowych komponentów środo-wiska Flex 3. Ponad to opowiadają o systemie zabezpieczeń języka ActionScript 3.0, zabezpieczeniach komunikacji, nowych crossdo-mains oraz mówią dlaczego warto używać Flash Media Server.

50 Test Driven Development – Testuj kod zanim go napiszeszPaweł Cichoń, Tomasz KulczyckiPaweł i Tomasz tłumaczą co to jest TDD, dlaczego i kiedy warto ko-rzystać z tej techniki i jak używać biblioteki FlexUnit.

56 Adobe Cairngorm – Framework architektoniczny dla Adobe FlexWojciech PtakWojtek 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.

64 Dostęp do danych z apli-kacji Flex – Adobe LiveCycle Data Services w praktyceBartłomiej SoinBartek uczy jak przy pomocy języka PHP tworzyć usługi internetowe oraz jak w języku ActionScript tworzyć aplikacje wykorzystujące usługi SOAP i Flash Remoting.

67 Flex i PHP – wykorzystanie technologii Web Services i Flash Remoting do komunikacji klient – serwerJakub WęgrzynJakub w artykule przedstawia możliwości wykorzystania technolo-gii PHP. Opisuje dwie metody pozwalające na komunikację aplikacji Flex z serwerem PHP – Web Services i Flash Remoting.

72 Podstawowe wzorce projektowe oraz idiomy ko-dowania w języku ActionScript 3.0Jakub WęgrzynJakub opisuje w jaki sposób implementować podstawowe wzor-ce projektowe w ActionScript 3 i jak radzić sobie z ograniczeniami w tym języku.

76 TIPS & TRICKSWojciech SiudzińskiWojtek pokazuje kilka sztuczek dla przyszłych specjalistów RIA.

78 Micke Chambers dla SDJ Extra – wywiadrozmowa przeprowadzona podczas konferencji onAIR w Warszawie.

Page 6: SDJExtra_31_2008_PL

6 FLEX

Opis DVD

Na 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 3Flex 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-nia, kompilowania oraz rozszerzania aplikacji Flex w połącze-niu z takimi technologiami jak XML i web serwisy SOAP. Roz-wiązanie umożliwia wykorzystanie różnych technologiami ser-werowych takich jak PHP, ColdFusion, Java i .NET z użyciem np. BlazeDS. Dostarcza języka i narzędzi umożliwiających de-veloperom maksymalizację efektywności podczas tworzenia za-awansowanych aplikacji Internetowych. Obecnie dostępna jest 3-cia wersja SDK, którego oficjalna premiera odbyła się 15 lu-tego 2008 roku. Trwają prace nad wersją 4. której nazwa kodo-wa brzmi Gumbo.

Wśród najistotniejszych zmian w stosunku do wersji 2 nale-ży wymienić dodanie natywnego wsparcia dla Adobe Integra-ted Runtime (AIR), znanego wcześniej jako Adobe Apollo, któ-ry stał się integralną częścią Flex 3. Nowa wersja rozszerza funk-cjonalność środowiska o możliwość tworzenia aplikacji deskto-powych. Programiści korzystając z gotowych komponentów i na-rzędzi wspierających Adobe AIR, mogą tworzyć oprogramowanie web działające zarówno w przeglądarce jak i bezpośrednio na sta-cjach roboczych.

Flex 3 SDK został wyposażony w nowy komponent Advan-ced DataGrid, który rozszerzył możliwości komponentu Data-

Page 7: SDJExtra_31_2008_PL

www.sdjournal.org

Opis CD

Redakcja nie udziela pomocy technicznej

w instalowaniu i użytkowaniu

programów zamieszczonych na płytach

DVD-ROM dostarczonych razem

z pismem.

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: [email protected]

Page 8: SDJExtra_31_2008_PL

8 FLEX

Opis DVD

Grid m.in. o tworzenie hierarchicznej prezentacji danych i tabe-le przestawne.

OLAP DatatGrid jest nowym komponentem, dostępny jedynie z Flex Builder Professional, pozwalającym na agregowanie i prezen-tację danych w wielowymiarowej strukturze analitycznej.

Flex Component Kit for Flash CS3 umożliwia łatwą integrację po-między aplikacjami Flex, a projektami wykonanymi we Flash CS3.

Developerów JavaScript ucieszy funkcjonalność biblioteki Flex Ajax Bridge umożliwiającej wykorzystanie klas ActionScript w Ja-vaScript.

Wraz z wersją trzecią Flex został przekształcony w projekt open source, wiec zainteresowani developerzy mogą uzyskać dostęp do kodu źródłowego framework'a, kompilatora i debugger'a.

Flex SDK 3 jest dostępny na wszystkie najpopularniejsze platfor-my - platformę Windows, Linux oraz Macintosh.

Flex Builder 3Wraz z trzecią wersją Flex SDK firma Adobe zaprezentowała nową wersję znanego narzędzia programistycznego Flex Builder 3.

Adobe Flex Builder 3 jest nowoczesnym i wydajnym rozwią-zaniem opartym o Eclipse, umożliwiającym intuicyjne tworze-nie aplikacji we Flex. Stanowi potężne narzędzie developerskie wspomagające programistę w tworzeniu kodu źródłowego, debu-gowaniu w trybie krok po kroku oraz wizualnym projektowaniu aplikacji RIA z wykorzystaniem bogatej palety gotowych kompo-nentów.

Flex Builder dostępny jest w dwóch wersjach - Standard oraz Pro-fessional edition.

Wśród najważniejszych komponentów wymienić należy intu-icyjny edytor kodu dla języków MXML, ActionScript oraz CSS wyposażony w funkcję kolorowania i wyróżniania kodu, podpo-wiadanie składni. W wersji 3 rozszerzono bibliotekę wbudowa-

nych komponentów graficznych umożliwiających budowanie layout'u aplikacji, a także umożliwiono korzystania z kompo-nentów wchodzących w skład Advanced Datagrid.

Warty uwagi jest wizualny edytor CSS, dzięki któremu w ła-twy sposób możemy zaprojektować arkusz stylów definiujący wygląd komponentów graficznych. Podczas pracy na bieżąco mo-żemy śledzić efekt naszych modyfikacji bez konieczności ponow-nej kompilacji projektu.

Nowy Builder oferuje możliwość pełnej integracji z Adobe Cre-ative Suit 3 pozwalając na łatwy import elementów wykonanych we Flashu, Fireworks, Photoshop czy Illustartorze.

Programistów ucieszy funkcjonalność refactoringu kodu, która jest istotnym udogodnieniem w stosunku do wersji poprzedniej.

Dzięki natywnemu wsparciu dla Adobe AIR, Flex Builder 3 wy-posażony został w narzędzia umożliwiające tworzenie również tra-dycyjnych aplikacji desktopowych.

W wersji Professional aplikacja posiada narzędzie testujące, które pozwala poprawić wydajność tworzonych aplikacji za po-mocą bieżącego monitorowania i analizowania zużycia pamięcii procesora. Builder pozwala również wykorzystywać zewnętrz-ne programy przeznaczone do automatycznego testowania opro-gramowania.

Wykorzystując Flex Builder 3 programista może tworzyć apli-kację zarówno w oparciu o Flex SDK 3 jak również w wersji Flex SDK 2.

Dzięki zastosowaniu nowego kreatora, ułatwiono również in-tegracje tworzonych aplikacji z technologiami serwerowymi jak PHP, ColdFusion czy Java. Nowa wersja środowiska dostępna jest też w darmowej wersji edukacyjnej przeznaczonej dla uczniów oraz studentów po wypełnieniu i wysłaniu odpowiedniego formu-larza rejestracyjnego, który znajduje się na specjalnej stronie pro-ducenta http://www.flexregistration.com/.

Page 9: SDJExtra_31_2008_PL
Page 10: SDJExtra_31_2008_PL

FLEX

Aktualności

10 www.sdjournal.org

Aktualności

11

Interaktywne aktualności z firmy JanmediaJanmedia Interactive zacieśnia współpracę z Adobe. Kooperacja obu firm służy popu-laryzacji technologii Flex i AIR jako atrak-cyjnego narzędzia budowania skutecznych i efektownych aplikacji biznesowych.

To strategiczne partnerstwo umożliwia nam dostęp do najnowszych technologii związanych z obiegiem dokumentów, podpi-sem cyfrowym, zaawansowanym streamin-giem video oraz budową aplikacji Flash, Flex oraz AIR – mówi Monika Mikowska, Dyrek-tor Sprzedaży i Marketingu Janmedia.

Janmedia to firma, która kompetencjami i wielkim entuzjazmem dla technologii Adobe zdobyła renomę wśród polskich i zagranicz-nych klientów – komentuje Tadeusz Chełkow-ski, Dyrektor Techniczny Adobe. W ramach współpracy powstają pierwsze wdrożenia korporacyjne w technologiach Flex i AIR dla klientów Janmedia z Europy i USA. Janmedia pracuje nad aplikacją RIA dla wydawcy ame-rykańskiej prasy codziennej oraz Flexowym systemem transakcyjnym dla polskiej insty-tucji finansowej – szczegóły współpracy do momentu zakończenia prac projektowych są objęte klauzulami poufności.

Janmedia Interactive jest agencją interak-tywną założoną w 2002 roku i ukierunkowa-ną na obsługę klientów międzynarodowych. Obecnie Janmedia posiada dwa oddziały w USA (Waszyngton i Richmond) oraz jeden w Polsce (Wrocław). Janmedia specjalizu-je się w zarządzaniu projektami interaktyw-nymi, technologiami Java i innymi techno-logiami sieciowymi, projektowaniu zgodnie z wytycznymi W3C, użyteczności i dostęp-ności serwisów WWW. www.janmedia.pl

Adobe otworzy FlashaAdobe poinformował o rozpoczęciu prac nad stworzeniem, w ramach projektu Open Screen Project, spójnego środowiska dla gamy urządzeń elektronicznych. W tym celu korporacja ma udostępnić specyfika-cję formatu Flash, zarówno .swf, jak i .flv/.f4v oraz usunąć wszystkie restrykcje licencyjne. W przyszłości taki sam los ma też spotkać AIR. Warto zaznaczyć, że Adobe już jakiś czas temu umożliwił deweloperom tworzenie narzędzi zapisujących we Flashu. Do ich odtworzenia konieczne było jednak posiadanie Flash Play-era. Teraz mają być one dostępne na każdym urządzeniu. Poza specyfikacją samego Flasha, Adobe planuje otwarcie specyfikacji proto-kołów Adobe Flash Cast i Action Message Format oraz API niezbędnego do wdrażania Flash Playera na różnych platformach. Otwar-cie specyfikacji Flasha wydaje się wyzwaniem rzuconym w stronę platformy Microsoftu do wyświetlania i tworzenia bogatych graficznie multimedialnych treści internetowych Silver-light. Adobe ma nadzieję, że przyczyni się to do jego popularyzacji na miarę wydanego w 1993 roku PDF, który w krótkim czasie stał się otwartym standardem zapisu dokumen-tów elektronicznych, a także wkrótce standar-dem ISO 32000.www.readwriteweb.com

Beta Dreamweaver, Fireworks i Soundbooth

Firma Adobe zaprezentowała przedpre-mierową wersję trzech aplikacji z na-stępnej edycji pakietu Adobe Creati-

ve Suite, zestawu programów do projektowa-nia graficznego, tworzenia serwisów interne-towych i edycji wideo. Firma udostępniła do bezpłatnego pobrania z serwisu Adobe Labs publiczne wersje beta nowych edycji progra-mów Adobe Dreamweaver, Adobe Fireworks i Adobe Soundbooth.

Właśnie udostępnione wersje beta ob-razują kierunek dalszego rozwoju pakietu Adobe Creative Suite. Zastosowane w nim nowe funkcje i technologie mają uprościć i usprawnić projektowanie oraz przepływ pracy z wykorzystaniem rówżnych narzę-dzi. Jak zwykle firma Adobe liczy też na kry-tyczne uwagi i sugestie przyszłych uzytkow-ników dotyczące dalszego rozwoju oprogra-mowania. Wersja beta nowego Dreamwe-avera zawiera pasek narzędzi Related Files oraz funkcję Code Navigator, które pozwa-lają użytkownikom wnikać głęboko w złożo-ne strony zawierające pliki HTML, łącza do dokumentów JavaScript i zintegrowane da-ne XML. Użytkownicy mogą przeglądać pli-ki powiązane widoczne w pasku narzędzi Re-lated Files i za pomocą funkcji Code Naviga-tor wprowadzać zmiany w kodzie, które uka-zują się w różnych częściach dokumentu po jednokrotnym naciśnięciu przycisku aktu-alizacji. Zaktualizowana wersja oprogramo-wania Dreamweaver jest również wyposażo-na w nowy tryb Live View, oparty na modu-le renderingu typu open source pod nazwą We-bkit. Tryb ten pozwala użytkownikom prze-glądać na bieżąco treści umieszczone w śro-dowisku rzeczywistym bez potrzeby wycho-dzenia z programu Dreamweaver w celu obejrzenia tych treści z poziomu przeglądar-ki. Funkcja ta umożliwia również użytkow-nikom zamrażanie kodu w języku JavaScript w celu debugowania stron interaktywnych, a także przeglądanie treści we Flash'u i inte-rakcje z nimi. Nowości w wersji beta progra-mu Fireworks obejmują nowy interfejs użyt-kownika, który jest obecnie zgodny z inny-mi aplikacjami wchodzącymi w skład pakie-tu Creative Suite. Ułatwia to użytkownikom przełączanie się między aplikacjami, które mają teraz taki sam wygląd i sposób obsłu-gi. Ponadto wersja beta programu Fireworks pozwala użytkownikom eksportować zapro-jektowane kompozycje w postaci zapewnia-jących dużą wierność obrazu, interaktyw-nych i bezpiecznych dokumentów w forma-

cie Adobe PDF. Najważniejszą cechą nowej wersji Fireworks jest pełna zgodność ze śro-dowiskiem Adobe AIR, technologią HTML i Adobe Flash oraz oprogramowaniem Ado-be Flex Builder, dzięki czemu użytkownicy mogą tworzyć uniwersalne projekty i wdra-żać je na dowolnej platformie. Z kolei wersja beta oprogramowania Soundbooth zawiera szereg nowych funkcji umożliwiających twórcom efektywniejszą realizację zadań związanych z produkcją dźwięku, w tym no-wą funkcję obsługi wielu ścieżek, która po-zwala użytkownikom edytować wiele klipów dźwiękowych na różnych ścieżkach, a tak-że nową możliwość dostosowywania przez użytkowników poziomów głośności plików dźwiękowych. Wersja umożliwia również przeglądanie ustawień kompresji plików MP3 przed ich zapisaniem. Zawiera tak-że nową technologię rozpoznawania mowy, która pozwala użytkownikom szybko two-rzyć transkrypcje ścieżek dialogowych oraz przeszukiwać je na ścieżce czasu pod kątem występowania określonych słów i fraz.

Dostępność i wymagania systemowePo załadowaniu i uruchomieniu wersje be-ta oprogramowania Dreamweaver,Fireworks i Soundbooth będą aktywne przez 48 godzin. Po tym czasie dostęp do nich będą mieli tyl-ko klienci posiadający pakiet CS3. Będą oni mogli, korzystając z numerów seryjnych swo-ich pakietów CS3, odblokować wersje beta i bezpłatnie ich używać do chwili udostęp-nienia następnej wersji pakietu Creative Su-ite. Dostęp do wersji beta pozwoli użytkow-nikom przekazywać za pośrednictwem ser-wisu Adobe Labs ich sugestie dotyczące przyszłego rozwoju produktu. Wersje beta programów Dreamweaver i Fireworks działa-ją pod kontrolą różnych systemów operacyj-nych, w tym systemu Microsoft Windows XP z pakietem Service Pack 2, systemu Windows Vista i systemu Mac OS X w wersji 10.4.11 lub nowszej zainstalowanego na kompute-rach Macintosh z procesorami PowerPC G5 lub Intel. Wersja beta programu Soundbo-oth działa pod kontrolą wszystkich wymie-nionych systemów poza systemami zainsta-lowanymi na komputerach Macintosh z pro-cesorami PowerPC. Wersje beta można już pobrać z serwisu Adobe Labs pod adresem www.labs.adobe.com.

Page 11: SDJExtra_31_2008_PL

FLEX

Aktualności

10 www.sdjournal.org

Aktualności

11

onAIR w Warszawie6 czerwca w Centrum Olimpijskim w War-szawie, odbyła się konferencja onAIR. Jest to cykl wykładów w języku angielskim, dotyczących technologii Adobe AIR. W tym roku impreza odbywa się w 11 krajach Europy (Warszawa była 8 z kolei).Na tym trwającym cały dzień, dostępnym nieodpłatnie dla wszystkich wydarzeniu, można było posłuchać znakomitych ewan-gelistów oraz specjalistów z Adobe takich jak: Mike Chambers, Serge Jespers, Kevin Hoyt, czy Daniel Dura. Poza zdobyciem ogromu wiedzy przekazanej na wykładach, można było w czasie przerwy porozmawiać z prelegentami, zadać nurtujące pytania i wymienić się wiedzą. Można było też odpo-cząć przy kawie, przekąskach, a nawet XBo-x’ach, które dostarczył organizator. Dodat-kową atrakcją było losowanie nagród w postaci oprogramowania Adobe. Ilość uczestników, którzy wzięli udział w warsz-tatach świadczy o dużym zainteresowaniu technologią AIR w Polsce.Więcej o onAIR na http://onair.adobe.com/

FlexChallenge – let’s flex what’s possibileJesteś programistą Flex? A może właśnie zacząłeś swoją przygodę z AIR? Bez względu na płeć, wiek, doświadczenie czy wykonywa-ny zawód zapraszamy do wzięcia udziału we FlexChallenge. Jeżeli chcesz pokazać światu swoje prace, podejmij wyzwanie! Adobe Flex oraz Adobe AIR to nowoczesne techno-logie pozwalające tworzyć bogate wizual-nie aplikacje (RIA), które są zorientowanie na środowisko internetowe oraz desktopowe. FlexChallenge to cykl ogólnopolskich zawo-dów w wytwarzaniu aplikacji RIA, umożli-wiających rywalizację z najlepszymi, zapre-zentowanie i doskonalenie swoich umiejęt-ności, a tym samym promocję utalentowa-nych osób tworzących w technologiach Flex i AIR. Konkurs wystartował 6 czerwca br., a kończy się jesienią. Skład sędziowski ocenia-jący zgłoszone prace stanowią doświadczo-ne osoby związane bezpośrednio z wytwa-rzaniem aplikacji RIA oraz uznani na świe-cie ewangeliści oraz inżynierowie technolo-gii Adobe. Nagrody rzeczowe, które można wygrać w konkursie są bardzo atrakcyjne – komputery MacBook, iPody, oprogramo-wanie Adobe oraz niespodzianki od sponso-rów i patronów medialnych. Głównym spon-sorem oraz patronem zawodów jest polski oddział firmy Adobe Systems. Organizato-rem zawodów jest polska grupa użytkow-ników technologii Flex oraz AIR – FlexTech, której sponsorem głównym jest międzyna-rodowa firma informatyczna Janmedia Inte-ractive. Zawody trwają! Zajrzyj na oficjalną stronę konkursu i zgłoś swój udział!http://www.flexchallenge.com

3dflash.pl tworzy adobe.com.pl

Pomysł na projekt systemu społeczno-ściowego dla użytkowników progra-mów z rodziny Adobe, powstał już rok

temu, gdy uzyskaliśmy domenę adobe.com.pl. Przez ten okres pracownicy naszej agencji tworzyli wzór największego systemu pod technologią Flex. Ze względu na ilość modu-łów jakie będzie serwis posiadał, agencja mu-siała rozwiązać szereg problemów technicz-nych, związanych z połączeniami modułów ze sobą, a także połączeniami z bazami da-nych. W pewnym momencie cały projekt sta-nął pod znakiem zapytania ze względu na re-alizacje serwisu Flextech firmy Janmedia, ale zorientowaliśmy się, że nie będzie on tak roz-budowany jak nasz projekt, dlatego nie za-trzymaliśmy prac nad adobe.com.pl.

Co serwis będzie oferowałPrzede wszystkim dzięki implementacji naj-nowszych technologii Flex użytkownicy bę-dą mogli dodawać swoje video i videotuto-riale w jakości dotąd niespotykanej, nawet do 480i (720x480), czyli dwukrotnie więcej niż obecne na Youtube. Ale to nie wszystko. Ze względu na to, że najnowszy Flash Player 9.0.124.0 ma możliwość odtwarzania plików MOV kodowanych kodekiem h264 i dźwię-ku kodekiem AAC+, wilekość pliku będzie porównywalna z wielkością plików na Youtu-be. Kolejnym modułem będzie personaliza-cja profilów o swoje prace, ciekawe informa-cje, linki do stron, własny avatar, ponadto wszystkie elmenety zdjęciowe będzie można obrabiać poprzez wbudowany edytor plików zdjęciowych. Za pomocą edytora będzie moż-na skalować, obcinać ,zmieniać kolorystykę, czy też dodawać np. loga do swoich zdjęć. Ponadto, system będzie posiadał forum, ser-wis ze zleceniami gdzie freelancerzy będą mo-gli zabiegać o pozyskanie projektów, a praco-dawcy będą mogli umieszczać zlecenia. Ko-lejnym modułem będzie miejsce, gdzie bę-dzie można oferować stałą prace.Będzie moż-liwość tworzenia grup Adobe i dopisywania się kolejnych osób do już stworzonych. Bę-dzie też mozliwość komunikacji pomiędzy osobami w danej grupie, a także umieszcza-nie przez użytkowników informacji o spotka-niach i seminariach. Sklepom sprzedających oprogramowanie Adobe będziemy oferowali system typu Ceneo. Będziemy też zamiesz-czać pełne opisy technologiczne tych progra-mów. Planujemy także powiązanie tego mo-dułu z sklepami Allegro, aby osoby odpowie-dzialne za administracje nie musiały osob-

no dodawać produktów do systemu Allegro i naszego. Oczywiście nie zabraknie tutoriali z zakresu użytkowania produktów Adobe. Poza tym dobrą informacją dla użytkowni-ków powinna być możliwość umieszczania w galerii plików JPG z własnymi pracami, podobnie jak w serwisie digart. Ponadto roz-szerzyliśmy funkcjonalność do plików SWF i PDF. Jeszcze jedną funkcjonalnością będzie moduł odpowiedzialny za odczyt nowych wiadomości i informacji z serwisów flab.pl oraz magazynu 3DFX (www.3dfxmag.pl). Jedną z głównych zalet tego modułu będzie dodawanie własnych źródeł np. z serwisów wp.pl czy Onet.pl.

Trochę o technologiachCały system będzie bazował zarówno na narzę-dziach komercyjnych, jak i Open Source. Naj-ważniejsze to:

Całość video-konwersji oraz wyświetla-nia będzie realizowane przez Adobe Flash Media Server 3. Połączenia z bazą będą re-alizowane poprzez darmowy amfphp i we-borb. Ze względu na to że moduł animiacji we Flex 3 nie jest dla nas najlepszy, dodta-kowym silnikiem napędowym będzie także darmowy Tweener. Pozostałe elementy stwo-rzone zostały we Flex w połączeniu z plika-mi PHP, które są silnikiem pozyskiwania in-formacji z róznych serwisów poprzez meto-dy parsowania.

Dla kogo jest adobe.com.pl?Serwis będzie prosty i zrozumiały dla wszyst-kich. Miejsce dla siebie znajdą tam zaawan-sowani użytkownicy programów Adobe oraz początkujący. Ważną rolę w tym aspekcie od-grywa layout tworzony przez naszego grafi-ka Monikę Onsowicz. Połączenie zaawan-sowanych funkcji z intuicyjną i przyjemną w odbiorze dla użytkowników aplikacją by-ło dużym wyzwaniem dla grafików i progra-mistów.

Termin zakończenia pracWersji finalnej na pewno jeszcze jakiś czas nie będzie, ale wersja testowa jest już od 7 lipca.

W dniu zamknięcia magazynu SDJ Extra skończone było 90% serwisu. Licząc z wszyst-kimi silnikami i kodami napisaliśmy około trzech milonów linii kodu. Zapraszamy do od-wiedzenia serwisu adobe.com.pl.

Page 12: SDJExtra_31_2008_PL

FLEX12

ADOBE FLEX

www.sdjournal.org

Obszar zastosowań Flash zaskoczył sa-mych producentów. Narzędzie prze-znaczone do tworzenia multimedial-

nej animacji opartej na wektorach stało się jednym z wiodących rozwiązań wykorzystywanych do projektowania witryn internetowych.

Model budowy projektów w oparciu o listwę czasową i sceny, stworzony z myślą o animacji, zo-stał zaadaptowany na potrzeby WWW. Często-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-

wych, wykorzystujących dynamicznie generowany jednoekranowy interfejs użytkownika. Debiut pro-duktu został poprzedzony wprowadzeniem nowe-go terminu dla projektów Internetowych – RIA (Rich Internet Application), co w dosłownym tłu-maczeniu brzmi bogata aplikacja internetowa. Po-jęcie oznacza nowoczesne dynamiczne aplikacje in-ternetowe, w których wyeliminowano uciążliwość standardowych technologii opartych o HTML. Aplikacje wykonane w oparciu o założenia RIA charakteryzują się jednoekranową prezentacją da-nych (znaną z rozwiązań desktopowych), brakiem konieczności przeładowywania zawartości ekranu podczas pracy oraz przyjaznym, zawierającym ele-menty multimedialne interfejsem.

Wprowadzenie do technologii FlexObszarem zastosowania Flex jest wspomaganie budowy aplikacji w zakresie tworzenia warstwy prezentacji. Flex skoncentrowany jest na dostar-czaniu rozwiązań wspierających budowę graficz-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 Development Kit (Flex SDK) oraz zaawansowa-ne środowisko developerskie Flex Builder. SDK to rozwiązanie darmowe, oferujące m.in. kompilator działający z linii poleceń. Siłą SDK jest wykorzy-stanie tandemu: języka MXML wraz z obiektowo zorientowanym językiem ActionScript 3, dobrze znanym wszystkim użytkownikom Flash.

MXML jest opartym o XML językiem cha-rakteryzującym się stosunkowo prostą składnią. Znacznikowa budowa szczególnie przypadnie do gustu tradycyjnym webmasterom oraz początku-jącym programistom. MXML umożliwia łatwe generowanie i zarządzanie komponentami wizu-alnymi, które można następnie wywoływać, zmie-niać właściwości i dodawać efekty.

Pierwsza aplikacja we FlexPrzeł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.

Dowiesz się...• O technologii Flex i środowisku Flex Builder 3;

• Nauczysz się korzystać z klasy HttpService

oraz komponentu Datagrid.

• Samodzielnie wykonasz program wyświetlają-

cy dane z pliku XML.

Powinieneś wiedzieć...• Wymagana jest podstawowa wiedza z zakresu

programowania oraz języka XML.

• Wiedza na temat aplikacji internetowych.

Poziom trudności

Rysunek 1. Zrzut ekranu po uruchomieniu Flex Builder 3

Page 13: SDJExtra_31_2008_PL

FLEX12

ADOBE FLEX

www.sdjournal.org

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>

Page 14: SDJExtra_31_2008_PL

FLEX14

ADOBE FLEX

mi, np. możemy przetworzyć dane wprowadzo-ne przez użytkownika w polach tekstowych, wy-konać obliczenia itd. Budowa Flex pozwala na bar-dzo intuicyjne łączenie obu języków, dlatego praca z dokumentem jest łatwa, a budowa projektu spój-na. Kod źródłowy aplikacji wykonanych we Flex przetwarzany jest do postaci kodu ActionScript, a następnie kompilowany do postaci pliku SWF. W skład SDK wchodzą również: biblioteka goto-wych klas - Flex Class Library oraz Flex Data Service umożliwiający łączenie warstwy prezen-tacji z warstwą biznesową.

Flex Data Sevice nie umożliwia bezpośred-niego dostępu do baz danych. Pełni rolę pośredni-ka umożliwiającego np. wywołanie na serwerze kodu Java, .Net, PHP, ASP czy ColdFusion, powo-dującego pobranie danych z bazy, a następnie ich przekazanie do warstwy prezentacji.

Wraz z pojawieniem się technologii Flex, Adobe zaoferowało dedykowane rozwiązanie wspomaga-jące pracę developerów - Flex Builder. Produkt jest zaawansowanym graficznym środowiskiem typu RAD opartym o dobrze znany programistom Ja-va - Eclipse.

Oprócz znanych z Eclipse narzędzi wspoma-gających tworzenie aplikacji, Flex Builder oferu-je graficzny edytor pozwalający na wizualną kre-ację projektu. Wszystkie niezbędne komponenty jak przyciski, pola tekstowe, elementy menu, moż-na w prosty sposób przeciągnąć myszką i umieścić w oknie projektu. Celowo pomijam opis samego środowiska Flex Builder oraz opis procesu insta-lacji. W poniższym opisie wykorzystałem najnow-szą, trzecią odsłonę Flex Buildera. Do dzieła! Za-czynamy przygodę z Flex!

Pierwszy projektWspólnie wykonamy projekt prostej aplikacji, któ-ra w przystępny sposób wyświetli nam zawartość pliku adresy.xml. Celem wykonania projektu jest zaprezentowanie składni języka MXML oraz pro-stoty tworzenia aplikacji we Flex.

Aby utworzyć aplikację, musimy stworzyć no-wy projekt, w którym Flex utworzy niezbędną strukturę katalogów i plików. W tym celu wybie-ramy menu File>New>Flex Project. W polu Pro-jectname wpisujemy nazwę naszego projektu np. PierwszaAplikacjaFlex. Inne opcje pozostawiamy z domyślnymi wartościami i klikamy przycisk Fi-nish. Po chwili nasz projekt zostanie załadowa-ny. Jak widać na Rysunku 1. w panelu Flex Na-vigator, stworzona została odpowiednia struktu-ra. W głównym oknie projektu znajdują się dwie zakładki: Source, w której możemy edytować kod źródłowy naszej aplikacji oraz Design, z której do-stęp mamy do edytora graficznego. Skupimy się na edycji kodu źródłowego, dlatego przejdźmy do za-kładki Source.

Jak widać, po stworzeniu projektu, utworzony został szkielet dokumentu z otwierającym i zamy-kającym znacznikiem Application.

Istnieje kilka możliwości uzyskana dostępu do zawartości pliku XML. Wykorzystamy kla-sę HTTPService, dzięki której Flex otrzyma da-ne z pliku XML w postaci odpowiedzi HTTP. W tym miejscu warto przypomnieć, że progra-mowanie we Flex jest zorientowane obiektowo i każdemu zdarzeniu przyporządkowana jest odpowiednia akcja. Zdarzeniem może być np. załadowanie aplikacji, kliknięcie przycisku lub wpisanie tekstu.

Pomiędzy głównymi znacznikami aplikacji wprowadzamy znacznik <HTTPService> opa-trzony wymaganym atrybutem id, przyjmij-my id=”adresy”. Kolejny atrybut URL definiu-je ścieżkę dostępu do pliku oraz jego nazwę, po-dajmy ścieżkę do katalogu gdzie umieściliśmy nasz plik adresy.xml. Nasz kod powinien wyglą-dać jak na Listingu 1.

Jak wspomniałem wcześniej, aby nastąpi-ła akcja, musi wystąpić zdarzenie, które ją wy-woła. Samo użycie klasy HTTPService do po-łączenia z plikiem XML nie jest rozpoznawa-ne jako zdarzenie, dlatego musimy zdefinio-wać inne zdarzenie. Użycie creatioComplete w głównym znaczniku Application spowo-duje, że fakt ukończenia ładowania aplikacji zwrócony zostanie jako zdarzenie mogące wy-wołać odpowiednią funkcję. W naszym przy-padku użyjemy funkcji send(), która zosta-nie wywołana w momencie załadowania apli-kacji. Brzmi to nieco zawile, ale w istocie jest

bardzo proste i logiczne. Uzupełniamy nasz kod źródłowy tak jak na Listingu 2. Wywołanie funkcji send() przekazuje dane z pliku XML do Flex w postaci obiektu, który zostaje ob-służony przez klasę HTTPService. Po otrzyma-niu danych HTTPService umieszcza je w obiek-cie lastResult. Za każdym razem, kiedy dane zostaną zmienione obiekt lastResult zostanie zaktualizowany.

Nadszedł czas, aby wyświetlić pobrane da-ne. W tym miejscu skorzystamy z komponen-tu DataGrid, który wyświetla dane znajdują-ce się w obiekcie w tabeli. Uzupełnijmy zatem nasz kod, dodając komponent wraz z atrybuta-mi definiującymi szerokość pola (width) oraz pozycje w poziomie (x) i pionie (y) (Listing 3.). Następnie musimy przekazać dane, które zo-stały przechwycone przez HTTPService do pola DataGrid, w tym przypadku HTTPService peł-ni rolę dostawcy danych, które chcemy wyświe-tlić. Aby wyświetlić dane, musimy odwołać się do obiektu lastResult (Listing 4.).

W zasadzie nasza aplikacja jest już gotowa, dodajmy jednak przyjazne użytkownikowi na-główki poszczególnych kolumn w tabeli wg Li-stingu 5.

Nasz projekt jest gotowy. Pozostaje jedynie skompilować i uruchomić program. W tym ce-lu z menu wybieramy Run>Run PierwszaApli-kacjaFlex lub wciskamy skrót klawiszowy [Ctrl] + [F11]. Po chwili w oknie domyślnej przeglą-darki ukaże się nasz program wyświetlający da-ne adresowe z pliku adresy.xml (na DVD).

PodsumowanieTworzenie aplikacji we Flex nie jest trudne. Jak łatwo zauważyć, ilość linii kodu potrzebnych do wyświetlenia pliku XML jest minimalna.

Poznaliśmy składnię języka MXML, a samo-dzielne wykonanie projektu przybliżyło moż-liwości klasy HTTPService oraz komponent DataGrid.

Mam nadzieję, że ten artykuł stanie się dla Was początkiem dalszej przygody z Flex, tech-nologią, która zmienia oblicze Internetu.

Propozycja dalszej literaturyNiestety brakuje polskojęzycznych podręczni-ków do nauki Flex, dlatego konieczne jest sko-rzystanie z anglojęzycznej literatury. Szczegól-nie dwie pozycje warte są polecenia:

• Flex 3: A Beginner's Guide By Michele E. Da-vis, Jon A. Phillips;

• The Essential Guide to Flex 3 By Charles E Brown.

Rysunek 3. Widok gotowego projektu

KRYSTIAN RAJSKIAutor 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.

Kontakt: [email protected]

Rysunek 2. Widok panelu Flex Navigator

Page 15: SDJExtra_31_2008_PL

Od formularza do RIA

www.sdjournal.org 15

W poniższym artykule postaram się przedstawić, jak prosto stwo-rzyć elektroniczny formularz, po-

mocny w zbieraniu danych, który następnie można równie łatwo zamienić w interfejs bę-dący bogatą aplikacją internetową w forma-cie SWF.

Narzędzie tworzenia formularzyZapewne większość z czytelników miała do czynienia z oprogramowaniem Adobe Acro-bat i formatem dokumentów PDF oraz dar-mowym czytnikiem Adobe Reader. Możli-we, że wielu czytelników tworzyło już wła-sne interaktywne formularze PDF w progra-mie Acrobat.

Jednakże Acrobat nie jest głównym narzę-dziem do projektowania formularzy. W tym artykule przedstawię sposób tworzenia inte-raktywnych formularzy w narzędziu specjal-nie do tego celu przeznaczonym i w pełni ten proces wspierającym – Adobe LiveCycle De-signer ES.

Adobe LiveCycle Designer ES to narzędzie z rodziny rozwiązań serwerowych Adobe Li-veCycle Enterprise Suite opartych o platfor-mę J2EE, łączących obsługę formularzy elek-tronicznych, zarządzanie procesami bizneso-

wymi, bezpieczeństwem dokumentów oraz ich automatycznym generowaniem. Adobe tworząc Designera, postanowiło wyjść na-przeciw oczekiwaniom różnych grup pro-jektantów.

Zwykli użytkownicy, którzy potrzebują w prosty i szybki sposób zebrać potrzebne infor-macje, pracę z Designerem mogą rozpocząć od wyboru jednego z kilku gotowych, prekonfi-gurowanych szablonów formularzy, a następ-nie za pomocą Asystenta Tworzenia Formula-rzy odpowiednio je przystosować do własnych potrzeb.

Graficy i webdesignerzy, którzy tworzą zop-tymalizowane interfejsy formularzy w celu uła-twienia użytkownikom wprowadzania danych, pracę z Designerem mogą rozpocząć od projek-towania układu strony lub zaimportowania ist-niejących już projektów z programów InDesign lub Illustrator.

Programistów oraz projektantów baz da-nych, którzy szczególnie skupiają swoją uwagę na właściwej organizacji i strukturze danych ucieszy zapewne fakt, że Designer umożliwia zaimportowanie pliku w postaci XML lub pli-ku schematu XSD, aby na ich podstawie au-tomatycznie wygenerować odpowiednie po-la formularza.

Każda z grup projektantów może rozpocząć pracę z Designerem w odpowiedni dla siebie sposób, zgodny z upodobaniami.

Wersja testowa programu Adobe LiveCyc-le Designer ES jest dostępna pod adresem: http://www.adobe.com/go/trylivecycle_desi-gner.

Pierwszy formularzNa początku stworzymy prosty formularz kontaktowy na podstawie jednego z goto-wych szablonów Designera. W tym celu uru-chom zainstalowany program Adobe Live-Cycle Designer ES i wykonaj poniższe pole-cenia:

• Z menu górnego File wybierz opcję New;• W oknie Asystenta New Form Assistant

na pierwszej stronie Getting Started wy-bierz opcję Based on a Template i naciśnij przycisk Next;

• Na stronie drugiej Document Setup z listy Select a template wybierz szablon pod na-zwą Contact Information i naciśnij przy-cisk Next;

• Wpisz nazwę firmy lub pozostaw przy-kładową, a następnie kliknij przycisk Next;

• Wskaż ścieżkę do pliku graficznego logo, które będzie zamieszczone w prawym, górnym rogu formularza lub pozostaw standardowe i naciśnij przycisk Next;

• Wprowadź dane teleadresowe na kolej-nych podstronach (Address, Contact), za-twierdzając je przyciskiem Next;

• Na ostatniej stronie Form Return Setup wpisz swój adres e–mail i naciśnij przy-cisk Finish;

• Zapisz stworzony formularz jako plik PDF (menu File) i wybierz opcję Save.

Właśnie udało Ci się stworzyć formularz słu-żący zbieraniu informacji kontaktowych od użytkowników.

Możesz podejrzeć jego działanie, wybierając zakładkę Preview PDF (Rysunek 1.).

Zbieranie danych za pomocą formularzaPrzygotowany w Designerze formularz możesz dystrybuować do użytkowników, by przy jego pomocy kolekcjonować dane. Użytkownicy wy-

Od formularza do RIA

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.

Dowiesz się...• Jak przy pomocy narzędzia Adobe LiveCycle

Designer ES szybko stworzyć formularz PDF

aby zebrać dane;

• Jak na podstawie przygotowanego formularza

utworzyć Form Guide.

Powinieneś wiedzieć...• Czym jest plik dokumentu PDF i do czego słu-

ży program Adobe Acrobat;

• Czym są formularze elektroniczne.

Poziom trudności

Adobe Form Guides

Page 16: SDJExtra_31_2008_PL

FLEX16

ADOBE FLEX

pełniają formularz danymi w programie Adobe Acrobat lub darmowym Adobe Reader i po je-go wypełnieniu, za pomocą przycisku Submit by Email, odsyłają formularz z powrotem do Ciebie. Warto wspomnieć, że odsyłany jest je-dynie kawałek dokumentu PDF – reprezenta-cja zebranych danych w pliku XML. Zawartość pliku może przedstawiać się jak na Listingu 1.

Formularze RIA – nowa technolo-gia Adobe o nazwie Form GuidesTo kolejna generacja w ewolucji interaktyw-nych interfejsów formularzy elektronicznych.

Można je tworzyć poprzez narzędzie LiveCyc-le Designer ES, a do zbierania danych i prezen-tacji on-line wymagana jest usługa renderowa-nia formularzy modułu serwerowego LiveCyc-le Forms ES.

Jedyne narzędzie, którego potrzebuje użyt-kownik końcowy formularza to przeglądar-ka internetowa z zainstalowanym Flash Play-erem.

Form Guides to połączenie siły technolo-gii LiveCycle z technologią RIA, zaawanso-wanych interfejsów użytkownika dostępną w Adobe Flex, a także animacji wykorzystują-

cej popularną technologię Flash. Ma to na ce-lu, z punktu widzenia użytkownika, jeszcze łatwiejsze wprowadzanie danych do formu-larzy, bogatszych wizualnie i o większej uży-teczności.

Nowa technologia Adobe Form Guides dia-metralnie zmienia sposób dostarczania i odbie-rania informacji.

Form Guides mogą być alternatywnym spo-sobem na wprowadzanie danych do istnieją-cych już formularzy PDF. Użytkownik wy-pełniając formularz w technologii Form Gu-ides nie widzi całej struktury formularza, a je-dynie prowadzony jest przez interaktywny in-terfejs z szeregiem pytań i użyteczną pomo-cą, podczas gdy zbierane w tle dane wpisy-wane są do formularza PDF. Podsumowując, Form Guide jest rodzajem asystenta wypełnia-nia formularzy.

Tworzenie Form GuideKażdy z Form Guide jest renderowany przez moduł serwerowy LiveCycle Forms ES. W tym celu należy zainstalować Adobe LiveCyc-le Enterprise Suite.

Wersja próbna dostępna jest pod adresem: http://www.adobe.com/go/trylivecycle, a infor-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-wisz [Shift], zaznacz i przeciągnij my-Rysunek 1. Okno programu LiveCycle Designer ES z nowo utworzonym formularzem kontaktowym

Listing 1. Zawartość pliku Xml z formularza wypełnionego danymi, który jest odsyłany przez klienta

<form1>

<Date>2008–05–23</Date>

<EmployeeName>Tomasz Lichota</EmployeeName>

<Address>ul. Prusa 2</Address>

<StateProv>mazowieckie</StateProv>

<ZipCode>00–493</ZipCode>

<SSNumber>00000001</SSNumber>

<HomePhone>1234556677</HomePhone>

<CellPhone>999100100</CellPhone>

<Comments>brak</Comments>

</form1>

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

Page 17: SDJExtra_31_2008_PL

Od formularza do RIA

www.sdjournal.org 17

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

Tabela 1. Programy do tworzenia formularzy Form Guides

Program: Zastosowanie:

Adobe Acrobat 8 Professional z programem LiveCycle Desi-gner 8.0

Tworzenie, konwersja i edycja elektronicznych dokumentów w formacie PDF, tworzenie 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

Rysunek 3. Okno narzędzia Guide Builder z widocznymi powiązaniami pól formularza i tworzonego Form Guide

Rysunek 4. Przykładowy wygląd Form Guide stworzonego w programie LiveCycle Designer ES w narzędziu Guide Builder na podstawie pliku PDF formularza kontaktowego

TOMASZ LICHOTAZajmuję się wsparciem klientów wykorzystujących

technologie formularzy elektronicznych.

http://www.adobe.pl

Page 18: SDJExtra_31_2008_PL

FLEX18

ADOBE FLEXFlex i AIR

www.sdjournal.org 19

Flex i AIR ze swoją multimedialnością, ła-twością w tworzeniu i dostępnością mo-że być prawdziwą konkurencją dla Ja-

vy. Oparcie o otwarte standardy daje nam nie-zliczoną ilość narzędzi i dodatków, tworzo-nych przez niezależnych programistów z całe-go świata. Należy tutaj dodać, że standardowe IDE dla Flex/AIR, to nic innego jak zmodyfi-kowane, tworzone i używane przez wielką spo-łeczność Eclipse.

Co daje AIR?Aplikacje AIR możemy uruchamiać na pra-wie dowolnym systemie operacyjnym. Aktual-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-cję naszego produktu możemy uprościć do mi-nimum, wykorzystując małą wklejkę we Flash, która dzięki częściowej integracji Flash Play-er’a z systemem, ogranicza użytkownika do wy-konania 3–4 kroków. Jedną z głównych części AIR jest silnik renderujący WebKit (będący ser-cem przeglądarek Safari i KHTML oraz jest uży-ty w telefonach S60 Nokii i Apple iPhone) ce-chujący się wysoką kompatybilnością ze stan-dardami (m.in. CSS 3) oraz wydajnością w po-równaniu z innymi silnikami (np. Mozilla Gec-ko). To dzięki niemu możemy użyć naszej zna-jomości HTML i JavaScript do tworzenia apli-kacji czy integrować usługi typu Google Maps lub biblioteki takie jak jQuery, Prototype.js, Dojo. Aplikacja uruchomiona w AIR posia-

da także większy dostęp do naszego systemu, w porównaniu do aplikacji Flash/Flex. Może-my manipulować schowkiem, ustawiać ikony w tray'u (Windows) lub docku (MacOS X), za-rządzać DRM, przeglądać i edytować zawartość dysku czy uzyskać dostęp do lokalnej bazy da-nych SQLite. Możemy więc połączyć estetykę i multimedialność Flash z możliwościami apli-kacji desktopowej.

Jak zacząć?Aby stworzyć naszą aplikację AIR, możemy użyć jednego z wielu narzędzi (zarówno autorstwa Adobe, jak i osób trzecich). Wydaje się, że naj-prostszym wyjściem jest zainstalowanie testo-wej (60–dniowej) wersji Flex Builder 3 (samo-dzielnej paczki lub wtyczki do Eclipse). Oczy-wiście możemy użyć Adobe Flash CS3 (po wcze-

śniejszym zainstalowaniu AIR update for Flash CS3 Professional) lub ściągnąć samo AIR SDK (lub Flex 3 SDK) i tworzyć aplikację za pomocą edytora tekstowego (lub IDE np. FlashDevelop). Opiszę jednak najprostszą, i jak dla mnie najwy-godniejszą, metodę – czyli Flex Builder 3.

Po ściągnięciu i zainstalowaniu Flex Builder 3, powinien nam się ukazać widok podobny do tego na Rysunku 1.

Nasze środowisko podzielone jest na trzy ko-lumny, które można dowolnie reorganizować. Po lewej znajduje się Flex Navigator, służący do zarządzania plikami w naszym projekcie, oraz Outline, pokazujący drzewko elementów aktyw-nego pliku w edytorze, który znajduje się w środ-kowej kolumnie. Pod edytorem widzimy zakład-kę Problems, która informuje o ostrzeżeniach i błędach w projekcie. W prawej kolumnie znaj-duje się pomoc kontekstowa. Klikając kompo-nent czy obiekt w edytorze i naciskając [F1], zo-baczymy tematy pomocy adekwatne do zazna-czenia. Kolejną zakładką jest Konsola, w której widzimy błędy, ostrzeżenia oraz wyjście funkcji

Flex i AIR

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

Dowiesz się...• Jakie funkcje oferuje Adobe AIR.

Powinieneś wiedzieć...• Powinieneś znać podstawy ActionScript i Flex.

Poziom trudności

Tworzenie aplikacji w oparciu o środowisko Adobe AIR z wykorzystaniem Adobe Flex.

Listing 1. Dostęp do schowka

import flash.desktop.*;

public function copy(text:String):void {

// Wyczyszczenie aktualnego schowka

Clipboard.generalClipboard.clear();

// Ustawienie naszych danych

Clipboard.generalClipboard.setData(ClipboardFormats.TEXT_FORMAT, text);

}

public function paste():String{

// Odczytujemy tylko tekstowy schowek

if(Clipboard.generalClipboard.hasFormat(ClipboardFormats.TEXT_FORMAT)) {

// Zwracamy zawartość rzutowaną jako String

return String(Clipboard.generalClipboard.getData(ClipboardFormats.TEXT_FORMAT));

} else {

return null;

}

}

Page 19: SDJExtra_31_2008_PL

FLEX18

ADOBE FLEXFlex i AIR

www.sdjournal.org 19

trace() podczas sesji debugowania. Ostatnia za-kładka to Debugger, który w tym widoku (wido-ki zmieniamy klikając przycisk w prawym gór-nym rogu) jest ograniczony do minimum.

Pierwsza aplikacjaGdy już oswoimy się ze środowiskiem, może-my stworzyć nasz pierwszy projekt AIR. Klika-

my na menu File>New>Flex Project. Ukaże nam się okno dialogowe New Flex Project, w którym wpisujemy nazwę projektu, lokalizację, w której będziemy przechowywać nasze pliki oraz zazna-czamy Desktop application w Application type. Na razie nie potrzebujemy zmieniać żadnych do-datkowych opcji, więc klikamy Finish. Po chwi-li zostanie wygenerowane kilka plików oraz ka-

talogów. Katalog bin–debug zawierać będzie na-szą zbudowaną aplikację w wersji do debugowa-nia, wewnątrz katalogu libs umieszczamy do-datkowe biblioteki (jeśli z nich korzystamy). Ka-talog src zawiera teraz dwa pliki dla nas najbar-dziej istotne. Są to: <nazwa_aplikacji>–app.xml opisujący nazwę, identyfikator czy wersję naszej 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-kiem jest <nazwa_aplikacji>.mxml, zawierający nasze główne okno. Należy zwrócić uwagę na je-go format. Jest to specjalny XML opisujący wy-gląd oraz zachowanie naszej aplikacji, który mo-że zawierać wewnątrz funkcje ActionScript, style CSS czy osadzone w aplikacji zasoby ty-pu grafika czy animacja. Pliki MXML możemy edytować tekstowo lub graficznie. Przełączamy się pomiędzy tymi trybami za pomocą przyci-sków Source i Design, znajdującymi się na górze edytora. W graficznym trybie edycji dochodzi nam kilka paneli. Components (przełączany na zmianę z Outline) to paleta dostępnych kom-ponentów, które dodajemy do projektu, prze-ciągając na okno edycji. Po prawej stronie po-jawia się kolumna zawierająca panel States, za-wierający zdefiniowane stany aplikacji oraz pa-nel Flex Properties, pozwalający łatwo zmieniać parametry zaznaczonego komponentu. W tym momencie możemy uruchomić naszą podsta-wową aplikację naciskając [Ctrl]+[F11] (lub sa-mo [F11], jeśli chcemy otworzyć sesję debugo-wania). Gdy zamierzamy udostępnić naszą apli-kację, musimy najpierw stworzyć paczkę AIR. Aby tego dokonać, wybieramy z menu Project>Export Release Build. W pierwszym oknie mo-żemy zmienić nazwę pliku paczki lub umożli-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 Create. Następnie wybieramy utworzony certy-fikat i podajemy do niego hasło, po czym klika-my Finish. Utworzony plik *.air możemy swo-bodnie rozprowadzać.

Podstawowa integracja z systememPodczas codziennej pracy przy komputerze przyzwyczailiśmy się do kopiowania, wklejania pomiędzy aplikacjami czy technologii przecią-gnij i upuść. Aplikacje pracujące w przeglądar-ce nie posiadają takich możliwości lub są one

Listing 2. Przeciągnij i upuść

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"

nativeDragEnter="onDragIn(event)" nativeDragDrop="onDrag(event)">

<mx:Script>

<![CDATA[

import flash.desktop.*;

public function onDragIn(event:NativeDragEvent):void{

// Zaakceptowanie dowolnego obiektu

NativeDragManager.acceptDragDrop(this);

}

public function onDrag(event:NativeDragEvent):void {

// Ustawienie domyslnej akcji

NativeDragManager.dropAction = NativeDragActions.COPY;

// Zakładamy że przeciągnięto plik

var dropfiles:Array = event.clipboard.getData( ClipboardFormats.FILE_LIST_FORMAT) as

Array;

// Wyliczamy wszystkie przeciągnięte pliki

for each (var file:File in dropfiles){

trace(file.nativePath);

}

}

]]>

</mx:Script>

Listing 3. Obsługa plików

// Funkcja obsługująca zakończenie operacji

public function onComplete(event:Event):void {

trace('Plik usunięty');

}

// Funkcja obsługująca błąd wejścia/wyjścia

public function onIoerror(event:IOErrorEvent):void {

trace('Błąd wejścia/wyjścia podczas usuwania pliku');

}

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();

}

Przedrostki ścieżek do pliku

• app:/ dla plików umieszczonych w folderze aplikacji;• app–storage:/ dla plików w wydzielonym folderze danych aplikacji;• file:/// dla plików rozmieszczonych w dowolnym miejscu na dysku.

Rysunek 1. Flex Builder 3 po uruchomieniu

Page 20: SDJExtra_31_2008_PL

FLEX20

ADOBE FLEXFlex i AIR

www.sdjournal.org 21

ograniczone. AIR zdejmuje z nas te ogranicze-nia. Obsługi schowka dokonujemy za pomocą klasy Clipboard (automatycznie inicjowanej) oraz statycznych stałych w ClipboardFormats i ClipboardTransferMode. Najczęściej stosowa-nymi metodami są getData() oraz setData(), ich przykładowe użycie mamy na Listingu 1.

Kolejną techniką jest przeciągnij i upuść. Jej ob-sługa jest wykonywana poprzez kilka zdarzeń: nativeDragEnter, nativeDragDrop, nativeDragStart, nativeDragUpdate, nativeDragOver, nativeDragExit i nativeDragComplete.

Najważniejsze są dwa pierwsze. Najpierw definiujemy funkcje obsługujące te zdarzenia w naszej aplikacji, a następnie piszemy funkcje obsługujące (Listing 2.).

Zależnie od typu przeciąganego obiektu mo-żemy zezwalać lub zabraniać upuszczania we-wnątrz funkcji onDragIn(). Tak przeciągnięty plik możemy odczytać z systemu plików.

Lokalny system plikówJedną z najważniejszych funkcji aplikacji są od-czyt, zapis oraz modyfikacja plików znajdują-cych się na dysku. Oprócz tych podstawowych metod AIR oferuje zaawansowane komponen-ty do wyświetlania zawartości folderu w róż-nych stylach. Może to być siatka ikon, drzew-ko, szczegółowa lista czy lista rozwijana. Dostęp do pliku uzyskujemy za pomocą klasy File oraz odpowiednio sformatowanej ścieżki. W zależ-ności gdzie znajduje się plik, mamy trzy przed-rostki do wyboru (przedrostki ścieżek do pliku opisane są w ramce).

Rozdzielenie katalogów uzyskujemy ukośni-kiem [/]. W systemach rodziny Windows moż-na także użyć backslasha [\]. Dostęp do plików może być synchroniczny lub asynchroniczny. Przy trybie synchronicznym, aplikacja zatrzy-ma swoje działanie do czasu zakończenia ope-racji na pliku. Jest to dosyć klasyczne podejście, jednak przy większych operacjach może być irytujące dla użytkownika. Dlatego lepiej uży-wać trybu asynchronicznego i dodając funkcje obsługi zdarzeń complete oraz ioError kontro-lować postęp jak na Listingu 3.

Strumieniowy odczyt i zapis do pliku wyko-nujemy za pomocą klasy FileStream. Możemy odczytywać/zapisywać dane w różnych forma-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-

my do dyspozycji także zdarzenia informujące o postępie operacji w trybie asynchronicznym. Są to outputProgress (postęp danych zapisy-wanych) oraz progress (postęp odczytu pliku). Przykład zastosowania mamy na Listingu 4.

Komponenty wyświetlające zawartość na-szego dysku także są bardzo proste w obsłu-

dze. Wystarczy podać folder początkowy w atrybucie directory i obsługiwać zdarzenia directoryChange i fileChoose.

Kontrolka HTMLOsadzony w AIR silnik WebKit daje nam nie tylko możliwość wyświetlania zawarto-

Listing 4. Asynchroniczny zapis do pliku

public function writeToFile():void {

var file:File = File.createTempFile();

var fileStream:FileStream = new FileStream();

// Otwarcie strumienia pliku asynchronicznie

fileStream.openAsync(file, FileMode.WRITE);

fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onOutputProgress);

// Zapisanie 1024kB losowych danych

for (var i:int = 0; i < 1024*1024; i++) {

fileStream.writeByte(Math.round(Math.random()*255));

}

}

public function onOutputProgress(event:ProgressEvent):void {

trace('Pozostało '+event.target.bytesPending+' bajtów');

}

Listing 5. Operacje na DOM

<mx:Script>

<![CDATA[

public function navigate():void {

// Ustawienie wartości input-a z zapytaniem

html.domWindow.document.getElementsByName('q')[0].value = 'adobe air';

// Wysłanie formularza

html.domWindow.document.getElementsByName('f')[0].submit();

}

]]>

</mx:Script>

<mx:Button x="10" y="10" label="Button" click="navigate()"/>

<mx:HTML location="http://www.google.pl" left="10" right="10" top="40" bottom="10"

id="html"/>

Listing 6. Przekazywanie zdarzeń DOM do aplikacji

<mx:Script>

<![CDATA[

public function setupListeners():void {

// Znalezienie wszystkich odnośników

var linki = html.domWindow.document.getElementsByTagName('a');

for(var i:int = 0; i < linki.length; i++) {

// Ustawienie własnej funkcji reagującej na kliknięcie

linki[i].addEventListener("click", onClick);

}

}

public function onClick(event:Object) {

// Wyświetlenie adresu docelowego

trace('Kliknięto link do '+event.target.href);

// Anulowanie domyślnej akcji (przejście do adresu)

event.preventDefault();

}

]]>

</mx:Script>

<mx:HTML location="http://www.google.pl" left="10" right="10" top="40" bottom="10"

id="html" complete="setupListeners()"/>

Przydatne adresy

• http://www.adobe.com/products/air/ strona domowa Adobe AIR• http://livedocs.adobe.com/flex/3/langref/ index.html – pełna dokumentacja Flex

wraz z AIR• http://www.onflex.org/ – blog Teda Pa-

tricka, jednego z najlepszych specjali-stów Flex

Page 21: SDJExtra_31_2008_PL

FLEX20

ADOBE FLEXFlex i AIR

www.sdjournal.org 21

ści serwisów WWW, ale także integrację Ac-tionScript z DOM i JavaScript. Nasza aplika-cja może reagować na zdarzenia pochodzące z DOM lub wyświetlana strona może wywo-ływać funkcje i modyfikować zmienne zawar-te w naszej aplikacji. Najprostszym wykorzy-

staniem tej kontrolki są np. historie rozmów w komunikatorach czy różnego rodzaju logi, gdzie pisanie własnego ItemRenderera wy-magałoby za dużo pracy. Oczywiście idąc da-lej możemy integrować usługi typu Google Maps, ale to już wyższa szkoła jazdy. Zacznij-

my od manipulacji DOM oraz wywoływania metod JavaScript (Listing 5.).

Obiekt domWindow jest odpowiednikiem obiektu window w JavaScript. Posiada wszystkie funkcje oraz własności obsługiwane przez We-bKit. Idąc w drugą stronę, możemy przekazać logikę otwartej strony do naszej aplikacji tak, jak na Listingu 6.

Oprócz znakomitego silnika JavaScript (na-zwanego JavaScriptCore) mamy także do dys-pozycji częściową obsługę CSS3, np. zaokrąglo-ne rogi (Listing 7.).

Przenosząc usługę z sieci na desktop, może-my to robić stopniowo, na początku integru-jąc ją w naszej aplikacji. Ze względu na swo-je możliwości dobrze jest pamiętać o istnie-niu tego komponentu przy tworzeniu kolej-nych projektów.

Baza danych SQLiteZazwyczaj każda aplikacja zapisuje i odczy-tuje pewne dane na dysku. Możemy to ro-bić poprzez wcześniej opisaną klasę File i FileStream lub znanym z Flash SharedObject. Gdy operujemy jednak na danych tabelarycz-nych z pewnymi relacjami, najlepiej składować je w bazie danych. Adobe AIR zawiera osadzo-ną bazę danych SQLite, która zyskała uznanie w wielu aplikacjach ze względu na swoje ma-łe rozmiary oraz wydajność. Baza jest transak-cyjna (obsługuje rozpoczynanie, zatwierdza-nie oraz cofanie transakcji) i odpytujemy ją za pomocą języka SQL. Obsługa bazy danych jest asynchroniczna, nie blokuje więc naszej aplikacji nawet przy większych zapytaniach. Podstawowymi klasami są SQLConnection, SQLStatement oraz SQLResult. Przykład użycia mamy na Listingu 8.

Zwrócony wynik może zostać zbindowany jako dataSource np. do DataGrid czy List. Do-datkowo możemy zarządzać schematami tabel czy wyzwalaczami, ale to bardziej zaawansowa-ne funkcje.

Na koniecJak widzimy, AIR jest naprawdę potężne i w moim odczuciu przyjemniejsze w pro-gramowaniu niż Java. Poruszyłem tylko ma-łą część możliwości tego środowiska. Dobrym źródłem wiedzy jest Internet, który jest pełen blogów oraz forów na temat AIR. Także Ado-be w swoim Developer Center zbiera wielką bazę wiedzy dotyczącej Flex czy AIR. Pole-cam zainteresowanie się tą technologią, zwa-żywszy jej bardzo szybki rozwój i rosnącą po-pularność.

Listing 7. Zaokrąglone rogi w CSS3

<mx:HTML left="10" right="10" top="40" bottom="10" id="html">

<mx:htmlText>

<![CDATA[

<div style="width: 100px; height: 50px; background: #FFBF02; -webkit-border-

radius: 5;">Test</div>

]]>

</mx:htmlText>

</mx:HTML>

Listing 8. Obsługa bazy SQLite

<mx:Script>

<![CDATA[

var connection:SQLConnection = new SQLConnection();

var query:SQLStatement = new SQLStatement();

public function connect():void {

// Ustawienie obsługi zdarzeń

connection.addEventListener(SQLEvent.OPEN, onOpen);

query.addEventListener(SQLEvent.RESULT, onResult);

// Przypisanie połączenia do zapytania

query.sqlConnection = connection;

// Stworzenie tymczasowego pliku

var dbFile:File = File.createTempFile();

// Otwarcie bazy danych

connection.open(dbFile);

}

public function execute():void {

query.text = taQuery.text;

query.execute();

}

public function onOpen(event:SQLEvent):void {

btnExecute.enabled = true;

}

public function onResult(event:SQLEvent):void {

// Pobranie wyniku

var result:SQLResult = query.getResult();

if (result != null) {

var numRows:int = result.data.length;

for (var i:int = 0; i < numRows; i++) {

var row:Object = result.data[i];

// Manipulacja danymi z rekordu

}

}

}

]]>

</mx:Script>

<mx:Button x="10" y="10" label="Połącz" click="connect()"/>

<mx:TextArea x="10" y="40" width="635" height="123" id="taQuery"/>

<mx:Button x="10" y="171" label="Wykonaj" id="btnExecute" click="execute()"

enabled="false"/>

WOJTEK SIUDZIŃSKIAutor jest programistą w firmie Kreativ sp. z o.o.

Programuje w PHP, JavaScript oraz Adobe Flex

z wykorzystaniem AIR. W czasie wolnym programu-

je dla własnej przyjemności. Prowadzi blog tech-

niczny http://blog.suda.pl

Kontakt z autorem: [email protected]

Page 22: SDJExtra_31_2008_PL

FLEX22

ADOBE FLEXAdobe AIR

www.sdjournal.org 23

Adobe AIR to nie tylko narzędzie umoż-liwiające produkcję aplikacji okienko-wych wykorzystujące Flexa, z powodze-

niem można w nim tworzyć wykorzystując tech-nologie Flash, HTML, JavaScript czy Ajax. AIR to skrót od Adobe Integrated Runtime i wywodzi się z projektu o kodowej nazwie Apollo. AIR działa nie tylko na Windowsie, ale także na Mac OS X, czy Linuxie. Przeniesienie na pulpit FlashPlayera to niejedyna zaleta AIR (bo to już było możliwe, używając projektorów FlashPlayera), rozbudowa-nie funkcji dostępnych w AIR jest nieporówny-walnie większe od FP działającego w przeglądarce, do najważniejszych zalet należą: tworzenie okie-nek wykorzystujących API systemowe, wsparcie dla plików PDF, dostęp do schowka systemowego, operacje drag&drop, operacje wejścia/wyjścia na plikach, SQLite, wsparcie dla XSLT, możliwość umieszczenia aplikacji w tray'u systemowym, au-tostart aplikacji z systemem oraz wiele, wiele in-nych, których ilość znacznie przekracza ramy te-go artykułu. Właśnie ze względu na stopień roz-budowania AIR ograniczymy się tylko do kilku ciekawszych cech tego środowiska.

Nowa funkcjonalność w AIRAby mieć pełny przegląd możliwości AIR, na-leży przyjrzeć się nowym klasom, jakie wraz z nim udostępnia nam Adobe, i które odróżnia-ją aplikacje tworzone w tej technologii od stan-

dardowych, odtwarzanych w oknie naszej prze-glądarki. Głębszą eksplorację AIR najlepiej za-cząć od zapoznania się z dokumentacją załączo-ną do tych klas (tabela z listą klas znajduje się na płycie dołączonej do magazynu).

Wiele klas dostępnych z poziomu SWF'ów w przeglądarce zyskało na nowej funkcjonalno-ści. Z AIR’em do Flexa doszło także kilka no-wych komponentów takich jak:

• FileSystemEnumerationMode,• FileEvent,• FileSystemComboBox,• FileSystemDataGrid,• FileSystemEnumerationMode,• FileSystemHistoryButton,• FileSystemList,• FileSystemDisplayMode,• FileSystemTree,• HTML,• Window, WindowedApplication.

Do dzieła

InstalacjaAby zacząć bawić się AIR’em we Flexie, na-leży ściągnąć i zainstalować środowisko uru-chomieniowe AIR dostępne pod adresem http://www.adobe.com/go/getair.

Instalacja nie powinna nastręczać kłopotów i każdy powinien sobie z nią poradzić bez pro-blemów.

Hello WorldJak chyba każdy początek przygody z nowym środowiskiem, językiem programowania naj-

lepiej zacząć od programu typu Hello World. Otwieramy FlexBuildera, z menu wybieramy File>New>Flex Project. Nazywamy projekt np.: helloAir. W panelu Application type wybieramy opcję Desktop application (runs in Adobe AIR). Klikamy przycisk Finish i gotowe. Jak widać, w okienku Flex Navigatora pojawił się nowy projekt z ikonką folderu i logo AIR. Struktura stworzonych katalogów jest niemal identycz-na jak w przypadku standardowego projektu Flexowego, jedynie brakuje katalogu html-tem-plate, za to pojawił się dodatkowy plik helloAir-app.xml. Jest to plik odpowiedzialny za opcje systemowe docelowego projektu, takie jak ikon-ka aplikacji, tytuł głównego okienka, opis pro-gramu w instalatorze itd. Opcje konfiguracyjne posiadają w tym samym pliku komentarze, któ-re pomagają zidentyfikować, do czego dany pa-rametr jest wykorzystywany.

Gdy otworzymy plik helloAir.mxml – główny plik źródła aplikacji zobaczymy, że różni się on od standardowego pliku projektu Flex tym, że główny tag xml-owy to nie <mx:Application> tylko <mx:WindowedApplication>. Aby prze-testować, czy projekt został prawidłowo wy-generowany, klikamy zieloną ikonkę Run hel-loAir i voila. Otworzy nam się zwykła aplika-cja desktopowa z tytułem okienka helloAir (to między innymi właśnie ten tytuł okna moż-na zmienić w pliku helloAir-app.xml). Właśnie stworzyliśmy pierwszą aplikację desktopową w AIR. Jeśli chcemy przenieść wcześniejszą Fle-xowo-webową aplikację do AIR, to wystarczy skopiować wszystko, co zawiera się wewnątrz taga <mx:Application> i wkleić do nowego projektu. Oczywiście, jeśli korzystaliśmy z ja-kichkolwiek klas, bibliotek czy plików to także należy je dołączyć do projektu AIR’owego.

Od ogółu do szczegółu

Detekcja połączenia z InternetemPomimo tego, że AIR służy do budowania apli-kacji desktopowych, to dalej mają to być Rich In-

Adobe AIR

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.

Dowiesz się:• Jak szybko, łatwo i przyjemnie tworzyć apli-

kacje okienkowe wykorzystując Flex Buildera

i Adobe AIR.

Powinieneś wiedzieć:• Powinieneś znać podstawy posługiwania się

programem Flex Builder, podstawy języka opi-

su danych MXML oraz programowania w Ac-

tionScript 3.0.

Poziom trudności

Powrót na desktop

Page 23: SDJExtra_31_2008_PL

FLEX22

ADOBE FLEXAdobe AIR

www.sdjournal.org 23

ternet Applications. Właśnie cała potęga AIR to możliwość łatwego połączenia aplikacji deskto-powych z Internetem. Aby przeprowadzić jaką-kolwiek interakcję aplikacji z siecią przydałoby się najpierw dowiedzieć, czy istnieje taka moż-liwość. Najprostszym sposobem na wykonanie tego jest sprawdzenie połączenia z witryną, np.: http://www.google.com. Wykorzystamy do tego klasę URLMonitor z paczki air.net monitoru-jącą status połączenia z Internetem.

Jak widzimy na Listingu 1. zaraz po zaini-cjowaniu aplikacji wywoływana jest funk-cja init(). Tworzymy tam instancję klasy URLMonitor, która jako parametr przyjmuje obiekt URLRequest, to on jest wykorzystywa-ny do przesyłania zapytań do domeny www.go-ogle.com. Dodaliśmy także funkcję nasłuchu-jącą zdarzeń zmiany statusu w obiekcie mo-nitor. Zaraz po uruchomieniu aplikacji wi-dzimy (o ile mamy połączenie z Internetem), że tekst komponentu label o identyfikatorze stat zmienił się na Status połączenia z interne-tem : true. W celu przetestowania, czy wszyst-ko działa jak należy, można wyłączyć na chwilę kartę sieciową lub fizycznie odłączyć kabel sie-ciowy od komputera i obserwować tekst w apli-kacji. Właściwość available (a razem z nią tekst na ekranie) powinna się zmieniać z true na fal-se i odwrotnie. Do monitorowania połączenia można wykorzystać połączenia nie tylko na standardowym porcie WWW (80) i protokole HTTP, ale także wykorzystując gniazda i klasę SocketMonitor.

Operacje na katalogach i plikachTo, czego naprawdę brakowało np. w Projekto-rach SWF'a to dostęp do systemu plików. Co ciekawsze, mamy dostęp nie tylko do katalo-gu aplikacji, ale także do standardowego kata-logu danych aplikacji desktopowych, do plików 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-

stęp do katalogu z obiektami na pulpicie. Me-toda getDirectoryListing zwraca tablicę ele-mentów w danym katalogu, w tym przypad-ku znajdujących się na pulpicie. W pętli ite-racyjnej sprawdzamy, czy obiekt nie jest lini-kiem symbolicznym i jeśli tak to listujemy go do okna konsoli Flex Buildera (pod warun-kiem, że testujemy aplikacje debugerem – od-powiednik okienka output znanego doskona-le Flash developerom). Równie dobrze istnie-je możliwość połączenia tej listy z komponen-tem TextArea. Zmienną len reprezentują-cą długość tablicy elementów w tego typu pę-tlach iteracyjnych można by pominąć, ale dla-tego, że wartość ta jest obliczana przy każdym kroku pętli, ze względów wydajnościowych, dobrze jest zachować tą wartość w zmiennej. Założyłem, że chcemy wykonać kopię katalo-gu test (i że taki katalog istnieje) pod nazwą test kopia. Metoda resolvePath zwraca ścieżkę do nowo tworzonego katalogu na pulpicie i wyko-nujemy operację kopiowania aktualnego ele-mentu właśnie do tego nowego katalogu.

Innym przykładem użytecznych opera-cji jest zapis i odczyt pliku. Na Listingu 3. przedstawiony jest najprostszy przykład za-pisu i odczytu do pliku tekstowego. Stworzy-liśmy dwa pola tekstowe: jedno do edycji da-nych do zapisania (writeTxt) i drugie do wy-świetlania danych pobranych z pliku (read-Txt). Po uruchomieniu aplikacji wywoływana jest metoda init(), gdzie inicjujemy uchwyt do pliku i strumień do wysyłania i odbiera-nia danych. Katalog danych aplikacji w syste-mie Windows XP dostępny jest pod ścieżką C:\Documents and Settings\{UŻYTKOWNIK}\Dane aplikacji\{NAZWA APLIKACJI}\Local Store\ gdzie w miejscu {UŻYTKOWNIK} jest aktualnie zalogowany do systemu użytkownik, a w miejscu {NAZWA APLIKACJI} jest nazwa

aplikacji, sytuacja jest analogiczna dla pozosta-łych systemów. Przykładem takiej ścieżki zapi-sywanego i odczytywanego pliku może być np.: C:\Documents and Settings\Szymek\Dane aplikacji\fileIOAsync\Local Store\test.txt. Do-stęp do katalogu danych aplikacji można także uzyskać za pomocą prefixu ścieżki app-storage:/ podobnie app:/ dla katalogu aplikacji, czy file:/// dla pełnej ścieżki pliku. Linię:

f = File.applicationStorageDirectory.re

solvePath(fileName);

można więc z powodzeniem zastąpić zapisem (zakomentowany kod):

f = new File();f.url = 'app-storage:/'+fileName;

i działanie aplikacji nie zmieniłoby się, jest to inny zapis tego samego działania. Po klik-nięciu przycisku Zapis wywoływana jest funkcja saveFile. Dla sprawdzenia i wy-krycia ewentualnych wyjątków i błędów ca-ła operacja zapisu jest zamknięta w bloku try … catch … finally. Blok try ... catch … finally jest przykładem bardzo dobrej praktyki przy wykrywaniu błędów i wyjąt-ków (nie tylko w języku ActionScript, ale w większości języków programowania). Dzięki stosowaniu tej techniki mamy du-żo większą kontrolę nad wykonywanym ko-dem i obsługujemy błędy, które niekoniecz-nie muszą spowodować zawieszenie apli-kacji, ale mogą umożliwić dalsze wykony-wanie programu pomimo tego, że niektó-re operacje nie zostały zakończone sukce-sem. Jeśli nie przygotujemy naszej aplika-cji na ewentualne błędy, to przeciętny użyt-kownik naszej aplikacji w momencie wystą-

Rysunek 1. Natywne okna

Page 24: SDJExtra_31_2008_PL

FLEX24

ADOBE FLEXAdobe AIR

www.sdjournal.org 25

pienia pierwszego z nich najczęściej porzu-ci jej użytkowanie i nigdy więcej jej nie uru-chomi. Wykorzystaliśmy także klasę Alert do wizualizacji błędów, tak przy zapisie, jak i odczycie pliku. Operacja zapisu, a tak-że odczytu jest banalnie prosta, otwiera-my strumień, wybierając przy tym tryb do-stępu do pliku (z dostępnych predefinio-wanych stałych klasy FileMode - READ /

WRITE / APPEND / UPDATE), zapisujemy/odczytujemy dane, zamykamy strumień do pliku. Możliwe są też operacje asynchro-niczne przy dostępie do plików (takie moż-liwości daje klasa FileStream – meto-da openAsync), wtedy należy jednak usta-wić funkcje nasłuchujące na odpowiednich zdarzeniach wysyłanych przez obiekt (me-todą addEventListener). Jak widać na Li-stingu 3. proces odczytu pliku został wy-konany właśnie asynchronicznie. Dzię-ki ustawieniu nasłuchiwaczy zdarzeń (Event.COMPLETE, ProgressEvent.PROGRESS, IOErrorEvent.IO _ ERROR) wiemy dokładnie co się dzieje podczas wykonywania aplika-cji. Do wyświetlania informacji o aktualnie wykonywanych operacjach wykorzystali-śmy globalną funkcję trace(). Listę wszyst-kich zdarzeń wysyłanych przez obiekt przy operacjach asynchronicznych moż-na znaleźć w manualu klasy FileStream . Dzięki ustawieniu wyzwalacza na zdarze-niu IOErrorEvent.IO _ ERROR dla funkcji onError wiemy, kiedy wystąpił błąd odczy-tu (jest to kolejna metoda obsługi wyjąt-ków w języku ActionScript). Jeśli z katalo-gu danych aplikacji usuniemy plik (lub przy pierwszym uruchomieniu zanim zapiszemy plik, spróbujemy go odczytać) dostaniemy informację (w konsoli Flex Buildera) podob-ną do poniższej:

Błąd odczytu: kod błędu: 3003, treść błędu:

Error #3003: File or directory does not

exist. file: C:\Documents and Settings\

Szymek\Dane aplikacji\fileIOAsync\Local

Store\test.txt

Oczywiście w docelowej aplikacji, w której wykorzystujemy zapis/odczyt do plików nale-ży poinformować użytkownika o wystąpieniu błędu (na przykład przy pomocy klasy Alert) wykorzystując kod błędu (event.errorID) oraz instrukcję warunkową switch … case 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.

OkienkaMożliwość dynamicznego tworzenia okien to kolejna wielka zaleta AIR. Najprostszym przy-kładem dynamicznego tworzenia okienek, jest stworzenie nowego komponentu bazującego na komponencie Window oraz utworzenie instan-

cji tego okna z poziomu ActionScript. Z me-nu File> New wybieramy opcję MXML Compo-nent. W polu Filename wpisujemy nazwę kom-ponentu, który chcemy stworzyć (ja nazwałem komponent BeautyWindow), a w ComboBoxie Based on wybieramy klasę Window. W kodzie

komponentu tworzymy instancję komponentu Label o nazwie infoText (Listing 4.).

Na listingu 5. przedstawiono kod aplikacji wy-korzystującej wcześniej stworzony komponent.

Naciśnięcie przycisku uruchamia funkcję createNewWindow(), która tworzy nowy kom-

Listing 1. Detekcja połączenia z Internetem

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

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"

initialize="init()">

<mx:Script>

<![CDATA[

import air.net.URLMonitor;

import flash.net.URLRequest;

import flash.events.StatusEvent;

private var monitor:URLMonitor;

private function init():void {

monitor = new URLMonitor(new URLRequest('http://www.google.com'));

monitor.addEventListener(StatusEvent.STATUS, onStatusChanged);

monitor.start();

}

private function onStatusChanged(e:StatusEvent):void {

stat.text = "Status połączenia z internetem : " + monitor.available;

}

]]>

</mx:Script>

<mx:Label horizontalCenter="0" verticalCenter="0" id="stat"/>

</mx:WindowedApplication>

Listing 2. Wylistowanie i kopiowanie katalogów na pulpicie

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

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"

width="376" height="327">

<mx:Script>

<![CDATA[

import flash.filesystem.File;

private function dirOpen():void {

var elems:Array = File.desktopDirectory.getDirectoryListing();

var f:File;

var len:uint = elems.length;

for ( var i:uint = 0; i < len; i++ ){

var n:String = elems[i].name;

if (!elems[i].isSymbolicLink) {

trace( n );

}

if( n == 'test' ) {

f = File.desktopDirectory.resolvePath( n+' kopia');

elems[i].copyTo( f );

}

}

}

]]>

</mx:Script>

<mx:Button label="Button" horizontalCenter="0" verticalCenter="0"

click="dirOpen()"/>

</mx:WindowedApplication>

Page 25: SDJExtra_31_2008_PL

FLEX24

ADOBE FLEXAdobe AIR

www.sdjournal.org 25

ponent typu BeautyWindow i otwiera okno. Ustawiamy tytuł okna i przypisujemy do pola infoText tekst identyfikujący okienko. Zmien-ną nr typu uint (typu oznaczającego całkowi-tą liczbę bez znaku) wykorzystaliśmy do nume-rowania okien – dlatego po stworzeniu nowe-go okna inkrementujemy (zwiększamy o 1) je-go wartość dla uzyskania numerów kolejnych okien. Należy pamiętać, że właściwość title należy do bazowych właściwości klasy Window, dlatego moglibyśmy ją przypisać przed otwo-rzeniem okna, ale już komponent infoText na-leży do interfejsu samego okienka. W związ-ku z tym, jeśli przesuniemy otwarcie okienka dwie linijki w dół, po przypisaniu tekstu do po-la infoText to wystąpi błąd wykonywania nu-mer 1009 (nie można się dostać do właściwo-ści lub metody obiektu typu null). Pomimo tego, że przy wyświetlaniu zmiennej nr moż-na by pominąć wywołanie metody toString() wykonującej rzutowanie zmiennej numerycz-nej na typ String – tekst (rzutowanie by by-ło wykonywane automatycznie), to bardzo do-brym nawykiem jest pamiętanie o kontroli ty-pów w językach programowania. Wielu po-czątkujących programistów (niezależnie od ję-zyka programowania) bardzo często zapomi-na o typach zmiennych, których używa i przez to sama komplikuje sobie przygodę z progra-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 tworzone są nowe okna z kolejnymi numera-mi. Jeśli do kodu Listingu 4. dodamy do taga Window właściwości transparent="true" oraz systemChrome="none" to otrzymamy okien-ko o przezroczystych rogach. Zmiana właści-wości systemChrome ze standard (wartość do-myślna) na none jest konieczna, ponieważ stan-dardowe okienka nie zakładają posiadania prze-zroczystości.

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 komponentach została już przedstawiona po-wyżej. Nic nie stoi oczywiście na przeszko-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-icyjny przy tym podejściu komponentowym. Jest jeszcze jedna metoda bazująca całkowicie na ActionScripcie, a konkretniej na klasach NativeWindow i NativeWindowInitOptions. Ba-zując na przykładzie z Listingu 5. dodajmy no-wy przycisk do głównego okna naszej aplikacji:

<mx:Button label="Nowe natywne okno"

horizontalCenter="0" verticalCenter="30"

click="createNewActionscriptWindow()"/>

oraz funkcję tworzącą nowe okno (Listing 6.).Jest to metoda trochę bardziej zaawansowa-

na od strony programistycznej, ale dająca du-

Listing 3. Zapis i odczyt pliku

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

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"

width="680" height="445" initialize="init()">

<mx:Script>

<![CDATA[

import flash.filesystem.File;

import flash.filesystem.FileMode;

import flash.filesystem.FileStream;

import mx.controls.Alert;

private var fileName:String = "test.txt";

private var f:File;

private var fs:FileStream;

private function init():void {

f = File.applicationStorageDirectory.resolvePath(fileName);

//f = new File();

//f.url = 'app-storage:/'+fileName;

fs = new FileStream();

}

private function saveFile():void {

try {

fs.open(f, FileMode.WRITE);

fs.writeUTFBytes(writeTxt.text);

} catch (e:Error) {

Alert.show('Błąd nr ' + e.errorID + "\nTreść błędu:\n" + e.message,

'Błąd');

} finally {

fs.close();

}

}

private function readFile():void {

fs.addEventListener(Event.COMPLETE, onComplete);

fs.addEventListener(ProgressEvent.PROGRESS, onProgress);

fs.addEventListener(IOErrorEvent.IO_ERROR, onError);

fs.openAsync(f, FileMode.READ);

}

private function onError(event:IOErrorEvent):void {

trace( 'Błąd odczytu: kod błędu: '+event.errorID+', treść błędu:

'+event.text );

}

private function onProgress(event:ProgressEvent):void {

trace( 'czytam plik: przeczytano ' + event.bytesLoaded+' z

'+event.bytesTotal + ' bajtów' );

}

private function onComplete(event:Event):void {

trace( 'zakończono' );

readTxt.text = fs.readUTFBytes(f.size);

fs.close();

}

]]>

</mx:Script>

<mx:TextArea id="writeTxt" x="29" y="83" width="291" height="263" text="Ala ma

kota"/>

<mx:TextArea id="readTxt" x="361" y="83" width="291" height="263"/>

<mx:Button x="264" y="381" label="Zapis" click="saveFile()"/>

<mx:Button x="361" y="381" label="Odczyt" click="readFile()"/>

</mx:WindowedApplication>

Page 26: SDJExtra_31_2008_PL

FLEX26

ADOBE FLEXAdobe AIR

www.sdjournal.org 27

żo więcej możliwości. Uruchamiając aplikację i klikając przycisk Nowe natywne okno powinno pojawić się okno jak na Rysunku 1.

Pomimo tego, że to co stworzyliśmy wcale nie wygląda jak standardowe okno, to jest to w rzeczywistości pełnowartościowe okno apli-kacji. W związku z tym, że konstruktor klasy Window przyjmuje jeden wymagany parametr (typu NativeWindowInitOptions) odpowiada-jący za parametry inicjujące okno trzeba naj-pierw stworzyć instancję tej klasy – zmienną options. Dla uzyskania przezroczystości nale-żało, podobnie jak przy modelu komponento-wym, ustawić właściwości systemChrome na no-ne oraz transparent na true. Gdybyśmy uży-wali standardowych okien, moglibyśmy usta-wić także takie właściwości jak, maximizable, minimizable, resizable itp., ale skoro wszyst-ko rysujemy kodem to o takie elementy jak mak-symalizacja czy minimalizacja okna także trze-ba się zatroszczyć samodzielnie. W systemach z rodziny OS X, w których operacja maksymali-zacja okien jest tożsama z operacją zmiany roz-miaru, aby zapobiec maksymalizacji okna obie właściwości (maximizable i resizable) trzeba ustawić na false. Proponuję przetestować apli-kację, zmieniając różne właściwości obiektu options. Jedną z ciekawszych z nich jest wła-ściwość type, która jak sama nazwa wskazuje pozwalająca na uzyskanie różnych typów okien często spotykanych w systemie, i tak wartości tego parametru mogą być wybrane z predefi-niowanych stałych klasy NativeWindowType:

• NativeWindowType.NORMAL – Najczęściej spotykane okna – pokazujące się na pasku zadań w systemie Windows a w systemie OS X w menu okien;

• NativeWindowType.LIGHTWEIGHT – Lekkie okienko – przy tej opcji nie można korzy-stać z systemowego chromu okien (sys-temChrome = „none”);

• NativeWindowType.UTILITY – Okien-ko narzędziowe – jest to trochę bardziej okrojona wersja okna typu NativeWindowType.NORMAL.

W momencie, gdy mamy już przygotowa-ne opcje inicjacyjne, tworzymy okno, a ja-ko parametr konstruktora podajemy właśnie zmienną options. Ustawiamy tytuł okna, wymiary oraz dodajemy do okna kilka za-okrąglonych prostokątów. W przeciwień-stwie do sytuacji, w której skorzystalibyśmy z systemowego chromu okien, musimy tak-że dodać obsługę przesuwania okna i zamy-kania go – przesuwanie po kliknięciu mysz-ką i zamykanie po naciśnięciu przycisku na klawiaturze. Przedstawiony sposób jest tro-chę bardziej zwięzłą wersją przypisywania wyzwalaczy na zdarzeniach w stosunku do poprzednich przykładów. Jako funkcję na-słuchującą na zdarzeniu nie przypisujemy uchwytu do funkcji (patrz Listing 3., funk-

cja readFile), ale bezpośrednio ciało funk-cji. Takie przypisywanie funkcji niczym się praktycznie nie różni w działaniu, ma jed-nak jedną poważną wadę w przypadku, gdy-byśmy chcieli ponownie wywołać tę funkcję w innym miejscu kodu. Musielibyśmy po-nownie pisać ciało funkcji, a nie tylko przy-pisać uchwyt do niej. Sposób, którego użyli-śmy, można więc używać pod warunkiem, że nie chcemy nigdzie indziej wykorzysty-wać danej funkcji. Ze względu na przejrzy-stość kodu dobrze też jest, jeśli nie ma go za dużo (jedna do dwóch operacji).

Tray systemowy i menuAIR umożliwia także budowanie aplikacji dzia-łających w tle. Można umieścić aplikację w za-sobniku systemowym (w Windowsie – ikonki aplikacji obok zegarka systemowego) jednocze-śnie usuwając aplikację z paska zadań, ale przy-kład z Listingu 6. będzie działał także pod syste-mem typu OS X – opis jednak będzie dotyczył tylko systemu z rodziny Windows.

Przykład jest trochę dłuższy od poprzed-nich, ale tylko z pozoru jest bardziej skompli-kowany. Budując tego typu aplikację, mamy do rozwiązania trzy problemy:

• przechwycenie zdarzenia zamykania apli-kacji (kliknięcie standardowego przycisku zamykającego okienko);

• ukrycie aplikacji w trayu (w tym załadowa-nie ikonki);

• dodanie menu umożliwiającego ponowne otworzenie aplikacji.

Na początku należy zaopatrzyć się w stosowną ikonkę zależnie od zastosowania w rozmiarze 16x16 lub 128x128 pikseli, w przykładzie z Li-stingu 7. są to pliki AIRApp_16.png i AIRApp_128.png umieszczone w katalogu icons.

Jak widać na listingu, w tagu WindowedApplication mamy ustawione wyzwalacze na-słuchujące na dwóch zdarzeniach, na moment inicjalizacji aplikacji (initialize – funk-cja init) i na chwilę przed zamknięciem apli-kacji (closing – funkcja hideApp). Założy-łem, że chcemy wrzucić aplikację do tray’a za-raz po uruchomieniu, ale nic nie stoi na prze-szkodzie, żeby to zrobić dopiero w momen-cie kliknięcia przycisku zamykającego, czy w dowolnym innym momencie działania apli-kacji. Na początku tworzymy obiekt Loader, umożliwiający w dalszej części załadowanie pliku ikonki do zasobnika systemowego. Na-stępnym krokiem jest stworzenie menu do-stępnego pod prawym przyciskiem myszy nad ikonką w tray'u – klasą odpowiednią do tego jest NativeMenu. Dodaliśmy tam dwa elemen-ty, jeden do ponownego otwarcia okna aplika-cji i drugi do całkowitego zamknięcia aplika-cji, funkcje wykonujące odpowiednio showApp i closeApp. Klasa NativeApplication umoż-liwia sprawdzenie, czy system pozwala na umieszczenie aplikacji w tray'u za pomocą właściwości supportsSystemTrayIcon, dlate-go wszystkie operacje dotyczące tray'a zostały wykonane pod warunkiem, że jest taka moż-liwość (analogicznie dla supportsDockIcon). Gdybyśmy nie sprawdzili tego, a system nie miałby takiej możliwości, to podczas wyko-

Listing 4. Nowy komponent okienkowy – BeautyWindow

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

<mx:Window xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="400"

height="300">

<mx:Label horizontalCenter="0" verticalCenter="0" id="infoText"/>

</mx:Window>

Listing 5. Dynamiczne tworzenie okienek z użyciem komponentów

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

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

<mx:Script>

<![CDATA[

private var nr:uint = 1;

private function createNewWindow():void {

var newWindow:BeautyWindow = new BeautyWindow();

newWindow.open(true);

newWindow.title = "Moje okienko nr " + nr.toString();

newWindow.infoText.text = "To jest nowo stworzone okienko numer " +

nr.toString();

nr++;

}

]]>

</mx:Script>

<mx:Button label="Nowe okno" verticalCenter="0" horizontalCenter="0" click="create

NewWindow()"/>

</mx:WindowedApplication>

Page 27: SDJExtra_31_2008_PL

FLEX26

ADOBE FLEXAdobe AIR

www.sdjournal.org 27

nywania operacji wystąpiłby błąd wykonywa-nia. Właściwość klasy NativeApplication o nazwie nativeApplication to instancja kla-sy NativeApplication w modelu Singletona i właśnie do niej należy się odwoływać, jeśli chcemy uzyskać uchwyt do aktualnie urucho-mionej aplikacji. Aby zapobiec automatyczne-mu zamykaniu aplikacji w momencie zamyka-nia wszystkich okien aplikacji (domyślnie tak się właśnie dzieje) należy zmienić właściwość autoExit instancji klasy NativeApplication na false. W tym konkretnym przykładzie jest to działanie na wyrost, ponieważ zapobiegnie-my automatycznemu zamykaniu aplikacji w trochę inny sposób. Wywołujemy załadowa-nie obrazu ikonki i po załadowaniu przypisuje-

my ją do właściwej aplikacji (iconLoadComple-te). Zmienna systray odpowiada już za właści-wą ikonkę umieszczoną w tray'u, przypisuje-my do niej dymek pokazujący się po najecha-niu na tę ikonkę i wcześniej stworzone menu. Sposób postępowania w przypadku DockIcon jest analogiczny jak przy SystemTrayIcon. Po-został jeszcze jeden problem do rozwiązania, pokazywanie i ukrywanie aplikacji. Funkcja hideApp jest wywoływana na chwilę przed za-mknięciem aplikacji, zazwyczaj używa się tego zdarzenia (closing) do posprzątania po sobie, czyli zapisanie zmian przed zamknięciem itp. Zapobiegniemy jednak zamykaniu programu ,używając do tego metody preventDefault() zdarzenia wywołującego funkcję, tylko ukryje-

my samo okno aplikacji z paska zadań (instan-cja nativeApplication dalej będzie urucho-miona w systemie). W momencie wybrania z menu aplikacji opcji Otwórz (funkcja showApp) ponownie pokazujemy okno programu. Metoda activate() uaktywnia okienko – ustawia na nim focus. Właściwe kończenie działania apli-kacji wykonamy w funkcji closeApp wywoła-nej po kliknięciu wcześniej stworzonego menu (opcja Zamknij), gdzie usuwamy ikonkę aplika-cji i kończymy jej działanie.

Coś większegoZnając już kilka elementów składowych środo-wiska AIR, spróbujmy stworzyć trochę bardziej skomplikowaną aplikację. W związku z natło-kiem niechcianej informacji w Internecie co-raz większą popularność zyskują czytniki RSS, na potrzeby tego artykułu napiszemy aplikację wykorzystującą dane w formacie RSS z witry-ny http://foto.moon.pl, czyli coś dla miłośników fotografii. Kanał RSS podaje informacje o naj-nowszych zdjęciach w serwisie. W skład źró-dła aplikacji wchodzą dwa pliki: główny plik projektu – FotoMoonRss.mxml oraz plik kom-ponentu okna powiadamiającego – NoticeWin-dow.mxml. Kodu jest oczywiście zdecydowanie więcej w stosunku do poprzednich aplikacji, ale większość to właśnie przykład wykorzysta-nia wcześniej przedstawionych elementów.

Wykorzystane zostały także dwa pliki graficzne: images/icon_128.png oraz images/icon_128_red.png jako ikonki w zasobniku systemowym. Plik icon_128.png odpowiada za pomyślne połączenie z witryną oraz icon_128_red.png jest tą samą ikonką tylko w kolo-rze czerwonym – reprezentuje ona brak po-łączenia z serwisem. Celowo nie wykorzysta-łem w ogóle layoutu głównego pliku aplikacji, aby pokazać jak można wykorzystać kompo-nent mx:Window do wyświetlania danych i po-wiadomień. Działanie elementów, które były wykorzystane we wcześniejszych przykładach nie będzie ponownie tłumaczone. Analizę ko-du zacznijmy od początku – jak w większości przykładów aplikacja rozpoczyna swoją pracę od funkcji init(). Tworzymy instancję kla-sy URLMonitor o nazwie monitor do sprawdza-nia połączenia z witryną http://foto.moon.pl/ (z tej witryny będziemy pobierać dane, dla-tego ta domena jest bardziej odpowiednia w odróżnieniu od http://www.google.com, jak to miało miejsce na Listingu 1.). Do cykliczne-go sprawdzania czy są nowe zdjęcia w serwi-sie, została wykorzystana klasa Timer, spraw-dzająca co 10 sekund dane w kanale RSS, wywołując funkcję loadData(). Ładujemy obie ikonki – po załadowaniu zmieniając właściwości odpowiednio iconLoaded oraz errorIconLoaded na true, oraz dodajemy wy-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łą-

Listing 6. Dynamiczne tworzenie okienek z użyciem kodu ActionScript

private function createNewActionscriptWindow():void {

//tworzymy opcje uruchomieniowe okna

var options:NativeWindowInitOptions = new NativeWindowInitOptions();

options.transparent = true;

options.systemChrome = "none";

//tworzymy okienko

var newWindow:NativeWindow = new NativeWindow(options);

newWindow.title = "Tytuł okna";

newWindow.width = 300;

newWindow.height = 300;

//dodajemy do okna elementy

var client:Sprite = new Sprite();

var rectSize:int = 40;

var rectSpace:int = 4;

with(client.graphics){

lineStyle(1,0,1);

beginFill(0xff0000,.5);

for(var i:int = 0; i <= 5; i++){

for (var j:int = 0; j <= 5; j++){

drawRoundRect(i*(rectSize+rectSpace),j*(rectSize+rectSpace),rectS

ize,rectSize,10,10);

}

}

endFill();

}

// dodajemy do okna grafikę

newWindow.stage.addChild(client);

/*

jeśli nie używamy systemowego wyglądu okien (systemChrome="none")

to dodajemy zdarzenia pozwalające zamknąć i przesuwać okno

*/

if(options.systemChrome == NativeWindowSystemChrome.NONE){

newWindow.stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:Event):

void{e.target.stage.nativeWindow.close();});

newWindow.stage.addEventListener(MouseEvent.MOUSE_DOWN,

function(e:Event):void{e.target.stage.nativeWindow.startMove();})

}

//pokazujemy nowe okno

newWindow.activate();

}

Page 28: SDJExtra_31_2008_PL

FLEX28

ADOBE FLEXAdobe AIR

www.sdjournal.org 29

czenia. Następnie minimalizujemy aplikację do zasobnika systemowego i tworzymy no-we okienko powiadamiające (nowo stworzo-nego typu NoticeWindow). Tonacja całego ser-wisu jest w szarych kolorach, dlatego za naj-odpowiedniejszy typ tworzonego okna uzna-łem NativeWindowType.UTILITY pozbawiony chromu systemowego i z przezroczystością. Pokazywane okno będzie zawsze na wierz-chu (alwaysInFront = true) oraz nie moż-na będzie zmieniać jego rozmiarów. Zaraz po otworzeniu okna przesuwamy je do prawego dolnego rogu pulpitu oraz ukrywamy głów-ne okno aplikacji (które tak naprawdę oprócz kodu aplikacji żadnych elementów interfejsu użytkownika nie zawiera). Jak już wspomnia-no wcześniej, obiekt którego używamy do transmisji danych jest httpRequest, który jest instancją klasy HTTPService. Dane, które do nas przyjdą po wysłaniu zapytania HTTP zosta-ną zrzutowane na obiekt (resultFormat="o-bject"), a metoda, która zostanie wykonana po odebraniu danych to onDataLoaded (re-sult="onDataLoaded(event)"). Przyjrzyjmysię funkcji onDataLoaded, jako parametr przyjmuje ona zdarzenie wywołujące(event), jest to uchwyt właśnie do kompo-nentu httpRequest. Dzięki temu, że da-ne zostały zrzutowane na obiekty możemy się odwoływać do tych danych (event.re-sult) tak, jakby to były właściwości obiektu httpRequest. Kolejne tagi i atrybuty xml-owe z drzewa RSS są rzutowane na kolejne podo-biekty, dla przykładu odpowiednikiem <rss …><channel><title> jest event.result.rss.channel.title i dla pozostałych elementów sytuacja jest analogiczna. Silnik do obsługi 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-bajtowych plików XML.

Przejdźmy teraz do Listingu 9. Zastosowali-śmy tutaj trochę bardziej zaawansowany kod. Jak widać wszystkie właściwości komponen-tu są ustawione jako prywatne – np.: private var _alphaTimer:Timer; itd. Aby móc się dostać do tych właściwości z zewnątrz (np.: 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-nych – to takie pewnego rodzaju bramki bez-pieczeństwa, jest to bardzo ważne, jeśli chce-my programować zgodnie z ogólnie przyjęty-mi kanonami sztuki programowania obiek-towego. Takie bramki dają nam dużo więk-szą stabilność i kontrolę nad kodem aplikacji (możemy na przykład w tym miejscu spraw-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 w przedziale od 0 do 60 i jeśli wykracza po-za zakres to ustawić wartość maksymalną do-stępną – 60 lub minimalną dostępną – 0).

Listing 7. Umieszczanie aplikacji w zasobniku systemowym

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

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"

initialize="init()" closing="hideApp(event)">

<mx:Script>

<![CDATA[

private function init():void {

var icon:Loader = new Loader();

var iconMenu:NativeMenu = new NativeMenu();

var showCommand:NativeMenuItem = iconMenu.addItem(new NativeMenuItem("Otw

órz"));

var exitCommand:NativeMenuItem = iconMenu.addItem(new NativeMenuItem("Zam

knij"));

exitCommand.addEventListener(Event.SELECT, closeApp);

showCommand.addEventListener(Event.SELECT, showApp);

NativeApplication.nativeApplication.autoExit = false;

if (NativeApplication.supportsSystemTrayIcon) { // Windows

icon.contentLoaderInfo.addEventListener(Event.COMPLETE,

iconLoadComplete);

icon.load(new URLRequest("icons/AIRApp_16.png"));

var systray:SystemTrayIcon = NativeApplication.nativeApplication.icon

as SystemTrayIcon;

systray.tooltip = "Ukryta aplikacja";

systray.menu = iconMenu;

}

if (NativeApplication.supportsDockIcon){ // OS X

icon.contentLoaderInfo.addEventListener(Event.COMPLETE,iconLoadComple

te);

icon.load(new URLRequest("icons/AIRApp_128.png"));

var dock:DockIcon = NativeApplication.nativeApplication.icon as

DockIcon;

dock.menu = iconMenu;

}

}

private function closeApp(event:Event):void {

NativeApplication.nativeApplication.icon.bitmaps = [];

NativeApplication.nativeApplication.exit();

}

private function hideApp(event:Event):void {

nativeWindow.visible = false;

event.preventDefault();

}

private function showApp(event:Event):void {

nativeWindow.visible = true;

nativeWindow.activate();

}

private function iconLoadComplete(event:Event):void {

NativeApplication.nativeApplication.icon.bitmaps = [event.target.content.

bitmapData];

}

]]>

</mx:Script>

</mx:WindowedApplication>

Page 29: SDJExtra_31_2008_PL

FLEX28

ADOBE FLEXAdobe AIR

www.sdjournal.org 29

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

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

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/

2006/mxml" layout="absolute"

initialize="init()">

<mx:Script>

<![CDATA[

import mx.controls.Image;

import air.net.URLMonitor;

import flash.display.Loader;

import flash.display.NativeMenu;

import flash.display.NativeMenuItem;

import flash.display.NativeWindow;

import flash.display.NativeWindowInitOptions;

import flash.display.NativeWindowType;

import flash.events.StatusEvent;

import flash.net.URLRequest;

import flash.utils.Timer;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;

import mx.rpc.soap.LoadEvent;

private var lastID:String = '';

private var actID:String = '';

private var monitor:URLMonitor;

private var timer:Timer;

private var nw:NoticeWindow;

private var win:NativeWindow;

private var errorIconLoader:Loader;

private var errorIconLoaded:Boolean = false;

private var iconLoader:Loader;

private var iconLoaded:Boolean = false;

private function init():void {

monitor = new URLMonitor(new URLRequest('http:

//foto.moon.pl'));

monitor.addEventListener(StatusEvent.STATUS,

netStatusChanged);

monitor.start();

timer = new Timer(10000);

timer.addEventListener(TimerEvent.TIMER

, function(event:TimerEvent):

void{loadData();});

timer.start();

iconLoader = new Loader();

iconLoader.contentLoaderInfo.addEventListener(Eve

nt.COMPLETE, function(event:Event):void

{iconLoaded = true;});

iconLoader.load(new URLRequest("images/icon_

128.png"));

errorIconLoader = new Loader();

errorIconLoader.contentLoaderInfo.addEventListener

(Event.COMPLETE, function(event:Event):

void {errorIconLoaded = true;});

errorIconLoader.load(new URLRequest("images/icon_

128_red.png"));

httpRequest.addEventListener(FaultEvent.FA

ULT, function(event:Event):void

{changeIcon();});

hideAppInTray();

createWindow();

}

private function hideAppInTray():void {

var iconMenu:NativeMenu = new NativeMenu();

var showCommand:NativeMenuItem =

iconMenu.addItem(new NativeMenuItem("O

twórz"));

var exitCommand:NativeMenuItem =

iconMenu.addItem(new NativeMenuItem("Za

mknij"));

exitCommand.addEventListener(Event.SELECT,

closeApp);

showCommand.addEventListener(Event.SELECT,

showApp);

if (NativeApplication.supportsSystemTrayIcon) {

var systray:SystemTrayIcon = NativeAppli

cation.nativeApplication.icon as

SystemTrayIcon;

systray.tooltip = "Foto moon pl - RSS";

systray.menu = iconMenu;

}

if (NativeApplication.supportsDockIcon){

var dock:DockIcon = NativeApplication.nativeApp

lication.icon as DockIcon;

dock.menu = iconMenu;

}

}

private function createWindow():void {

nw = new NoticeWindow();

nw.type = NativeWindowType.UTILITY;

nw.alwaysInFront = true;

nw.maximizable = false;

nw.resizable = false;

nw.minimizable = false;

nw.open();

nw.move(Screen.mainScreen.bounds.width - nw.wid

th,Screen.mainScreen.bounds.height -

nw.height - 100);

nativeWindow.close(); // zamykamy główne okno

aplikacji

}

private function closeApp(event:Event):void {

NativeApplication.nativeApplication.icon.bitmaps

= [];

NativeApplication.nativeApplication.exit();

}

private function showApp(event:Event):void {

nw.visible = true;

}

private function netStatusChanged(event:StatusEvent):

void {

changeIcon();

if( monitor.available ) {

loadData();

}

}

private function changeIcon():void {

if( monitor.available && iconLoaded ) {

NativeApplication.nativeApplication.icon.bitmaps =

[iconLoader.content];

Page 30: SDJExtra_31_2008_PL

FLEX30

ADOBE FLEXAdobe AIR

www.sdjournal.org 31

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

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

} else if( !monitor.available && errorIconLoaded

) {

NativeApplication.nativeApplication.icon.bitmaps =

[errorIconLoader.content];

}

}

private function loadData():void {

if( monitor.available ) {

httpRequest.send();

}

}

private function onDataLoaded(event:ResultEvent):

void {

var rss:Object = event.result.rss;

if( nw.logotype.source == null ) { // pierwsze

załadowanie

nw.logotype.source = rss.channel.image.url;

}

if( nw.lastID != rss.channel.item[0].guid ) { //

sprawdzenie czy zostało dodane nowe

zdjecie

nw.lastID = rss.channel.item[0].guid.toString

();

nw.items = rss.channel.item;

}

}

]]>

</mx:Script>

<mx:HTTPService id="httpRequest" resultFormat="object"

result="onDataLoaded(event)"

showBusyCursor="false" url="http://

foto.moon.pl/rss/zdjecia"/>

</mx:WindowedApplication>

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

<mx:Window xmlns:mx="http://www.adobe.com/2006/mxml"

layout="absolute" width="198"

height="262" backgroundColor="#FFFFFF"

systemChrome="none" transparent="true"

closing="beforeClose(event)">

<mx:Script>

<![CDATA[

import mx.collections.ArrayCollection;

private var _alphaTimer:Timer;

private var _closeTimer:Timer;

private var _lastID:String = '';

private var _currentIndex:uint = 0;

private var _lastIndex:uint = 0;

private var _items:ArrayCollection;

public function set items(items:ArrayCollection):

void {

_items = items;

_lastIndex = _items.length - 1;

_currentIndex = 0;

checkButtons();

loadPhoto();

}

public function set lastID(ID:String):void {

_lastID = ID;

}

public function get lastID():String {

return _lastID;

}

private function beforeClose(event:Event):void {

visible = false;

event.preventDefault();

}

private function showNext():void {

if( _currentIndex != 0 ) {

_currentIndex--;

loadPhoto();

checkButtons();

}

}

private function showPrev():void {

if( _currentIndex != _lastIndex ) {

_currentIndex++;

loadPhoto();

checkButtons();

}

}

private function loadPhoto():void {

if( !visible ) {

visible = true;

}

var item:Object = _items[_currentIndex];

box.toolTip = (item.title != null ) ? "Tytuł: \n"

+ item.title : '';

image.source = item.thumbnail.url;

image.addEventListener(MouseEvent.CLICK,onPhotoC

lick);

autor.text = "Autor: " + item.author;

opis.text = (_currentIndex + 1).toString()+'/'+(_

lastIndex+1).toString();

}

private function onPhotoClick(event:MouseEvent):void

{

navigateToURL(new URLRequest(_items[_

currentIndex].link));

}

private function checkButtons():void {

nextBtn.enabled = ( _currentIndex == 0 ) ? false

: true;

prevBtn.enabled = ( _lastIndex == _currentIndex )

? false : true;

}

override public function set visible(value:Boolean):

Page 31: SDJExtra_31_2008_PL

FLEX30

ADOBE FLEXAdobe AIR

www.sdjournal.org 31

Najprostszym przykładem wykorzystania tych pośredniczących funkcji jest ustawienie właściwości _lastID poprzez funkcje get/set lastID() – jest to zmienna wykorzysta-na do identyfikacji ostatnio dodanego zdjęcia. Dla właściwości _items jest przypisany tylko setter, więc z zewnątrz (poza kodem kompo-nentu) nie można jej odczytać, można ją tyl-ko przypisać. Ciekawym przykładem wyko-rzystania takiego settera jest pokazywanie i ukrywanie okna z danymi aplikacji – usta-wienie właściwości visible. Zamiast standar-dowego momentalnego pokazania i ukrycia aplikacji dodaliśmy przejście, które płynnie zmienia widoczność okienka. Wykorzystali-śmy do tego właściwość alpha, odpowiada-jącą za przezroczystość okna, którą zmienia-my w przedziale od 0 do 1, pokazując lub od 1 do 0 ukrywając okno. Mamy tutaj kolejny przykład wykorzystania klasy Timer powodu-jący zmianę właściwości alpha okna co jakiś odstęp czasu. Wnikliwsi czytelnicy z pewno-ścią zauważyli dodatkowy parametr override w deklaracji funkcji przypisującej. Użyliśmy tego słowa dlatego, że zmieniamy standardo-wą funkcję przypisującą, która należy do ba-zowych właściwości klasy Window (po której dziedziczymy tworząc aktualny komponent). Nie jest właściwością należącą do tego pokole-nia obiektu (do komponentu NoticeWindow) tylko do bazowej klasy Window. Bez tego sło-wa kluczowego override aplikacja nie skom-pilowała by się poprawnie. W funkcji tej, dla

właściwego wywołania ukrycia okna użyliśmy słowa kluczowego super odnoszącego się wła-śnie do tzw. superklasy – klasy rodzica, po któ-rej dziedziczymy (w tym przypadku Window). Nawigacja po kolejnych elementach kanału (poprzednich i następnych zdjęciach) została zrealizowana w sposób wykorzystujący index aktualnego elementu (_currentIndex) kolek-cji tablicy _items. Jak pamiętamy z Listingu 8. w momencie załadowania nowych danych do kolekcji _items, przypisane zostają dane z kanału RSS. Zaraz po przypisaniu ustawiamy aktualny index na 0, sprawdzamy czy możli-wa jest nawigacja po elementach (poprzednie, następne zdjęcie) oraz ładujemy najnowsze z nich. W funkcji loadPhoto na samym po-czątku sprawdzamy, czy okienko interfejsu aplikacji jest aktualnie widoczne – dzięki te-mu użytkownik zostanie automatycznie po-wiadomiony (poprzez pokazanie się okien-ka aplikacji) o nowo dodanym zdjęciu do ser-wisu, bez konieczności ręcznego otwierania okienka aplikacji. Dodaliśmy także obsługę zdarzenia wywołanego przez kliknięcie zdję-cia (onPhotoClick) – powodującego przej-ście do witryny z pełną wersją aktualnie wi-docznego elementu (zdjęcia). W kodzie apli-kacji nie przewidzieliśmy sytuacji, w której najnowsze zdjęcie zostanie usunięte z serwi-su – w takim przypadku poprzednie zdjęcie zostanie wyświetlone jako pierwsze, ale roz-wiązanie tego problemu pozostawiam czytel-nikowi jako formę treningu.

PodsumowanieEksplorując zasoby sieci, czy dokumentację AIR, często zadawałem sobie pytanie: ciekawe, czy jest to możliwe w AIR. Z czasem, odnajdując kolejne odpowiedzi, okazało się, że w większo-ści przypadków odpowiedź na tego typu pyta-nia jest twierdząca. Dlatego odnoszę wraże-nie, że to dopiero początek wielkiej przygo-dy z AIR’em (biorąc pod uwagę fakt, że AIR jest aktualnie w wersji 1.0.1, a prace nad Fle-xem 4 trwają).

SZYMON KOSYDORChief Technology Officer Internet Designers

(www.id.pl)

Geek technologiczny w pełnym wymiarze. Absol-

went Politechniki Wrocławskiej na kierunku Fizyki

Technicznej specjalność Fotonika.

Od 2001 roku związany z Internet Designers

(www.id.pl). Obecnie zajmuje stanowisko szefa

sekcji wdrożeń i rozwoju technologicznego (Chief

Technology Officer).

„Moje zainteresowania technologiczne to przede

wszystkim flash, php i łączenie różnych technologii.

Od kilku lat programuję praktycznie tylko obiek-

towo głównie we Flashu, PHP, a także w technolo-

gii Flex. Napisałem własnego cms’a w PHP5 + AJAX

z całkiem pokaźną na dziś listą wdrożeń. Po godzi-

nach: wspinaczka, rower, fotografia.”

Kontakt z autorem: [email protected]

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

void {

if( _alphaTimer == null ) {

_alphaTimer = new Timer(10);

_alphaTimer.addEventListener(TimerEvent.TIMER,

showAlpha);

_closeTimer = new Timer(10);

_closeTimer.addEventListener(TimerEvent.TIMER,

hideAlpha);

}

if( value && alpha != 1 ) {

super.visible = true;

_alphaTimer.start();

_closeTimer.stop();

} else if( !value && alpha != 0 ){

_closeTimer.start();

_alphaTimer.stop();

}

}

private function hideAlpha(e:TimerEvent):void {

if( alpha > .05 ) {

alpha -= .05;

_closeTimer.start();

} else {

_closeTimer.stop();

alpha = 0;

super.visible = false;

}

}

private function showAlpha(e:TimerEvent):void {

if( alpha < .99 ) {

alpha += .01;

_alphaTimer.start();

} else {

alpha = 1;

_alphaTimer.stop();

}

}

]]>

</mx:Script>

<mx:Image horizontalCenter="0" top="10" id="logotype"/>

<mx:Button label="»" width="41" click="showPrev()"

id="prevBtn" right="10" bottom="10"/>

<mx:Button label="«" width="41" click="showNext()"

id="nextBtn" bottom="10" left="10"/>

<mx:VBox horizontalAlign="center" verticalAlign="middle"

id="box" top="67" bottom="40" left="10"

right="10" >

<mx:Image id="image"/>

</mx:VBox>

<mx:Label bottom="8" horizontalCenter="0" id="opis"/>

<mx:Label horizontalCenter="0" top="41" id="autor"/>

</mx:Window>

Page 32: SDJExtra_31_2008_PL

FLEX32

ADOBE FLEXTworzenie aplikacji wykorzystujących mapy w Adobe Flex

www.sdjournal.org 33

Mamy możliwość korzystania z kil-ku środowisk klienckich (AJAX, Flash, Flex lub w przyszłości Silver-

light), jak i interfejsów aplikacji (API). Głów-nymi dostarczycielami technologii są Google Maps, Yahoo Maps oraz Microsoft Live Search Maps.Dlaczego warto połączyć te technologie z platformą Adobe Flex? Odpowiedź na to py-tanie można podzielić na kilka punktów. Po pierwsze – łatwiejsza komunikacja z API do-starczycieli map. Z reguły odbywa się ona za pomocą Web Services SOAP lub REST, które z kolei są mocno osadzone w środowisku Flex. Po drugie – możemy stworzyć rozbudowany interfejs korzystający z dużego modelu danych. Często przy wykorzystaniu technologi AJAX musimy wybrać, ze względu na optymalizację, jedno lub drugie. Korzystając zaś z Flexa – nie musimy rezygnować z ciekawych rozwiązań, wręcz przeciwnie – możemy często dopieścić nawet bardzo skomplikowaną aplikację cieka-wym i nietuzinkowym interfejsem. Po trzecie – Flex będąc zbudowanym na Flashu, jest z na-tury środowiskiem graficznym. Oznacza to, że możemy w łatwy sposób łączyć elementy wizu-alne z wybraną technologią map.

Istnieje już kilka ciekawych projektów apli-kacji internetowych RIA opartych na mapach

oraz środowisku Flex. Spektrum zastosowań biznesowych tego typu rozwiązań może być bardzo szerokie. Jeżeli puścimy wodze fanta-zji projektując aplikację, a dodatkowo skorzy-stamy z usług agregujących dane gromadzone we wszelkiego rodzaju serwisach, aby pobrać dodatkowe dane, możemy zbudować aplikację realizującą dowolne zadania. Ciekawymi reali-zacjami są np.:

• Aplikacja do mierzenia własnego postępu podczas biegania lub jeżdżenia na rowe-rze. Gotowe rozwiązanie możemy znaleźć pod adresem http://www.traxmeet.com/traxmeet/TraxmeetPlayer.html?performan-ceid=12726591&josso_ assertion_id=1E-32082B39AA1FA4. Pozwala nam na re-gularne mierzenie poczynanych przez nas postępów poprzez integrację z danymi po-bieranymi z GPS, a następnie dokładną ich analizę;

• Aplikacja, która umożliwia naniesienie na mapę zdjęć oraz danych geolokalizacyj-nych odczytanych z urządzeń zapisują-cych pozycję GPS. Całość pozwala np. na odtworzenie odbytej przez nas wycieczki, dodatkowo nanosząc wprowadzone przez nas dane. Następnie możemy rozesłać tak przygotowaną mapę do znajomych. Projekt znajdziemy pod adresem http://mapmypix.com/;

• Prosty, ale ciekawy przykład znajdziemy również pod na stronie http://www.earth-measurements.com/. Jest to rozwiązanie po-

zwalające na mierzenie odległości pomię-dzy kolejnymi punktami przez nas wyzna-czonymi. Odległości pomiędzy punktami przedstawione są jako kolejne elementy wykresu;

• HomeLocator jest przykładem aplikacji po-zwalającej na zestawienie w ciekawy spo-sób informacji o sprzedawanych domach, jak i ich lokalizacji geograficznej. Aby za-poznać się z tym przykładem, należy od-wiedzić stronę http://www.asfusion.com/apps/homelocator/. Całość została zaopa-trzona w intuicyjny i przyjazny interfejs;

• TrailTracer to aplikacja służąca do tworze-nia i współdzielenia spersonalizowanych map. Znajdziemy ją pod adresem http://www.trailtracer.com/;

• Oobgolf Course Finder jest narzędziem do przeglądania informacji o wprowadzonych do bazy serwisu polach golfowych. Serwis można pochwalić za jakość wykonania aplikacji, jak i ilość oraz dokładne poło-żenie przeglądanych miejsc. Znajdziemy go pod adresem http://www.oobgolf.com/courses/finder/;

• Często stosowanym rozwiązaniem jest geolokalizacja punktów sprzedaży danej sieci, tak aby klienci mogli znaleźć najle-piej im odpowiadający. Przykładowe roz-wiązanie zastosowała firma Rolex. Roz-wiązanie znajdziemy pod adresem http://www.rolex.com /en /inside–rolex /sales–service/find–a–rolex–dealer/index.jsp.

Osobiście jako konsultant i programista Ado-be Flex wykonałem kilka ciekawych projek-tów wykorzystując mechanizm map. Najbar-dziej interesującym z nich jest aplikacja po-zwalająca na śledzenie w czasie rzeczywi-stym oraz przeglądanie danych historycznych o włamaniach. Jest to ciągle rozwijany projekt, jednak udowodnił on, że Flex jest doskonale sprawdzającym się narzędziem do takich za-stosowań. Aplikacja opiera się na danych kil-

Aplikacje wykorzystujące mapy w Adobe FlexPopularność 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.

Dowiesz się...• Jakiego typu aplikacje możemy stworzyć za

pomocą tego typu rozwiązań;

• Jakich bibliotek możemy użyć wraz z platfor-

mą Adobe Flex;

• Jak stworzyć przykładowe elementy projektu

opartego o Flex i Yahoo Maps.

Powinieneś wiedzieć...• Wymagane są: podstawowa wiedza z zakre-

su użycia Web Services oraz tworzenia aplika-

cji opartych o zewnętrzne dane (mashups), jak

i podstawowa umiejętność pracy ze środowi-

skiem Flex.

Poziom trudności

Page 33: SDJExtra_31_2008_PL

FLEX32

ADOBE FLEXTworzenie aplikacji wykorzystujących mapy w Adobe Flex

www.sdjournal.org 33

kuset do kilkunastu tysięcy obiektów, a do tego obserwacja zgłoszonych zdarzeń w za-bezpieczanych budynkach może odbywać się w czasie rzeczywistym. Całość została zaopa-trzona w ciekawy i przyjemny dla użytkow-nika interfejs. Pozwala on na zmianę parame-trów aktualnie przeglądanych wydarzeń oraz ich filtrowanie. Projekt jest wykonywany na zlecenie firmy ochroniarskiej pragnącej narzę-dzia pozwalającego na szybkie i przejrzyste za-poznanie się i analizowanie danych o przestęp-stwach (Rysunek 1.).

Bardzo ciekawe możliwości daje połączenie platformy Flex, map oraz technologii zdalne-go dostępu i wymiany wiadomości BlazeDS lub LiveCycle DS (technologie umożliwiają-ce budowę aplikacji korzystających z logiki biznesowej serwerów Java w czasie rzeczywi-stym). Możliwości biznesowe takich rozwią-zań są bardzo obiecujące. Przykładowo, po-zwalają one na współdzielenie w czasie rze-czywistym map przez kilku użytkowników, np. podczas telekonferencji. Tak wykonaną prostą aplikację wraz ze źródłem oraz instruk-cjami wykonania znajdziemy pod adresem http://coenraets.org/blog/2008/04/yahoo–maps–collaboration–using–flex–and–blazeds/. Zain-teresowanych tematyką koniecznie odsyłam do zapoznania się z przedstawionym rozwią-zaniem.

Flex i API gotowych bibliotekJak wspomnieliśmy we wstępie podczas projek-towania i wykonywania aplikacji do dyspozycji mamy kilka rozwiązań, jak i gotowych do uży-cia bibliotek. Podczas pracy z platformą Flex najlepiej jest skorzystać z:

• Yahoo Maps (http://developer.yahoo.com/maps/). Rozwiązanie jest wygodne, do-starczone zostało API dla ActionScript w wersjach 2 oraz 3, AJAX i Simple API (usługa niewymagająca umiejętności pro-gramowania). Całość jest dobrze udoku-mentowana, posiada wiele przykłado-wych zastosowań, jak i instrukcji krok po kroku. Projekt jest również bardzo czyn-nie wspierany przez środowisko. Wszela-kie pytania możemy zadawać na oficjal-nym forum http://tech.groups.yahoo.com/group/yws–maps/;

• UMap firmy Advanced Flash Compo-nents (http://www.afcomponents.com/components/umap_as3/). Dostarczone API dla ActionScript 3.0 oferuje wie-le ciekawych funkcji. Rozwiązaniu te-mu warto jest się przyjrzeć bliżej, pro-ducent oferuje kilka instrukcji wprowa-dzających do swojego produktu. Ten pro-jekt również posiada mocne wsparcie śro-dowiska, forum znajdziemy pod adre-sem http://www.afcomponents.com/forum/viewforum.php?f=20. Standardowo użyte mapy mają trochę niższą jakość niż wy-

Listing 1. Zastosowanie biblioteki Yahoo Map<mx:Application

xmlns:mx="http://www.adobe.com/2006/mxml"

layout="absolute"

creationComplete="onCreationComplete()">

<mx:Script>

<![CDATA[

import mx.events.ResizeEvent;

import com.yahoo.maps.api.YahooMap;

import com.yahoo.maps.api.YahooMapEvent;

import com.yahoo.maps.api.core.location.Address;

import com.yahoo.maps.webservices.geocoder.GeocoderResult;

import com.yahoo.maps.webservices.geocoder.events.GeocoderEvent;

private var _yahooMap:YahooMap;

private var _address:Address;

private function onCreationComplete():void

{

var appid:String = Application.application.parameters.appid;

_yahooMap = new YahooMap();

_yahooMap.addEventListener(YahooMapEvent.MAP_INITIALIZE,

handleMapInitialize);

_yahooMap.init(appid,mapContainer.width,mapContainer.height);

mapContainer.addChild(_yahooMap);

mapContainer.addEventListener(ResizeEvent.RESIZE, onMapContainerResize);

_yahooMap.addPanControl();

_yahooMap.addZoomWidget();

_yahooMap.addTypeWidget();

_yahooMap.addScaleBar();

}

private function handleMapInitialize(event:YahooMapEvent):void {

// Tu dodajemy isntrukcje wykonywane po zainicjalizowaniu mapy,

// np. wyszukiwanie i dodawanie punktów na mapie

_address = new Address("warszawa");

_address.addEventListener(GeocoderEvent.GEOCODER_SUCCESS,

onGeocodeSuccess);

_address.geocode();

}

private function onGeocodeSuccess(event:GeocoderEvent):void

{

var result:GeocoderResult = _address.geocoderResultSet.firstResult;

_yahooMap.zoomLevel = result.zoomLevel;

_yahooMap.centerLatLon = result.latlon;

}

private function onMapContainerResize(event:ResizeEvent):void {

_yahooMap.setSize(mapContainer.width,mapContainer.height);

}

]]>

</mx:Script>

<mx:UIComponent id="mapContainer" width="100%" height="100%"/>

</mx:Application>

Page 34: SDJExtra_31_2008_PL

FLEX34

ADOBE FLEXTworzenie aplikacji wykorzystujących mapy w Adobe Flex

www.sdjournal.org 35

mienione powyżej Yahoo Maps, ich głów-nym dostarczycielem jest serwis http://openstreetmap.com/ (możemy go jednak zamienić np. na Google Maps);

• Modest Maps (http://www.modestmaps.com/). Zespół pro-

gramistów tworzy rozwiązanie w opar-ciu o licencję BSD, dając nam do dyspozy-cji API ActionScriptowe w wersji 2 oraz 3, jak i dla języka Python. Do wyboru mamy kilku dostarczycieli map, możemy skorzy-stać z zasobów Open Street Map, NASA, Blue Marble, Google, Yahoo oraz Micro-softu. Projekt nie jest rozwijany tak pręż-nie jak wcześniejsze i nie posiada tak silne-go wsparcia jak one.

Najlepszym rozwiązaniem z naszego punk-tu widzenia są Yahoo Maps. Poza obsługą sa-mych map bezpośrednio z poziomu Action-

Script 3.0 mamy do dyspozycji wiele przydat-nych Web Services, m.in.:

• Yahoo! Weather (http://developer.yahoo.com/weather/). Umożliwia on połączenie map z danymi pogodowymi dla zadanej lo-kacji. Przykładowo prognoza pogody dla Krakowa znajduje się pod adresem http://weather.yahooapis.com/forecastrss?p=PLXX0012;

• Yahoo! Traffic (http://developer.yahoo.com/traffic/). REST API daje nam możliwość dostępu do bieżących danych o natężeniu ruchu ulicznego w żądanej lokalizacji;

• Yahoo! HotJobs (http://developer.yahoo.com/hotjobs/). Dzię-

ki faktowi, że ogłoszenia pracy w serwi-sie Yahoo możemy przeglądać wyszu-kując m.in. po nazwach miast, możliwe jest stworzenie aplikacji łączącej tę usłu-

gę wraz z mapami. Rezultat może być na-prawdę ciekawy;

• Yahoo! Travel (http://developer.yahoo.com/travel/). REST API pozwala nam na dostęp do danych zawierających informacje o wy-cieczkach, ciekawych miejscach, możli-wych połączeniach lotniczych czy miej-scach hotelowych. Aplikacja stworzona w oparciu o takie rozwiązanie może udo-stępnić użytkownikom nowe, przyjazne podejście do tej tematyki.

Możemy również użyć gotowych biblio-tek stworzonych pod ActionScript 3.0 uła-twiających korzystanie z udostępnionych przez Yahoo serwisów. Biblioteka ta to Yahoo! Astra Web Library. Aby się z nią zapoznać, należy odwiedzić stronę http://developer.yahoo.com/flash/astra–webapis/. Dzię-ki niej mamy uproszczony dostęp np. do Yahoo! Weather.

Yahoo Maps ActionScript 3.0 APIStronę 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-czamy w katalogu libs tworzonych we Flex Bu-ilderze aplikacji. Aby móc w pełni korzystać z serwisu Yahoo Maps, będziemy potrzebo-wać jeszcze swój klucz API, potrzebny pod-czas inicjalizacji mapy. Aby go otrzymać, re-jestrujemy naszą aplikację pod adresem http://developer.yahoo.com/wsregapp/index.php. Przejdźmy teraz do najprostszego przykładu zastosowania komponentu (Listing 1.). Aby móc umieścić obiekt mapy w naszym projek-cie, musimy umieścić go jako element kompo-

Listing 2. Modyfikacja funkcji onGeocodeSuccess()

private function onGeocodeSuccess(event:GeocoderEvent):void

{

var result:GeocoderResult = _address.geocoderResultSet.firstResult;

_yahooMap.zoomLevel = result.zoomLevel;

_yahooMap.centerLatLon = result.latlon;

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 1. Przykład własnej aplikacji – mapa z danymi o włamaniach do budynków

Rysunek 2. Wskaźnik graficzny stworzony w programie Flash

Page 35: SDJExtra_31_2008_PL

FLEX34

ADOBE FLEXTworzenie aplikacji wykorzystujących mapy w Adobe Flex

www.sdjournal.org 35

nentu UIComponent. Dzieje się tak, ponieważ dostarczone przez Yahoo rozwiązanie dzie-dziczy bezpośrednio po Sprite. Przeanali-zujmy przykład z Listingu 1. Po zakończeniu tworzenia aplikacji wywoływana jest funkcja onCreationComplete(). W niej przechwytu-jemy parametr przekazany do Flexa zawiera-jący nasz klucz API:

var appid:String = Application.application.

parameters.appid;

Następnie tworzymy obiekt YahooMap, doda-jemy jako odbiorcę zdarzenia zakończenia ini-cjalizacji tego komponentu funkcję handleMapInitialize()oraz wywołujemy metodę inicja-lizującą mapę, przekazując jej nasz klucz oraz rozmiar okna, w którym jest wyświetlana:

_ yahooMap = new YahooMap();

_yahooMap.addEventListener(YahooMapEvent

.MAP_INITIALIZE, handleMapInitialize);

_yahooMap.init(appid,mapContainer.width,

mapContainer.height);

Kolejne linijki to: dodanie obiektu do wspo-mnianego UIComponent oraz nasłuchiwanie zdarzenia zmiany rozmiarów komponen-tu kontenera mapy oraz, w wypadku wystą-pienia zdarzenia, wywołanie odpowiedniej funkcji:

mapContainer.addChild( _ yahooMap);

mapContainer.addEventListener(ResizeEvent

.RESIZE, onMapContainerResize);

Następne linijki umożliwiają dodanie do obiektu mapy odpowiednich elementów uła-twiających korzystanie z mapy, są to m.in.: Pan Control – element umożliwiający prze-ciąganie mapy, Type Control – przełącza-nie pomiędzy typami widoków, Scale Bar

– wyświetla aktualną skalę mapy oraz Zoom Widget – pozwala na zmianę przybliżenia:

_yahooMap.addPanControl();

_yahooMap.addZoomWidget();

_yahooMap.addTypeWidget();

_yahooMap.addScaleBar();

Po zakończeniu inicjalizacji mapy możemy wykonać dodawanie do niej elementów, np. wskaźników na mapie (Marker) czy usta-lić punkt centralny, na który ustawi się no-wo załadowana mapa. W naszym prostym przykładzie wykorzystaliśmy bardzo przy-datny element biblioteki Yahoo Map, ja-ką jest mechanizm dekodujący zapytanie (w postaci obiektu Adress) do konkretnej lo-kalizacji geograficznej zawierającej dokład-ne współrzędne oraz zalecany poziom zbli-żenia. Zwracany w wyniku zapytania obiekt (GeocoderResult) zawiera również inne da-

Listing 3. Tworzenie CustomMarker.as

this.adress = customAdress;

this.imageURL = customImageURL;

this.marker = new FlashMarker();

this.marker.filters = [this.dropShadowFilter];

this.addChild(this.marker);

this.toolTip = this.drawToolTip();

this.addChild(this.toolTip);

}

private function onMouseOver(event:MouseEvent):void

{

this.promoteToTop();

if(this.toolTip) this.toolTip.visible = true;

}

private function onMouseOut(event:MouseEvent):void

{

if(this.toolTip) this.toolTip.visible = false;

}

private function drawToolTip():MovieClip

{

var toolTipMC:MovieClip = new MovieClip();

toolTipMC.graphics.beginFill(0x3c3c3c, 0.66);

toolTipMC.graphics.drawRoundRect(–80, –155, 160, 125,

10, 10);

toolTipMC.graphics.endFill();

toolTipMC.visible = false;

var name:TextField = new TextField();

name.width = 160;

name.height = 20;

name.x = –80;

name.y = –150;

name.text = this.name;

package

{

import com.yahoo.maps.api.markers.Marker;

import flash.display.Loader;

import flash.display.MovieClip;

import flash.events.MouseEvent;

import flash.filters.BitmapFilterQuality;

import flash.filters.DropShadowFilter;

import flash.net.URLRequest;

import flash.text.TextField;

import flash.text.TextFormat;

public class CustomMarker extends Marker

{

private var dropShadowFilter:DropShadowFilter = new

DropShadowFilter(0, 0, 0, 1, 12, 12,

1.5, 3);

private var marker:MovieClip;

private var toolTip:MovieClip;

private var adress:String;

private var imageURL:String;

public function CustomMarker(customName:String,

customAdress:String, customImageURL:

String)

{

super();

this.addEventListener(MouseEvent.MOUSE_OVER,

this.onMouseOver);

this.addEventListener(MouseEvent.MOUSE_OUT,

this.onMouseOut);

this.addEventListener(MouseEvent.ROLL_OUT,

this.onMouseOut);

this.name = customName;

Page 36: SDJExtra_31_2008_PL

FLEX36

ADOBE FLEXTworzenie aplikacji wykorzystujących mapy w Adobe Flex

www.sdjournal.org 37

ne, np. nazwę państwa, miasta, hrabstwa (w Polsce – powiatu), kod kraju, kod pocz-towy itp. Możemy oczywiście wykonać za-pytanie o wiele elementów naraz. Pamiętaj-my jednak, wykonywane są one asynchro-nicznie, co wymusza na nas kontrolę odbie-ranych danych. Przyjrzyjmy się zawartości funkcji handleMapInitialize():

_address = new Address("warszawa");

_address.addEventListener(GeocoderEvent.

GEOCODER_SUCCESS,

onGeocodeSuccess);

_address.geocode();

Tworzymy obiekt Adress, przekazując do nie-go treść zapytania. Następnie, jako odbiorcę zdarzenia powodzenia zapytania, ustalamy funkcję onGeocodeSuccess(). Kolejna linijka wykonuje zapytanie. Przejdźmy więc do funk-cji odbierającej wymienione zdarzenie. Po ode-braniu rezultatu w postaci zdarzenia, na jego podstawie ustalamy poziom zbliżenia mapy oraz jest punkt centralny (obiekt LatLon):

var result:GeocoderResult = _ address.geoco

derResultSet.firstResult;

_yahooMap.zoomLevel = result.zoomLevel;

_yahooMap.centerLatLon = result.latlon;

Ostatnią funkcją jest onMapContainerResize(). Jak już wcześniej wspomnieliśmy, wywoływa-na ona jest automatycznie po zmianie rozmia-ru komponentu zawierającego mapę. Aby za-pewnić poprawne wyświetlanie mapy, musimy upewnić się, że nowe wartości zostaną przeka-zane jej obiektowi1. Spowoduje to przerysowanie elementów składowych (mapa, wskaźniki, ele-menty interfejsu mapy). W naszym przykładzie sytuacja ta wystąpi w momencie zmiany rozmia-rów okna przeglądarki. Zadanie to jest realizowa-ne wywołaniem odpowiedniej metody:

_yahooMap.setSize(mapContainer.width,mapCon

tainer.height);

Jak widzimy zastosowanie komponentuYahooMap jest bardzo proste, a jego stosowanie logiczne.

Dodanie wskaźników do mapyWizualizacja danych w aplikacjach wykorzy-stujących mapy odbywa się poprzez zastoso-wanie wskaźników (Markers), które zosta-ją umieszczone w odpowiadających im po-zycjach. W dalszej części omówimy umiesz-czanie prostych wskaźników, jak i stworzenie własnych oparte na stworzonych przez nas ele-mentach graficznych.

Zarządzaniem wskaźnikami zajmuje się klasa MarkerManager. Przy użyciu kompo-nentu YahooMap, używając standardowej kla-sy map, biblioteka sama stworzy dla nas odpo-wiedni obiekt. Następnie będziemy mogli do niego dodawać wskaźniki, upewniając się, tyl-ko aby miały one poprawne dane geograficzne. Jako wskaźników użyjemy prostych obiektów SimpleMarker. Są one wbudowane w omawia-ną bibliotekę. Rozszerzmy więc poprzedni przykład. Dodamy wokół punktu centralne-go kilka losowo umieszczonych wskaźników. Aby to zrobić, musimy najpierw mieć zwró-coną treść zapytania GeoCoderResult. Mody-fikujemy funkcję onGeocodeSuccess().

Jest to maksymalnie uproszczony przykład, mający zobrazować zasadę działania tego me-chanizmu. Aby stworzyć własny wskaźnik, roz-szerzamy klasę Marker. Klasa ta posiada już kil-ka przydatnych dla nas właściwości, jak np. ad-res, własne dane geograficzne, referencję do obiektu mapy, na której jest umieszczony, naj-większy i najmniejszy poziom zbliżenia, przy którym wskaźnik jest widoczny, a także cha-rakterystyczny identyfikator grupy wskaźni-ków. Jeżeli chcemy przyporządkować wskaź-niki do takiej grupy, będziemy mogli pobierać tablicę zawierającą referencję do wszystkich jej elementów z poziomu obiektu MarkerManager. Przyda się to np. w sytuacji, gdy chcemy szyb-ko ustawić danej grupie pewne właściwości, np. ich widoczność.

Załóżmy, że na potrzeby projektu musimy stworzyć wskaźniki graficzne według projektu graficznego, który nam dostarczono. Najprost-szy sposób, w jakim możemy tego dokonać to wykonać odpowiednie grafiki w programie Flash, wyeksportować je do plików SWF, które to z kolei możemy wprowadzić do naszej aplika-cji. Zacznijmy więc od początku – tworząc grafi-kę. Przykład zamieszczony jest na Rysunku 2.

Wygodne jest stworzenie wskaźników w aplikacji Flash, bo tworzonym elementom możemy automatycznie przyporządkować punkt odniesienia. Jest to o tyle ważne, że nie musimy później pamiętać o przesunięciu wskaźników. Sytuacja taka zdarzyłaby się przy użyciu np. grafik .png, które są pozycjonowa-ne w swoim górnym lewym rogu. Aby tego uniknąć, musimy korzystać ze specjalnej kla-sy, CustomImageMarker.

Mając przygotowany wskaźnik w posta-ci pliku .swf, przygotujemy klasę dziedziczą-cą po Movie Clip, który będzie go zawierać. Obrany tu przeze mnie sposób dobrze ilustru-je, jak możemy szybko osiągnąć pożądany re-zultat. Przy użyciu wielu różnych wskaźni-ków najlepiej jest stworzyć we Flashu odpo-wiedni plik zawierający, który je zawiera, i na-pisać metody, które będą zwracały nam od-powiednie obiekty. Całość eksportujemy do Flexa za pomocą narzędzia Flex Component Kit for Flash (http://www.adobe.com/go/flex3_cs3_swfkit). Wracając do omawianego przy-kładu, napiszmy klasę Movie Clip zawierający plik Flash (Listing 4.). Mając gotowy do uży-cia symbol graficzny, możemy stworzyć wła-sny wskaźnik. Załóżmy, że chcemy wykorzy-stać przygotowaną grafikę, a klient dodatko-wo żąda od nas wyświetlenia dymku z infor-macją o danej lokalizacji, zawierającego dodat-kowo pewną ikonkę. Tworzymy plik Custom-Marker.as (Listing 3.).

Omówmy ten przykład. Do konstruktora wskaźnika przekazujemy jego nazwę, pewien adres (pojawi się on w dymku), oraz adres URL obrazka, który chcemy załadować. Nasłuchiwa-

Listing 4. Załączenie pliku swf

package

{

import flash.display.MovieClip;

[Embed("Marker.swf", symbol="MarkerRed")]

public class FlashMarker extends

MovieClip

{

public function FlashMarker()

{

super();

}

}

}

Listing 5. Modyfikacja funkcji onGeocodeSuccess

private function onGeocodeSuccess

(event:GeocoderEvent):void

{

var result:GeocoderResult = _address.geocoderResultSet.firstResult;

_yahooMap.zoomLevel = result.zoomLevel;

_yahooMap.centerLatLon = result.latlon;

var customMarker:CustomMarker =

new CustomMarker

("Przyklad", "Warszawa, Centrum", "icon.jpg");

customMarker.latlon = result.latlon;

_yahooMap.markerManager.addMarker(customMarker);

}

Page 37: SDJExtra_31_2008_PL

FLEX36

ADOBE FLEXTworzenie aplikacji wykorzystujących mapy w Adobe Flex

www.sdjournal.org 37

nie zdarzeń związanych z ruchem myszki po-zwoli na pokazanie lub ukrycie podpowiedzi. Stworzony wcześniej FlashMarker dodajemy do naszego wskaźnika poprzez (dodajemy do niego również cień):

this.marker = new FlashMarker();this.marker.filters =

[this.dropShadowFilter];

this.addChild(this.marker);

Funkcja drawToolTip() powinna być dosko-nale zrozumiała dla osób na co dzień korzy-stających z aplikacji Flash i języka Action-Script. Ręcznie rysujemy w niej dymek, do-dajemy i formatujemy tekst, który ma się w nim ukazać a także ładujemy i wyświetla-my żądany obrazek. Powróćmy do głównego pliku naszej aplikacji i zmodyfikujmy funkcję onGeocodeSuccess() (Listing 5.). Wynik na-szej pracy możemy zobaczyć na Rysunku 3.

Możliwości bilioteki Yahoo Maps Actionscript 3.0 APIWiększość elementów biblioteki zosta-ła doskonale omówiona na stronie http://developer.yahoo.com/flash/maps/examples.html. Przedstawione tam przykłady zawierają pod-gląd źródła, możemy więc zapoznać się krok po kroku z kolejnymi funkcjami tego API. Wstęp-nie zapoznaliśmy się z możliwością zadawania zapytań o adres, pozycjonowaniem wskaźni-ków, a także z tworzeniem własnych obiektów służących do wyświetlania danych. Przejrze-nie przykładów ze wspomnianej strony pozwo-li nam na zrozumienie zasad:

• Obsługi kolejnych zdarzeń komponentu YahooMap ;

• Rysowania polilinii w przedstawianych mapach (jest to o tyle łatwe, że kolejne wierzchołki możemy definiować za pomo-cą współrzędnych geograficznych);

• Rysowania tzw. Geodesic Polyline, są to spe-cyficzne krzywe, często wykorzystywane przy aplikacjach wykorzystujących mapy;

• Rysowania na mapach własnych kształ-tów, są one przechowywane w specjalnej warstwie;

• Korzystania z serwisu Yahoo! Local Se-arch. Umożliwia on znajdowanie obiek-tów zainteresowań w bazie serwisu Yahoo! i umieszczania ich na prezentowanej ma-pie;

• Zbudowania serwisu w oparciu o biblio-tekę Yahoo Maps oraz ASTRA Web API – korzystającej z danych meteorologicz-nych.

ZakończeniePodczas wykonywania tego typu aplikacji pa-miętajmy o pewnych ograniczeniach technicz-nych – spotkamy się z nimi na pewno w apli-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-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?

Rysunek 3. Wskaźnik na mapie

Rysunek 4. Aplikacja Flex z ASTRA Web Services

WOJCIECH PTAKOd 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

oparte o Adobe Flex oraz AIR.

Page 38: SDJExtra_31_2008_PL

FLEX38

ADOBE FLEXFlex na Javie

www.sdjournal.org 39

W lutym 2008 roku ukazała się trze-cia wersja Flex SDK wydana na Mozilla Public License. Jednak na

licencji ogólnej wciąż prawa pozostają Adobe Flash Player, który pozwala uruchamiać apli-kacje flashowe oraz flexowe i Flex Builder, czy-li IDE (używane do budowania aplikacji flexo-wych) oparte o Eclipse.

We Flexie wykorzystano MXML, czyli 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

(znane użytkownikom Flasha) oraz odpowied-nie pliki .html, w których osadzone będą pliki .swf. Po uruchomieniu strony w przeglądarce, zostanie załadowany odtwarzacz Flasha, który można uruchomić bez włączania strony, a włą-czając jedynie plik .swf. I voila! Możemy cieszyć się naszą aplikacją.

O Flexie można by dużo mówić. Nie będę jednak dłużej owijał w bawełnę i powiem krót-ko – stwórzmy coś!

Instalujemy i konfigurujemyPrzygotujmy sobie środowisko pracy. Co ro-bimy? Programujemy we Fleksie. Do tego ce-lu będziemy potrzebowali Flex Buildera, któ-

rego możemy pobrać ze strony domowej pro-jektu Adobe Flex lub z płyty DVD. Dostępna jest wersja 60-dniowa, którą możemy wyko-rzystywać do celów niekomercyjnych. Przygo-towano także specjalną edycję dla studentów. 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-brać i zainstalować jako wtyczkę do Eclipse. Flex Builder nie jest niezbędny, jednak przy-daje się, jeśli chcemy nasze aplikacje budować w sposób graficzny. Jeśli nie, wystarczy zwy-kły notatnik, bo kompilację i tak przerzucimy na nasz serwer, o którym za chwilę.

Instalacja przebiega bezproblemowo. Kli-kamy jedynie przycisk Dalej, w odpowiednim miejscu akceptujemy licencję i czekamy na za-kończenie kopiowania plików. Po zakończonej instalacji, w menu Start czeka na nas Flex Buil-der. Uruchamiamy go i naszym oczom ukazu-je się GUI znane z Eclipse, zatem osoby, któ-re miały już wcześniej do czynienia z tym śro-dowiskiem, bez problemu się w nim odnajdą.

Flex na JavieHistoria 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.

Dowiesz się...• W jaki sposób tworzyć aplikacje RIA, na przy-

kładzie forum, wykorzystując różne technolo-

gie Internetowe, a w szczególności Javę, a tak-

że SQL, JSP oraz Flex.

Powinieneś wiedzieć...• W jaki sposób korzystać z SQL (także z pozio-

mu Javy). Znać podstawy JSP, RIA, Flex.

Poziom trudności

Rysunek 1. Okno rejestracji

Page 39: SDJExtra_31_2008_PL

FLEX38

ADOBE FLEXFlex na Javie

www.sdjournal.org 39

Jeśli jednak masz pewne problemy, to nie oba-wiaj się – poprowadzę Cię za rękę.

W artykule wykorzystamy także język Java, zatem warto doinstalować wtyczkę pozwala-jącą na programowanie w tymże języku za po-mocą Flex Buildera. Aby to zrobić, klikamy kolejno Help>Software Updates>Find and In-stall. W oknie, które się pojawi, zaznaczamy opcję Search for new features to install, klikamy przycisk Next i na liście zaznaczamy pozycję The Eclipse Project Updates. Gdy otrzymamy li-stę pakietów, które możemy zainstalować, od-szukujemy najnowszą wersję Eclipse Java De-velopment Tools i przystępujemy do jej insta-lacji. Zaopatrzmy się także w specjalnie przy-gotowany i skonfigurowany serwer FDS-Tom-cat, który pobrać można z Internetu (link w ramce). Rozpakujmy go najlepiej na dysk C, po czym (korzystając z konsoli), przejdźmy do folderu C:\fds-tomcat\bin i wpiszmy pole-cenie catalina run. Musimy pamiętać o tym, że potrzebna jest zdefiniowana zmienna śro-dowiskowa JAVA_HOME. Można ją zdefiniować albo za pomocą narzędzi systemowych, albo zdefiniować ją tymczasowo, nieco modyfi-kując polecenie: JAVA_HOME=dysk:\sciezka\do\javy\ catalina run. Okno konsoli mo-żemy zminimalizować, ale nie należy go za-mykać. FDS-Tomcat bez problemu działa tak-że na Linuksie (na moim laptopie czas startu serwera pod Linuksem był blisko dwukrotnie krótszy!), a uruchamiany jest analogicznie jak na innych platformach, pamiętając o zmien-nej JAVA_HOME – JAVA_HOME=/sciezka/do/

javy/ ./catalina.sh run, uprzednio na-dając prawa wykonania pliku poprzez po-lecenie chmod +x catalina.sh. W syste-mie Windows, Java znajduje się domyślnie w C:\Program Files\Java\jre-numer-wersji\, natomiast w moim Linuksie (Ubuntu) pod ścieżką /usr/share/java-numer-wersji/. Może-my także skorzystać z ręcznie postawionego Tomcata oraz jakiejś bazy danych SQL (np. MySQL) zamiast z FDS-Tomcata, który nie jest dość stabilny i bezpieczny do codzienne-go użytku, natomiast do celów edukacyjnych nadaje się znakomicie. Instalację i konfigura-cję pozostawiam drogi czytelniku Tobie – wy-starczy zajrzeć do dokumentacji wyżej wy-mienionych projektów. Uwaga dla tych, któ-rzy zdecydują się samodzielnie ustawić ser-wer: domyślnie skonfigurowany Tomcat nie skompiluje plików .mxml, a FDS-Tomcat tak. W artykule proces kompilacji został pominię-ty i przerzucony właśnie na FDS-Tomcat, tak-że w przypadku korzystania z czystego Tom-cata należy go albo przekonfigurować, albo we Flex Builderze skompilować plik .mxml do pliku .swf i umieścić go w odpowiednim kata-logu, do którego Tomcat sięgnie wyświetlając strony internetowe.

To tyle, jeśli chodzi o przygotowania. Śro-dowisko jest podzielone na trzy główne czę-ści – w środkowej piszemy kod, po bokach ma-

my przydatne narzędzia, na dole konsolę in-formująca o błędach itp. Jeśli natomiast cho-dzi o FDS-Tomcat, najważniejsze, co musimy wiedzieć jest to, że przy uruchomieniu ser-wera wczytywany jest m.in. plik fds-tomca\

db\flexdemodb.script, który zawiera komplet-ny opis bazy danych. Wszystkie operacje na tej bazie danych w trakcie działania serwera wykonywane są w pamięci, a dopiero podczas poprawnego zamknięcia serwera, zmodyfiko-

Listing 1. Pierwsza aplikacja

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

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

<mx:ApplicationControlBar x="239" y="36" dock="true" height="60">

<mx:Label text="FlexForum" fontSize=”25”/>

</mx:ApplicationControlBar>

</mx:Application>

Listing 2. Dodajemy stopkę

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

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

<mx:ApplicationControlBar x="239" y="36" dock="true" height="60">

<mx:Label text="FlexForum" fontSize=”25”/>

</mx:ApplicationControlBar>

<mx:Label text="(C) 2008" horizontalCenter="0" bottom="0"/>

</mx:Application>

Listing 3. FlexForum.mxml

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

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

<mx:states>

<mx:State name="logged">

<mx:RemoveChild target="{lpBox}"/>

<mx:RemoveChild target="{registerButton}"/>

<mx:RemoveChild target="{loginButton}"/>

<mx:AddChild relativeTo="{lrBox}" position="lastChild">

<mx:LinkButton id="logoutButton" label="Logout" click="logout()"/>

</mx:AddChild>

</mx:State>

</mx:states>

<mx:Script source="as/FlexForum.as"/>

<mx:ApplicationControlBar x="0" y="0" dock="true" height="65">

<mx:Canvas width="100%" height="100%" horizontalScrollPolicy="off" verticalScrollPo

licy="off">

<mx:Image source="logo.png" scaleContent="true" width="100%" height="100%"/>

<mx:VBox verticalCenter="0" right="0">

<mx:HBox id="lpBox" width="100%" height="100%">

<mx:Label text="Login"/>

<mx:TextInput id="loginTextInput" width="80"/>

<mx:Label text="Password"/>

<mx:TextInput id="passwordTextInput" width="80"/>

</mx:HBox>

<mx:HBox id="lrBox" width="100%" height="100%">

<mx:Spacer width="100%"/>

<mx:LinkButton id="loginButton" label="Login" click="login()"/>

<mx:LinkButton id="registerButton" label="Register" click="showRegisterPopUp()"/>

<mx:Spacer width="100%"/>

</mx:HBox>

</mx:VBox>

</mx:Canvas>

</mx:ApplicationControlBar>

<mx:Label text="(C) 2008" horizontalCenter="0" bottom="0"/>

<mx:HTTPService id="srv" url="http://localhost:8600/FlexForum/Login.jsp"

method="POST" result="srvResult(event)"/>

</mx:Application>

Page 40: SDJExtra_31_2008_PL

FLEX40

ADOBE FLEXFlex na Javie

www.sdjournal.org 41

wane dane zapisywane są ponownie w tym samym pliku. Baza ta nie jest w żaden spo-sób szyfrowana, jest to plik napisany w czy-stym SQL.

Pora zabrać się do pracy. Zaczynamy od stworzenia nowego projektu. W tym ce-lu klikamy File>New>Flex Project. Nazwijmy go FlexForum. Możemy teraz zmienić ścież-kę, pod którą przechowywane będą pliki źró-dłowe (i wynikowe). Wprowadźmy więc: C:\fds-tomcat\webapps\ROOT\FlexForum. Mamy także możliwość wyboru typu aplikacji – webowa, oparta na Flash Player albo deskto-powa, oparta na Adobe Air. W naszym przy-padku decydujemy się na aplikację webową i klikamy Next. Następnie wybieramy miejsce, w którym przechowywane będą skompilowa-ne pliki. Zostawmy to pole puste, tak aby pli-ki te pojawiały się w katalogu głównym naszej aplikacji. Idąc dalej, wybieramy folder dla ko-dów źródłowych, które także powinny znajdo-wać się w katalogu głównym, więc zostawmy także to pole puste. Klikamy Finish. Wyłącz-my automatyczne budowanie projektu (gdyż zadba o to serwer FDS-Tomcat), odznaczając opcję Project>Build Automatically.

KodujemyZauważmy, że w głównej części okna pojawia się niebieski obszar, a nad nim przyciski Sour-ce oraz Design, dzięki czemu możemy swobod-nie przełączać się między trybami programo-wania a projektowania. Będąc w trybie pro-jektowania, po lewej stronie znajduje się za-kładka Components, z której możemy przecią-gać kontrolki do naszej aplikacji oraz zmieniać ich właściwości za pomocą elementów znajdu-jących się na zakładce Flex Proporties po pra-wej stronie.

Dodajmy więc do naszej aplikacji kontro-lkę ApplicationControlBar (znajduje się ona w sekcji Layout) i ustawmy jej właściwość Dock na true, a Height na 60. Teraz do Application-ControlBar dodajmy komponent Label (sek-cja Controls), a właściwość Text ustawiamy na FlexForum. Przełączmy się teraz do trybu So-urce (patrz Listing 1.). Jego pierwsza nagłów-kowa linia pozostaje bez zmian, gdyż jest do dokument typu XML. Ciekawsze natomiast

Listing 4. Register.mxml

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

<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal"

title="Register" close="PopUpManager.removePopUp(this)"

showCloseButton="true" x="{this.parentApplication.width/

2 - this.width/2}" y="{this.parentApplication.height/2 -

this.height/2}">

<mx:Script source="../as/Register.as"/>

<mx:Form width="100%" height="100%">

<mx:FormItem label="Login">

<mx:TextInput id="login"/>

</mx:FormItem>

<mx:FormItem label="Password">

<mx:TextInput id="password" displayAsPassword="true"/>

</mx:FormItem>

<mx:FormItem label="E-Mail">

<mx:TextInput id="email"/>

</mx:FormItem>

<mx:FormItem label="Gender">

<mx:HBox width="100%" height="100%">

<mx:RadioButtonGroup/>

<mx:RadioButton id="male" label="Male" groupName="" selected="true"/>

<mx:RadioButton id="female" label="Female" groupName=""/>

</mx:HBox>

</mx:FormItem>

<mx:FormItem>

<mx:HBox width="100%" height="100%">

<mx:Button label="Register" click="register()"/>

<mx:Button label="Cancel" click="hideRegisterPopUp()"/>

</mx:HBox>

</mx:FormItem>

</mx:Form>

<mx:HTTPService id="srv" url="http://localhost:8600/FlexForum/Register.jsp"

method="POST" result="srvResult(event)"/>

</mx:TitleWindow>

Listing 5. FlexForum.as

import mx.managers.PopUpManager;

import mx.rpc.events.ResultEvent;

import views.Register;

public function login() : void {

var p : Object = new Object();

p.login = loginTextInput.text;

p.password = passwordTextInput.text;

srv.send(p);

}

public function logout() : void {

this.currentState='';

}

public function showRegisterPopUp() : void {

PopUpManager.createPopUp(this, views.Register, true);

}

public function srvResult(event : ResultEvent) : void {

var tmp : String = event.result.login;

if (tmp == "Success")

this.currentState = 'logged';

else if (tmp == "Failure")

PopUpManager.createPopUp(this, views.LoginFail, true);

}

W Sieci

• http://www.adobe.com – Strona domo-wa firmy Adobe

• http://www.adobe.com/products/flex/ Flex Builder

• http://www.flex.org – Strona społeczno-ści Flexa

• http://www.riadocs.com – Artykuły i do-kumenty na temat RIA

• http://livedocs.adobe.com/flex/3/html/index.html – Pomoc do Adobe Flex 3

• http://coenraets.org/download/fds-tom-cat.zip – FDS-Tomcat

Page 41: SDJExtra_31_2008_PL

FLEX40

ADOBE FLEXFlex na Javie

www.sdjournal.org 41

są kolejne linie. Najpierw tworzymy obiekt typu <mx:Application>, a w nim dwa kolej-ne obiekty – <mx:ApplicationControlBar>, które zawierają w sobie <mx:Label>. Za-uważmy, że wszystkie te obiekty znajdują się w klasie mx. Każdy obiekt opisywany jest przez pewne parametry. Pamiętamy, że usta-wiliśmy wartość dock naszego Application-ControlBar na true i jest to widoczne w ko-dzie źródłowym aplikacji. Możemy teraz za-pisać projekt oraz uruchomić go wpisując 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 się nasza stopka. Efekt dynamicznego dostoso-wania położenia można uzyskać także w tym trybie poprzez zaznaczenie interesującego nas obiektu i ustaleniu odpowiednich właściwości w sekcji Layout na zakładce Flex Proporties. Za-pisujemy projekt i w przeglądarce odświeża-my stronę.

Jak widzimy, mamy do dyspozycji dwa tryby tworzenia aplikacji. W zależności od potrzeb, jeden z nich będzie wygodniejszy, od drugiego.

Przejdźmy do konkretów. Klikając prawym przyciskiem na projekt, utwórzmy dwa folde-ry – views i as. W pierwszym z nich utwórz-my nowy MXML Component o nazwie Regi-ster.mxml, (pola width i height zostawiamy puste, natomiast w polu Based on wybiera-my TitleWindow), a w drugim nowy Action-Script File o nazwie FlexForum.as i o nazwie Register.as. Otoczmy wszystko, co znajdu-je się w ApplicationControlBar, za pomocą <mx:Canvas> i dodajmy kilka dodatkowych elementów jak skrypt, kontenery czy spacery. Kod powinien prezentować się tak, jak na Li-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 poukładać. Jeżeli jednak zdecydujesz się mo-dyfikować tę aplikację w trybie Design, aby wiedzieć, w którym kontenerze umieszczasz obiekt, wygodnie jest włączyć opcję Show Surrounding Containers za pomocą klawisza [F4] lub klikając na drugą ikonkę na prawo

od przycisku Design. W pliku Register.mxml przygotowujemy kontrolki pozwalające na rejestracje – Listing 4. Efekt widoczny jest na Rysunku 1.

Obiekt HTTPService pozwala na wysyłanie zapytań do zdalnego serwera (w naszym przy-padku jest to localhost). Odwołujemy się tu-taj do Register.jsp, który pobierając odpowied-nie parametry przekazane metodą POST, po-zwoli na rejestrację korzystając z przygotowa-nych przez nas w Javie klas.

ActionScriptPlik FlexForum.as będzie zawierał odpowied-nie skrypty. Na razie umieścimy w nim funk-cje, zawarte na Listingu 5.

W funkcji login przygotowujemy parame-try, które przekażemy metodą POST do na-szego pliku Java Server Page. Parametry two-rzymy poprzez przygotowanie obiektu ty-pu Object, a następnie odwołujemy się do niego przy pomocy odpowiedniej referencji (w naszym przypadku r), podając po kropce

Listing 6. Register.as

import mx.managers.PopUpManager;

import mx.rpc.events.ResultEvent;

public function hideRegisterPopUp() : void {

PopUpManager.removePopUp(this)

}

public function register() : void {

var params : Object = new Object();

params.login = login.text;

params.password = password.text;

params.email = email.text;

params.gender = (male.selected ? "male" : "female");

srv.send(params);

}

public function srvResult(event : ResultEvent) : void {

var tmp : String = event.result.registration;

if (tmp == "Success") {

hideRegisterPopUp();

this.parentApplication.currentState = 'logged';

} else if (tmp == "Failure")

PopUpManager.createPopUp(this, views.RegisterFail, true);

}

Listing 7. Uwidaczniamy naszą klasę

<destination id="forum">

<properties>

<source>flex.Forum.Forum</source>

</properties>

</destination>

Rysunek 3. Efekt po zalogowaniu.

Page 42: SDJExtra_31_2008_PL

FLEX42

ADOBE FLEXFlex na Javie

www.sdjournal.org 43

nazwę parametru. Nazwę tę ustalamy sobie sa-mi. W pliku FlexForum.mxml przy tworzeniu obiektu HTTPService, ustaliliśmy, iż parametr result wskazuje na funkcję srvResult(event : ResultEvent) : void, zatem musimy ją także umieścić w naszym skrypcie. Funkcja ta jest wywoływana zawsze, gdy nasza aplika-

cja otrzyma zwrotne dane po wysłaniu zapy-tania do zdalnego serwera. W event.result znajduje się cały dokument XML utworzony za pomocą kodu zawartego w pliku Login.jsp. Dokument ten będzie wyglądał przy udanym logowaniu tak: <login>Success</login>. Po-przez odwołanie event.result.login zyskujemy

to wszystko, co znajduje się pomiędzy znacz-nikami <login> i </login>. W zależności od tego jaka wartość tam wystąpi, zostaną wywo-łane odpowiednie instrukcje.

Ostatni plik – Register.as – ma wyglądać tak, jak na Listingu 6.

Podobnie w przypadku plików Register.as i Register.mxml mamy funkcję, która przygo-towuje parametry do zapytania wysyłanego do zdalnego serwera oraz funkcję, która prze-twarza dane otrzymane z tegoż serwera. Dzia-ła ona na podobnej zasadzie jak w poprzednim przypadku.

JavaZajmijmy się teraz Javą. Klikamy: File>New>Other i wybieramy Java Project. Nazwijmy go Forum, wybierzmy przycisk Next, w kolejnym oknie dialogowym zmieniamy domyślny fol-der dla plików wynikowych, klikając przycisk Browse. W oknie dialogowym wybieramy z li-sty nazwę projektu (Forum), klikamy Create New Folder..., gdzie zaznaczamy opcję Link to folder in the file system, po rozwinięciu sek-cji Advanced. W pole, które się pojawiło, wpi-sujemy ścieżkę na C:\fds-tomcat\webapps\ROOT\WEB-INF\classes. Ok, Ok, Finish. Folder C:\fds-tomcat\webapps\ROOT\WEB-INF\classes\flex\Forum musi istnieć.

Od razu utwórzmy w naszym nowym pro-jekcie klasę o nazwie Forum, podając dla niej nazwę pakietu flex.Forum. Zostaliśmy także przełączeni do perspektywy Java. Możemy łatwo przełączać się między perspektywami, korzystając z przycisków w menu, w prawym górnym rogu okna Flex Buildera. Domyślna perspektywa dla projektów flexowych to Flex Development.

Musimy teraz edytować plik C:\fds-tomcat\webapps\ROOT\WEB-INF\flex\remoting-con-fig.xml, tak aby serwer wiedział, do której kla-sy będziemy się odwoływać. Wewnątrz sek-cji <service> (najlepiej przed jej zakończe-niem) musimy umiescić kod zamieszczony na Listingu 7.

Restartujemy serwer i wracamy do progra-mowania. W pliku Forum.java umieszczamy taki kod jak na Listingu 8.

Tutaj przyda się odrobina wiedzy z zakresu wykorzystania SQL z poziomu Javy. Zauważ-my, że funkcje zwracają wartości true/false.

Pozostaje nam jeszcze utworzyć dwa pli-ki w katalogu głównym naszej aplikacji inter-netowej, czyli tam, gdzie umieszczone są pli-ki .mxml. Tworzymy więc plik Register.jsp oraz Login.jsp. Zawartość tych plików przedstawio-no odpowiednio na Listingach 9. i 10.

Aby zrozumieć o co tutaj chodzi, trze-ba znać podstawy JSP. Wytłumaczę jednak 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-

Listing 8. Forum.java

package flex.Forum;

import java.sql.Connection;

import java.sql.PreparedStatement;

import javax.servlet.http.HttpServlet;

public class Forum extends HttpServlet {

public boolean login(String login, String password) {

// TODO

return true;

}

public boolean logout(String login) {

//TODO

return true;

}

public boolean register(String login, String password, String email, String gender)

{

Connection c = null;

PreparedStatement ps = null;

try {

c = ConnectionHelper.getConnection();

ps = c.prepareStatement("INSERT INTO user (login, password, email, gender, type)

VALUES (?, ?, ?, ?, ?)");

ps.setString(1, login);

ps.setString(2, password);

ps.setString(3, email);

ps.setString(4, gender);

ps.setString(5, "user");

ps.executeUpdate();

} catch (Exception e) {

e.printStackTrace();

} finally {

ConnectionHelper.close(c);

}

return true;

}

}

Listing 9. Register.jsp

<%@ page import="flex.Forum.Forum" contentType="text/html"%>

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

<%

Forum f = new Forum();

if (f.register(request.getParameter("login"), request.getParameter("password"),

request.getParameter("email"), request.getParameter("gender"))

== true) {

%>

<registration>Success</registration>

<%

} else {

%>

<registration>Failure</registration>

<%

}

%>

Page 43: SDJExtra_31_2008_PL

FLEX42

ADOBE FLEXFlex na Javie

www.sdjournal.org 43

vę, natomiast poza nimi jest XML. W pierw-szej linii umieszczamy informację o impor-towanych klasach. Zaznaczamy, że będzie-my korzystać z klasy Forum, która znajduje się w pakiecie flex.Forum. Następnie definiuje-my typ dokumentu XML, a później przecho-dzimy już do właściwego kodu. Zaczynamy od utworzenia obiektu klasy Forum, po czym na rzecz tego obiektu wywołujemy funkcję login() z odpowiednimi parametrami. Pa-rametry te to obiekty klasy String, wydoby-te z obiektu request. Obiekt request posia-da wszystkie potrzebne informacje dotyczące klienta, który wysyła zapytanie. Możemy wy-dobyć z niego takie dane jak adres IP, typ prze-glądarki itp., ale w tym przypadku interesu-ją nas jedynie parametry, które zostały prze-kazane przez użytkownika. Piszemy więc np. request.getParameter("login"), gdzie login, to parametr utworzony w pliku FlexForum.as w funkcji login() poprzez instrukcję p.login = loginTextInput.text;.

Sprawdzamy także, jaki wynik da nam wy-wołanie tej funkcji. Jeśli uda się zalogować, z pewnością będzie to true. Warunkowo więc kończymy kod, zapisując w naszym doku-mencie XML znacznik <login>Success</login>, po czym znów otwieramy blok kodu, a następnie wykonujemy blok else gdzie, je-śli coś poszło źle, znów zakończymy kod Javy i zapiszemy w dokumencie <login>Failure</login>.

SQLOstatnią rzeczą, jaką musimy przygotować, to tabele w bazie danych. W katalogu głównym FDS-Tomcat, jest folder db, który zawiera plik flexdemodb.script. Plik ten powinien mieć za-wartość jak na Listingu 11.

Zostawiam CięOdpowiednie funkcje w plikach .java będą od-woływać się do utworzonej tutaj tabeli, doda-jąc do niej rekordy, modyfikując je, usuwając itp. Aplikacja utworzona w ramach tego ar-tykułu nie pozwala na wszystkie te operacje, jednak możesz na własną rękę w odpowied-ni sposób ją później rozwinąć. W przypad-ku logowania, rekord zostanie zmodyfikowa-ny w taki sposób, że pole LOGGED przybie-rze wartość true, a w polu IP zapisany zosta-nie adres IP klienta. Jest to bardzo proste za-bezpieczenie pozwalające na pozostanie za-logowanym przez jakiś czas, ale które uchro-ni nas częściowo przed tym, że ktoś inny pod-szyje się pod innego zalogowanego użytkowni-ka. Jeżeli chcemy zrobić to profesjonalnie, na-leży skorzystać z zarządzania sesjami z pozio-mu JSP. Podobnie wygląda to w przypadku aplikacji PHP.

Końcowy efekt (uwzględniając logowanie) widzimy na Rysunku 3. Brakuje jedynie wy-świetlania postów.

Pozostawiam Ci także, Czytelniku, przy-gotowanie tabeli, która będzie przechowy-

wać posty użytkowników. Na pewno warto umieścić tam (oprócz treści postu) datę je-go umieszczenia na forum, nazwę autora itp. Wymaga to umieszczenia dodatkowych funk-cji w klasie Forum oraz przygotowania odpo-wiednich plików .jsp, a także plików .mxml, które będą opisywały np. okno edycji posta.

Następnie powinieneś zrobić pobieranie tematów/postów z bazy danych i wyświetlanie ich w swojej aplikacji. Tutaj wystarczy również nowa funkcja w klasie Forum oraz dodatkowy plik .jsp, który będzie zawierał dokument XML z odpowiednimi informacjami. Plik ten zosta-nie przeanalizowany w naszej fleksowej aplika-cji podobnie, jak analizowane są pliki Register.jsp i Login.jsp. Tematy i posty wydobyte z tegoż pli-ku można umieścić np. w komponencie <mx:Tree> lub napisać własny komponent wyświe-tlający te informacje według własnego uznania, tzw. renderer. To wszystko pozostawiam jednak Tobie jako pracę domową. Pokazałem Ci jak za-cząć, a Ty dokończ to tak, jak zechcesz. Sposo-bów jest naprawdę wiele. Do dzieła!

JutroTworząc naszą aplikację, nie wykorzystaliśmy w pełni wszystkich możliwości Flexa, gdyż moż-liwości te są nieograniczone, a objętość tego arty-kułu nie jest duża. Jeżeli chcesz poszerzyć swo-ją wiedzę w tym zakresie, koniecznie odwiedź strony, których adresy znajdziesz w tabelce.

Co przyniesie przyszłość? Adobe poinfor-mowała, że Flex 4.0 (znany pod nazwą kodową Gumbo) ukaże się w roku 2009. W chwili pi-sania tego tekstu nie są znane jeszcze dokładne plany, ale pojawiło się już kilka ogólników. I tak oto w kolejnej wersji Flexa mają pojawić się ta-kie elementy jak:

• Design in Mind (projektuj w myślach) – framework pozwalający na poszerza-nie współpracy pomiędzy developeramia designerami;

• Accelerated Development (przyspieszone rozwijanie) – pozwoli przejść od koncep-cji do realiów bardzo szybko;

• Horizontal Platform Improvements (ulep-szenia platformy) – wydajność kompila-tora, uwydatnienie języka, komponenty BiDi, uwydatnienie tekstu;

• Broadening Horizons (poszerzanie hory-zontów) – znalezienie sposobów na uczy-nienie frameworka lżejszym, poprawa ob-sługi MXML.

Pierwsza beta ukaże się z końcem 2008 roku, a wersja finalna w 2009 roku.

ROGER ZACHARCZYKAutor jest stałym współpracownikiem Software-

Wydawnictwo. Interesuje się głównie programowa-

niem (C/C++, Java, PHP, AJAX). Jest zwolennikiem

ruchu Open Source.

Kontakt z autorem: [email protected]

Listing 10. login.jsp

<%@ page import="flex.Forum.Forum" contentType="text/html"%>

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

<%

Forum f = new Forum();

if (f.login(request.getParameter("login"), request.getParameter("password")) ==

false) {

%>

<login>Success</login>

<%

} else {

%>

<login>Failure</login>

<%

}

%>

Listing 11. flexdemodb.script

CREATE SCHEMA PUBLIC AUTHORIZATION DBA

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

VARCHAR(65),GENDER VARCHAR(6),TYPE VARCHAR(9),LOGGED BOOLEAN,IP

VARCHAR(15))

ALTER TABLE USER ALTER COLUMN ID RESTART WITH 12

CREATE USER SA PASSWORD ""

GRANT DBA TO SA

SET WRITE_DELAY 20

SET SCHEMA PUBLIC

Page 44: SDJExtra_31_2008_PL

FLEX44

ADOBE FLEXFlex.Security.allowSecureCommunication(‘*’);

www.sdjournal.org 45

Po krótce scharakteryzujemy dostępne metody – ich zalety i wady – jak rów-nież porównamy wydajność wymie-

nionych rozwiązań, takich jak: flashvars, <mx:WebService>, <mx:RemoteObject>, <mx:HTTPService>, URLLoader. Zastanowimy się też nad różnymi formatami danych.

Dalszą część artykułu poświęcimy bezpie-czeństwu w obrębie flash playera (sandboxy i crossdomain) oraz sposobom ochrony przesy-łanych informacji. Opisywane przez nas me-tody zabezpieczenia komunikacji poparte są wieloma projektami i doświadczeniem au-torów z zakresu architektury środowisk bac-kendowych, frontendowych i co najważniejsze – ich integracji. Poruszymy tak oczywiste roz-wiązania, jak sesja po stronie serwera, znaczni-ki czasu, sumy kontrolne zapytań oraz ciekaw-sze podejście do tematu jak choćby wykorzy-stanie FMS 3, czy generowanie dynamicznych plików SWF po stronie serwera zawierających klucze czasowe.

Zbliżając się do końca artykułu, w ostatnich paragrafach postaramy się przybliżyć i opisać najczęstsze sposoby łamania zabezpieczeń dla plików SWF i ich komunikacji ze światem ze-wnętrznym. Poczynając od wtyczki DataTam-per dla Firefox, przez komercyjne sniffery oraz dekompilery.

Podsumowując wcześniejsze zagadnienia, wspomnimy również o możliwości kradzie-ży własności intelektualnej, mechanizmach DRM, zaprezentujemy za i przeciw zabezpie-czaniu plików SWF oraz przyjrzymy się kilku prostym metodom śledzenia prób fałszowania komunikacji klient–serwer.

Różne źródła danychPodczas projektowania nawet najprostszych aplikacji działających po stronie klienta, szyb-ko nadchodzi potrzeba parametryzowania aplikacji, dostarczania jej dynamicznych źró-deł danych, uzyskania obustronnej komunika-cji. Runtime Flash udostępnia nam kilka możli-wości, by zrealizować te potrzeby.

Pierwszą i najprostszą metodą na dostar-czenie do naszej aplikacji (pisanej na przy-kład we Flexie) zmiennych jest posłużenie się obiektem flashvars. Do osadzenia projektu na stronie HTML użyję biblioteki JavaScript SWFObject2 (http://code.google.com/p/swfobject) – patrz Listing 1.

Już ten prosty sposób daje nam możliwość dynamicznego generowania zmiennych wraz z wartościami, które na Listingu 2. zostaną od-czytane z poziomu Flexa:

Podobnym jednostronnym sposobem ko-munikacji jest sczytywanie parametrów prze-kazanych w URL–u. Flashvarsy są wygodne je-śli chodzi o jakieś małe zmienne, kluczowe do prawidłowego zainicjalizowania aplikacji – na przykład adres webservice'u.

Jeżeli chodzi o bardziej zaawansowane tech-niki komunikacji jak webservice i flash remoting

zostały one opisane w artykule pt. Flex i php – wykorzystanie web services i technologii flash remoting.

Chciałbym jednakże pokrótce opisać wyko-rzystanie klasy flash.net.URLLoader po stronie Flexa do komunikacji z backendem w PHP. Po stronie serwera będzie znajdował się wystawio-ny gateway nasłuchujący naszych żądań, który przyjmować będzie argumenty zarówno z ta-blicy $_GET jak i $_POST. Adres gateway'a ustalimy na: http://example.com/gateway.php.

Założę również, że na żądanie ?action=getDummyData dostanę zwrot w postaci XML:

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

<return><row attr1=”hello” /><row>world</

row></return>

Na Listingu 3. przedstawię fragment ko-du w ActionScript, który wyśle przykłado-we dane i odbierze zwrot. Dla uproszcze-nia przykładu nie dodałem obsługi zdarzenia IOErrorEvent.IO _ ERROR oraz nie przepro-wadziłem walidacji zwrotu, co jest niezbędne w komercyjnych projektach.

Chciałbym jeszcze zaznaczyć, iż Flex po-zwala również na bezpośrednią komunika-cję na bardzo niskim poziomie jakim są gniaz-da (ang. sockets). Wyróżnić można dwa rodza-je połączeń – poprzez XMLSocket, który wy-musza posługiwanie się dokumentami XML oraz klasę Socket, która pozwala na binarny przesył danych.

Chciałbym jeszcze wymienić trzy sposo-by komunikowania się ze światem zewnętrz-nym. Pierwszy z nich to wykorzystanie kla-sy ExternalInterface. Pozwala ona na wy-woływanie funkcji osadzonych w skryptach JavaScript, które mogą towarzyszyć aplika-cji Flex osadzonej na stronie HTML. Dodat-kowo dzięki tej klasie możemy umożliwić ko-munikację w drugą stronę – JavaScript może wywołać wystawione funkcje z aplikacji Fle-

Flex.Security.allowSecureCommunication('*'); 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.

Dowiesz się..• O systemie zabezpieczeń języka ActionScript 3;

• zabezpieczeniach komunikacji;

• nowych crossdomains;

• oraz dlaczego warto używać Flash Media Se-

rver.

Powinieneś wiedzieć...• Wymagana jest podstawowa wiedza z zakresu

wymiany danych backend–frontend.

Poziom trudności

Page 45: SDJExtra_31_2008_PL

FLEX44

ADOBE FLEXFlex.Security.allowSecureCommunication(‘*’);

www.sdjournal.org 45

xowej. Natomiast drugi to używanie Local-Connection do komunikacji z innymi plika-mi SWF (również różne ich wersje wchodzą

w grę – np. 8 i 9) osadzonymi na danej stro-nie HTML. Trzecim sposobem są SharedO-bjects, które na pierwszy rzut oka wyglądają

identycznie jak cookies w przeglądarce. Tech-nika ta pozwala na zapisywanie dowolnych in-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-nia i dobrania optymalnej formy integracji. Podczas fazy projektowej biorę pod uwagę:

• czy istnieje już gotowe API po stronie backendu,

• czy aplikacja we Flexie/Flashu będzie je-dynym klientem,

• czy chcę mieć możliwość buforowania zwrotów po stronie klienta – jest to bar-dzo ważne w większych projektach,

• kwestię poufności wymienianych da-nych,

• rząd wielkości zwrotów,• elastyczność zmian na wypadek zmian

w specyfikacji,• wydajność konkretnej technologii.

Zabezpieczanie komunikacjiNa samym wstępie należy jasno powiedzieć, że nie ma bezwzględnie bezpiecznej formy komunikacji z aplikacji klienckiej do serwe-ra. Jednakże już najprostsze formy uwierzy-telniania i komplikowania wymiany danych w bardzo dużym stopniu skomplikują ży-cie osobom, które próbowałyby ją fałszować. Z własnego doświadczenia mogę powiedzieć, aby zwracać szczególną uwagę na aspekt bez-pieczeństwa w grach online i wszelkiego ty-pu konkursach internetowych. Należy rów-nież cały czas mieć na uwadze, iż aplikacja kliencka z łatwością może być zdekompilo-wana, a cały ruch Internetowy, który generu-je – podsłuchany. Naturalne jest dla mnie nie-zapisywanie poufnych danych po stronie apli-kacji klienckiej, takiego typu jak użytkownik i hasło do bazy danych. Owszem istnieje taka możliwość by z poziomu Flexa/ActionScriptu bezpośrednio łączyć się do bazy danych, lecz dla mnie jest to zupełne nieporozumienie.

Pierwsza bardzo prosta technika zabez-pieczania komunikacji polega na wysyłaniu sumy kontrolnej dotyczącej danej paczki.

Listing 1. Osadzenie aplikacji poprzez SWFObject2

<script type="text/javascript">

var flashvars = { };

flashvars.name1 = "hello";

flashvars.name2 = "world";

var params = { };

params.menu = "false";

var attributes = { };

swfobject.embedSWF( "aplikacyjka.swf", "myContent", "300", "120", "9.0.0","expressI

nstall.swf", flashvars, params, attributes );

</script>

Listing 2. Wczytanie flashvars

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initFlash

Vars()">

<mx:Script><![CDATA[

[Bindable]

public var myName1:String;

[Bindable]

public var myName2:String;

private function initFlashVars():void {

myName1 = Application.application.parameters.name1;

myName2 = Application.application.parameters.name2;

}

]]></mx:Script>

<mx:HBox>

<mx:Label text="Name1: {myName1}"/>

<mx:Label text="Name2: {myName2}"/>

</mx:HBox>

</mx:Application>

Rysunek 1. Porównanie wydajności metod komunikacji. http://www.jamesward.org/census/

Page 46: SDJExtra_31_2008_PL

FLEX46

ADOBE FLEXFlex.Security.allowSecureCommunication(‘*’);

www.sdjournal.org 47

Dla przykładu w pewnym momencie z Fle-xa wychodzi dowolną metodą ciąg danych zmienna1=wartosc1, zmienna2=wartosc2, zmienna3=wartosc3, checksum=123456. Niech cheksum będzie wartością funkcji MD5 obliczo-nej na podstawie wartości1 oraz wartości2. Takie samo obliczenie checksum może się wy-konać po stronie backendu celem weryfikacji źródła pochodzenia danych. Oczywiście func-kja hashująca może być o wiele bardziej skom-plikowana lub złożona z wielu dostępnych na-raz. Jest to metoda bardzo prosta, a zarazem całkiem efektywna i niewymagająca duże-go nakładu pracy programisty frontendowego oraz backendowego.

Równie prostym sposobem na weryfikację źródła pochodzenia danych jest dostarczanie znaczników czasu podczas wysyłania zapy-tań – polecam, aby i one były w formie zako-dowanej. Weryfikacja po stronie serwera mo-że polegać na sprawdzaniu, czy każdy nowy znacznik jest większy od poprzedniego. Ko-lejnym elementem, który jest możliwy do we-ryfikacji przy tej metodzie, jest sprawdzanie czy zapytania przychodzą w racjonalnych od-stępach czasowych stosownych do profilu na-szej aplikacji.

Następnym elementem wartym uwagi, jest stosowanie nieintuicyjnych nazw me-tod. Jednakże należy się poważnie zastano-wić nad stosowaniem tej techniki, gdyż może ona przysporzyć wiele kłopotów przy robie-niu poprawek w aplikacji po dłuższej prze-rwie lub też na samym etapie debugowania 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-zacji. Mankamenty takiego rozwiązania mogą się pojawić podczas uploadu plików ze strony Flexa, co można zawsze rozwiązać dosyłając identyfikator sesyjny podczas uploadu, który pozwoli na manualne ustawienie sesji po stro-nie backendu.

Bardziej wyrafinowane rozwiązanie za-bezpieczające komunikację polegać będzie na pobieraniu przez Flexa dynamicznie wy-generowanego pliku SWF po stronie backen-du i wykorzystywaniu informacji w nim za-wartych do dalszego wysyłania danych. Do tego celu posłużyć może biblioteka MING w PHP – http://php.net/ming .Idea jest nastę-pująca:

• Flex wysyła zapytanie o wygenerowanie dynamicznego SWF–a.

• Backend generuje bardzo lekki (1kb) plik SWF zawierający unikalny klucz.

• Flex ładuje wygenerowany plik i wyko-nuje właściwe zapytanie dodając wartość pobranego klucza.

• Backend weryfikuje zgodność kluczy podczas obsługi zapytania, dodatkowo

ustawiając czas ważności klucza na przy-kładowe pięć minut.

Na Listingu 4. pokażę krótki sposób na wy-generowanie SWF za pomocą biblioteki MING.

By następnie na Listingu 5. z poziomu Ac-tionScriptu we Flexie odebrać klucz. Proszę zwrócić uwagę na użycie LocalConnection do

komunikacji z wczytanym plikiem – jest to konieczne, by z poziomu Flash 9 komuniko-wać się z Flash 8.

Dodatkowym sposobem na zabezpieczenie aplikacji klienckiej jest technika obfuskacji wy-nikowego SWF. Można do tego celu znaleźć darmowe programy w sieci, które w ogrom-nym stopniu utrudniają dekompilację skompi-lowanych kodów z Flexa do postaci SWF.

Listing 3. Zastosowanie URLLoader

package {

import flash.display.Sprite;

import flash.events.Event;

import flash.net.URLLoader;

import flash.net.URLRequest;

import flash.net.URLRequestMethod;

import flash.net.URLVariables;

public class myClass extends Sprite {

public function myClass( ) {

var request:URLRequest = new URLRequest( "http://example.com/gateway.php?ac

tion=getDummyData" );

request.method = URLRequestMethod.POST;

request.data = new URLVariables( );

request.data.myVariable1 = 'raz dwa trzy';

var loader:URLLoader = new URLLoader( );

loader.addEventListener(Event.COMPLETE, onComplete );

loader.load(request);

}

private function onComplete( event:Event ):void {

var dataXML:XML = XML( event.target.data );

}

}

}

Listing 4. Użycie MING w PHP

<?php

$secretKey = '123456';

$m = new SWFMovie( );

$m–>add( new SWFAction( "key = '$secretKey';

var sending_lc:LocalConnection = new LocalConnection( );

sending_lc.send( 'lc_name', 'setKey', key );" ) );

header( 'Content–type: application/x–shockwave–flash' );

$m–>output( );

?>

Listing 5. Obiór klucza we Flexie

var l = new Loader( );

l.load( new URLRequest( 'http://example.com/gateway.php?getSecretKeySwf' ) );

var receivingLC:LocalConnection = new LocalConnection();

receivingLC.client = this;

receivingLC.connect('lc_name');

function setKey( key ) {

trace( 'dostalem klucz z wczytanego swfa skompilowanego do wersji 8: ', key

);

}

Page 47: SDJExtra_31_2008_PL

FLEX46

ADOBE FLEXFlex.Security.allowSecureCommunication(‘*’);

www.sdjournal.org 47

Warto również, po stronie backendu, po-kusić się o sprawdzanie adresu URL z którego przychodzą żądania. Jest to dobry sposób na wstępną weryfikację prawdziwości generowa-nych zapytań.

Podsłuchiwanie i próby fałszowania komunikacjiZapewne jedną z pierwszych rzeczy, któ-rą zrobi osoba zainteresowana fałszowaniem komunikacji, będzie sprawdzenie, w jaki spo-sób ona się odbywa. Najprostszym sposobem na to jest zainstalowanie wtyczki DataTamper dostępnej dla przeglądarki Firefox – widok na Rysunku 2.

W interesujących nas momentach w okien-ku wtyczki widać wszystkie zapytania GET, POST jak również ich treść oraz cookies, któ-re również mogą zawierać ciekawe rzeczy jak choćby identyfikator sesyjny. Kolejnym eta-pem będzie sprawdzenie jak została osadzo-na aplikacja, a co za tym idzie odszukanie ewentualnych flashvars. Uzbrojony w ta-ką wiedzę użytkownik może przystąpić do działania. Jeśli użyto najprostszej formy wy-miany danych na przykład w postaci wysyła-

nia żądania na adres http://example.com/gate-way.php?action=someAction i zwracana jest odpowiedź w formie XML, a całość nie jest w żaden sposób zabezpieczona, wówczas za-danie podmiany danych jest wręcz banalne.

Sytuacja nieznacznie się komplikuje, gdy komunikacja odbywa się za pomocą FlashRe-moting, na przykład wykorzystując AMFPHP. Jednakże i tutaj dla wprawnego oka, dokład-ne przeanalizowanie RAW_POST_DATA pozwo-li na wyłuskanie nazw metod i argumentów. Takie informację przydadzą się do napisania własnej klasy po stronie ActionScript, która zasymuluje oryginalną, wykorzystaną w apli-kacji klienckiej.

Kolejnym krokiem, na jaki zapewne zdecy-duje się włamywacz, będzie dekompilacja pli-ku SWF. Jeżeli będzie on w stanie odnaleźć interesujący go fragment kodu i skutecznie go podmieni, wówczas po kompilacji takie-go projektu aplikacja kliencka w krytycznym momencie wyśle sfałszowane dane. Oczywi-ście, to czy backend przyjmie takie zapytanie, zależy od tego, czy jakkolwiek będziemy we-ryfikować wierzytelność zapytań. Jeśli użyt-kownik po dekompilacji i udanej zamianie

wrażliwego kodu, uruchomi aplikację lokal-nie, jego zapytania będą przychodziły z inne-go URL’a niż backend powinien się spodzie-wać – chyba, że użytkownik będzie na tyle dociekliwy, by podmienić nagłówki preparu-jąc właściwy adres URL.

Stosowanie więcej niż jednego zabezpie-czenia przesyłu danych zdecydowanie odstra-szy większą część osób, które bądź to dla za-bawy, bądź dla konkretnego efektu będą pró-bowały ją zafałszować.

FlashMediaServer 3Popularność materiałów wideo w sieci WWW rośnie lawinowo z roku na rok. Nie możemy przejść obojętnie obok faktu, że tak duża popularność była możliwa tylko dzięki prostemu, szybkiemu, a zarazem przyjazne-mu dla użytkownika systemowi dostępu do materiałów video. Pomimo wieloletniej obec-ności odtwarzaczy multimedialnych na ryn-ku, takich jak Windows Media Player–Mi-crosoftu, czy Quicktime'a firmy Apple, nic nie przyspieszyło rewolucji tak jak format plików FLV od Adobe. Jednak wraz ze wzro-stem popularności formatu FLV, pojawił się problem nieautoryzowanego przechwytywa-nia plików audio i video (na przykład płatnej zawartości serwisu internetowego). Istnieje wiele sposobów przechwycenia video z pliku FLV. Rozpoczynając od nasłuchiwania zapy-tań HTTP, poprzez wyciąganie pliku z kata-logu pamięci podręcznej przeglądarki, aż do poklatkowego zapisywania video przez klasę flash.display.BitmapData.

Między innymi dlatego też powstał Flash 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 aplikacji poprzez dopuszczanie jedynie tych Rysunek 2. Wtyczka DataTamper dla Firefox

Listing 6. Standardowy plik crossdomain.xml

<cross–domain–policy>

<allow–access–from domain="www.przykladowa_strona.com">

</cross–domain–policy>

Listing 7. Nagłówek odpowiedzi dla pliku crossdomain.xml

HTTP/1.1 200 OK

X–Permitted–Cross–Domain–Policies: none

Page 48: SDJExtra_31_2008_PL

FLEX48

ADOBE FLEXFlex.Security.allowSecureCommunication(‘*’);

www.sdjournal.org 49

plików, które pochodzą z autoryzowanego źródła. Za każdym razem, kiedy plik SWF zostaje wysłany do klienta, jego kopia rezy-duje na serwerze. W razie wykrycia różnic w strukturze pliku, serwer odrzuci zapytanie klienta o żądany plik. Oczywiście oprócz te-go mamy możliwość autoryzacji użytkowni-ka przez sumy kontrolne MD5, unikalne klu-cze, czy przekazanie użytkownika i hasła. Te aspekty zostały poruszone we wcześniej-szej części artykułu, tak więc nie będę ich tu-taj rozwijał.

Dlaczego zatem rozwiązanie to nie stało się bardzo popularne? Otóż dość poważnym problemem okazała się cena, która nierzad-ko przewyższała możliwości finansowe nie-których serwisów, szczególnie w sytuacji, kiedy ilość połączeń i transfer danych podle-gały ograniczeniom. W odpowiedzi na brak taniego rozwiązania powstał serwer RED5. Rozwiązanie Open Source przedstawiane ja-ko alternatywa dla FMS. Obecnie prowadzo-ne są prace nad rozwojem do wersji 1.0 (obec-na to 0.7.0), tak więc widać, że determinacja twórców w rozwoju tego projektu nie słabnie (więcej na http://osflash.org).

Na szczęście FMS w wersji trzeciej nie po-siada ograniczeń transferu i limitu jednocze-snych połączeń co znacząco zwiększa opła-calność tego rozwiązania, które oferuje do-skonałe zabezpieczenia przy niewielkim na-kładzie środków, a także odciąża administra-torów oraz twórców programów, którzy nie muszą wymyślać setek sposobów na ochro-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-duktów oferowanych przez Adobe, które pojawiły się wraz z premierą wersji trzeciej (więcej na : http://www.adobe.com/products/flashmediaserver/).

Bezpieczeństwo od strony developeraW pierwszej części artykułu zostały prze-analizowane dodatkowe metody zabezpie-czenia danych przesyłanych pomiędzy użyt-kownikiem a serwerem. Czy oznacza to, że firma Adobe nie wyposażyła Flash Playera 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 danych oraz maksymalnie ograniczyć możli-wości nieautoryzowanego dostępu do działa-jącego programu.

Każdy plik SWF posiada swój własny ob-szar bezpieczeństwa, w obrębie którego możemy poruszać się bez większych prze-szkód przesyłając dane, nazywany powszech-nie sandboxem (ang. Piaskownica). Podsta-wowo zdefiniowana ilość możliwych ope-racji jest ściśle ograniczona do niezbędne-go minimum, tak abyśmy nie musieli two-

rzyć wszystkich reguł zabezpieczających, je-żeli planujemy niewielką stronę internetową bądź aplikację. Im większy projekt tym więk-sze potrzeby zapewnienia mu bezpieczeń-stwa oraz umożliwienia swobodnego dostę-pu danych zewnętrznych, takich jak doku-menty, pliki video i audio, a także w niektó-rych przypadkach pliki SWF innych autorów, znajdujące się w domenach innych niż nasza aplikacja.

Domyślnie, plik SWF może wczytywać je-dynie te pliki, które znajdują się w tej samej domenie co nasza aplikacja. Jednak bardzo często, w szczególności przy tworzeniu du-żych serwisów, pojawia się konieczność wy-świetlania zawartości dostarczanej z innych serwerów. Aby możliwe było wczytywanie plików znajdujących się w innej domenie, niezbędny jest plik XML o nazwie crossdoma-in.xml . Informacje w nim zawarte pozwalają określić, między innymi, jakie domeny i ad-resy IP mają prawo do pobierania zawartości z serwera, na którym ów plik się znajduje.

Plik crossdomain przedstawiony na Listin-gu 6. pozwala na wczytanie danych każdemu plikowi SWF znajdującemu się w domenie przykladowa_strona.com. Jeżeli plik zostanie umieszczony w katalogu głównym domeny nie musimy martwić się potrzebą wczytywa-nia go, ponieważ przy pierwszej próbie wczy-tania danych z domeny, na której znajduje się plik crossdomain.xml, SWF automatycz-nie spróbuje go pobrać. Jeżeli operacja się nie powiedzie, wynikiem będzie błąd SecurityEr-

ror, informujący nas o braku możliwości do-stępu do danych. Oczywiście nie zawsze ma-my możliwość umieszczenia pliku crossdo-main.xml w dowolnym miejscu. W tym wy-padku z pomocą przychodzi nam metoda flash.system.SecurityloadPolicyFile(), która pozwala nam określić dokładne położe-nie pliku. Niestety możliwość wczytania do-wolnej ilości plików crossdomain.xml, zwięk-sza ryzyko ingerencji w nasz obszar bezpie-czeństwa, poprzez wczytanie innych pli-ków crossdomain w trakcie działania nasze-go programu. Aby zabezpieczyć się przed taką możliwością, możemy wybrać jedną z dwóch opcji:

• Zmodyfkować plik crossdomain.xml do-dając do niego znacznik <site–control> zawierający atrybut permitted–cross–

domain–policies.• Używając nagłówka odpowiedzi HTTP

X–permitted–Cross–Domain–Policies, jak przedstawiono na Listingu 7.

Pomimo, iż znacznik meta–policy zo-stał wprowadzony stosunkowo niedawno, Adobe zaleca umieszczanie go we wszyst-kich plikach master policy files, ponieważ ze względów bezpieczeństwa domyślna war-tość all zostanie zamieniona na none, co mo-że spowodować utrudnienia w działaniu już istniejących aplikacji, które korzystają z tych plików. Wszystkie powyższe operacje na pliku crossdomain.xml dotyczące znaczni-

Opcje konfiguracji znacznika meta–policy w pliku crossdomain.xml

• all –Domyślna konfiguracja. Wszystkie pliki crossdomain.xml są akceptowane.• by–content–type – Akceptowane są tylko pliki corssdomain, których nagłówek Content–

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.

Tylko dla serwerów FTP.• 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. • none – Żadne pliki crossdomain.xml nie są akceptowane. Jeżeli umieścimy takowy w kata-

logu głównym aplikacji, będzie on mógł zawierać jedynie znacznik meta–policy, wszystkie inne będą ignorowane.

• none–this–response – dostepny tylko dla nagłówka odpowiedzi HTTP, uniemożliwiający in-terpretację zwrotu jako pliku crossdomain. Dotyczy to tylko aktualnie przychodzącego na-główka i nie wpływa na wczytywanie innych plików crossdomain.

Listing 8. Przykładowy znacznik allow–http–request–headers–from

<allow–http–request–headers–from domain="www.przykladowa_strona.com" headers="Moj–

Naglowek"/>

Listing 9. Przykładowy plik crossdomain dla połączeń typu Sachet

<cross–domain–policy>

<allow–access–from domain="www.przykladowa_strona.com" secure="true" to–

ports="3050"/>

</cross–domain–policy>

Page 49: SDJExtra_31_2008_PL

FLEX48

ADOBE FLEXFlex.Security.allowSecureCommunication(‘*’);

www.sdjournal.org 49

ka meta–policy dotyczą pliku master policy fi-le, czyli znajdującego się w głównym katalo-gu domeny.

Flash Player od wersji 9 oferuje możliwość wysyłania własnych nagłówków HTTP. Jest to kolejna okazja, aby wydobyć informacje z naszej aplikacji. Aby temu zapobiec, moż-liwości konfiguracji pliku crossdomain zosta-ły wzbogacone o znacznik allow–http–requ-est–headers–from , który pozwala nam okre-ślić domenę, z której będą akceptowane przy-chodzące nagłówki, oraz ich dokładny typ. Przykładowy wygląd tego znacznika przed-stawiono na Listingu 8.

Wraz z pojawieniem się rewizji Flash Play-era 9.0.115, nastąpiła zmiana w dostępie do danych poprzez klasę Socket, służącą do przesyłania binarnych danych na wskazanym przez nas porcie. Dzięki niej mamy możli-wość napisania na przykład własnego klienta pocztowego. Dotychczas do kontroli upraw-nień dla tej klasy wystarczył plik crossdoma-in.xml, jednak ze względów bezpieczeństwa postanowiono odseparować te dwa typy połą-czeń. Obecnie, zanim zostanie nawiązane po-łączenie z serwerem (nawet jeżeli plik SWF należy do tej samej domeny) sprawdzana jest obecność pliku autoryzującego znajdu-jącego się domyślnie na porcie 843 (podob-nie jak plik crossdomain.xml domyślnie powi-nien znajdować się w katalogu głównym do-meny), możliwe jest wysłanie ów pliku z do-wolnego dostępnego portu, jednak podobnie jak w wypadku połączeń przez HTTP musi-my wczytać plik samodzielnie poprzez me-todę loadPolicyFile(). Format pliku auto-ryzującego połączenia portów jest taki sam jak pliku autoryzującego połączenia HTTP i HTTPS, z jedną małą różnicą, którą przed-stawia Listing 9.

Znacznik to–ports określa port bądź za-kres portów, do których nasza aplikacja otrzyma dostęp. Podobnie do połączeń przez HTTP, połączenia poprzez porty również po-siadają możliwości kontrolowania, które pli-ki autoryzacyjne powinny być zaakceptowa-ne. Znacznik meta–policy w tym wypadku ma mniej możliwości konfiguracji.

Zamykając temat plików autoryzacyjnych, należy wspomnieć o jeszcze jednym elemen-cie, który jest wspólny dla połączeń przez HTTP i porty. Atrybut secure dla znacznika allow–access–from, jeżeli ustawiony na true, <allow–access–from secure='true'>, nie

zezwala na nawiązanie połączenia z portem czy przesłanie danych, jeżeli zapytanie nie pochodzi z bezpiecznego protokołu HTTPS. Dla połączeń HTTPS domyślną wartością jej true, Adobe zaś nie zaleca zmiany jej zamia-ny na false.

Kiedy jesteśmy już pewni, że zabezpie-czyliśmy się przed nieautoryzowanymi pró-bami pobierania zawartości naszego serwe-ra, a zarazem zapewniliśmy bezproblemo-we działanie naszej aplikacji, powinniśmy za-pobiec próbom spenetrowania naszego ko-du przez inne pliki SWF, a także udostęp-nić możliwość komunikacji naszego progra-mu z innymi plikami SWF, jeżeli jest to wy-magane. Aby umożliwić bądź zablokować wymianę informacji, tak zwany cross–scrip-ting, korzystamy przede wszystkim z meto-dy flash.system.Security.allowDomain

(). Pozwala ona na dostęp wczytanego pli-ku SWF do pliku wczytującego. Dla przy-kładu, jeżeli chcemy zareagować na zdarze-nie Event.RESIZE, nie będziemy w stanie te-go zrobić, jeżeli główny plik aplikacji nie ze-zwoli nam na dostęp. Oczywiście pojawia się problem, jeżeli w chwili kompilacji nie zna-my dokładnego adresu IP lub domeny, z któ-rej będzie wczytywany plik SWF. W takiej sy-tuacji możemy adres takiej domeny przeka-zać w obiekcie flashvars podczas osadza-nia pliku SWF bądź wykorzystać informacje z obiektu loaderInfo, aby przyznać dostęp adresowi przechowywanemu w zmiennej url. Niestety oba te rozwiązania niosą ze so-bą wysokie ryzyko łatwej modyfikacji obu ad-resów, tak więc są tutaj bardziej przykładem, niż zalecanym rozwiązaniem. Na szczęście w większości przypadków znamy adres do-meny, która będzie chciała komunikować się z naszym plikiem SWF, tak więc dynamiczne przyznawanie dostępu plikom SWF, nie jest tutaj standardem.

Podobnie do powyższej metody działa flash.system.Security.allowInsecureDomain(), z tą różnicą jednak, że w tym wypadku zezwa-lamy na dostęp do plików SWF dostępnych przez HTTPS plikom SWF dostępnym przez protokół HTTP. Oczywiście taką komunikację otwieramy na własną odpowiedzialność, z peł-ną świadomością faktu, że osłabiamy tym sa-mym bezpieczeństwo naszej aplikacji.

Pomimo ścisłej kontroli domen, z których pliki SWF mogą komunikować się z naszym programem, istnieje jeszcze jeden sposób

na komunikację pomiędzy dwoma plikami SWF, znajdującymi się na komputerze użyt-kownika.

Klasa LocalConnection umożliwia na na-wiązanie połączenia pomiędzy dwoma uru-chomionymi plikami SWF (nawet jeżeli znaj-dują się one w odrębnych oknach przeglądar-ki) i jest jedynym sposobem na komunikację pomiędzy plikami SWF starszych wersji ob-sługiwanych przez pierwszą wersję maszyny wirtualnej AVM1. Jest to kolejna okazja do niepożądanego dostępu do aplikacji, jeżeli nierozważnie będziemy rozporządzać prawa-mi dostępu do naszej aplikacji. Sposoby kon-troli przesyłanych tą drogą informacji, działa-ją podobnie jak przy wczytywaniu zewnętrz-nych plików SWF i składają się na nie metody LocalConnection.allowDomain() oraz LocalConnection.allowInsecureDomain() .

Pomimo wszystkich tych możliwości, oso-by o dostatecznie dużej determinacji znaj-dą drogę dostępu do naszej aplikacji. Dlate-go też ciągle staramy się wymyślać nowe, bar-dziej efektywne zabezpieczenia i utrudnie-nia dostępu osobom niepożądanym. Nawet pomimo nieudanych prób wstrzyknięcia ko-du do naszego programu, nasze pliki SWF, mogą zostać poddane próbie dekompilacji i późniejszej kompilacji ze zmodyfikowanym wewnątrz kodem. Obecnie dekompilacja pli-ków SWF powstałych przy użyciu Flex Fra-mework nie jest jeszcze taka prosta, jednak jest to tylko kwestią czasu, zanim powstanie odpowiednie komercyjne rozwiązanie, gdyż dekompilacja plików SWF kompilowanych w środowisku IDE Flasha jest już możliwa. Dlatego też pamiętajmy, aby nasze aplikacje zawierały możliwie jak najmniej informacji, które umożliwiłyby dostęp do danych nasze-go serwera, bądź ich modyfikację.

Stworzenie aplikacji całkowicie odpornej na ataki jest praktycznie niemożliwe, jed-nak dzięki świadomemu i rozważnemu ko-rzystaniu z reguł bezpieczeństwa i dostępu, już z pomocą standardowych narzędzi jeste-śmy w stanie choć trochę utrudnić penetra-cję stworzonej aplikacji. Dużo lepszym wy-borem będzie spojrzenie do plików pomocy, czy rozbudowanej dokumentacji udostępnia-nej przez Adobe, niż posługiwanie się asteri-skiem (*) przy przyznawaniu praw dostępu do danych na serwerze i aplikacji.

Opcje konfiguracji znacznika meta–policy w pliku autoryzacyjnym dla połączeń przez klasę Socket

• all –Domyślna konfiguracja. Wszystkie pliki autoryzacyjne dla połączeń przez porty są ak-ceptowane.

• master–only – Jedynym możliwym plikiem będzie tak zwany socket master policy file, czyli plik crossdomain dostepny przez port 843.

• none – Żadne pliki autoryzacyjne dla portów nie są akceptowane.

ŁUKASZ ZMYWACZYKDevelopment Team Leader w agencji T-SIGN STU-

DIOS.

Kontakt: [email protected]

JAKUB MATUSZEWSKISenior Flash Developer oraz Development Team Le-

ader w agencji T–SIGN STUDIOS. Z ActionScriptem

związany od 5 lat.

Kontakt: jacob@t–sign.com

Page 50: SDJExtra_31_2008_PL

FLEX50

ADOBE FLEXTest Driven Development

www.sdjournal.org 51

Technologia Flex i język programowa-nia ActionScript wdzierają się do roz-wiązań korporacyjnych na tyle szybko,

że coraz częściej zespoły wytwarzające oprogra-mowanie w oparciu o Flex, stosują znane me-todyki programowania, używane w innych środowiskach/technologiach wytwarzania od dosyć dawna. Same przez siebie niejako nobi-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-dukcyjne.

Biorąc pod uwagę fakt kompleksowości apli-kacji Flex, która bierze się między innymi z du-żej liczby możliwych ścieżek kolaboracji mię-dzy odrębnymi obszarami funkcjonalnymi – wydaje się, że nie powinno się zakładać z gó-ry, że oprogramowanie danych funkcjonalno-ści w kontekście jednostkowych pakietów, klas, a ostatecznie wyrażeń behawioralnych będzie pozbawione błędów. Dlatego poszukiwano sposobu na automatyzację wykrywania błędów w funkcjonowaniu aplikacji w możliwie naj-wcześniejszych fazach produkcyjnych, co jest szczególnie ważne przy wytwarzaniu aplikacji zorientowanym na klienta, które zakłada pro-gresywną realizację funkcjonalności przy moż-liwie najkrótszych iteracjach. Na takim tle po-wstał pomysł na TDD (ang. Test Driven Develop-ment), czyli na wytwarzanie oprogramowania zorientowanego na testy.

TDD a FlexTermin TDD pojawił się niedługo po ukuciu i rozpowszechnieniu się terminu XP (ang. eXtre-me Programming), jednej z bardziej popular-nych metodyk lekkich (inaczej zwanych zwin-nymi – ang. agile) wytwarzania oprogramowa-nia, które kładą nacisk na dostarczanie kliento-wi artefaktów programowych, zamiast papiero-wych tj. dokumentacji – która w XP ma formę szczątkową w porównaniu m.in. do RUP (ang.

Rational Unified Process), który ma korzenie w USDP (ang. Unified Software Development Pro-cess) i jest reprezentantem metodyk ciężkich. XP jako uznana metodyka zwinna, zaczęła perma-nentnie dążyć do skracania faz produkcyjnych, i tak m.in. powstał pomysł na to, aby zautoma-tyzować testowanie poprzez wprowadzenie te-stów jednostkowych (nazwa bierze się z testo-wania danej jednostki, jaką jest metoda – funk-cja lub klasa) oraz przeniesienie fazy testowa-nia na początek fazy implementacji, a docelowo zmusić programistę, aby pisał przypadki testo-we przed napisaniem właściwego kodu aplikacji programowej. W skrócie, programista powinien opisywać i precyzować na początku, czego ocze-kuje po działaniu przyszłego kodu, zanim zaj-mie się jego pisaniem. W porównaniu do trady-

Test Driven Development

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?

Dowiesz się...• Co to jest TDD, dlaczego i kiedy warto używać

tej techniki.

• Jak używać biblioteki FlexUnit.

Powinieneś wiedzieć...• Jak pracuje się ze środowiskiem FlexBuilder 3.

Poziom trudności

Testuj kod zanim go napiszesz

Listing 1. Przypadek testowy

public class SampleTest extends TestCase //przypadek testowy

{

public function SampleTest(methodName : String = null) {

super(methodName);

}

public static function suite():TestSuite {

var sampleTS:TestSuite = new TestSuite(); // zestaw testowy

sampleTS.addTestSuite(SampleTest);

accountTS.addTest(new SampleTest("testA"));

return sampleTS;

}

public function testA():void { // metoda testowa

var sample:Sample = new Sample();

assertEquals("Expecting zero", 0, sample.getBalance()); // asercja

}

override public function setUp():void {

}

override public function tearDown():void {

}

}

Page 51: SDJExtra_31_2008_PL

FLEX50

ADOBE FLEXTest Driven Development

www.sdjournal.org 51

cyjnego procesu wytwarzania oprogramowania, w którym testy (czy to weryfikacyjne, walidacyj-ne, wydajnościowe, czy to ilościowe) są przepro-wadzane zazwyczaj w końcowych fazach proce-su wytwarzania oprogramowania z domniema-niem sukcesu, o którym była mowa wyżej, była to koncepcja nadzwyczaj rewolucyjna, ale jak się później okazało słuszna. Ze zdroworozsądkowego punktu widzenia, wydawało się od razu, że pro-gramiści będą mieć większy zapał, aby pisać te-sty na początku fazy wdrożenia, niż w kolejnych fazach. Każdy z nas ma najwięcej zaangażowania na początku prac, najmniej na żmudnym końcu, kiedy należy poprawiać i poprawiać, i nie zawsze wiadomo, gdzie się popełniło błąd. Kod tworzo-ny wedle ścisłych reguł umożliwiających auto-matyzację testowania oraz przypadków testo-wych będzie łatwiejszy w pielęgnacji i rozbudo-wie. TDD nie jest metodyką testowania, ale uży-wania testów w celu wytwarzania oprogramowa-nia w sposób przyrostowy i zorientowany na me-todyki lekkie. Owe używanie testów w procesie produkcyjnym powinno mieć cykl zaprezento-wany na Rysunku 1.

Utylitarność metodologii TDD bierze się nie tylko z faktu, niezaprzeczalnych atutów płyną-cych z teorii, ale również, a być może należy na-

pisać przede wszystkim, z łatwości zaadaptowa-nia procesu produkcyjnego pod nią oraz z do-syć dużej liczby narzędzi wspierających jej sto-sowanie w praktyce.

Słuszność tej tezy potwierdza się również w przypadku wytwarzania oprogramowania w oparciu o technologię Flex, dla której najbar-dziej popularnym w tej chwili frameworkiem testów jednostkowych pozwalającym na stoso-wanie idei TDD jest FlexUnit.

Zanim zaczniemyPrzed rozpoczęciem instalacji oraz stworze-niem przykładowych przypadków testowych, musimy zrozumieć podstawowe terminy me-todyki TDD.

Przypadek testowy (ang. test case)Przypadek testowy to najmniejsza jednostka te-stowa, która sprawdza poprawność wartości, ja-ką zwraca test na wyjściu, biorąc pod uwagę war-tość, która pojawia się na jego wejściu. Przypa-dek testowy w kontekście elementów języka Ac-tionScript stanowi klasę, która dziedziczy po kla-sie TestCase i ma konstruktor, który wywołu-je za pomocą metody super() konstruktor kla-sy bazowej. Klasa przypadku testowego może za-

wierać przeciążone dwie metody setUp() oraz tearDown(), które służą do ustawiania warto-ści obiektów niezbędnych dla środowiska, w któ-rym wykonuje się przypadek testowy przed wy-konaniem testu setUp() oraz po jego zakończe-niu tearDown(). Metody te ułatwiają m.in. inicja-cję wspólnego zbioru obiektów dla więcej niż jed-nego przypadku testowego (patrz na Listing 1.).

Zestaw testowy (ang. test suite)Służy do grupowania przypadków testowych oraz innych zestawów testowych. Agregacja wy-branych testów w zestaw testowy jest niezbęd-na dla możliwości zadeklarowania, jakie testy mają się wykonać w danej sesji.

Asercja (ang. assertion)Predykat to wyrażenie behawioralne, któ-re zwraca prawdę lub fałsz, umieszczamy go w pewnym miejscu w kodzie przypadku testo-wego. Wskazuje on, że programista zakłada, że dany warunek jest prawdziwy. W przypadku,

Rysunek 1. Cykl TDD

�����������

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

����������

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

����

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

Rysunek 2. Flex Builder 3

Rysunek 3. Tworzenie nowego projektu

Rysunek 4. Dodanie zewnętrznej biblioteki

Page 52: SDJExtra_31_2008_PL

FLEX52

ADOBE FLEXTest Driven Development

www.sdjournal.org 53

gdy predykat jest fałszywy, (czyli niespełnio-ne są warunki postawione przez programistę) asercja powoduje przerwanie wykonania pro-gramu. Asercja jest realizowana za pomocą me-tod np. assertEquals (message, input – war-tość oczekiwana, output – wartość aktualna), które sprawdzają poprawność predykatów.

Operator testu (ang. test runner)Jest to komponent uruchomieniowy zestawów testów bądź przypadków testowych. Ma on gra-ficzny interfejs oraz pozwala zaprezentować wykonywanie się zadeklarowanych przypad-ków testowych. Robimy to przypisując do pa-rametru test komponentu TestRunner zestaw testowy. Uruchamia się go używając metody startTest() komponentu TestRunner.

Przykład znajduje się na Listingu 2.

No to zaczynamy!Pierwsze co musimy zrobić to pobrać źródła bi-blioteki FlexUnit. Znajdują się one pod adresem:

ht t p : / / labs .adobe .com/wik i / inde x.php/ActionScript_3:resources:apis:libraries#FlexUnit.

Instalacja ogranicza się do rozpakowania ar-chiwum. Ja wypakowane pliki umieściłem w katalogu: D:\Programowanie\flexDev\flexUnit. Po rozpakowaniu archiwum w katalogu flexUnit znajdą się katalogi bin, docs i src oraz plik z licencją (license.txt).

Przykładowy projektStworzymy klasę obsługującą prosty koszyk w sklepie internetowym. Każdy, kto chociaż raz odwiedził taki sklep zauważy, że jest ona trywialna i brakuje jej wielu niezbędnych funk-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/cfusion/tdrc/index.cfm?product=flex lub dostęp-ne na DVD.

Utworzenie nowego projektuZ menu File wybieramy pozycję New/Flex Pro-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 wybrany odznaczając pozycję Use default loca-tion. Pozostałe opcje pozostaw bez zmian i na-ciśnij Next. W kolejnym kroku ustaw katalog, gdzie będą zapisywane skompilowane pliki. Tu

Listing 2. Operator testu

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

<mx:Application

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:flexunit="flexunit.flexui.*"

creationComplete="onCreationComplete()">

<mx:Script>

<![CDATA[

private function onCreationComplete():void

{

testRunner.test =CartTest.suite();

testRunner.startTest();

}

]]>

</mx:Script>

<flexunit:TestRunnerBase id="testRunner" width="100%" height="100%" /> // operator

testu

</mx:Application>

Listing 3. Klasa zawierająca przypadek testowy

package

{

import flexunit.framework.TestCase;

import flexunit.framework.TestSuite;

public class CartTest extends TestCase

{

public function CartTest(methodName : String){

super(methodName);

}

public static function suite():TestSuite{

var cartTS:TestSuite = new TestSuite();

//tutaj umieścisz testy

return cartTS;

}

}

}

Listing 4. Klasa, którą będziemy testować

package

{

public class Cart

{

public function Cart(){

}

}

}

Listing 5. Test nr 1

public function testNew():void{

var cart:Cart = new Cart();

assertEquals("Nic nie powinno być w koszyku", 0, cart.getQuantity());

}

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

Page 53: SDJExtra_31_2008_PL

FLEX52

ADOBE FLEXTest Driven Development

www.sdjournal.org 53

taj możesz nic nie zmieniać i przejść od razu do kolejnego kroku (przyciskając Next). W tym kroku ustawimy ścieżki do zewnętrznych bi-bliotek – czyli w tym przypadki do FlexUnit. Wybierz zakładkę Library path i naciśnij przy-cisk Add SWC (Rysunek 4.). Wskaż plik flexu-nit.swc, znajduje się on w podkatalogu bin, kata-logu flexUnit. Teraz możesz już wcisnąć Finish – projekt został utworzony.

Utworzenie pliku main.mxmlPlik MXML dla tego przykładu znajduje się już w części opisującej operatora testu (test runner), Listing 2. W pliku tym przede wszystkim:

• tworzymy nową przestrzeń nazw dla na-szej aplikacji,

• 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 TestRunnerBase, 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

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 testowegoTeraz 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);

Zawiera też jedną statyczną metodę suite(), która w wyniku swojego działania zwraca ze-staw testowy.

Utworzenie klasy koszykaOczywiście musisz utworzyć jeszcze klasę, któ-rą będziesz testować. Umieść ją w pliku Cart.as Na początku będzie ona bardzo prosta jak na Listingu 4.

Pierwszy testKiedy pierwszy raz wchodzisz do sklepu in-ternetowego, Twój koszyk jest na początku pu-sty. Jest to oczywiste, nie zdążyłeś jeszcze wy-brać niczego co chciałbyś kupić. Jednak, aby się o tym przekonać potrzebna jest metoda, która poda ilość towarów znajdujących się w koszyku,

a w tym konkretnym przypadku poda 0. Czyli masz już założenia do pierwszego testu.

W TDD piszesz najpierw test, a dopiero póź-niej testowaną metodę. Test umieść w funkcji testNew() w pliku CartTest.as (Listing 5.).

Funkcja testująca tworzy nową zmienną kla-sy Cart oraz ustanawia nową asercję metodą assertEquals(). Metoda ta ma trzy parametry:

assertEquals(„Nic nie powinno być w

koszyku”, 0, cart.getQuantity());

String Nic nie powinno być w koszyku to po pro-stu komentarz dodany w celach informacyj-nych. 0 to wartość, jaką powinna zwrócić testo-wana metoda, a cart.getQuantity() to wła-śnie testowana metoda.

Rysunek 6. Odwołanie do nieznanej metody

Rysunek 7. Okno operatora testu

Page 54: SDJExtra_31_2008_PL

FLEX54

ADOBE FLEXTest Driven Development

55

Metoda assertEquals() porównuje otrzy-many wynik działania z zakładanym.

Aby test został wykonany, musisz go jeszcze dodać do zestawu. Dopisz poniższy kod do me-tody suite() w pliku CartTest.as

cartTS.addTest(new CartTest("testNew"));

Czyli dodajesz test (nową zmienną klasy CartTest – tej, w której właśnie jesteś) do zestawu za pomocą metody addTest(). Ja-ko parametr dla konstruktora podajesz na-zwę funkcji testującej (w konstruktorze: super(methodName);).

Teraz metoda suite() powinna wyglądać tak jak na Listingu 6.

Pierwszy etap projektowania aplikacji masz już za sobą (Rysunek 1.). Aby przejść do następnego, skompiluj i uruchom aplikację [Ctrl] + [F11].

Powinieneś otrzymać raport o pierwszym błędzie (Rysunek 5.). Przyczyną jest oczywi-ście to, że nie zaimplementowałeś jeszcze testo-wanej metody (Rysunek 6.).

Przejdź zatem do etapu 3 z Rysunku 1. i na-pisz odpowiednią metodę w klasie Cart. Będzie ona teraz wyglądała tak jak na Listingu 7.

Utworzyłeś zmienną quantity i napisałeś metodę getQuantity(), która zwraca jej war-tość. Skompiluj ponownie projekt. Powinieneś otrzymać rezultat jak na Rysunku 7.

Operator wykonał pierwszy test, który za-kończył się niepowodzeniem. Oczekiwali-

śmy wartości 0, a otrzymaliśmy NaN (Not a Number). Aby go poprawić, wystarczy nadać zmiennej _quantity wartość 0 podczas two-rzenia nowej zmiennej tej klasy, czyli w kon-struktorze:

public function Cart(){

_quantity = 0;

}

Listing 7. Piszemy metodę w klasie Cart

package

{

public class Cart

{

private var _quantity:Number;

public function Cart(){

}

public function getQuantity():

Number{

return _quantity;

}

}

}

Rysunek 8. Okno operatora testu – test zaliczony

Listing 8. Test ilości przedmiotów w koszyku

public function testAddNewItem():void{

var cart:Cart = new Cart();

var newItem:Object = {id:731, name:"Książka", price:26.80};

cart.addItem(newItem);

assertEquals("Powinien być jeden przedmiot", 1, cart.getQuantity());

}

Listing 9. Dodajemy nowy test

public static function suite():TestSuite{

var cartTS:TestSuite = new TestSuite();

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(){

}

public function getQuantity():Number{

return CartItems.length;

}

public function addItem(item:Object):void{

CartItems.push(item);

}

}

}

Listing 11. Testujemy i wprowadzamy nowe funkcjonalności

public function testAddItemAndCalc():void{

var cart:Cart = new Cart();

var newItem:Object = {id:731, name:"Książka", price:26.80};

cart.addItem(newItem);

newItem = {id:945, name:"Płyta", price:32.50};

cart.addItem(newItem);

assertEquals("Powinienny być dwa przedmioty", 2, cart.getQuantity());

assertEquals("Wartość towarów w koszyku", 59.30, cart.getValue());

}

Listing 12. Dodajemy kolejną metodę do klasy Cart

public function getValue():Number{

var val:Number = 0;

for(var i:int = 0; i<CartItems.length; i++){

val += CartItems[i].price;

}

return val;

}

Rysunek 9. Wynik czwartego testu

Page 55: SDJExtra_31_2008_PL

FLEX54

ADOBE FLEXTest Driven Development

55

Skompiluj projekt ponownie. Tym razem test powinien zostać zaliczony (Rysunek 8.).

Udało ci się przejść pełny cykl TDD, w wy-niku czego napisałeś klasę poprawnie inicjali-zującą koszyk.

Kolejne testyTeraz przydałoby się coś wrzucić do koszyka. Napiszmy więc test, który doda jakiś towar do koszyka i sprawdzi ile przedmiotów się w nim znajduje po tej operacji (Listing 8.). A następ-nie dodajmy nowy test do zestawu wg Listingu 9. Oczywiście po kompilacji otrzymasz błąd:

Error: Powinien być jeden przedmiot -

expected:<1> but was:<0>

Jest to spowodowane tym, że w klasie Cart nie ma jeszcze metody addItem(). Dopiszmy ją zatem. W tym momencie zauważysz też błąd w początkowych założeniach klasy Cart. Bardziej logiczne byłoby utworzenie tablicy, gdzie będą zapisywane kolejne przedmioty. W takim przypadku nie będzie już potrzeb-na zmienna _ quantity, ponieważ zawsze mo-żemy odczytać długość takiej tablicy. Wpro-wadź zatem zmiany do pliku Cart.as wg Li-stingu 10.

Skompiluj projekt. Tym razem nie powinie-neś otrzymać żadnych błędów.

Kolejną funkcjonalnością, jaką dodamy do naszego koszyka, będzie podanie wartości na-szych zakupów. Dodajmy też jeszcze jeden przedmiot, aby sprawdzić czy poprawnie jest obliczana wartość całego zamówienia. Zacznie-my oczywiście od testu (Listing 11.).

W tym teście wprowadziliśmy dwie asercje. Pierwsza sprawdza ilość towarów w koszyku, a druga ich łączną wartość. Dodaj jeszcze test od zbioru, umieszczając kolejną linie w meto-dzie suite():

cartTS.addTest(new CartTest("testAddItemAnd

Calc"));

Po kompilacji otrzymasz znany już błąd o bra-ku metody w klasie Cart, czyli należy ją dopi-sać wg Listingu 12.

Po kompilacji testy powinny wykonać się po-prawnie.

Załóżmy, że projektowany przez nas sklep bę-dzie udzielał rabatów niektórym klientom. Na-pisz zatem test, który sprawdza poprawność obliczenia rabatu 15%, tak jak na Listingu 13.

Dodaj go do zestawu dopisując linię:

cartTS.addTest(new CartTest("testPriceWithD

iscount"));

do metody suite() w klasie CartTest.

Po kompilacji ponownie otrzymałeś błąd in-formujący o braku metody w klasie Cart. Tym razem chodzi o metodę getDiscountValue(). Obliczy ona cenę towarów po rabacie i zwróci jej wartość. Procent rabatu przekażemy do me-tody jako parametr (Listing 14).

Skoro funkcja jest gotowa, skompiluj projekt. Powinieneś uzyskać efekt podobny do tego z Rysunku 9. Test zwrócił błąd:

Error: Wartość towarów po udzieleniu rabatu

15% - expected:<50.41> but was:<50.405>

Czyli rabat jest obliczony poprawnie, jednak cenę należy zaokrąglić do pełnych groszy. Za-tem musisz dodać odpowiednie obliczenia do naszej metody (Listing 15.).

Skompiluj projekt jeszcze raz. Teraz wszyst-ko powinno być już w porządku.

PodsumowanieNa tym prostym przykładzie powinieneś zro-zumieć technikę TDD. Oczywiście w prak-tyce będziesz ją wykorzystywał do progra-mowania bardziej skomplikowanych rze-czy. Przekonałeś się, jak można programo-wać od tyłu – najpierw sprawdzając wynik, a później pisząc i poprawiając kod generują-cy. Przy projektowaniu dużych i skompliko-wanych aplikacji technika ta może okazać się nieoceniona, skracając i upraszczając pracę programistów.

Słowniczek stosowanych terminów

• Test jednostkowy (ang. unit test) – to w pro-gramowaniu obiektowym, a w szczegól-ności programowaniu ekstremalnym kod, który uruchamia fragment testowanego programu i porównuje jego wynik z oczeki-wanym;

• eXtreme programming (XP) – programo-wanie ekstremalne jest reprezentantem zwinnych metodyk programowania (ang. agile), która kładzie nacisk na dostar-czanie klientowi funkcjonalności przy szczątkowej formie dokumentacji;

• Test Driven Development (TDD) – jest techniką wytwarzania oprogramowania w kontekście zwinnej metodyki XP zo-rientowaną na iteracje oraz przypadki te-stowe. Podstawowa zasada – testuj kod zanim go napiszesz;

• FlexUnit – jest frameworkiem testów jednostkowych dla języka programowa-nia ActionScript 3.0 oraz środowiska Flex.

Listing 13. Test obliczeń rabatu

public function testPriceWithDiscount():void{

var cart:Cart = new Cart();

var newItem:Object = {id:731, name:"Książka", price:26.80};

cart.addItem(newItem);

newItem = {id:945, name:"Płyta", price:32.50};

cart.addItem(newItem);

assertEquals("Wartość towarów po udzieleniu rabatu 15%", 50.41, cart.getDiscountVa

lue(15));

}

Listing 14. metoda getDiscountValue() obliczy cenę towarów po rabacie i zwróci jej wartość

public function getDiscountValue(discount:Number):Number{

var val:Number = getValue();

val -= val * (discount/100);

return val;

}

Listing 15. Szlifujemy metodę, tak by zaokrąglała cenę do pełnych groszy

public function getDiscountValue(discount:Number):Number{

var val:Number = getValue();

var roundVal:Number = 0;

val -= val * (discount/100);

roundVal = Math.round(val * 100)/100;

return roundVal;

}

PAWEŁ CICHOŃ, TOMASZ KULCZYCKIJanmedia Interactive

http://www.janmedia.pl/

www.sdjournal.org

Page 56: SDJExtra_31_2008_PL

FLEX56

ADOBE FLEXCairngorm

www.sdjournal.org 57

Po pierwszych sukcesach Adobe Flex, Microsoft prężnie zaczął rozwijać swój najnowszy produkt – Silverlight,

a Sun oficjalnie ogłosił stworzenie konku-rencyjnej technologii JavaFX. Spośród nich, omawiana platforma jest najbardziej dojrza-łą i rozbudowaną. Jako programista i konsul-tant korzystający na co dzień z Adobe Flex wierzę, że jej nazwa ukrywa w sobie cechę tego środowiska (flex – ang. giętki). Jest ono przyjazne osobom w nim pracującym, za-wsze gotowe na zmiany w projekcie, zarów-no graficzne, jak i funkcjonalne. Flex w wer-sji 3 jest opublikowany na licencji Open Sour-ce, co oznacza, że środowisko jest rozszerzal-ne i stale udoskonalane.

Projekty Flexowe z natury są aplikacjami internetowymi wypełnionymi funkcjonalno-ściami, które mają za zadanie stworzenie wy-soce interaktywnego, atrakcyjnego i przyja-znego interfejsu. Wykorzystując tę platfor-mę, możemy dostarczać naszym klientom produkty przynoszące nową jakość usług biz-nesowych.

Przepis jest prosty: potrzebujemy jakieś źródło danych, np. Web Service, kilka goto-wych komponentów interfejsu użytkowni-ka, trochę ActionScriptu, aby wszystko zwią-zać razem i mamy działającą aplikację inter-

netową! Rezultat, który otrzymujemy jest za-skakujący w porównaniu, do pracy jaką wło-żyliśmy w jego stworzenie. Jest to jedna z za-sad tworzenia współczesnego oprogramowa-nia Internetowego. Prędkość i poziom funk-cjonalności z jaką możemy stworzyć gotowy produkt stały się najważniejszymi wartościa-mi biznesowymi.

Jednak co się wydarzy, gdy zaczniemy się mierzyć z kolejnymi modyfikacjami funkcjo-nalności, graficy zarzucą nas nowymi elemen-tami interfejsu, a technologia połączenia z ser-werem, jak i komunikat z niego otrzymywany gruntowanie się zmieni? Co będzie, gdy zajdzie się potrzeba dodania kolejnych elementów apli-kacji? Gdy do zespołu dołączy nowy programi-sta? Odpowiedź jest prosta – jakość pracy w ze-spole będzie współzależna od jakości dotych-czasowego kodu. Niestety wraz z wprowadza-niem zmian w projekcie, rozpoczyna się cha-os. W takiej sytuacji z pomocą przychodzą fra-meworki architektoniczne. Dlaczego warto więc podjąć wyzwanie wprowadzając tego typu roz-wiązania do projektów? Odpowiedzi można mnożyć, poniżej wymienię te najważniejsze:

• Dostajemy do ręki gotowy i sprawdzony przepis na dobrze rozwarstwioną i prze-myślaną aplikację, mogąc skupić się na pro-gramowaniu elementów naszej aplikacji, a nie na tym jak rozwiązać problem archi-tektury;

• Nie chcemy spędzać kolejnych dni na wprowadzaniu nawet najprostszych zmian do naszej aplikacji;

• Możemy programować równolegle z wielo-ma programistami, mając jasny podział ról i odpowiedzialności, wykorzystując usta-loną komunikację między warstwami na-szego projektu.

Cairngorm jest z natury lekkim framewor-kiem (obciążenie klasami tego frameworka jest stosunkowo nieduże). Idee będące jego filarem zostały nakreślone już w 2002 roku przez zespół Macromedii. Miały one za za-danie zastosowanie sprawdzonych wzorców projektowych języka Java (Core J2EE Pat-tern Catalog) we współczesnym Flash MX. Duży wpływ na projekt mieli programi-ści iteration::two, Steven Webster oraz Ali-star McLeod, którzy obecnie należą do ze-społu Adobe Consulting oficjalnie tworzą-cego ten produkt. Opierając się na silnych podstawach programistycznych, Cairngorm był rozwijany wewnątrz firmy Adobe i zo-stał publicznie zaprezentowany jako pro-jekt typu Open Source w listopadzie 2004 ro-ku podczas konferencji Macromedia MAX 2004 w Nowym Orleanie. Wówczas była to wersja oznaczona numerem 0.95. Aktual-nie Cairngorm jest rozbudowywany przez zespół doświadczonych programistów i dzie-li się na dwie wersje Standard oraz Enterpri-se, znajdując wykorzystanie zarówno w ty-powych aplikacjach internetowych opartych o Flex, jak i aplikacjach desktopowych wyko-rzystujących Adobe AIR.

Cairngorm jest w pełni oparty o architektu-rę MVC. Będąc całkowicie przygotowanym pod środowisko Flexa, pozwala on w pełni wykorzy-stać zalety, jakie ono niesie. Wykorzystuje zna-ne wzorce projektowe, które omówimy w kolej-nych częściach tego artykułu. Stworzenie apli-kacji opartej o ten fremawork wymaga zrozu-mienia poszczególnych elementów go współ-tworzących. W tym artykule stworzymy pro-stą aplikację wyświetlającą książki, wchodzące w skład pewnej podręcznej biblioteczki.

Adobe Cairngorm

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.

Dowiesz się...• O najpopularniejszym frameworku MVC dla

platformy Adobe Flex.

• Jaka jest jego zasada działania.

• Jak wykonać przykładowy projekt wykorzy-

stując Adobe Cairngorm.

Powinieneś wiedzieć...• Wymagana jest znajomość zasady działania

wzorca MVC.

• Wiedza na temat wzorców projektowych i za-

sad programowania obiektowego.

Poziom trudności

Framework architektoniczny dla Adobe Flex

Page 57: SDJExtra_31_2008_PL

FLEX56

ADOBE FLEXCairngorm

www.sdjournal.org 57

Struktura aplikacji opartej o CairngormPrzedstawiona na Rysunku 1. struktura, opiera się o podzielenie elementów na główne składo-we naszej aplikacji. Całość zostanie omówiona w poszczególnych częściach tego artykułu.

Zarządzanie danymi aplikacjiPodczas tworzenia aplikacji, do pobrania i prezentowania danych korzystamy z war-stwy pośredniej, znanej jako warswa bizne-sowa (ang. Business Tier). Dane przechowywa-ne w relacyjnych bazach danych muszą zostać zamienione na konkretne obiekty. Dodatko-wo spoczywa na nas zadanie podtrzymania ich spójności.

Z pomocą programistom przychodzą róż-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ć się na odpowiednim przemyśleniu i zastoso-waniu odpowiedniego modelu danych war-stwy biznesowej i przedstawieniu go za po-mocą warstwy prezentacji. Cairngorm opie-ra się na dwóch wzorcach projektowych uży-tych do zarządzania informacją przechowy-waną w naszej aplikacji: Model Locator oraz Value Object.

Dane dostarczone nam przez zewnętrzne źródło przechowywane są w postaci obiektów implementujących interfejs IValueObject. W naszym przykładzie klasa ta będzie bardzo prosta – będziemy mieć tu kilka właściwości tj. tytuł, autor, wydawnictwo i datę wydania. Całość obejmiemy metatagiem [Bindable], co pozwoli na skorzystanie z mechanizmu tzw. Data Bindingu. Ułatwia on prezentowa-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-nizm działa w dwie strony (zmienny wpro-wadzane w elementach interfejsu automa-tycznie zostaną naniesione na odpowiadają-ce obiekty modelu). Jest to jedna z cech Fle-xa, która bardzo ułatwia pracę nad aplika-cjami RIA. Możemy tu również skorzystać z mechanizmu Remote Class, który pozwo-li nam na bezpośrednie zmapowanie obiek-

tów strony serwera (obiektów platform Ja-va, ColdFusion, PHP, Ruby lub .Net). Imple-mentując ten interfejs, możemy rozszerzać

istniejące już klasy, np. bardzo często zda-rza się użycie obiektów opartych o kolekcję ArrayCollection. Przykładowa implementa-

Rysunek1. Struktura Projektu

Listing 1. Implementacja oparta na wzorcu Value Object

package com.wjptak.samplelibrary.vo

{

import com.adobe.cairngorm.vo.IValueObject;

[Bindable]

public class BookVO implements IValueObject

{

public var title:String;

public var author:String;

public var publisher:String;

public var yearPublished:Number;

}

}

Listing 2. Implementacja Model Locator

package com.wjptak.samplelibrary.model

{

import com.adobe.cairngorm.CairngormError;

import com.adobe.cairngorm.CairngormMessageCodes;

import com.adobe.cairngorm.model.IModelLocator;

import mx.collections.ArrayCollection;

[Bindable]

public class LibraryModelLocator implements IModelLocator

{

private static var modelLocator:LibraryModelLocator;

public static function getInstance():LibraryModelLocator

{

if(modelLocator == null) {

modelLocator = new LibraryModelLocator();

}

return modelLocator;

}

public function LibraryModelLocator():void {

if(modelLocator != null) {

throw new CairngormError(

CairngormMessageCodes.SINGLETON_EXCEPTION, "ModelLocator"

);

}

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;

}

}

Page 58: SDJExtra_31_2008_PL

FLEX58

ADOBE FLEXCairngorm

www.sdjournal.org 59

cja oparta na wzorcu Value Object przedsta-wiona jest na Listingu 1.

Konstrukcja pliku jest dość prosta, więc przejdźmy dalej. Do przechowywania pre-zentowanych informacji, jak i wszelkich danych dotyczących naszej aplikacji, jak np. stanów komponentów widoku, uży-wamy obiektu implementującego interfejs IModelLocator. Model Locator jest wzorcem projektowym opartym o wzorzec Singleton.

Rozwiązanie to posiada zarówno zalety, jak i wady – w związku z kontrowersjami, jakie budzi wśród programistów prawdopodob-nie w następnych wersjach frameworka zosta-nie zamienione na inne. Zaletą tego rozwią-zania jest prosty dostęp do danych przecho-wywanych w naszej aplikacji, natomiast wią-że się to ze złamaniem kilku zasad obiekto-wości (do Singletona nie możemy zastoso-wać zasad polimorfizmu). Implementacja te-

go wzorca w naszej aplikacji jest następująca (Listing 2.).

W katalogu model możemy umieścić rów-nież inne klasy rozszerzające funkcjonalność naszego modelu, w miarę jak stopień skom-plikowania aplikacji wzrasta. Charaktery-styczna implementacja wzorca Singleton wynika z cechy ActionScript 3.0, jaką jest nieudostępnienie prywatnych konstrukto-rów. Dostęp do obiektu mamy więc za pomo-cą wywołania metody LibraryModelLocator.getInstance().

Możemy zauważyć, że dane w na-szej aplikacji przechowujemy w kolekcji ArrayCollection. Umożliwia ona zastoso-wanie mechanizmu wspomnianego wcze-śniej – Data Bindingu, co ułatwi nam znacz-nie prezentowanie przechowywanych w niej obiektów.

Komunikacja z zasobami danychIdeą każdej aplikacji RIA jest przedstawienie w interaktywny sposób pewnych danych użyt-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-ła umieszczona również aplikacja. Flex daje nam bardzo duże możliwości połączenia z do-wolnymi współczesnymi językami serwerowy-mi przy wykorzystaniu kilku mechanizmów, m.in. HTTPService – pliki XML oraz komu-nikaty w formie JSON, Web Service – za-równo REST, jak i SOAP oraz RemoteObject – najsilniejsze rozwiązania przesyłające obiek-ty w ich natywnej formie. Cairngorm wystę-puje w wersjach Standard oraz Enterprise. Ta druga rozszerza funkcjonalność frameworka o klasy wspomagające mechanizmy Remote Object, szczególnie mowa tu o LiveCycle Data Services.

Aplikacja oparta o Cairngorm jako central-ne miejsce przechowujące dostęp do możli-wych do użycia serwisów wykorzystuje wzo-rzec Service Locator. Jest to klasa oparta na Singletonie, której implementacja w tworzo-nej aplikacji sprowadza się do stworzenia na-stępującego pliku business/Services.mxml (Li-sting 3.).

W naszym przykładzie aplikacja będzie ko-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ę przez odpowiednio przygotowany mechanizm,

Listing 3. Tworzenie pliku business/Services.mxml

<cairngorm:ServiceLocator

xmlns:cairngorm="com.adobe.cairngorm.business.*"

xmlns:mx="http://www.adobe.com/2006/mxml">

<mx:HTTPService id="BookAssets"

url="data/sample_books.xml"

makeObjectsBindable="true"

showBusyCursor="true"

resultFormat="e4x" />

</cairngorm:ServiceLocator>

Listing 4. Tworzenie klasy Business Delegate w katalogu business

package com.wjptak.samplelibrary.business

{

import com.adobe.cairngorm.business.ServiceLocator;

import mx.rpc.AsyncToken;

import mx.rpc.IResponder;

public class GetBasicDataDelegate

{

private var responder : IResponder;

private var service : Object;

public function GetBasicDataDelegate( responder : IResponder )

{

this.service = ServiceLocator.getInstance().getHTTPService( "BookAssets" );

this.responder = responder;

}

public function getData():void

{

var call:AsyncToken = service.send();

call.addResponder( this.responder );

}

}

}

Rysunek 2. Przepływ zdarzenia w aplikacji opartej o Cairngorm

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

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

Page 59: SDJExtra_31_2008_PL

FLEX58

ADOBE FLEXCairngorm

www.sdjournal.org 59

oparty o zdarzenia, który zostanie omówiony w dalszej części. Cairngorm do wywołania kon-kretnego serwisu używa klas wzorca Business Delegate. Spełniają one potrójne zadanie – lo-kalizują poprzez Service Locator odpowied-ni serwis, wywołują go oraz przesyłają wynik zapytania do odpowiedniego obiektu rozsze-rzającego klasę Responder. W naszym przykła-dzie odwołujemy się do pliku sample_books.xml poprzez HTTPService. Aby z niego skorzy-stać, tworzymy odpowiednią klasę Business Delegate w katalogu business, co widać na Li-stingu 4.

Do konstruktora tej klasy przekazujemy re-ferencję do obiektu opartego o Responder. Na-stępnie chcąc wywołać dany serwis, korzysta-my z metody getData(). Analogicznie wygląda zapytanie, mającego na celu przesłanie danych do serwera np. zapisu do bazy danych. W takim przypadku wywołujemy odpowiednią metodę obiektu service, przekazując jako parametry przesyłane dane.

Warstwa kontrolera aplikacji opartej o CairngormAplikacje tworzone w oparciu o omawiany fra-mework wykorzystują wzorzec Service to

Worker. Cairngorm jest oparty o to rozwiązanie. Na pierwszy rzut oka konstrukcja, z której przyj-dzie nam skorzystać, może wydawać się zagma-twana. Aby lepiej zrozumieć tę ideę, przybliżmy klasy wchodzące w skład frameworka:

• CairgnormEvent – dziedziczy po Event. Aby zbudować poprawną komunikację opartą o zdarzenia, na której opiera się Ca-irngorm, wykorzystujemy obiekty budo-wane w oparciu o tą właśnie klasę;

• CairngormEventDispatcher – centralny 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;

• FrontController – przyporządkowuje stworzone przez nas klasy rozszerzające CairngormEvent do odpowiadających im klasom wzorca Command ;

• ICommand – Budując klasy korzystające ze wzorca Command , musimy zaimplemento-wać ten interfejs. Wymaga to od nas opra-cowania odpowiedniej metody execute(), która jest przyporządkowana poprzez FrontController do odpowiedniego zda-rzenia CairngormEvent.

Podczas fazy analizy projektowanej aplika-cji tworzymy diagramy przypadków uży-cia. Następnie, stosując Cairngorm, każdy przypadek użycia zamieniamy na parę klas CairngormEvent – ICommand . Jeżeli wymaga on komunikacji z serwerem, musimy rozsze-rzyć klasę implementującą ICommand poprzez Responder, a dodatkowo stworzyć omówio-

ną wcześniej implementację wzorca Business Delegate oraz określony odpowiednio serwis w pliku Services.mxml. Za dobrą praktykę uwa-ża się oddzielenie Responder od ICommand – tak aby wszystkie klasy wzorca Command mia-ły zbliżoną konstrukcję.

Przepływ zdarzenia w aplikacji opartej o Ca-irngorm jest taki jak na Rysunku 2.

Jako prosty przykład posłużą nam klasy służące do zmiany aktualnie wyświetlane-go interfejsu naszej aplikacji. Klasa rozsze-rzająca Cairngorm Event jest taka jak na Li-stingu 5.

Konstruktor tej klasy został tak zaprojekto-wany, że rozgłoszenie zdarzenia możemy wyko-

nać poprzez bezpośrednie przekazanie pożąda-nego widoku, np.:

new SwitchViewEvent( LibraryModelLoca

tor.ENTRY_DATA ).dispatch();

Dokładnie będzie to pokazane podczas oma-wiania elementów warstwy prezentacji. Zwróćmy uwagę, że użycie tego mechani-zmu jest bardzo proste. Nie musimy pisać kil-ku linijek, załatwiamy wszystko w jednej. In-ny element omawianej klasy, na który należy zwrócić uwagę, to stała określająca typ zda-rzenia. Zastosowanie tu pełnej ścieżki klasy pozwala uniknąć sytuacji, gdy budując dużą

Listing 5. Klasa rozszerzająca Cairngorm Event

package com.wjptak.samplelibrary.events

{

import com.adobe.cairngorm.control.CairngormEvent;

import flash.events.Event;

public class SwitchViewEvent extends CairngormEvent

{

public static const SWITCH_VIEW:String = "com.wjptak.samplelibrary.events.Switc

hView";

public var view:Number;

public function SwitchViewEvent( newView:Number )

{

super( SwitchViewEvent.SWITCH_VIEW );

view = newView;

}

override public function clone():Event

{

return new SwitchViewEvent( view );

}

}

}

Listing 6. Klasa implementująca wzorzec Command

package com.wjptak.samplelibrary.commands

{

import com.adobe.cairngorm.commands.ICommand;

import com.adobe.cairngorm.control.CairngormEvent;

import com.wjptak.samplelibrary.events.SwitchViewEvent;

import com.wjptak.samplelibrary.model.LibraryModelLocator;

public class SwitchViewCommand implements ICommand

{

public function execute(eventParam:CairngormEvent):void

{

var event:SwitchViewEvent = eventParam as SwitchViewEvent;

LibraryModelLocator.getInstance().applicatio

nState = event.view;

}

}

}

Page 60: SDJExtra_31_2008_PL

FLEX60

ADOBE FLEXCairngorm

www.sdjournal.org 61

aplikację zaczniemy duplikować nazwy ty-pów zdarzeń.

Jak już wspomniałem, potrzebna jest nam również klasa implementująca wzorzec Command. Dla pokazanego tu zdarzenia będzie ona wyglądać tak jak na Listingu 6.

Możliwe jest automatyczne stworzenie ta-kiej klasy rozgłaszającej kolejne zdarzenie po wykonaniu swojego zadania. W tym ce-lu należy zbudować ją poprzez rozszerze-nie klasy SequenceCommand. Następnie dopi-

sujemy w konstruktorze, jakie zdarzenie bę-dzie rozgłoszone i w odpowiednim miejscu metody execute() należy wykonać metodę executeNextCommand(). W tworzonym przez nas przykładzie możemy pomyśleć o rozwiąza-niu dodającym do naszej kolekcji książek nowe egzemplarze, a następnie automatycznie prze-łączającym widok (Listing 7.).

Zauważmy, że takie rozwiązanie upraszcza zaprogramowanie skomplikowanych interak-cji, gdzie musimy wykonać wiele operacji. Wy-

obraźmy sobie także inną sytuację – synchro-niczne pobieranie danych z serwera. Zastoso-wanie tego mechanizmu znacznie upraszcza naszą pracę.

Już wcześniej wspomnieliśmy o potrzebie zaprogramowania przypadków użycia komu-nikujących się z warstwami serwerowymi. Aby przybliżyć mechanizm stosowany przez Cairn-gorm, przeanalizujmy Rysunek 3.

To, co jest tu dla nas nowe to implemen-tacja wzorca Command oraz Responder. Kla-sa Business Delegate została już omówio-na – jak pamiętamy, aby wywołać żądany ser-wis, musimy do jej konstruktora przekazać re-ferencję do obiektu Respondera, odpowiadają-cego za zapis otrzymanego wyniku do nasze-go Modelu.

W związku z tym, przykładowe rozwiąza-nie wygląda następująco – najpierw przyjrzyj-my się klasie Command, znajdującej się podob-nie, jak i poprzednie w katalogu commands (Listing 8.).

Jak widzimy, rozwiązanie jest niezwy-kle przejrzyste. Przypatrzmy się więc ko-lejnej klasie, tj. Responder. W poprzednich wersjach frameworka zalecało się tworzenie dwóch rodzajów implementujących wzo-rzec Command – jednej do zwykłych wywo-łań zmiany widoku, innych wykorzystują-cych również metody Respondera służących do komunikacji poza aplikacją. We współ-czesnym podejściu rozdziela się te role, two-rząc osobną klasę. Powoduje to spójne podej-ście do klas wzorca Command. Spójrzmy więc na przykład z tworzonej przez nas aplikacji (Listing 9.).

Implementacja interfejsu IResponder wią-że się z zaprogramowaniem dwóch metod: result() oraz fault(). Nasz przykład po po-prawnym przesłaniu żądanego pliku odczytuje kolejne wpisy w nim zawarte, przy użyciu me-chanizmu E4X. Przykładowy wpis wygląda na-stępująco:

<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 prezentacjiNasza aplikacja umożliwia zarówno wprowa-dzenie danych, jak i ich wyświetlanie w postaci tabeli. Dla potrzeb tego przykładu zastosujemy komponent ViewStack. Umożliwia on proste

Listing 7. Dodawanie do biblioteki nowych książek

package com.wjptak.samplelibrary.commands

{

import com.adobe.cairngorm.commands.ICommand;

import com.adobe.cairngorm.commands.SequenceCommand;

import com.adobe.cairngorm.control.CairngormEvent;

import com.wjptak.samplelibrary.events.AddElementEvent;

import com.wjptak.samplelibrary.events.SwitchViewEvent;

import com.wjptak.samplelibrary.model.LibraryModelLocator;

import com.wjptak.samplelibrary.vo.BookVO;

public class AddElementCommand extends SequenceCommand implements ICommand

{

public function AddElementCommand()

{

this.nextEvent = new SwitchViewEvent( LibraryModelLocator.VIEW_DATA );

}

override public function execute( eventParam:CairngormEvent ):void

{

var event:AddElementEvent = eventParam as AddElementEvent;

var bookVO:BookVO = new BookVO();

bookVO.title = event.title;

bookVO.author = event.author;

bookVO.publisher = event.publisher;

bookVO.yearPublished = event.yearPublished;

LibraryModelLocator.getInstance().books.addItem( bookVO );

executeNextCommand();

}

}

}

Rysunek 3. Mechanizm zdarzeń – komunikacja z serwem

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

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

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

Page 61: SDJExtra_31_2008_PL

FLEX60

ADOBE FLEXCairngorm

www.sdjournal.org 61

przełączenie pomiędzy stanami aplikacji. Do tego w naszym modelu służą te linie:

public var applicationState:Number = 0;

publicstaticconst VIEW_DATA:Number = 0;

publicstaticconst ENTRY_DATA:Number = 1;

Stwórzmy więc komponent odpowiadający za prezentację danych. Wykorzystamy tu kilku-krotnie wcześniej wspomniany mechanizm Data Bindingu, dzięki czemu stanie się on w pełni zrozumiały. Skorzystamy również ze stworzonych wcześniej klas. Przykładowy plik MXML, view/MainView.mxml, znajduje się na Listingu 10.

Przypatrzmy się kolejnym elementom tego pliku. Do wyświetlania stanów aplikacji (wy-świetlanie lub wprowadzanie danych) służy komponent View Stack. Jedna z jego właści-wości wykorzystuje Data Binding, co możemy w kodzie MXML rozpoznać po klamrowych nawiasach {}:

selectedIndex="{model.applicationState}"

Widzimy już jak wykorzystać siłę tego roz-wiązania w połączeniu z resztą aplikacji opartej o Cairngorm. Innym ważnym ele-mentem jest komponent DataGrid , służą-cy do tabelarycznego przedstawienia kolek-cji, którą tworzyliśmy w kolejnych krokach. Przekazujemy jej, w podobny sposób referen-cję do kolekcji:

dataProvider="{model.books}"

Tworząc odpowiednie kolumny, informujemy, z jakich pól przekazanych w kolekcji obiektów mogą one odczytać swoje dane. Całość odby-wa się automatycznie, co w połączeniu z tech-nologią Data Binding znacznie przyspiesza na-szą pracę. W ekranie wyświetlającym kolekcję obiektów BookVO znajduje się również przy-cisk, którego kliknięcie powoduje wykona-nie odpowiedniej funkcji, która rozgłasza od-powiednie zdarzenie, przełączajac wyświetla-ny ekran:

new SwitchViewEvent( LibraryModelLoca

tor.ENTRY_DATA ).dispatch();

Ekran wprowadzania danych składa się z formularza, którego pola muszą pomyślnie 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-ków walidacji rozgłaszane jest odpowiednie zdarzenie, do którego przekazujemy dane z for-mularza:

new AddElementEvent( bookTitle.text,

bookAuthor.text, bookPublisher.text,

bookYearPublished.value ).dispatch();

Jak pamiętamy ze wcześniejszego przykła-du, wywołuje ono odpowiednią implemen-tację wzorca Command , która zapisuje obiekt

do kolekcji w naszym modelu, a następ-nie samoczynnie wywołuje zmianę ekranu, na ekran prezentujący dane. Komponent

Listing 8. Implementacja wzorca Command

package com.wjptak.samplelibrary.commands

{

import com.adobe.cairngorm.commands.ICommand;

import com.adobe.cairngorm.control.CairngormEvent;

import com.wjptak.samplelibrary.business.GetBasicDataDelegate;

public class GetBasicDataCommand implements ICommand

{

public function execute( eventParam:CairngormEvent ):void

{

var delegate:GetBasicDataDelegate = new GetBasicDataDelegate( new

GetBasicDataResponder() );

delegate.getData();

}

}

}

Listing 9. Implementacja wzorca Responder

package com.wjptak.samplelibrary.commands

{

import com.wjptak.samplelibrary.model.LibraryModelLocator;

import com.wjptak.samplelibrary.vo.BookVO;

import mx.controls.Alert;

import mx.rpc.IResponder;

public class GetBasicDataResponder implements IResponder

{

public function GetBasicDataResponder()

{

super();

}

public function result(data:Object):void

{

var result:XML = data.result as XML;

for each (var book:XML in result.book )

{

var bookVO:BookVO = new BookVO();

bookVO.title = book.@title;

bookVO.author = book.@author;

bookVO.publisher = book.@publisher;

bookVO.yearPublished = book.@yearPublished;

LibraryModelLocator.getInstance().books.addItem( bookVO );

}

}

public function fault(info:Object):void

{

Alert.show("Blad podczas pobierania pliku z danymi", "Blad!!");

}

}

}

Page 62: SDJExtra_31_2008_PL

FLEX62

ADOBE FLEXCairngorm

www.sdjournal.org 63

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

<mx:Canvas

xmlns:mx="http://www.adobe.com/2006/mxml"

width="640" height="480">

<mx:Script>

<![CDATA[

import com.wjptak.samplelibrary.events.AddElementEvent;

import com.wjptak.samplelibrary.events.SwitchViewEv

ent;

import com.wjptak.samplelibrary.model.LibraryModelLo

cator;

import mx.events.ValidationResultEvent;

[Bindable] private var model:LibraryModelLocator =

LibraryModelLocator.getInstance();

private function addElement():void

{

if( vTitle.validate().type == ValidationResultEven

t.VALID &&

vAuthor.validate().type == ValidationResultEven

t.VALID &&

vPublisher.validate().type == ValidationResultE

vent.VALID )

{

new AddElementEvent( bookTitle.text,

bookAuthor.text, bookPublisher.text,

bookYearPublished.value ).dispatch();

}

}

private function switchToDataEntryScreen():void

{

new SwitchViewEvent( LibraryModelLocator.ENTRY_

DATA ).dispatch();

}

]]>

</mx:Script>

<mx:StringValidator id="vTitle" source="{bookTitle}"

property="text" minLength="4"

maxLength="40" required="true" />

<mx:StringValidator id="vAuthor" source="{bookAuthor}"

property="text" minLength="4"

maxLength="40" required="true" />

<mx:StringValidator id="vPublisher"

source="{bookPublisher}" property="text"

minLength="4" maxLength="40"

required="false" />

<mx:ViewStack

selectedIndex="{model.applicationState}"

width="100%" height="100%">

<mx:Panel

title="Pozycje w bibliotece"

width="100%" height="100%">

<mx:DataGrid

dataProvider="{model.books}"

width="100%" height="100%"

sortableColumns="true">

<mx:columns>

<mx:DataGridColumn dataField="title"

headerText="Tytul" />

<mx:DataGridColumn dataField="author"

headerText="Autor" />

<mx:DataGridColumn dataField="publisher"

headerText="Wydawca" />

<mx:DataGridColumn dataField="yearPublished"

headerText="Rok wydania" />

</mx:columns>

</mx:DataGrid>

<mx:Button

label="Wprowadz pozycje"

click="switchToDataEntryScreen()" />

</mx:Panel>

<mx:Panel

title="Wprowadzanie nowej pozycji w bibliotece"

width="100%" height="100%">

<mx:Form

defaultButton="{processBtn}"

width="100%" height="100%">

<mx:FormHeading

label="Wypelnij dane i nacisnij przycisk 'Dodaj'"

textAlign="center"

width="100%"/>

<mx:FormItem

label="Tytul"

required="true">

<mx:TextInput id="bookTitle" width="150"/>

</mx:FormItem>

<mx:FormItem

label="Autor"

required="true">

<mx:TextInput id="bookAuthor" width="150"/>

</mx:FormItem>

<mx:FormItem

label="Wydawnictwo">

<mx:TextInput id="bookPublisher"

width="150"/>

</mx:FormItem>

<mx:FormItem

label="Rok wydania">

<mx:NumericStepper id="bookYearPublished"

minimum="1990" maximum="2008"

stepSize="1" />

</mx:FormItem>

<mx:FormItem>

<mx:Button id="processBtn"

label="Dodaj"

click="addElement()" />

</mx:FormItem>

</mx:Form>

</mx:Panel>

</mx:ViewStack>

</mx:Canvas>

Page 63: SDJExtra_31_2008_PL

FLEX62

ADOBE FLEXCairngorm

www.sdjournal.org 63

DataGrid automatycznie zaktualizuje wy-świetlane dane.

Główny plik aplikacjiAplikacje Flex budowane w oparciu o Cairn-gorm zakładają charakterystyczne przygoto-wanie głównego pliku aplikacji. Musimy tu zainicjalizować poszczególne elementy fra-meworka – Model Locator, Service Locator, Front Controller i główny plik widoku. W tym pliku możemy zainicjalizować rów-nież pierwsze zdarzenia jak np. pobranie da-nych początkowych.

Przykład stworzony dla opracowywanej przez nas aplikacji pozwoli zrozumieć zasady nakre-ślone przez Cairngorm. Spójrzmy na Listing 11. Model Locator inicjalizujemy poprzez:

[Bindable] private var model:

LibraryModelLocator = LibraryModelLocato

r.getInstance();

A kolejne elementy jako komponenty MXML:

<business:Services id="services" />

<control:LibraryController id="controller" />

<view:MainViewwidth="100%" height="100%" />

Aplikacja została ukończona. Możemy teraz skompilować projekt.

Dobre praktykiZasady pomagające tworzyć aplikacje w opar-ciu o Cairngorma można by mnożyć, jednak należy wymienić kilka, które na pewno okażą się przydatne.

• Nie należy używać wzorców View Helper oraz View Locator. Nie są one potrzebne, gdy poznamy pełne możliwości platformy, zostały oficjalnie usunięte z frameworka. Dodatkowo, zwiększylibyśmy znacznie narzut plików ActionScript;

• Zmiana modelu może odbyć się tylko poprzez obiekty Command i Responder. Elementy widoku powinny bąbelko-wać zdarzenia w górę, gdzie odpowied-nie funkcje wywołują odpowiadające im CairngormEventy. Złamanie tej za-sady powoduje naruszenie zasad wzorca MVC, jak i powoduje zaśmiecenie kodu aplikacji;

• Dla każdego przypadku użycia opraco-wujemy jedną klasę Command oraz jed-ną CairngormEvent. W razie potrzeby komunikacji dodajemy po jednej klasie Delegate i Responder oraz modyfikujemy odpowiednio plik Services.mxml;

• Dobrą praktyką jest używanie wzorca Factory do parsowania danych otrzyma-nych z serwera. Jest to przydatne z kilku powodów, m.in. uproszczenia pozosta-łych klas, jak i lepszego zoptymalizowania kodu pliku wzorca Factory. Odczujemy to szczególnie przy użyciu wielu różnych źródeł danych w jednej aplikacji przesyła-jących duże ilości danych;

• Tylko obiekty klas Business Delegate mają dostęp do danych w formatach po-średnich jak np. JSON, natomiast tylko Responder powinien otrzymywać wstęp-nie przygotowane dane i zamieniać je na konkretne obiekty Value Object ;

• Obiekty Command nie mogą zawierać ja-kichkolwiek implementacji komunikacji, zadanie to należy do Service Locatora i obiektów Business Delegate.

ZakończenieZapoznaliśmy się z frameworkiem Cairn-gorm, najszerzej stosowanym w środowisku Adobe Flex, rozwijanym wewnątrz tej samej firmy.

W przyszłości będzie on zapewne coraz bar-dziej zoptymalizowany, co pozwoli na dostar-czenie nowych funkcjonalności, m.in. do two-rzenia aplikacji typu Enterprise. Stosowanie tego typu rozwiązań pozwoli nam uporząd-kować nie nasz kod, ułatwi wprowadzanie ciągłych zmian, a także wspomoże równole-głą pracę wielu programistów. Polecam bliż-sze zapoznanie się z opisanym powyżej fra-meworkiem.

WOJCIECH PTAKOd 2 lat konsultant i programista Adobe Flex

oraz Adobe Integrated Runtime (AIR) (przez rok

obejmował to stanowisko w norweskiej firmie

Making Waves). Wykonał w całości m.in. aplika-

cję Kalkulator Energetyczny Vattenfall, która zo-

stała wyróżniona w międzynarodowym konkur-

sie Webby Awards 2008. Aktualnie pracuje dla

takich klientów jak Adidas, Heineken, Coca–Co-

la, Schweppes czy British Telecom, dostarczając

kompleksowe aplikacje B2B oparte o Adobe Flex

oraz AIR.

Listing 11. Tworzenie głównego pliku aplikacji

<mx:Application

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:business="com.wjptak.samplelibrary.business.*"

xmlns:control="com.wjptak.samplelibrary.control.*"

xmlns:view="com.wjptak.samplelibrary.view.*"

layout="absolute"

creationComplete="this.onCreationComplete()">

<mx:Script>

<![CDATA[

import com.wjptak.samplelibrary.events.GetBasicDataEvent;

import com.wjptak.samplelibrary.model.LibraryModelLocator;

[Bindable] private var model:LibraryModelLocator = LibraryModelLocator.getIn

stance();

private function onCreationComplete():void {

new GetBasicDataEvent().dispatch();

}

]]>

</mx:Script>

<business:Services id="services" />

<control:LibraryController id="controller" />

<view:MainView

width="100%" height="100%" />

</mx:Application>

Listing 12. Wyróżniony fragment Listingu 10.

<mx:StringValidator id="vTitle" source="{bookTitle}" property="text" minLength="4"

maxLength="40" required="true" />;

<mx:StringValidator id="vAuthor" source="{bookAuthor}" property="text" minLength="4"

maxLength="40" required="true" />;

<mx:StringValidator id="vPublisher" source="{bookPublisher}" property="text"

minLength="4" maxLength="40" required="false" />.

Page 64: SDJExtra_31_2008_PL

FLEX64

ADOBE FLEXDostęp do danych z aplikacji Flex

www.sdjournal.org 65

Budowana aplikacja zazwyczaj będzie prezentowała i modyfikowała dane z relacyjnej bazy danych (bezpośrednio

lub przez rozwiązania typu ORM (ang. Object – Relational Mapping)) lub z zewnętrznych sys-temów firmy.

Standardowo Flex SDK dostarcza trzech me-chanizmów dostępu do danych:

• HTTPService;• WebService;• Remote Object.

Pierwsze dwa mechanizmy opierają się na zwykłych wywołaniach HTTP i mogą być wykorzystane z dowolną technologią serwe-rową. Remote Object umożliwia proste i wy-dajne wywołania zdalnych metod, jednakże wymaga dodatkowego komponentu po stro-nie serwera. Komponent ten, o nazwie Ado-be LiveCycle Data Services ES (wcześniej Flex Data Services) oraz jego dodatkowe funkcjo-nalności i praktyczne zastosowanie są tema-tem poniższego artykułu.

Od strony technicznej LiveCycle Data Servi-ces jest aplikacją J2EE. Instalacja na serwerze sprowadza się do wdrożenia archiwum WAR;

po zakończeniu jesteśmy gotowi do skorzysta-nia z usług, które nam udostępnia. Podstawo-we usługi to:

• RPC Service, w której skład wchodzi Re-mote Object, czyli zestaw usług umoż-liwiających zdalne wywołania metod obiektów Javy (POJO, EJB, itp.) bezpo-średnio z Flexa;

• Messaging Service – mechanizm przesyła-nia komunikatów wraz z adapterem JMS;

• Data Management Service – alternatywny sposób dostępu do danych, opierający się na zarządzanych kolekcjach danych.

Przyjrzyjmy się bliżej mechanizmowi Remo-te Object. Najłatwiej zaprezentować to na ni-żej opisanym przykładzie. Zakładając, że Live-Cycle Data Services jest już zainstalowane (na czas tworzenia aplikacji najwygodniej jest ko-rzystać z rozpakowanego archiwum WAR; da-lej katalog instalacji będzie nazywany {LCDS_HOME}), a serwer aplikacji uruchomiony, za-cznijmy od standardowego HelloWorld – klasy Javy, która udostępni nam metodę sayHello z jednym parametrem (Listing 1.).

Aby móc wywołać tę metodę z Flexa, nie jest potrzebny żaden dodatkowy kod. Wystarczy umieścić powyższą klasę w CLASSPATH naszego serwera aplikacji i poinformować LiveCycle Da-ta Services, że będziemy chcieli z niej korzystać. W tym celu otwieramy plik konfiguracyjny {LCDS_HOME}/WEB–INF/flex/remoting–con-

fig.xml i poniżej default–channels dodajemy de-klarację punktu docelowego (destination) – Li-sting 2.

Deklaracja informuje LiveCycle Data Se-rvices, że chcemy wywoływać metody klasy hello.HelloWorld (element source) i nadajemy jej identyfikator HelloWorld (atrybut id). Ele-ment scope określa zakres dostępności obiek-tu podobnie jak znacznik <jsp:useBean> z tą różnicą, że dostępne są wartości request, session i application (bez page). Oprócz po-wyższej deklaracji po stronie serwera nie po-trzebujemy nic więcej. Spójrzmy na przykła-dową aplikację kliencką.

Tworzymy główny plik aplikacji Ma-in.mxml. Jeśli korzystamy z Flex Buildera, podczas tworzenia projektu należy zaznaczyć wykorzystanie LiveCycle Data Services jak na Rysunku 1.

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.

Dostęp do danych z aplikacji Flex

Dowiesz się...• Jak wywoływać metody obiektów Javy bezpo-

średnio z Flexa.

Adobe LiveCycle Data Services w praktyce

Powinieneś wiedzieć...• Powinieneś znać podstawy tworzenia aplikacji

w technologii Flex;

• Powinieneś znać podstawy Java Enterprise

Edition.

Poziom trudności

Page 65: SDJExtra_31_2008_PL

FLEX64

ADOBE FLEXDostęp do danych z aplikacji Flex

www.sdjournal.org 65

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

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 + "!";

}

}

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 1. Zaznaczamy LiveCycle Data Services we Flex Builder

Rysunek 2. Aplikacja po skompilowaniu i uruchomieniu

Rysunek 3. Wynik wywolania

Page 66: SDJExtra_31_2008_PL

FLEX66

ADOBE FLEX

z Flex SDK i LiveCycle Data Services. Po skompilowaniu i uruchomieniu aplikacja po-winna wyglądać tak jak na Rysunku 2.

Naciśnięcie przycisku powinno wywo-łać metodę i wyświetlić komunikat zwróco-ny przez metodę obiektu HelloWorld w Javie (Rysunek 3.).

Przyjrzyjmy się teraz szczegółom powyż-szego wywołania zdalnej metody. Gdy po stronie Flexa wywołujemy metodę na rzecz instancji klasy RemoteObject, tworzony jest obiekt mx.rpc.remoting.Operation i do je-

go metody send przekazywane są parametry pierwotnego wywołania. Następnie nazwa zdalnej metody i parametry zostają opakowa-ne w komunikat RemotingMessage i wysła-ne przez odpowiedni kanał komunikacyjny. Czym jest kanał? Jest to sposób przesyłania komunikatów, np. przez zwykły HTTP lub specjalny protokół RTMP. Definicje dostęp-nych kanałów znajdują się w pliku {LCDS_HOME}/WEB–INF/flex/services–config.xml, m.in.: kanał my–amf (Listing 6.), a w pli-ku remoting–config.xml występuje deklaracja

domyślnego kanału wykorzystywanego przy zdalnych wywołaniach (Listing 7.).

W definicji kanału znajduje się URL servle-tu, który odpowiada za odbieranie komuni-katów od klienta, wywoływanie odpowied-nich metod i serializację zwracanych wyni-ków. Tajmniczy skrót AMF oznacza Action Message Format – binarny format przekazy-wania danych, który zapewnia mały rozmiar komunikatu i bardzo szybką serializację i de-serializację obiektów. Oprócz wygody uży-cia mechanizmu Remote Object, to właśnie AMF jest jego główną zaletą, która powodu-je, że komunikacja jest znacznie wydajniej-sza niż przy użyciu XML (jak w HTTPServi-ce i WebService).

Wykorzystanie Remote Object, nie ograni-cza się do przekazywania parametrów typu String. Możliwe jest przekazywanie i zwra-canie obiektów dowolnego typu, a zasady konwersji typów między Javą i ActionScrip-tem sa określone w dokumentacji LiveCycle Data Services.

Za tworzenie instancji obiektów po stro-nie serwera odpowiada tzw. fabryka, czyli implementacja interfejsu flex.messaging.Fle-xFactory. Domyślna fabryka w LiveCycle Da-ta Services tworzy obiekty za pomocą opera-tora new. Jeśli chcemy korzystać z komponen-tów EJB lub obiektów zarządzanych przez Springa, wystarczy podać nazwę fabryki w deklaracji punktu docelowego; w kodzie fabryki znajdują się odpowiednie instruk-cje tworzenia obiektu (np. zamiast new – lo-okup lub getBean).

Na koniec warto poruszyć kwestię licen-cjonowania. Adobe LiveCycle Data Services ES jest produktem komercyjnym, dostępnym w sprzedaży u dystrybutorów Adobe. Jed-nak do mniejszych zastosowań istnieje wersja Express Edition, która oferuje pełną funkcjo-nalność z jednym ograniczeniem: może być instalowana wyłącznie na serwerach z jed-nym procesorem, gdzie dwa rdzenie liczą się jako jeden procesor. Z drugiej strony, w celu popularyzacji technologii Flex, Adobe udo-stępniło podzbiór funkcjonalności LiveCyc-le Data Services w otwartym projekcie Bla-zeDS. Używając BlazeDS koncepcja Remote Object, pozostaje taka sama, a licencja typu Open Source pozwala na zastosowanie przy budowie aplikacji dowolnej wielkości bez opłat licencyjnych.

Listing 4. Skrypt do obsługi zdarzeń związanych z wywołaniem Remote Object

<mx:Script>

<![CDATA[

import mx.controls.Alert;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;

public function success(event:ResultEvent):void

{

Alert.show(event.result.toString());

}

public function failure(event:FaultEvent):void

{

Alert.show(event.fault.faultDetail, event.fault.faultString);

}

]]>

</mx:Script>

Listing 5. Interfejs użytkownika do wywołania zdalnej metody

<mx:TextInput id="nameInput" x="10" y="10"/>

<mx:Button x="180" y="10" label="sayHello"

click="helloWorld.sayHello(nameInput.text);"/>

Listing 6. Definicja kanału my–amf w services–config.xml

<channel–definition id="my–amf" class="mx.messaging.channels.AMFChannel">

<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"

class="flex.messaging.endpoints.AMFEndpoint"/>

<properties>

<polling–enabled>false</polling–enabled>

</properties>

</channel–definition>

Listing 7.Ustawienie domyślnego kanału w remoting–config.xml

<default–channels>

<channel ref="my–amf"/>

</default–channels>

W Sieci:

• http://www.adobe.com/products/livecycle/dataservices – Adobe LiveCycle Data Services ES;• http://opensource.adobe.com/blazeds – BlazeDS;• http://www.adobe.com/devnet/flex – Flex Developer Center.

BARTŁOMIEJ SOINSpecjalista w zakresie technologii Flex i LiveCycle

w polskim oddziale Adobe. Wolny czas spędza na

aktywnym wypoczynku (kolarstwo górskie, wspi-

naczka, snowboard), zgłębianiu tajników foto-

grafii i rozpoznawaniu najnowszych technologii

internetowych.

Page 67: SDJExtra_31_2008_PL

Flex i PHP

www.sdjournal.org 67

W artykule przedstawione zostaną możliwości wykorzystania techno-logii PHP. Przedstawię dwie meto-

dy pozwalające na komunikację aplikacji Flex z serwerem PHP – Web Services i Flash Remoting.

Web ServicesW przypadku usług internetowych dane pomię-dzy klientem i serwerem przesyłane są w forma-cie XML. Dzięki temu stworzenie takich usług na serwerze nie ograniczy ich wykorzystania tyl-ko do aplikacji Flex. Większość popularnych ję-zyków programowania posiada odpowiednie bi-blioteki wspierające obsługę Web Services.

Dla języka PHP powstało kilka takich biblio-tek. Na potrzeby niniejszego artykułu przedsta-wiona zostanie jedna z nich – NuSOAP. Najwięk-szą zaletę wspomnianej biblioteki stanowi fakt, iż nie wymaga ona żadnych dodatkowych roz-szerzeń PHP. W rezultacie więc można jej uży-wać nawet na bardzo ograniczonych serwerach. Po pobraniu biblioteki i umieszczeniu jej na serwerze możemy przejść do tworzenia usługi.

W pierwszej kolejności stworzymy usłu-gę, której jedynym zadaniem jest odesłanie do klienta prostego powitania. Pierwszym etapem jest dołączenie biblioteki NuSOAP:

require_once('nusoap/nusoap.php');

Następnie należy utworzyć instancję serwe-ra SOAP:

$server = new soap_server();

Aby możliwe było wykorzystanie tworzonej usługi w aplikacji Flex, konieczne jest skonfi-gurowanie serwera tak aby generował odpo-wiedni plik WSDL (Web Services Definition Language), który jest odpowiedzialny za opi-sanie usługi:

$server–>configureWSDL( 'sample', 'http:

//localhost' );

Jako pierwszy argument metody należy podać nazwę, która będzie identyfikować opisywa-ną usługę. Drugi argument określa przestrzeń nazw, w której będą się znajdować metody udo-stępniane przez usługę. Kolejnym etapem jest utworzenie pierwszej metody. Będzie ona od-powiedzialna za odesłanie do klienta komuni-katu powitalnego (Listing 1.).

Ważną czynnością jest teraz zarejestrowanie utworzonej metody tak, by możliwe było jej udostępnienie klientom oraz wygenerowanie odpowiedniego opisu WSDL (Listing 2.).

Pierwszym argumentem jest nazwa udostęp-nianej metody – musi ona być dokładnie taka sama jak nazwa wcześniej utworzonej funk-cji. Kolejnym argumentem jest lista przyjmo-wanych parametrów. W naszym przypadku funkcja nie przyjmuje żadnych argumentów, więc jako wartość przekazujemy pustą tablicę. Analogicznie, jako wartość trzeciego argumen-tu należy podać listę zwracanych wartości okre-ślonych jako pary nazwa – typ. Przykładowa funkcja zwraca tekst, dlatego też jako typ po-dajemy xsd:string. Listę wszystkich dostęp-nych typów danych można znaleźć w specyfi-kacji protokołu SOAP. Ostatni argument okre-śla przestrzeń nazw, w jakiej znajdzie się opisy-wana metoda.

Ostatnią czynnością jest przekazanie otrzy-manego zapytania do serwera SOAP w celu wy-wołania metody:

$HTTP_RAW_POST_DATA = isset( $HTTP_RAW_POST_

DATA ) ? $HTTP_RAW_POST_DATA : '';

$server–>service( $HTTP_RAW_POST_DATA );

Mając już przygotowaną usługę interne-tową udostępniającą przygotowane meto-dy, możemy przystąpić do utworzenia aplika-cji klienta. W tym celu wykorzystamy klasę mx.rpc.soap.WebService. Tworząc instancję tej klasy, należy podać adres, pod którym jest udostępniana usługa. W naszym przypadku będzie to adres utworzonego wcześniej skryp-tu PHP.

var webService:WebService = new WebService(

"http://localhost/ws/sample.php" );

Flex i PHP

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.

Dowiesz się...• Jak za pomocą języka PHP tworzyć usługi in-

ternetowe.

• Jak w języku ActionScript tworzyć aplikacje wy-

korzystujące usługi SOAP oraz Flash Remoting.

Powinieneś wiedzieć...• Czytelnik powinien znać podstawy technolo-

gii SOAP.

• Znać podstawy języka ActionScript i PHP.

• Znać podstawy systemu obsługi zdarzeń w ję-

zyku ActionScript.

Poziom trudności

Wykorzystanie technologii Web Services i Flash Remoting do komunikacji klient – serwer

W Sieci

• NuSOAP – http://sourceforge.net/projects/nusoap/;• Programming with NuSOAP using WSDL – http://www.scottnichol.com;• AMFPHP – http://www.amfphp.org;• Flex and ActionScript with AMFPHP – http://www.sephiroth.it.

Page 68: SDJExtra_31_2008_PL

FLEX68

ADOBE FLEXFlex i PHP

www.sdjournal.org 69

Następnie należy podać adres, pod którym dostępny jest opis WSDL podanej usługi. Bi-blioteka NuSOAP generuje plik opisu automa-tycznie i jest on dostępny pod tym samym ad-resem co sama usługa. Należy jedynie dodać do niego argument wsdl:

webService.wsdl = "http://localhost/ws/

sample.php?wsdl";

Zanim możliwe będzie wywołanie metod usługi, konieczne jest wcześniejsze załadowa-nie opisu WSDL. W tym celu należy wywołać metodę loadWSDL:

webService.loadWSDL();

Ładowanie opisu usługi odbywa się asynchro-nicznie, dlatego też, aby wywołać metodę usługi zaraz po jego załadowaniu, konieczne jest zareje-strowanie metody obsługującej odpowiednie zda-rzenie:

webService.addEventListener( LoadEvent.LOAD,

onWsdlLoad );

Również wywoływanie metod udostępnia-nych przez usługę internetową odbywa się asynchronicznie. Aby wykonać kod korzystają-cy z wyniku otrzymanego po wykonaniu wywo-ływanej metody, należy ponownie skorzystać z mechanizmu obsługi zdarzeń (Listing 3.).

Na koniec wystarczy już tylko utworzyć funkcję, która zostanie wykonana w momencie otrzymania od usługi wyniku działania wywo-łanej wcześniej metody (Listing 4.).

Warto również zadbać o właściwą obsłu-gę błędów, które mogą się pojawić chociażby w przypadku wystąpienia problemów z połą-czeniem (Listing 5.).

W ten sposób udało się nam utworzyć usłu-gę internetową oraz aplikację klienta. Oczywi-ście przykład ten jest bardzo uproszczony, jed-nakże ogólny schemat postępowania pozostaje dokładnie taki sam, nawet w przypadku zdecy-dowanie bardziej złożonych aplikacji.

Dotychczas nasza usługa udostępniała tyl-ko jedną metodę, która nie wymagała podania żadnych argumentów, dlatego teraz zajmiemy się dodaniem kolejnej metody, która w wyni-ku działania będzie zwracać wartość otrzyma-ną po zsumowaniu dwóch liczb. W tym celu do utworzonego wcześniej pliku PHP dołączy-my jej implementację (Listing 6.).

Następnie, tak jak miało to miejsce w przy-padku metody welcome, musimy dokonać jej rejestracji (Listing 7.).

Ze względu na to, iż metoda sum przyjmuje dwa argumenty, musimy podać ich listę. Jest to konieczne do wygenerowania prawidłowego opisu usługi. Lista ta ma taką samą postać jak lista zwracanych wartości, jednak w tym przy-padku ich typ to xsd:int. Przejdźmy teraz do modyfikacji aplikacji klienta, tak aby wywoły-

Listing 1. Metoda zwracająca do klienta wiadomość powitalną

function welcome()

{

return "Welcome client!";

}

Listing 2. Kod odpowiedzialny za rejestrację metody zdalnej

$server–>register(

'welcome',

array(),

array( 'return' => 'xsd:string' ),

'http://localhost'

);

Listing 3. Kod odpowiedzialny za wywołanie metody welcome

function onWsdlLoad( event:LoadEvent ):void

{

webService.welcome.addEventListener( ResultEvent.RESULT, onWelcome );

webService.welcome.addEventListener( FaultEvent.FAULT, onFault );

webService.welcome();

}

Listing 4. Funkcja odpowiedzialna za odebranie wyniku działania zdalnej metody welcome

function onWelcome( event:ResultEvent ):void

{

trace( event.result.toString() );

}

Listing 5. Funkcja obsługi błędów

function onFault( event:FaultEvent ):void

{

trace( event.fault.getStackTrace() );

}

Listing 6. Metoda usługi odpowiedzialna za obliczenie sumy argumentów

function sum( $a, $b )

{

return $a + $b;

}

Listing 7. Kod odpowiedzialny za rejestrację metody zdalnej

$server–>register(

'sum',

array( 'a' => 'xsd:int', 'b' => 'xsd:int' ),

array( 'return' => 'xsd:int' ),

'http://localhost'

);]

Listing 8. Kod wywołujący zdalną metodę sum wraz z obsługą zdarzenia informującego o otrzymaniu wyniku jej wykonania

function onWsdlLoad( event:LoadEvent ):void

{

webService.sum.addEventListener( ResultEvent.RESULT, onSum );

webService.sum.addEventListener( FaultEvent.FAULT, onFault );

webService.sum( 5, 3 );

}

private function onSum( event:ResultEvent ):void

{

trace( event.result.toString() );

}

Page 69: SDJExtra_31_2008_PL

FLEX68

ADOBE FLEXFlex i PHP

www.sdjournal.org 69

wała ona nowo utworzoną metodę (Listing 8.). Jak widać poza zmianą nazwy metody, podczas

jej wywołania przekazane zostały dwie liczby. Jako wynik otrzymamy ich sumę.

Analizując przedstawione wyżej przykłady 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 RemotingFlash 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 jest w dużym stopniu oparta na wspomnianym wcześniej protokole SOAP, jednak w przypadku AMF dane przesyłane są w formie binarnej.

Tworzenie usług Flash Remoting za pomocą PHP możliwe jest dzięki bibliotece AMFPHP. Jest ona cały czas rozwijana, aktualnie trwają prace nad wersją 2.0. Po skopiowaniu plików źródłowych na serwer można przystąpić do tworzenia usług, któ-re umieszczamy w katalogu amfphp/services.

W przypadku AMFPHP usługi tworzone są w formie klas zawierających udostępniane me-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 w poprzednim przykładzie.

Na początek należy do skryptu tworzonej usługi dołączyć klasę MethodTable dostarcza-ną wraz z biblioteką AMFPHP:

include_once( AMFPHP_BASE . "shared/util/

MethodTable.php" );

Następnie tworzymy klasę, która będzie repre-zentować naszą usługę. Zawiera ona dwie me-tody, które były już wykorzystywane wcześniej (Listing 15.).

Poważną zaletą wykorzystania biblioteki AMFPHP jest to, iż nie musimy zajmować się tworzeniem opisu usługi ani nawet w żaden sposób rejestro-wać udostępnianych metod. Wszystko odbywa się automatycznie, co bardzo ułatwia pracę i pozwala uniknąć ewentualnych błędów. Dodatkowym atu-tem AMFPHP jest to, iż nie narzuca ona konieczno-ści aktualizacji informacji o udostępnianych meto-dach podczas dokonywania zmian dotyczących li-sty argumentów czy też zwracanych wartości.

Autorzy AMFPHP przygotowali również na-rzędzie ułatwiające testowanie utworzonych usług bez potrzeby tworzenia testowych apli-

Listing 15. Kod źródłowy usługi Flash Remoting wykorzystującej AMFPHP

<?php

include_once( AMFPHP_BASE . "shared/util/MethodTable.php" );

class Sample

{

function welcome()

{

return "Welcome client!";

}

function sum( $a, $b )

{

return $a + $b;

}

}

?>

Listing 9. Funkcja odpowiedzialna za odebranie wyniku wykonania zdalnej metody welcome

function onWelcomeResult( message:String ):void

{

trace( message );

}

Listing 10. Funkcja obsługi błędów

function onFault( fault:Object ):void

{

trace( “Flash Remoting error!” );

}

Listing 11. Funkcja odpowiedzialna za odebranie wyniku wykonania zdalnej metody sum

function onSumResult( result:Number ):void

{

trace( result );

}

Rysunek 1. Service Browser dostarczany wraz z biblioteką AMFPHP pozwala na szybkie testowanie tworzonych usług

Page 70: SDJExtra_31_2008_PL

FLEX70

ADOBE FLEXFlex i PHP

www.sdjournal.org 71

kacji. Service Browser przedstawia listę dostęp-nych usług oraz ich metod umożliwiając jed-nocześnie podanie argumentów i sprawdzenie wyniku działania. Narzędzie to dostępne jest w katalogu amfphp/browser/index.html i jest nie-

ocenioną pomocą w codziennej pracy (patrz: Rysunek 1.).

Tworzenie klienta usług Flash Remoting jest w pewnym stopniu podobne do tworzenia klien-tów Web Services. W tym przypadku wykorzy-

stywane są klasy flash.net.NetConnection oraz flash.net.Responder. Pierwsza z nich odpowiada za obsługę połączenia z usługą, dru-ga natomiast zajmuje się obsługą wywołania udostępnionej metody. W pierwszej kolejności

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

// File: SoapClient.as

package

{

import mx.core.Application;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;

import mx.rpc.soap.LoadEvent;

import mx.rpc.soap.WebService;

public class SoapClient extends Application

{

private var webService:WebService;

public function SoapClient()

{

super();

webService = new WebService( "http://localhost/ws/

sample.php" );

webService.wsdl = "http://localhost/ws/

sample.php?wsdl";

webService.addEventListener(

LoadEvent.LOAD, onWsdlLoad );

webService.loadWSDL();

}

private function onWsdlLoad( event:LoadEvent ):void

{

webService.welcome.addEventListener(

ResultEvent.RESULT, onWelcome );

webService.welcome.addEventListener(

FaultEvent.FAULT, onFault );

Listing 13. Kod źródłowy usługi Web Services wykorzystującej bibliotekę NuSOAP

<?php

require_once( 'nusoap/nusoap.php' );

$server = new soap_server();

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

$server–>register(

'welcome',

array(),

array('return' => 'xsd:string'),

'http://localhost');

$server–>register(

'sum',

array( 'a' => "xsd:int", 'b' => 'xsd:int' ),

array('return' => 'xsd:int'),

webService.welcome();

webService.sum.addEventListener(

ResultEvent.RESULT, onSum );

webService.sum.addEventListener( FaultEvent.FAULT,

onFault );

webService.sum( 5, 3 );

}

private function onWelcome( event:ResultEvent ):void

{

trace( event.result.toString() );

}

private function onSum( event:ResultEvent ):void

{

trace( event.result.toString() );

}

private function onFault( event:FaultEvent ):void

{

trace( event.fault.getStackTrace() );

}

}

}

<!– File: SoapClientView.mxml –>

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

<SoapClient

xmlns="*"

xmlns:mx="http://www.adobe.com/2006/mxml"

layout="absolute">

</SoapClient>

'http://localhost'

);

function welcome()

{

return "Welcome client!";

}

function sum( $a, $b )

{

return $a + $b;

}

$HTTP_RAW_POST_DATA = isset( $HTTP_RAW_POST_DATA ) ? $HTTP_

RAW_POST_DATA : '';

$server–>service( $HTTP_RAW_POST_DATA );

?>

Page 71: SDJExtra_31_2008_PL

FLEX70

ADOBE FLEXFlex i PHP

www.sdjournal.org 71

należy utworzyć instancję klasę NetConnection i nawiązać połączenie z bramą AMFPHP, która odpowiada za dostęp do usług:

var connection:NetConnection = new NetConnec

tion();

connection.connect( "http://localhost/amfphp/

gateway.php" );

Wykorzystanie Flash Remoting pozwala unik-nąć konieczności ładowania opisu usługi, dzię-ki czemu możemy przystąpić do wywoływa-nia usług.

Najpierw zajmiemy się przygotowaniem funkcji odpowiedzialnej za odebranie wyniku wykonania wywoływanej metody. Na początek zajmiemy się metodą welcome. W przypadku wykorzystania Flash Remoting funkcja ta będzie

otrzymywać wynik bezpośrednio w formie ar-gumentu (Listing 9.).

Natomiast funkcja obsługi błędów została przedstawiona na Listingu 10.

W celu wywołania metody konieczne jest utworzenie instancji klasy Responder. Odpo-wiada ona za przekazanie wyniku do odpo-wiedniej funkcji lub też poinformowania o wy-stąpieniu błędu:

var responder:Responder = new Responder( on-

WelcomeResult, onFault );

Jako pierwszy argument podajemy referencję do funkcji, która jest odpowiedzialna za ode-branie wyniku działania wywoływanej metody, natomiast drugi argument to referencja do me-tody obsługi błędu. W celu wykonania metody

zdalnej należy wykonać metodę call clasy

NetConnection.

connection.call( "Sample.welcome", responder );

Nazwa wywoływanej metody zdalnej jest prze-kazywana w formie NazwaUsługi.NazwaMetody. W przypadku wykorzystania AMFPHP nazwa usługi odnosi się do klasy, w której zdefinio-wana została wykonywana metoda. Drugi ar-gument to wcześniej utworzony obiekt odpo-wiedzialny za obsługę tego wywołania meto-dy zdalnej.

Przejdziemy teraz do drugiej metody udostęp-nianej przez naszą usługę. W jej przypadku ko-nieczne jest przekazanie dwóch argumentów, któ-re w wyniku jej działania zostaną zsumowane:

var responder:Responder = new Responder( on-

SumResult, onFault );

connection.call( "Sample.sum", responder, 4, 5 );

W tej sytuacji metoda onSumResult odpowie-dzialna za odebranie wyniku działania me-tody zdalnej będzie się różnic od metody onWelcomeResult tylko typem przyjmowane-go argumentu (Listing 11.).

PodsumowanieZapewnienie komunikacji na linii klient – ser-wer jest możliwe na wiele różnych sposobów. Jednak wykorzystanie Web Services i Flash Re-moting w dużym stopniu ułatwia i przyspiesza związane z tym prace. Warto tutaj nadmienić, iż obie technologie umożliwiają przesyłanie złożonych obiektów, zagadnienie to jednak wy-kracza poza ramy niniejszego artykułu.

W przypadku Web Service dane przesyłane są w formacie XML, co ma duży wpływ na szyb-kość i ilość przesyłanych informacji. Jednak dzięki wykorzystaniu protokołu SOAP, usługi te będą również dostępne dla aplikacji tworzo-nych w innych językach programowania.

Flash Remoting przesyła dane w formie binar-nej, co w znacznym stopniu przyspiesza trans-misję. Niestety protokół AMF ogranicza wyko-rzystanie tych usług do aplikacji utworzonych w języku ActionScript.

Listing 14. Kod źródłowy kompletnej aplikacji klienta Flash Remoting

// File: SoapClient.as

package

{

import flash.net.NetConnection;

import flash.net.Responder;

import mx.core.Application;

public class AmfClient extends Application

{

private var connection:NetConnection;

public function AmfClient()

{

connection = new NetConnection();

connection.connect( "http://localhost/amfphp/gateway.php" );

var responder:Responder = new Responder( onWelcomeResult, onFault );

connection.call( "Sample.welcome", responder );

responder = new Responder( onSumResult, onFault );

connection.call( "Sample.sum", responder, 4, 5 );

}

private function onWelcomeResult( message:String ):void

{

trace( message );

}

private function onSumResult( result:Number ):void

{

trace( result );

}

private function onFault( event:Object ):void

{

trace( "Flash Remoting error!" );

}

}

}

<!– File: AmfClientView.mxml –>

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

<AmfClient

xmlns="*"

xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

</AmfClient>

JAKUB WĘGRZYNPracuje na stanowisku Technical Unit Manager w fir-

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-

ducentów oprogramowania – BLStream i Game-

lion. Firmy wchodzące w skład grupy specjalizują się

w wytwarzaniu oprogramowania dla klientów kor-

poracyjnych, w rozwiązaniach mobilnych oraz pro-

dukcji i testowaniu gier.

Kontakt z autorem: jakub.wegrzyn@game–lion.com

Page 72: SDJExtra_31_2008_PL

FLEX72

ADOBE FLEXActionScript 3.0

www.sdjournal.org 73

Wspomniane rozwiązania zostały po raz pierwszy skatalogowane i opi-sane przez tzw. Bandę Czterech

(ang. Gang of Four, w skrócie GoF) w książ-ce Wzorce projektowe – elementy oprogramowa-nia obiektowego wielokrotnego użytku. Pozy-cja ta została wydana na polskim rynku przez wydawnictwo WNT w ramach serii Inżynieria Oprogramowania. W artykule tym przedsta-wię sposoby implementacji oraz wykorzysta-nia kilku popularnych wzorców projektowych w odniesieniu do języka ActionScript.

Warto w tym miejscu podkreślić, iż ce-lem tego artykułu nie jest dokładne przed-stawienie wszystkich opracowanych do tej pory wzorców, lecz przedstawienie pewnych przekrojowych problemów związanych z ich implementacją w języku ActionScript 3.0. W tym kontekście opisane zostaną tylko dwa popularne wzorce projektowe – Singleton oraz Metoda Wytwórcza, wraz z jednym idiomem językowym – Wyliczeniem. Osoby zaintereso-wane zgłębianiem wiedzy z tej dziedziny odsy-łam do literatury zamieszczonej w ramce.

SingletonSingelton jest to chyba jeden z najbardziej roz-powszechnionych wzorców projektowych za-proponowanych przez GoF. Duża część pro-

gramistów rozpoczyna właśnie od niego swo-ją przygodę ze wzorcami. Wykorzystuje się go w celu zagwarantowania tego, iż klasa bę-dzie posiadać tylko jeden egzemplarz. Do-datkowym zadaniem Singeltonu jest zapew-nienie globalnego dostępu do wspomniane-go egzemplarza.

Standardowa implementacja Singletonu w języku ActionScript 3 jest przedstawiona

na Listingu 1. Osoby, które miały już wcze-śniej do czynienia z tym wzorcem w innych językach programowania, zapewne zauwa-żą w przedstawionej implementacji pewien zasadniczy problem – brak zabezpieczenia przed tworzeniem wielu egzemplarzy kla-sy. Dla przykładu, w języku C++ wystarczy w tym celu zadeklarować konstruktor klasy Singleton jako prywatny lub chroniony. Jed-nak podczas prac nad językiem ActionScript 3, w celu spełnienia standardów określo-nych w specyfikacji ECMAScript, zrezygno-wano z możliwości tworzenia prywatnych konstruktorów. Na szczęście można rozwią-zać ten problem na kilka sposobów. Jednym z nich jest wykorzystanie prywatnych klas. W tym celu używa się pewnej sztuczki, po-legającej na zadeklarowaniu klasy poza zasię-

ActionScript 3.0

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.

Dowiesz się...• W jaki sposób implementować podstawowe

wzorce projektowe w języku ActionScript 3.

• Jak radzić sobie z ograniczeniami w Action-

Script 3.

Powinieneś wiedzieć...• Czytelnik powinien znać podstawy programo-

wania w języku ActionScript.

• Znać podstawowe koncepcje związane z pro-

gramowaniem zorientowanym obiektowo

(OOP – ang. Object Oriented Programming).

Poziom trudności

Podstawowe wzorce projektowe oraz idiomy kodowania.

Listing 1. Prosta implementacja wzorca Singleton w języku ActionScript

package

{

public class Singleton

{

private static var instance:Singleton;

public function Singleton()

{

// Initialization code

}

public static function getInstance():Singleton

{

if ( !instance )

{

instance = new Singleton();

}

return instance;

}

}

}

Page 73: SDJExtra_31_2008_PL

FLEX72

ADOBE FLEXActionScript 3.0

www.sdjournal.org 73

giem jakiejkolwiek przestrzeni nazw, co au-tomatycznie sprawia, że klasa ta jest dostęp-

na tylko w obrębie tego samego pliku źródło-wego (Listing 2.).

Oczywiście zaproponowane rozwiązanie może być uznane za swojego rodzaju hak lub nadużycie. Jednak z powodu braku możli-wości stosowania prywatnych konstrukto-rów konieczne jest poszukiwanie alterna-tywnych rozwiązań. W przeciwnym wypad-ku pozostaje jedynie nadzieja na to, że oso-by korzystające z tej klasy będą wiedziały, aby samodzielnie nie tworzyć egzemplarzy klasy Singleton, co należy uznać za jeszcze gorsze nadużycie.

Typy wyliczeniowe (enum)Wyliczenie jest to raczej idiom kodowania, a nie klasyczny wzorzec projektowy, jednak-że brak tej konstrukcji w języku ActionScript 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-pię się w tym miejscu na rozwiązaniu, któ-re może spełnić większość wymagań stawia-nych przez programistów chcących go wyko-rzystać w swojej codziennej pracy.

Najważniejszym problemem, z którym trzeba się zmierzyć jest zapewnienie kontro-li typu tak, aby korzystanie ze zdefiniowane-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.).

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.

Kolejny raz można zauważyć pewien pro-blem związany z wykorzystywaniem klasy reprezentującej typ wyliczeniowy niezgodnie z przeznaczeniem. Dokładniej chodzi tutaj o problem prywatnego konstruktora. W ce-lu zabezpieczenia właściwej kontroli typu konieczne jest zapewnienie tego, iż egzem-plarze tej klasy nie będą tworzone poza nią samą. Innymi słowy, chcemy mieć pewność, że jej instancje są tworzone tylko podczas ini-cjalizacji statycznych stałych identyfikują-cych wartości wyliczenia.

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-

Listing 2. Propozycja rozwiązania problemu prywatnego konstruktora za pomocą klasy zadeklarowanej poza przestrzenią nazw

package

{

public class Singleton

{

private static var instance:Singleton;

public function Singleton( blocker:SingletonBlocker )

{

if ( blocker == null )

{

throw new Error( "Cannot instantiate Singleton class!" );

}

}

public static function getInstance():Singleton

{

if ( !instance )

{

instance = new Singleton( new SingletonBlocker() );

}

return instance;

}

}

}

class SingletonBlocker

{

}

Listing 3. Przykład implementacji wyliczenia umożliwiający wykorzystanie kontroli typu

package{

public class ShapeEnum

{

public function ShapeEnum()

{

public static const TRIANGLE:ShapeEnum = new ShapeEnum();

public static const RECTANGLE:ShapeEnum = new ShapeEnum();

public static const CIRCLE:ShapeEnum = new ShapeEnum();

public function ShapeEnum()

{

}

}

}

}

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.

Page 74: SDJExtra_31_2008_PL

FLEX74

ADOBE FLEXActionScript 3.0

www.sdjournal.org 75

niona na zewnątrz klasy, ale już po inicjalizacji jej statycznych pól.

Dodatkowym elementem ułatwiającym korzy-stanie z wyliczenia będzie przeciążenie metody

Object.toString, co ułatwi kontrolę wartości wyliczenia za pomocą funkcji trace (Listing 5.).

Powyższy przykład wykorzystuje statycz-ny inicjalizator do zmiany wartości pola loc-

ked na true tuż po zainicjalizowaniu wszyst-kich pól statycznych, co uniemożliwi wyko-rzystanie klasy ShapeEnum poza przewidzia-nym zakresem.

Zaprezentowana realizacja typu wyliczenio-wego w ActionScript 3 na pewno nie jest ideal-na. Jedną z jej wad jest konieczność tworzenia klasy dla każdego wyliczenia. Ponadto nie ofe-ruje ona możliwości iterowania po kolejnych wartościach, tak jak ma to miejsce w innych ję-zykach programowania. Jednak zapewnienie silnej kontroli typu może być wystarczającym argumentem przemawiającym za wykorzysta-niem tego rozwiązania.

Metoda Wytwórcza (ang. Factory Method)Jest to jeden z najprostszych wzorców pro-jektowych. Metoda wytwórcza odpowiada za 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 implementacji tego interfejsu.

Na początek konieczne jest określenie in-terfejsu produktu metody wytwórczej (Li-sting 6.). Następnie należy zdefiniować kla-sy implementujące ten interfejs (Listing 7.). Oczywiście jest to tylko mocno uproszczo-ny kod mający za zadanie ułatwienie zrozu-mienia specyfiki korzystania z metody wy-twórczej.

Listing 4. Przykład wykorzystania przedstawionej implementacji wyliczenia

function drawShape( shape:ShapeEnum ):void

{

switch ( shape )

{

case ShapeEnum.TRIANGLE:

// Draw triangle

break;

case ShapeEnum.RECTANGLE:

// Draw rectangle

break;

case ShapeEnum.CIRCLE:

// Draw circle

break;

}

}

Listing 5. Poprawiona implementacja wyliczenia wykorzystująca statyczny inicjalizator

package

{

public class ShapeEnum

{

public function ShapeEnum()

{

public static const TRIANGLE:ShapeEnum = new ShapeEnum( “Triangle” );

public static const RECTANGLE:ShapeEnum = new ShapeEnum( “Rectangle” );

public static const CIRCLE:ShapeEnum = new ShapeEnum( “Circle” );

private static var locked:Boolean = false;

{

locked = true;

}

private var _name:String;

public function ShapeEnum( name:String )

{

if ( locked )

{

throw new Error( "Cannot instantiate ShapeEnum class!" );

}

_name = name;

}

public override function toString():String

{

return “ShapeEnum.” + _name;

}

}

}

}

Listing 6. Przykładowy interfejs produktu metody wytwórczej

interface Ishape

{

function draw():void;

}

Listing 7. Definicje klas implementujących interfejs produktu metody wytwórczej

// File: Triangle.as

class Triangle implements Ishape

{

public function draw():void

{

// Draw triangle

}

}

// File: Rectangle.as

class Rectangle implements Ishape

{

public function draw():void

{

// Draw rectangle

}

}

// File: Circle.as

class Circle implements Ishape

{

public function draw():void

{

// Draw circle

}

}

Page 75: SDJExtra_31_2008_PL

FLEX74

ADOBE FLEXActionScript 3.0

www.sdjournal.org 75

W artykule przedstawimy odmianę wzor-ca nazywaną Sparametryzowaną Metodą Wy-twórczą. Główna zasada jej działania pole-ga na utworzeniu metody przyjmującej jako argument wartość pozwalającą zidentyfiko-wać metodzie wytwórczej typ obiektu oczeki-wanego jako produkt. Oczywiście metoda wy-twórcza może podejmować decyzję o wyborze konkretnej implementacji produktu na pod-stawie dowolnych danych przewidzianych przez programistę. W przykładzie zostanie wykorzystany typ wyliczeniowy przedstawio-ny w poprzedniej części artykułu (Listing 8.).

Zaproponowana implementacja wzorca jest oczywiście prosta i ma jedynie wartość czysto merytoryczną. Warto jednak zauwa-żyć, że jej stosowanie pozwala na tworzenie obiektów, których inicjalizacja wymaga wy-konania większej ilości operacji w celu cho-ciażby przygotowania dużej ilości danych.

Warto również zauważyć, że możliwe jest rozszerzenie przedstawionej klasy w celu umożliwienia tworzenia dodatkowych obiek-tów. Przedstawia to Listing 9.

Metoda wytwórcza jest popularnym wzor-cem, który często jest wykorzystywany bez

świadomości jego istnienia. Jego stosowa-nie może być po prostu wynikiem własnych przemyśleń. Jednak faktem jest, że wzorzec ten jest bardzo praktyczny, a jednocześnie dzięki swojej prostocie jego użycie nie spra-wia większym problemów i nie wprowadza dodatkowych ograniczeń. Podobnym wzor-cem jest Fabryka Abstrakcyjna (ang. Abstract Factory), który zapewnia interfejs odpowie-dzialny za tworzenie rodzin powiązanych ze sobą obiektów bez znajomości ich konkret-nych implementacji. Jednak opis tego wzor-ca wykracza poza łamy niniejszego artykułu, dlatego też zachęcam do zapoznania się z lite-raturą opisującą wzorce projektowe.

PodsumowanieWzorce projektowe są nieocenionym na-rzędziem każdego programisty. Pomagają w szybkim projektowaniu i tworzeniu opro-gramowania, co w oczywisty sposób wpisuje się w ideę RIA. Wzorce ułatwiają też komu-nikację pomiędzy programistami (na przy-kład, posługując się ustandaryzowanym ję-zykiem wzorców projektowych łatwiej pro-wadzić dyskusję o architekturze danego roz-wiązania). Niestety, język ActionScript 3.0 w pewnych kwestiach utrudnia ich imple-mentację, wymuszając w ten sposób stoso-wanie sztuczek, które nie są powszechnie znane.

Podobnie sytuacja wygląda w przypadku braku pewnych idiomów językowych, któ-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ń czasowych.

W przedstawionym artykule podałem ze-staw gotowych rozwiązań nawiązujących do popularnych wzorców projektowych i idio-mów kodowania. Mam nadzieję, że rozwią-zania te pozwolą zaoszczędzić cenny czas czytelników tworzących projekty w Action-Script 3.

Listing 8. Implementacja metody wytwórczej wykorzystując typ wyliczeniowy

class ShapeCreator

{

public function createShape( type:ShapeEnum ):Ishape

{

switch ( shape )

{

case ShapeEnum.TRIANGLE:

return new Triangle();

break;

case ShapeEnum.RECTANGLE:

return new Rectangle();

break;

case ShapeEnum.CIRCLE:

return new Circle();

break;

default:

throw new Error( “Unknown shape!” );

break;

}

}

}

Listing 9. Rozszerzenie metody wytwórczej o nowy produkt

class AdvancedShapeCreator extends ShapeCreator

{

public function createShape( type:ShapeEnum ):Ishape

{

if ( type == ShapeEnum.STAR )

{

return new Star();

}

else

{

return super.createShape( type );

}

}

}

W Sieci

• ActionScript 3 Design Patterns – http://www.as3dp.com/;• Introduction to Design Patterns – http://www.moock.org/lectures/introToPatterns/;• Enums and ActionScript's Static Initializers – http://www.barneyb.com/barneyblog/;• AS3: Singletons – http://www.gskinner.com/blog/;• ActionScript 3 Singleton Redux – http://www.darronschall.com/weblog/.

JAKUB WĘGRZYNPracuje 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-

wania – BLStream i Gamelion. Firmy wchodzą-

ce w skład grupy specjalizują się w wytwarzaniu

oprogramowania dla klientów korporacyjnych,

w rozwiązaniach mobilnych oraz produkcji i te-

stowaniu gier.

Kontakt z autorem:

jakub.wegrzyn@game–lion.com

Page 76: SDJExtra_31_2008_PL

TIPS & TRICKS

76 FLEX

TIPS & TRICKS

77www.sdjournal.org

Chciałbym odtworzyć plik MP3 we Flex. Jak to zrobić?Do odtwarzania dźwięków, wykorzystujemy klasę Sound w połączeniu z URLRequest. Przykładowo:

Możemy także podać funkcji play() parametry takie jak miejsce, od które-go ma zacząć odtwarzać (w milisekundach) lub ilość powtórzeń:

Mam tablicę zawierającą kilka rekordów, gdzie każdy z nich po-siada dane takie jak imię, nazwisko czy datę urodzenia. Chciał-bym je wyświetlać jako listę, a nie siatkę. Czy jest to możliwe?Oczywiście, Wystarczy użyć komponentu List (lub HorizontalList je-śli wolimy) i ustawić mu własność itemRenderer.

Następnie tworzymy nowy komponent, w którym ustalamy sposób wy-świetlania naszych danych:

Renderer może być edytowany graficznie, więc ułatwia to nam jego pro-jektowanie.

Jak obliczyć ilość dni pomiędzy zaznaczonymi datami w kontrolce DateChooser?Kontrolka DateChooser poza zaznaczeniem jednej daty, pozwala zaznaczyć jeden lub więcej przedziałów dni. Dostęp do tych informacji mamy poprzez

własność selectedRanges, która jest tablicą obiektów zawierających dane rangeStart oraz rangeEnd, na podstawie których można łatwo obliczyć różnicę dni za pomocą ActionScript.

W jaki sposób formatować daty w kontrolce DateField?Do formatowania dat Flex posiada klasę DateFormatter, którą można użyć za pomocą małej funkcji przypisanej jako labelFunction:

Jak zrobić aby zamienić kolorowy obrazek w czarno-biały?Do tego celu musimy użyć filtru ColorMatrixFilter i odpowiedniej ma-trycy kolorów:

var snd:Sound = new Sound(new URLRequest("muzyka.mp3"));

snd.play();

// Stała zawierająca ilość milisekund w jednym dniu

private const MS_PER_DAY:uint = 1000 * 60 * 60 * 24;

// Parametem jest jeden z obiektów

tablicy selectedRanges

private function calculateDays(item:Object):String {

var tempDate:Date = new Date(item.rangeEnd – item.rangeStart);

return Math.round((tempDate.time / MS_PER_DAY) +

1).toString();

}

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

<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"

width="100%" height="40">

<mx:Label text="{data.name}" x="5" y="0" />

<mx:Label text="{data.surname}" x="5" y="15" />

<mx:Label text="{data.birthdate}" x="5" y="30" />

</mx:Canvas>

snd.play(1000, 3); // Odtwórz od pierwszej sekundy trzy razy

<mx:List itemRenderer="MyItemRenderer" x="0" y="0" width="300"

height="300">

<mx:dataProvider>

<mx:Array>

<mx:Object name="Jan" surname="Kowalski" birthdate="1-2-1950" />

<mx:Object name="Adam" surname="Marek" birthdate="4-7-1968" />

<mx:Object name="Marcin" surname="Iksiński" birthdate="8-12-

1989" />

</mx:Array>

</mx:dataProvider>

</mx:List>

<mx:Script>

<![CDATA[

private var rLum:Number = 0.2225;

private var gLum:Number = 0.7169;

private var bLum:Number = 0.0606;

[Bindable]

private var bwMatrix:Array =

[rLum, gLum, bLum, 0, 0, rLum,

gLum, bLum, 0, 0, rLum, gLum,

bLum, 0, 0, 0, 0, 0, 1, 0];

[Bindable]

[Embed('obrazek.jpg')]

private var image:Class;

]]> </mx:Script>

<mx:ColorMatrixFilter id="cmf" matrix="{bwMatrix}" />

<mx:Image source="{image}" filters="{[cmf]}" />

Flex Tips & Tricks

<mx:Script>

<![CDATA[

private function doLabel(item:Date):String {

return dateFormatter.format(item);

}

]]>

</mx:Script>

<mx:DateFormatter id="dateFormatter" formatString="D MMM YYYY"/>

<mx:DateField labelFunction="doLabel" />

Page 77: SDJExtra_31_2008_PL

TIPS & TRICKS

76 FLEX

TIPS & TRICKS

77www.sdjournal.org

Polecam poczytać o tym filtrze oraz pobawić się z wartościami matrycy. Daje to czasami ciekawe rezultaty.

Jak wyświetlić dane XML wewnątrz komponentu DataGrid?Obsługa XML jest bardzo prosta we Flex. Wystarczy użyć klasy XML oraz XMLListCollection w połączeniu z DataGrid.Mając przykładowy plik XML "dane.xml":

Wystarczy poniższy kod:

Czy mogę zmienić czas po jakim znika podpowiedź (ToolTip)?Tak. Wystarczy użyć klasy ToolTipManager:

Jak ustawić ikonę w przycisku?Ustawienie ikony wymaga poprzedniego je osadzenia w aplikacji lub za-ładowania jej z zewnątrz. Osadzić ją możemy na dwa sposoby: poprzez ActionScript lub MXML według kodów poniżej.

W jaki sposób wyświetlić okno dialogowe z przyciskami Tak i Nie?Flex udostępnia klasę Alert, która może być zastosowana do tego celu:

Niestety przyciski są w języku angielskim, więc jeśli chcemy mieć je po polsku, musimy stworzyć własne okno dialogowe.

Jak zmienić format podpowiedzi w kontrolce Slider?Do tego celu musimy ustawić własność dataTipFormatFunction na na-szą funkcję:

<mx:Script>

<![CDATA[

import mx.managers.ToolTipManager;

ToolTipManager.hideDelay = 2500;

]]>

</mx:Script>

<mx:Button id="button" label="Najedź na mnie" toolTip="Jestem

podpowiedzią która zniknie po 2,5s." />

<mx:Script>

<![CDATA[

[Bindable]

[Embed(source="ikona.png")]

private var Icon:Class;

]]>

</mx:Script>

<mx:Button label="[Embed(source='ikona.png')]" icon="{Icon}" />

<mx:Button label="@Embed('ikona.png')" icon="@Embed('ikona.png

')" />

<mx:Script>

<![CDATA[

import mx.controls.Alert;

private var alert:Alert;

private function showAlert():void {

var text:String = "Czy na pewno chcesz wykonać tą jakże

ważną akcję?";

var title:String = "Tytuł okienka";

alert = Alert.show(text, title, Alert.YES | Alert.NO);

}

]]>

</mx:Script>

<mx:Button label="Alert.show()" click="showAlert();" />

<mx:XML id="myXML" source="dane.xml" />

<mx:XMLListCollection id="myXMLList" source="{myXML.osoba}" />

<mx:DataGrid id="dataGrid" dataProvider="{myXMLList}"

width="100%" rowCount=

"{myXMLList.length + 1}">

<mx:columns>

<mx:DataGridColumn id="nameCol" dataField="name"

headerText="Imie" />

<mx:DataGridColumn id="surnameCol" dataField="surname"

headerText="Nazwisko" />

<mx:DataGridColumn

id="birthdateCol" dataField="birthdate" headerText="Data

urodzenia" />

</mx:columns>

</mx:DataGrid>

<mx:Script>

<![CDATA[

private function formatFunction(item:Object):String {

return "Minimalna cena: " + item.toString() + "zł";

}

]]>

</mx:Script>

<mx:HSlider id="slider" width="200" liveDragging="true"

minimum="1" snapInterval="1"

tickInterval="1" value="3" dataTipFormat

Function="formatFunction" />

<mx:Label id="lbl" text="{slider.value}" />

Więcej przykładów w języku angielskim, można znaleźć na: http://blog.flexexamples.com/

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

<osoby>

<osoba>

<name>Jan</name>

<surname>Kowalski</surname>

<birthdate>1-2-1950</birthdate>

</osoba>

<osoba>

<name>Adam</name>

<surname>Marek</surname>

<birthdate>4-7-1968</birthdate>

</osoba>

<osoba>

<name>Marcin</name>

<surname>Iksiński</surname>

<birthdate>8-12-1989</birthdate>

</osoba>

</osoby>

Page 78: SDJExtra_31_2008_PL

Wywiad

FLEX78

wypracowało nam metody wdrażania tych aplikacji. Było to coś, z czym musieliśmy uporać się dawno temu, ale nie mieliśmy ty-le zasobów ile byśmy sobie życzyli jako fir-ma, dlatego połączyliśmy się z Adobe, co spowodowało znaczne zwiększenie możli-wości zespołu. Adobe wykonywał podob-ną pracę z PDF, firma posiada know-how. In-tegracja z Adobe była znakomitym momen-tem na rozpoczęcie pracy nad AIR.

SDJ: Jakie ograniczenia technologiczne przeglądarki musieliście rozważyć?MC: Jeśli spojrzeć szczególnie na dwa ostat-nie lata, można zauważyć niesamowitą eks-plozję aplikacji internetowych i aplikacji wdrażanych na przeglądarki. Jest wiele po-wodów takich wdrożeń. Przeglądarki trochę dojrzały, także typ interakcji oferowany przez AJAX okazał się niesamowicie prosty we wdrażaniu aplikacji internetowych, do któ-rych użytkownicy mogą uzyskać dostęp wła-ściwie zewsząd. Są też ograniczania, ponie-waż aplikacje są uruchamiane w przeglądar-ce z wieloma różnymi dodatkowymi, wbu-dowanymi wtyczkami. Jeśli przypadkowo zamkniesz przeglądarkę, stracisz połączenie z aplikacją. Przeszkadza to, bo nie możesz prowadzić tego typu interakcji jaką prowa-dzisz z innymi aplikacjami. Np. nie możesz chwycić i przeciągnąć elementu z desktopu do przeglądarki. Przeglądarka jest jak pudeł-ko i nie ma zbyt dużego dostępu do twojego systemu plików. AIR stara się korzystać w jak najlepszy sposób z tych dwóch światów. Bu-dujemy to środowisko na szczycie interne-towych technologii. Jest to w miarę prosty proces w sferze projektowania aplikacji i jej wdrażania, ale jednocześnie, zbliżamy się do integracji z pulpitem. Dzięki temu użytkow-nik może wchodzić w interakcję z aplikacją w taki sposób, jakby pracował w regularnym programie. Nie oznacza to oczywiście śmier-ci przeglądarek internetowych. Jest wiele po-wodów i sytuacji, w których chcemy używać zwykłej przeglądarki internetowej, jeśli jed-

nak chcesz być bliżej użytkownika, wtedy Adobe AIR jest tym czego warto szukać.

SDJ: Jak wyglądają plany na rozwój AIR?MC: Obecnie jesteśmy na etapie angloję-zycznej wersji AIR 1.0. Pracę nad kolejną wer-sją rozpoczęliśmy w lutym i zbliżamy się do wydania AIR 1.1. Automatycznie zaoferuje-my wsparcie dla 10 języków. Następnie zaj-miemy się pracą nad następną pełną wer-sją środowiska. W międzyczasie wprowadzi-my wersję dla Linuxa, integrację odtwarza-cza Flash 10 i inne rzeczy.

SDJ: Możesz nam opowiedzieć trochę wię-cej o przyszłości Flasha?MC: Na razie wydaliśmy on-line wersję beta Flash 10. Jest w niej wiele rożnych, świetnych rozwiązań, takich jak wsparcie dla sprzęto-wej akceleracji 3D i całkiem nowy silnik tek-stu - obecny ma bardzo ograniczone możli-wości edycyjne. Dysponujemy również pro-jektem o nazwie Pixel Bender (formalnie: Hy-dra), który pozwala użytkownikowi na budo-wanie własnych bitmapowych filtrów tak, aby mógł je uruchomić natywnie w odtwa-rzaczu Flash. To tylko niektóre z rozwiązań. Jest oczywiście jeszcze wiele innych udo-godnień, na razie jesteśmy na etapie wersji beta, tak więc praca wre.

SDJ: Wszystkie te rozwiązania wdraża-ne w odtwarzacz Flash 10 będą dostępne także dla AIR?MC: Zdecydowanie tak. Jądro AIR zbudowane jest na odtwarzaczu Flash, tak więc zsynchro-nizujemy te rozwiązania w następnej wersji po AIR 1.1. Będzie ona miała całkowite wspar-cie dla wszystkich rozwiązań Flasha 10. Oczy-wiście wyposażymy ją także w inne technolo-gie. To samo zrobimy z WebKit'em. Wykona-my update wersji WebKit, którą mamy w Ado-be AIR i otrzyma ona wszystkie te świetne rze-czy, które pojawią się już niedługo.

SDJ: Mike, dziękuję za wywiad.

Mike Chambers dla SDJ ExtraMagazyn 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 Product Manager Developer Relations Flash Platform

SDJ: Cześć Mike, mógłbyś opowiedzieć nam trochę o sobie, swoim doświadcze-niu? W jaki sposób rozpocząłeś swoją pra-cę w Adobe?MC: Nazywam się Mike Chambers i pracuję dla Adobe. Jestem Głównym Kierownikiem Projektu odpowiedzialnym za relacje pomię-dzy deweloperami. Jest to dosyć tajemnicza nazwa stanowiska, ale właściwie to pracuję nad odtwarzaczem Flash i zespołami odpo-wiedzialnymi za środowisko AIR. Dbam o do-bre stosunki i przepływ informacji pomiędzy nami i deweloperami. Pracuję dla Adobe od około 8 lat. Pierwotnie związany byłem z Ma-cromedią i zostałem zatrudniony z powodu mojej pracy nad Generatorem. Obecnie jest to już stary produkt i trudno go gdziekolwiek znaleźć, ale używałem go często w przypad-ku Flasha i wdrażaniu rozwiązań Java. W ta-ki oto sposób związałem się z Macromedią, a dzisiaj Adobe.

SDJ: W jakich okolicznościach pojawił się AIR?MC: Idea Flasha jako aplikacji desktopo-wej jest czymś, co zaprzątało moją głowę już podczas pracy w Macromedii i przero-dziło się w projekt nazywany Macromedia Central. Było to trzy lata temu. Właściwie to pracowałem z zespołem, który w tym cza-sie przeprowadził pierwszą próbę zaimple-mentowania Flasha na pulpit. Nie odnieśli-śmy wtedy sukcesu z wielu różnych powo-dów, ale najważniejsze jest to, że wynieśli-śmy z tego projektu solidny kawał wiedzy i doświadczenia. Zdaliśmy sobie sprawę z tego, że odtwarzacz Flash nie był wystar-czająco szybki jak na nasze potrzeby. Mu-sieliśmy więc go przyśpieszyć, spowodowa-ło to wydanie Flasha 9 i ActionScript 3 oraz

Page 79: SDJExtra_31_2008_PL
Page 80: SDJExtra_31_2008_PL

v

Kontakt 1. Telefon+48 22 427 36 53+48 22 427 36 79

2. Fax+48 22 244 24 59

2. [email protected]

3. AdresBokserska 102-682 WarszawaPolska

Roczna prenumerata

tylko180

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.

,-

Page 81: SDJExtra_31_2008_PL

v 1

Zamówienie prenumeraty

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

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

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

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

Telefon ............................................................................................

E–mail .............................................................................................

ID kontrahenta ................................................................................

Numer NIP firmy .............................................................................

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

Prosimy wypełniać czytelnie i przesyłać faksem na numer: 00 48 22 244 24 59lub listownie na adres: Software-Wydawnictwo Sp. z o. o.ul. Bokserska 102-682 WarszawaPolskaE-Mail: [email protected] też zamównienia telefoniczne:0048 22 427 36 530048 22 427 36 79

Jeżeli chcesz zapłacić kartą kredytową, wejdź na stronę naszego sklepu internetowego www.buyitpress.com.

Prenumerujesz – zyskujeszl oszczędność pieniędzy l szybka dostawa l prezentyl bezpieczna płatność on–line

TytułIlość

nume-rów

Ilość zama-

wianych prenume-

rat

Od numeru pisma

lub mie-siąca

Cena

Software Developer’sJournal (1 płyta CD) – dawniej Software 2.0

12 180*/250PLN

□ automatyczne przedłużenie prenumeraty

* cena prenumeraty rocznej dla osób prywatnych

Zadzwoń+48 22 427 36 79

lubzamów

mailowo!

Page 82: SDJExtra_31_2008_PL
Page 83: SDJExtra_31_2008_PL
Page 84: SDJExtra_31_2008_PL