P. 1
SDJ_11_2008_PL_E-Commerce

SDJ_11_2008_PL_E-Commerce

|Views: 8,113|Likes:
Wydawca: Jerzy Wach

More info:

Published by: Jerzy Wach on Dec 05, 2010
Prawo autorskie:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as PDF, TXT or read online from Scribd
See more
See less

07/10/2013

pdf

text

original

11/2008 (167

)

SPIS TREŚCI
06 AKTUALNOŚCI
Rafał Kocisz

PROGRAMOWANIE PHP
32 Opensource-owe platformy blogowe
Lech Albrzykowski Lech opisuje jak w przeciągu ostatnich lat blogi internetowe zjednały sobie wielką popularność wśród użytkowników internetu. Przestały być tylko i wyłącznie formą pamiętników a stały się miejscem wymiany zdań pomiędzy różnymi środowiskami jak choćby programistów.

12 OPIS CD

BIBLIOTEKA MIESIĄCA
14 Jericho HTML
David de Rosier David opisuje Jericho jako prostą, lekką i darmową bibliotekę użyteczną dla wszystkich programistów Java przetwarzających bądź generujących kod HTML. Jericho dostarcza klasy umożliwiające analizę i przekształcanie istniejących dokumentów HTML bądź też generowanie nowych. Wszystko z użyciem minimalnego nakładu pracy ze strony programisty.

TESTOWANIE OPROGRAMOWANIA
36 SAP GUI Scripting API
Roman Gryzowski Roman opisuje że SAP GUI Scripting API to interfejs pozwalający na emulowanie każdej czynności jaką może wykonać użytkownik w środowisku SAP GUI. Dzięki jego użyciu można zautomatyzować czynności powtarzalne, ale również uzyskać dostęp do SAP GUI z poziomu innych aplikacji, np. Windows Scripting Host.

ECOMMERCE
20 Sklep internetowy w PHP i SQLite
Grzegorz Hibner Zdaniem Grzegorza gotowych rozwiązań na rynku e-commerce są setki. Znajdziemy gotowe skrypty o funkcjonalności systemów aukcyjnych, sklepów internetowych oraz systemów barterowych. To najczęściej sprawdzone i tanie rozwiązania, regularnie aktualizowane – dlatego skorzystanie z nich najczęściej bywa bardzo kuszące. Jednak czy zawsze uzasadnione? Najczęściej o wiele lepiej stworzyć własną platformę e-commerce. Nie jest to trudne – zajmie to 60 minut.

40 IBM Rational Data Architect – pierwsze kroki
Szymon Gruszewski Wyobraźmy sobie sytuację, w której musimy stworzyć oprogramowanie dla biblioteki. Chcąc wywiązać się z zadania musimy zaprojektować system, który będzie spełniał wymagania stawiane przez naszego zleceniodawcę. Z pomocą przychodzi nam Rational Data Architect, który jest narzędziem służącym do tworzenia zarówno prostych, jak i bardzo złożonych modeli bazodanowych.

28 Wydajny, elastyczny i przyjazny CMS
Krystian Rajski Krystian napisał że Textpattern nie jest tak popularny jak np. Joomla. Nie posiada tak rozbudowanej listy plugin'ów i dodatków. Mniej znany, nie oznacza jednak gorszy czy też mniej wydajny. Stanowi ciekawą alternatywę i chociażby tylko ze względu na to warto poszerzyć horyzonty i przyjrzeć się rozwiązaniu bliżej. Niniejszy artykuł pełni rolę wprowadzenia.

44 Bezpieczne partycjonowanie – systemy wielordzeniowe QNX
Kerry Johnson, Romain Saha Autorzy opisują że w dzisiejszych czasach praktycznie każdy wbudowany system podłączony jest fizycznie lub bezprzewodowo to świata zewnętrznego. Taka łączność sieciowa pozwala użytkow-

Miesięcznik Software Developer’s Journal (12 numerów w roku) jest wydawany przez Software-Wydawnictwo Sp. z o.o. Dyrektor wydawniczy: Sylwia Małecka Junior Market Manager: Anna Adamczyk Senior Product Manager: Katarzyna Juszczyńska Redaktor naczelny: Iwona Chwedoruk iwona.chwedoruk@software.com.pl Kierownik produkcji: Marta Kurpiewska marta.kurpiewska@software.com.pl Projekt okładki: Agnieszka Marchocka Skład i łamanie: Monika Grotkowska monika.grotkowska@software.com.pl Wyróżnieni betatesterzy: Ł. Lechert, S. Nieszwiec, R. Zacharczyk Nakład: 6 000 egz.

Le périodique hakin9 est publié par Adres korespondencyjny: Software-Wydawnictwo Sp. z o.o. o.o., Bokserska, 02-682 Varsovie, Pologne ul. Bokserska 1, 02-682 Warszawa, Polska Tél.+48 22 427 36 86, fax +48 2222 887 10 11 tel. +48 22 887 10 10, Fax. +48 427 36 69 www.phpsolmag.org cooperation@software.com.pl Directeur de la publication : Jarosław Szumski Dział reklamy: adv@software.com.pl Prenumerata: Marzena Dmowska pren@software.com.pl, Imprimerie, photogravure : 101 Studio, Firma Tęgi tel. +48 22 427 36 79; +48 22 427 Ekonomiczna 30/36, 93-426 Łódź 36 53 Imprimé en Pologne/Printed in Poland Dołączoną do magazynu płytę CD przetestowano programem AntiVirenKit firmy G DATA Software Sp. métropolitaine, DOM/TOM) : 1 an Abonnement (France z o.o. (soit 6 numéros) 38 € 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 Dépôt légal : à parution za efekty wykorzystania ich; nie gwarantuje także poprawnego działania programów ISSN : 1731-7037 shareware, : MLP Distribution freeware i public domain. 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 Uszkodzone podczas wysyłki płyty wymienia redakcja.

4

11/2008

nikom na zdalne monitorowanie i sterowanie oraz umożliwia systemom pobieranie nowych programów i treści wtedy, kiedy jest to konieczne.

ki z takich reklam są jednak stosunkowo niewielkie, stąd istnieje zapotrzebowanie na inne formy reklamy. Gwarantowany zarobek oferuje nowy wchodzący do Polski LinkLift.

48 Joomla 1.5 – nowości
Stefan Wajda Nowe wydanie Joomla! zapewnia użytkownikom i projektantom wygodny i łatwy w użyciu szkielet publikacji treści w witrynach internetowych wszelkiego typu. Stworzenie doskonałej witryny ze wszystkimi funkcjami, jakie sobie wymarzysz, może wymagać czasu i zaangażowania. Ale ze społecznością Joomla!, wsparciem projektantów oraz dzięki licznym rozszerzeniom tworzonym dla Joomla! 1.5, jest to jak najbardziej możliwe. Możesz również tworzyć własne rozszerzenia i udostępniać je ku uciesze całej społeczności.

NARZĘDZIA PROGRAMISTYCZNE
60 Plugin – wielokrotne wykorzystanie sprawdzonych narzędzi
Piotr Plenik Tworzenie aplikacji, składa się zarówno z tych bardziej twórczych, jak i bardziej odtwórczych prac. Mimo wszelkich naszych starań tworzenia wedle zasady DRY (z ang. DRY – Don't Repeat Yourself ), zdarza się, że dla tej samej funkcjonalności powielamy i dostosowujemy ten sam kod na wielu różnych elementach aplikacji lub pomiędzy różnymi aplikacjami. Na początek zaprezentujemy najczęściej wykorzystywane pluginy w Symfony, których jest w chwili obecnej ponad 200. Następnie stworzymy prosty dodatek do wysyłania maila w symfony bez dodatkowego nakładu naszej pracy.

XML
52 Spring 2 Schema – własne przestrzenie nazw w Spring 2.x
Henryk Konsek Osoby intensywnie wykorzystujące Springa w swoich aplikacjach często narzekają na ogrom konfiguracji XML koniecznej do utworzenia aplikacji o większym stopniu zaawansowania. Autorzy Spring Framework pisząc o dobrym oprogramowaniu promują zasadę DRY (Don't Repeat Yourself ) – wyraźnie widać to w mechanizmie rozszerzania konfiguracji XML kontenera Springa. Ten artykuł wprowadzi Cię szybko w podstawowe techniki tworzenia własnych przestrzeni nazw XML Schema dla plików konfiguracyjnych Spring IOC.

PROGRAMOWANIE URZĄDZEŃ MOBILNYCH
64 Programowanie gier dla Symbian OS – budujemy grę!
Rafał Kocisz W poprzednim, pierwszym odcinku z serii „Programowanie gier dla Symbian OS” Mieliśmy okazję przebrnąć przez gąszcz stosunkowo zawiłych i miejscami mało interesujących szczegółów dotyczących programowania aplikacji pod Symbiana. W rezultacie powstał prosty szkielet gry pod wspomniany system. W niniejszej części cyklu zajmiemy się tematem znacznie ciekawszym – odejdziemy (chwilowo) od niskopoziomowych zagadnień systemowych i zrobimy to co Tygrysy lubią najbardziej – zbudujemy grę!

KASA DLA WEBMASTERA
58 LinkLift – koniec z reklamą kontekstową
Krzysztof Trynkiewicz W internecie królują systemy reklamy kontekstowej. W oparciu o treść witryny, wyświetlane są odpowiednie reklamy z takich serwisów jak Google AdSense, czy AdKontekst Wirtualnej Polski. Zarob-

WYWIAD
76 Wywiad z Bartoszem Stebnickim – dyrektorem generalnym firmy EMC

Wszystkie en chef : Marek Bettman marekb@software.com.pl Rédacteur znaki firmowe zawarte w piśmie są własności odpowiednich firm. Zostały użyte wyłącznie w celach informacyjnych. Rédacteurs : Aneta Cejmańska anetta@software.com.pl Ewa Dudzic ewal@software.com.pl Redakcja używa systemu Core Team Préparation du CD : Auroxautomatycznego składu Maquette : Anna Osiecka annao@software.com.pl Couverture : Agnieszka Marchocka Traduction : Iwona Czarnota, Aneta Lasota, Marie-Laure Perrotey, Osoby zainteresowane współpracą prosimy o kontakt: Grazyna Wełna cooperation@software.com.pl Bêta-testeurs : Thomas Bores, Tony Boucheau, Pascal Foulon, Pascal Miquet, Romain Lévy, Augustin Pascual, Julien Poulalion, Alain Ribault Druk: ArtDruk Les personnes intéressées par la coopération sont priées de nous contacter : cooperation@software.com.pl Abonnement : abonnement@software.com.pl Wysokość : Marta obejmuje również dodruki. Redakcja Fabrication nakładu Kurpiewska marta@software.com.pl nie udziela pomocy technicznej w instalowaniu i użytkowaniu programów zamieszczonych na płycie Diffusion : Monika Godlewska monikag@software.com.pl CD-ROM: dostarczonej razem z pismem. Publicité publicite@software.com.pl Sprzedaż aktualnych lub archiwalnych numerów pisma po innej merci de Si vous êtes intéressé par l’achat de licence de publication de revuescenie niż wydrukowana na Godlewska monikag@software.com.pl tél : +48 (22) jego contacter : Monika okładce – bez zgody wydawcy – jest ,działaniem na887 12 szkodę skutkuje odpowiedzialnością sądową. 66 fax : i+48 (22) 887 10 11

www.sdjournal.org

5

Aktualności
Windows 7 Beta 1 jeszcze w tym roku?
Wygląda na to, że Microsoft dojrzał już, by publicznie i konkretnie mówić o przyszłej wersji systemu Windows oznaczonej kodowo cyfrą 7. Sesje techniczne poświęcone następcy Visty są już zaplanowane na listopadowej Windows Hardware Engineering Conference. Nie oznacza to oczywiście, że już wtedy testowe kompilacje będą rozdawane uczestnikom. Niemniej z najnowszych, oczywiście nieoficjalnych informacji wynika, że wersja Beta 1 nowych Okienek może zostać wydana szerszej grupie testerów jeszcze w tym roku, a konkretnie w połowie grudnia. Niewielka grupa wybrańców już bierze udział w pracach nad Windows 7 – dotychczas Microsoft wydał dwie wersje Milestone 1 i Milestone 2 tego systemu, a przygotowania do wydania Milestone 3 właśnie mają się ku końcowi. Wydanie pierwszej Bety 1 już w grudniu sugerowałoby znaczne przyspieszenie prac i mogłoby rodzić oczekiwania co do wydania finalnej wersji produktu jeszcze w 2009 roku. Pytanie zasadnicze brzmi więc – kiedy Microsoft zdecyduje się na szerszy program beta, a nawet na publiczną betę? Większość obserwatorów uważa, że całkowite otwarcie programu beta nastąpi dopiero w momencie, gdy system będzie kompletny funkcjonalnie – choć pojawiają się coraz poważniejsze głosy, że Windows 7 będzie wydany publicznie jeszcze wcześniej, niż w przypadku Visty (w której przypadku była to faza Beta 2). http://www.techit.pl/

Google Chrome

G

Ile znaczy Google News?
Mały błąd Google spowodował, że właściciele linii United Airlines stracili 1,14 miliarda dolarów. W 2002 roku linia lotnicza United Airlines była bliska bankructwa. Informację o tym zamieściły różne serwisy, w tym także Google News. Google jednak nie ustawiło daty newsa co spowodowało, że pojawił się ponownie – w połowie września 2008 roku. Został on szybko podchwycony przez inne serwisy informacyjne, łącznie z Bloombergiem. Jak się łatwo domyślić, spowodowało to gwałtowny spadek ceny akcji linii z 12 na 3 dolary, a ich posiadacze stracili łącznie ponad miliard. Na szczęście szybko zauważono pomyłkę i cena akcji znów wzrosła, osiągając poziom ok. 10 dolarów. Jak się później okazało, informacja pojawiła się na Google News ponieważ robot Google dostrzegł jej popularność na stronach gazety South Florida Sun-Sentinel. Przypadek ten pokazuje jak duże jest obecnie uzależnienie globalnego rynku od serwisów firmy Google. Jeszcze niedawno ciekawostką były procesy wytaczane w sytuacjach, gdy na skutek zmian w algorytmie wyszukiwarki Google czyjaś strona nagle spadała na dalsze miejsca w rankingach. Aktualnie, wraz ze wzrostem znaczenia Google, takich incydentów może pojawiać się coraz więcej. http://online.wsj.com/

oogle zaprezentowało nową, zbudowaną w oparciu o otwarte oprogramowanie, przeglądarkę mającą ułatwić użytkownikom na całym świecie korzystanie z Internetu. Dostępny w wersji beta w 43 językach, Google Chrome odzwierciedla nowe podejście do przeglądarek, oparte na prostych i skutecznych rozwiązaniach, do których przyzwyczajeni są użytkownicy produktów korporacji. Google projektując Chrome położyło szczególny nacisk na jej lekkość, przekładającą na niskie wykorzystanie zasobów systemowych. Wykorzystuje ona silnik renderowania stron webKit – framework używany w Safari i iPhone, wraz z autorskimi rozwiązaniami z Montain View, dostarczającymi gamę innowacyjnych rozwiązań. Jednym z nich jest funkcja dynamicznych kart, pozwalająca na tworzenie nowych kart poprzez przeciągnięcie jej poza aktywny obszar przeglądarki. Dodatkowo, dzięki Kontroli awarii, każda z nich jest uruchamiana oddzielnie, co sprawia, iż wskutek zawieszenia się jednej, nie wpłynie to na funkcjonowanie pozostałych. Prócz tego, tryb incognito oferuje możliwość niezapisywania odwiedzanych witryn w historii. W Chrome znalazły się także mechanizmy zabezpieczające takie jak Bezpieczne przeglądanie – ostrzegający przed wejściem na witryny podejrzewane o phishing czy rozpowszechniającymi złośliwe oprogramowanie, z dwoma aktualizowanymi okresowo blacklistsami. W programie nie zabrakło również opcji importu ustawień, menadżera pobierania plików i procesów. Dostępna jest też możliwość instalacji wtyczek, poszerzających możliwości aplikacji, wsparcie dla technologii Gears, a rosnące wykorzystanie zasobów może być rozkładane na wiele rdzeni procesora. Najnowszą testową wersję Google Chrome dla systemów Windows można pobrać bezpośrednio ze strony twórców (http://www.google.com/ chrome/index.html). W chwili obecnej, trwają prace na wersjami przeglądarki dla systemów Linuks

i Mac OS X. Co ciekawe, już po trzech dniach od wydania aktualizacji dla przeglądarki Chrome, jej twórcy opisali na łamach oficjalnego blogu aplikacji zmiany jakie wprowadzono w aplikacji za jej pośrednictwem. Aktualizacja niweluje dwie, poważne luki w zabezpieczeniach, oraz trzy mniej groźne. Instalacja aktualizacji odbywa się automatycznie u wszystkich użytkowników przeglądarki i nie daje żadnych nowych funkcjonalności. Kolejna ciekawostka dotycząca przeglądarki rodem z Mountain View wiąże się z jej licencją i rzekomo niepokojących zapisach znajdujących się w jej treści. Licencja Chrome mówi, że Google ma nieograniczone czasowo, ogólnoświatowe, nieodwołalne prawo do reprodukcji, adaptacji, modyfikowania, publikowania i tłumaczenia każdej treści, którą użytkownik wysyła lub wyświetla za pomocą przeglądarki. Brzmi to groźne, jednak w rzeczywistości nie jest to nic nowego. Google stosuje podobne warunki także przy innych swoich usługach. Stosowane jest to w celu uproszczenia obowiązujących zasad i może nie zawsze pasować do wszystkich produktów Google. W odpowiedzi na kontrowersje Google zapowiedziało jednak zmiany w licencji Chrome. W przeszłości internetowy gigant postąpił tak z licencją Google Docs. Należy przy okazji zauważyć, że Chrome jest otwarte i kod wysyłający do Google dane użytkownika zostałby szybko zauważony. Ponadto kod Chrome jest objęty licencją BSD, która narzuca bardzo małe ograniczenia na programistów chcących modyfikować kod przeglądarki, np. w celu usunięcia niechcianych funkcji. Należy się jednak spodziewać, że mało kto zrezygnuje z funkcjonalności paska adresowo-wyszukiwawczego i nadal wszystkie wpisywane tam słowa, także adresy odwiedzanych przez internautów stron, będą trafiały do Google wraz z adresami IP użytkowników. http://www.google.com/chrome/index.html http://dobreprogramy.pl/

6

11/2008

Aktualności

Apache nie daje za wygraną

Luka w DNS poważniejsza niż przewidywano
Od jakiegoś czasu wiele się słyszy o luce w systemie nazw Domian Name Sever (DNS). Wydawać by się mogło, że luka ta została usunięta. Niestety, eksperci są zgodni co do tego, że sprawa jest nadal daleka od pomyślnego zakończenia. Na trop wspomnianej usterki wpadła na początku bieżącego roku firma IOActive, a konkretnie Dan Kaminsky, prowadząc w ten sposób do największego łatania w historii Internetu. Wspomniana luka pozwala atakującemu wykorzystać specjalny typ żądań w celu doprowadzenia do przejęcia sesji TCP/IP, a wskutek tego – przekierowania sporej ilości osób na odpowiednio spreparowane witryny. Działanie opracowanych poprawek, bez względu na platformę systemową, polega na dodaniu mechanizmu losowania portów co zmniejsza ryzyko wykorzystania luki. Jak pokazują badania po takim zabiegu liczba serwerów podatnych na ataki z ponad 85%, zmalała do około 30. Jednak zdaniem Kamińskiego i innych ekspertów z branży, opisane wyżej zabiegi nie eliminują w całości luki, a jednie utrudniają napastnikowi przeprowadzenie pomyślnego ataku. Przewiduje się więc kolejną porcję poprawek do wprowadzenia w najbliższym czasie. Niestety, ze względu na liczne problemy techniczne szansa ich równoczesnego wdrożenia przez administratorów wszystkich środowisk serwerów DNS jest znacznie mniejsza niż w przypadku poprzednich poprawek. http://www.techit.pl/

W

przeciągu ostatnich miesięcy dało się zaobserwować dynamiczny wzrost udziału usług Internet Information Services w rynku serwerów internetowych przy jednocześnie słabnącej popularności konkurencyjnego serwera Apache. Z badań firmy Netcraft wynikało wówczas, że IIS wbudowany w systemy z rodziny Windows Server konsekwentnie umacnia swoją pozycję, a oglądając dane za październik można było dojść do wniosku, że jeszcze nigdy dotąd obu rozwiązań nie dzieliła tak niewielka różnica. Co ciekawe, we wrześniu bieżącego roku nastąpiła zdecydowana zamiana w dynamice tych statystyk. Z wykonanego przez Netcraft sierpniowego badania wynika, że w Sieci pojawiło się ponad 1,3 miliona nowych witryn z czego 1,2 mln wykorzystuje serwer Apache zaś pół miliona hostowana jest na rozwiązaniu oferowanym przez Google. Z sieci jednocześnie zniknęło 760 tysięcy witryn obsługiwanych przez IIS. Udział serwera Microsoft w rynku odnotował spadek o 1,74 punktu procentowego (strata blisko dwóch milionów witryn), zaś udział Apache wzrósł o 0,33 punktu procentowego. W badaniu łącznie sprawdzono ponad 176 748 506 stron. Po uwzględnieniu tych danych w ogólnej klasyfikacji nadal prowadzi Apache z 46.84% udziałem i 33 milionami witryn. Tuż za nim jest Microsoft IIS wykorzystywany na 34,83% serwerów WWW (24,5 mln stron). Trzecie miejsce zajmuje zmo-

dyfikowana przez Google wersja Apache (Google Front End) z wynikiem ok. 8 miliona witryn, co daje prawie 11-procentowy udział. Na dalszych miejscach plasują się lighttpd, Sun, Zeus, oraz dynamicznie pnący się w górę nginx. Równocześnie, jak wynika z najnowszego raportu firmy analitycznej IDC, wzrasta także sprzedaż serwerów z Linuksem. W porównaniu z rokiem ubiegłym, kiedy zainteresowanie nimi kształtowało się na poziomie 9,4%, odnotowano wzrost o całe cztery punkty procentowe, wskutek czego dzisiaj liczba ta wynosi już 13,4%. Sprzedaż maszyn z Uniksem stanowiła 7,7%, z kolei sprzedaż serwerów z Windows –36,5%. W sumie, w drugim kwartale, dochód z pierwszych z nich wyniósł 4,6 miliardów dolarów, co jest tylko o pół miliarda dolarów mniej, w porównaniu z maszynami wyposażonymi w Windows Server. Niezmiennie liderem w ich sprzedaży pozostaje IBM, na drugim miejscu uplasował się HP, trzecie miejsce cały czas zajmuje Dell, który przewodzi w sprzedaży maszyn 32bitowych (x86). Analizując dane z przedstawionych badań można dojść do wniosku, że, zarówno Apache, jak i IIS idą niemalże łeb w łeb. Pierwszy z nich kroczy niemalże cały czas w granicach 50% udziałów w rynku, drugi natomiast sukcesywnie nadrabia straty. Zanosi się na to, iż taka równowaga będzie trwała jeszcze długo, a wojowniczy Apache niełatwo da się pokonać. http://netcraft.com/

Apple prezentuje iTunes 8 oraz nowe iPody

Google skraca czas przechowywania adresów IP w logach
Pod presją Unii Europejskiej Google poinformował, że skraca czas, przez jaki w logach serwerów webowych przechowywane są informacje o adresach IP pozwalające zidentyfikować użytkowników korzystających z wyszukiwarki i pozostałych usług firmy. Dotychczas dane te były przechowywane przez 18 miesięcy, po czym adresy IP były z nich usuwane. Teraz czas ten został skrócony o połowę – do 9 miesięcy. Trudno powiedzieć, czy Komisja Europejska będzie zadowolona z takiego kroku – w oficjalnym oświadczeniu wydanym w kwietniu apelowała do Google, by dane w logach serwerów były neutralizowane już po sześciu miesiącach. Google broniło się twierdząc, że korzysta z tych danych do opracowywania nowych usług i polepszania jakości już istniejących – oczywiście przy jednoczesnej odpowiedniej ochronie prywatności użytkowników, których adresy IP widnieją w logach. Teraz firma w tonie ubolewania zapewnia, że choć ma do dyspozycji o połowę mniej logów, to jest na dobrej drodze do opracowania nowych metod analizowania przechowywanych danych – bardziej polegających na informacjach innych niż adresy IP. http://www.google.com/

K

onferencję Let's Rock rozpoczęły adekwatne do nazwy, rockowe brzmienia Rolling Stones oraz Jimmiego Hendrixa. Muzyka była tematem przewodnim wydarzenia. Steve Jobs rozpoczął prezentację od iTunes. iTunes Store, według rankingów największy dystrybutor multimediów na świecie, teraz wzbogaci się o filmy HD. Również odcinki seriali będzie można ściągnąć w SD lub HD i obejrzeć na komputerze za pomocą nowego iTunes lub na AppleTV. Poza tym, tak jak niosły plotki, iTunes posiada teraz możliwość tworzenia zestawu piosenek o podobnym nastroju (funkcja znana z serwisu Pandora). Ale to nie wszystko. Nowym elementem programu jest Genius Sidebar. Za pomocą tego paska nie tylko stworzymy nastrojową playlistę z własnej kolekcji, ale też dowiemy się jakie utwory z iTunes Store mogą się spodobać. Propozycje dobierane są na podstawie statystyk zbieranych przez program oraz ocen użytkownika i wysyłanych, oczywiście anonimowo, do serwisu. Sam

odtwarzacz iTunes przeszedł prawdziwą metamorfozę, jeśli chodzi o wygląd. Jobs zaprezentował zupełnie nowy sposób przeglądania muzyki i filmów. Wizualnie przeglądarka przypomina iPhoto i pozwala przeglądać albumy, artystów, kompozytorów, gatunki etc. Co więcej, ten sam mechanizm pozwala przeglądać filmy, na przykład sezony seriali. A wszystko to można kontrolować głosem (voice-over)! Skoro mowa o muzyce, nie można pominąć odtwarzacza iPod. Tutaj również Apple przygotowało nie lada nowość w postaci całej tęczy (czarny, fioletowy, niebieski, zielony, żółty, pomarańczowy, czerwony, różowy) Nano. Najnowsza wersja jest najcieńsza z wyprodukowanych do tej pory a jednocześnie najbardziej przyjazna środowisku. Towarzyszą mu nowe modele słuchawek i większa pojemność (8 i 16GB). iPod Touch również jest teraz cieńszy, ale przede wszystkim jego oprogramowanie również zostało wzbogacone o zestaw usług Genius. http://www.apple.com/

www.sdjournal.org

7

Aktualności
Microsoft przegrał z Komisją Europejską jednym głosem
Okazuje się, że zawarcie ugody z Komisją Europejską tuż po kolejnym niekorzystnym wyroku z 17 września ubiegłego roku mogło być ogromnym błędem Microsoftu. Koncern z Redmond nie wiedział bowiem wtedy, że przegrał całą sprawę zaledwie... jednym głosem. Głosowanie w unijnym sądzie było oczywiście tajne, ale teraz na jaw wyszła informacja, że Microsoft przegrał stosunkiem głosów 7 do 6. Źródłem przecieku było dwóch proszących o anonimowość urzędników z bezpośrednią wiedzą na temat procesu. Analitycy są zgodni, że w takiej sytuacji zawarcie ugody nie musiało być najlepszą decyzją prawników Microsoftu. Sędziowie unijni byli dalecy od jednomyślności i jak widać, mieli całkiem sporo wątpliwości. W kolejnej apelacji mogłoby więc okazać się, że Microsoft wygrałby. Taka wygrana pozwoliłaby uniknąć płacenia rekordowej w historii firmy i w całej historii Unii Europejskiej kary finansowej, razem z odsetkami i kosztami procesowymi grubo przekraczającej miliard euro, a przede wszystkim miałaby zupełnie inny wpływ na przemysł IT. W tej sytuacji przedstawiciele Microsoftu mogą czuć się mocno rozgoryczeni. Według źródeł wewnątrz firmy, prawnicy korporacji dowiedzieli się o stosunku głosów dopiero w maju bieżącego roku. http://seattletimes.nwsource.com/

OpenGL 3.0 – początek końca?

G

Ubiquity – wykonaj to co napiszę
Fundacja Mozilla poinformowała o wydaniu pierwszej wersji nowego rozszerzenia dla Firefoksa – Ubiquity 0.1. Jest to dosyć nietypowy dodatek, pozwalający na zastąpienie najpopularniejszych czynności wykonywanych podczas korzystania z Internetu słownymi poleceniami. Rozszerzenie Ubiquity pozwala użytkownikowi na integrację funkcji wielu aplikacji sieciowych. Przykładowo chcąc zaprosić znajomych do restauracji wystarczy użyć kilka prostych komend, które np. przekierują użytkownika do usługi Google Maps, bądź zaprezentują mu recenzje danego lokalu z serwisu Yelp. Następnie pozostaje tylko skopiowanie kodu i wklejenie go do wiadomości mailowej, która wyląduje w elektronicznych skrzynkach pocztowych uczestników imprezy. Dodatek oferuje użytkownikom wiele przydatnych komend i poleceń, które usprawnią ich pracę w Internecie. Wśród nich znaleźć można m.in. defi – wywołujący definicję, trans – tłumaczący wskazany tekst, czy np. twit – kopiujący materiał do serwisu Twitter. Ponadto każdy zainteresowany może w prosty sposób zdefiniować własne polecenia. Dodatek Ubiquity pobrać można z oficjalnej strony projektu. http://www.mozilla.org/

rupa Khronos udostępniła ostateczną wersję specyfikacji OpenGL 3.0, będącej otwartym, wieloplatformowym API pozwalającym na sprzętową obsługę grafiki 3D. Firmom rozwijającym oprogramowanie CAD nowa wersja biblioteki z pewnością się spodoba, stanowi bowiem rozwinięcie wydania 2.1, aczkolwiek wielu deweloperów otwarcie wyraża frustrację. Ich zdaniem biblioteki są mocno zacofane pod względem możliwości, zwłaszcza w kontekście wykorzystania ich jako platformy do rozwoju gier. OpenGL 3.0 pojawił się z ponad rocznym opóźnieniem, półtora roku po premierze DirectX 10, a ciągle jeszcze nie obsługuje wszystkich funkcji, jakie dawno temu zostały zaimplementowane przez Microsoft. Jak powszechnie wiadomo OpenGL jest zestawem standardów umożliwiających deweloperom tworzenie aplikacji graficznych dla Windows, Mac OS oraz Linuksa. Według szacunków, ilość sprzętu zainstalowanego w komputerach i posiadającego wsparcie dla OpenGL 3.0 przekracza 60 milionów. Firmy takie jak Intel, Advanced Micro Devices czy NVidia znacząco przyczyniły się do rozwoju specyfikacji i dziś wszystkie trzy przyznają, że w ich intencji leży wprowadzenie obsługi standardu we wszystkich możliwych produktach. Jednak od zapewnień do realizacji droga daleka. Ani chipsety Intela, ani ATI (AMD) nie błyszczą, gdy wziąć pod uwagę wydajność aplikacji OpenGL w porównaniu do szybkości przetwarzania w wypadku DirectX. Kiedy opublikowano specyfikację OpenGL 3.0, na forum Khronos Group podniósł się lament. Wielu deweloperów uznało, że zapomniano o obietnicach, które rok i dwa lata temu dano programistom. Co ciekawe, a jednocześnie niepokojące, do pełnej obsługi OpenGL 3.0 konieczne jest stosowanie kart kompatybilnych z DirectX 10, ale jednocześnie sam OpenGL 3.0 nie implementuje wszystkich funkcji dostępnych w DX10. Wśród opinii deweloperów nie brakuje radykalnych stwierdzeń – niektórzy z miejsca deklarują „przesiadkę” na standard Microsoftu. Pojawiły się również opinie, że opublikowana właśnie specyfikacja jest zacofana aż o siedem lat względem DirectX – a przepaść ma rosnąć z każdą chwilą. Co gorsza, mniej więcej w tym samym czasie Gigant z Redmond zapowiedział przypadającą na koniec bieżącego roku premierę DirectX 11. Nehe, popularny serwis poświęcony programowaniu aplikacji na bazie Open jako największe grzechy no-

wej odsłony OpenGL wymienia następujące kwestie – brak obiecanego obiektowego modelu API, zachowanie wstecznej kompatybilności (czynniki mocno hamujący rozwój), utrudnienie procesu tworzenia sterowników. W tym samy miejscu podkreślone jest jednak iż nowo wprowadzony kontekst GL3 stanowi rozwiązanie przyszłościowe i otwiera szerokie możliwości dla kolejnych odsłon standardu. Pocieszający może być również fakt, iż wraz z premierą Larrabee i innych GPU ogólnego zastosowania (GPGPU) wojna na liczbę obsługiwanych funkcji przez DirectX i OpenGL powinna stać się przeszłością. Deweloperzy gier nie będą musieli już czekać, aż firma X udostępni chipset implementujący funkcję Y, a następnie wypatrywać API, za pomocą którego ją obsłużą. Zamiast tego sami będą mogli zaprogramować chip do własnych potrzeb korzystając z klasycznych narzędzi i języków wykorzystywanych na platformie x86. Co by nie mówić, nowy standard wprowadza pewne nowości. Wśród nowinek wprowadzonych w OpenGL 3.0 znalazło się kilka rozszerzeń potencjalnie mogących zwiększyć możliwości następnej wersji bibliotek. Oprócz tego API pozwala na obsługę GLSL 1.30, nowej wersję języka cieniowania oraz posiada wszechstronne wsparcie dla funkcji oferowanych przez akceleratory graficzne ostatniej generacji. Ponadto w bibliotekach pojawiła się implementacja Vertex Array Objects, funkcja kompaktowania danych pikseli i werteksów w celu oszczędzania pamięci i pasma, wsparcie dla 32-bitowego bufora głębi, cztery nowe schematy kompresji tekstur, nieblokowalny dostęp do obiektów bufora werteksów oraz funkcja renderowania warunkowego zwiększającego wydajność. Jak potoczą się dalsze losy standardu OpenGL? Trudno przewidzieć. Teraz kolej na ruch Microsoftu. Jedno jest niestety pewne – niesmak i niedosyt związane z ogłoszeniem trzeciej odsłony pozostaną na długo w głowach użytkowników tej – jak by nie patrzeć – istotnej we współczesnym świecie informatycznym bibliotece. http://www.idg.pl/ http://nehe.gamedev.net/

8

11/2008

Aktualności

20 lat Internetu w Polsce

Red Hat kupił KVMa
W czerwcu bieżącego roku pojawiły się informacje o pracach Red Hata nad wbudowanym linuksowym hypervisorem, który ma być uzupełnieniem, a nie konkurencją dla istniejącego już rozwiązania Xen. Fundament nowego hypervisora miał stanowić projekt Kernel-based Virtual Machine. Tymczasem korporacja oficjalnie poinformowała o kupnie, za kwotę 107 milionów USD jego producenta – firmy Qumranet. Zdaniem Paula Cormiera, jednego z prezesów Red Hata, fuzja obu przedsiębiorstw ma wprowadzić niespotykane dotąd możliwości wirtualizacyjne w produktach spółki. Ich połączenie może się bowiem przyczynić do eliminacji kilku problemów. Przede wszystkim, stworzenia własnego silnika wirtualizacyjnego, czego korporacja wcześniej nie była w stanie zrobić z Xenem, ze względu na XenSource, który niedawno wykupiony został przez Citriksa. Uzyska za to gotową platformę, cechującą się przede wszystkim elastycznością pozwalającą na jej wdrożenie na różnego rodzaju serwerach, komputerach stacjonarnych, urządzeniach wbudowanych oraz jakichkolwiek innych pracujących pod kontrolą Linuksa. Może to również pomóc w umocnieniu pozycji na rynku wirtualizacyjnym, a także lepszej konkurencji z Novellem, krytykowanym za współpracę z Microsoftem. Jednym z ciekawszych rozwiązań opracowanych przez Qumranet jest oprogramowanie o nazwie Virtual Desktop Interface (VDI) – połączenie brokera z nową wersję protokołu Remote Desktop. Inną, wartą uwagi technologią jest SolidICE. Pozwala ona – przy wykorzystaniu techniki wirtualizacji pulpitów – na uruchomienie dowolnej liczby maszyn wirtualnych, zarówno z Windows, jak i Linuksem pod kontrolą KVM, pracującego na centralnym serwerze. Red Hat już teraz zapowiedział wdrożenie w swojej sztandarowej dystrybucji – Red Hat Enterprise Linux – KVM w zastępstwie do tej pory wykorzystywanego Xena oraz otwarcie źródeł SPICE (Simple Protocol for Independent Computing Enviromentns), z kolei opracowywany przez Red Hata hypervisor ma ujrzeć światło dzienne na początku przyszłego roku. http://www.techit.pl/

1

7 sierpnia bieżącego roku Polski Internet obchodził 20 urodzimy. Równo 20 lat temu, 17 sierpnia 1988 roku, Polska po raz pierwszy połączyła się z Kopenhagą, za pośrednictwem łącza internetowego o prędkości 9600 bitów na sekundę (bps). Trzy lata później, dr Rafał Pietrak z Uniwersytetu Warszawskiego nawiązał łączność w oparciu o protokół TCP/IP z pracownikiem Uniwersytetu w Kopenhadze, wysyłając elektroniczną wiadomość pocztową. Wraz ze wzrostem popularności Internetu w Polsce, medium to nabrało zupełnie nowego znaczenia. O ile kiedyś Internet był obecny na uczelniach technicznych, a jego znajomość rozpoczynało się od nauki Uniksa, obecnie, z pojawieniem się pierwszych wersji Windows oraz spadkiem cen utrzymania łącz, niemal każdy może mieć go w zasięgu ręki. Dzisiaj Internet jest powszechnie wykorzystywany głównie do przeglądania witryn WWW, korzystania z Usenetu, czyli powstałych w 1979 roku grup dyskusyjnych, czy prowadzenia różnego rodzaju rozmów, realizowanych za pośrednictwem komunikatorów, czy IRC-a. Dużą popularnością cieszą się też serwisy umożliwiające udostępnianie zdjęć czy filmów wideo. Przy takiej okrągłej rocznicy warto zadać sobie pytanie jaka będzie przyszłość globalnej sieci. W ciągu najbliższych lat, nasz kraj czeka między innymi przejście na protokół IPv6, oferują-

cy dużo większą liczbę możliwych adresów (teoretycznie nawet 2 do potęgi 128), które nawet przy niezbyt oszczędnym rozdzielaniu nie powinny się wyczerpać, pozwalając na bezpośrednie podłączenie do sieci praktycznie każdego urządzenia. IPv6 wprowadza również wiele ulepszeń w zakresie bezpieczeństwa. Proces migracji na ten protokół wspomaga od niedawna Unia Europejska, a na początku lutego br. ICANN, organizacja zajmująca się między innymi zarządzaniem domenami najwyższego poziomu uaktualniła sześć z trzynastu głównych serwerów DNS o adresy IPv6. Przyszłość Internetu to również nowe techniki tworzenia witryn internetowych oraz takie standardy jak Web 2 i 3.0, czy HTML5. http://gazeta.pl/

TinEye – nowa wyszukiwarka plików graficznych

P

owstała nowa, ciekawa wyszukiwarka plików graficznych, TinEye. W przeciwieństwie do tradycyjnych wyszukiwarek, nie odnajduje ona plików graficznych na podstawie słów, które im towarzyszą na stronach internetowych. Nie oczekuje nawet na wpisanie słów kluczowych. Zamiast tego użytkownik wysyła plik graficzny ze swojego komputera lub podaje adres URL. TinEye wyszukuje wskazany plik w Internecie, nawet jeśli jest on w innym formacie, ma inne rozmiary a nawet jeśli obraz został przetworzony z użyciem różnych efektów lub też został włączony do innego zdjęcia/grafiki. Pozwalają na to dosyć zaawansowane algorytmy, które tworzą sygnaturę danego obrazu analizując zawarte w nim kształty i kolory. TinEye jest wyszukiwarką wyjątkową nie tylko dlatego, że nie opiera się w ogóle na tekście, ale przede wszystkim dlatego, że służy do wyszukiwania plików, które użytkownicy już posiadają. Ma więc inne zastosowania niż zwykła wyszu-

kiwarka. Pozwala ona np. śledzić autorom zdjęć i grafik co się dzieje z ich twórczością, np. czy ich praca nie jest wykorzystywana w sposób nielegalny. Może też pomóc w przypadku posiadania plików o których nie wiadomo co przedstawiają lub kto jest ich autorem. Dzięki TinyEye odnaleźć można bowiem strony, które zawierają informacje o danym pliku. Wyszukiwarka jest obecnie w fazie beta i ma zaindeksowanych przeszło 700 milionów plików graficznych. Korzystanie z niej wymaga logowania. http://tineye.com/

Java Lightweight UI Toolkit otwarty
Sun otworzył Java Lightweight UI Toolkit, zestaw narzędzi do tworzenia mobilnych aplikacji w języku Java. LWUIT został udostępniony na licencji GPLv2 with Classpath Exception jako projekt-inkubator hostowany w ramach serwisu java.net. Bazując na Java Mobile Edition oferuje wiele komponentów graficznych, tematów, czcionek, animacji i efektów przejść, obsługę ekranów dotykowych oraz obsługę formatu SVG przy wykorzystaniu Java Specification Request (JSR) 226. http://www.theregister.com/

www.sdjournal.org

9

Aktualności
Milion dolarów za włamanie
Jak informuje serwis Hacking.pl, firma Permanent Privacy złożyła hakerom publiczną ofertę – jeśli uda im się złamać stworzone przez nich zabezpieczenia, będą mogli odejść z milionem dolarów. Platforma Permanent Privacy bazuje na szyfrowaniu AES, dodaje natomiast dodatkową warstwę zabezpieczającą, która, jak twierdzą jej projektanci, jest nie do zdobycia. Ogólnie rzecz biorąc, pomysł wziął się z zaszyfrowania fragmentu bezsensownego tekstu. Autorzy zabezpieczenia są tak pewni siły zabezpieczenia, że postanowili wypłacić milion dolarów każdej osobie, która zdoła się włamać do systemu. Peter White, dyrektor zarządzający firmy Permanent Privacy zapewnia, że użytkownicy mogą teraz wysyłać listy elektroniczne i przechowywać dane ze 100-procentową pewnością, iż pozostaną one zabezpieczone. Nawet Pentagon nie może odczytać waszych sekretów, jeśli nie ma kluczy – dodaje. Być może niedługo ktoś będzie bogatszy o milion... http://hacking.pl/

Układ scalony ma już 50 lat!

C

Keyczar – usługi kryptograficzne od Google
Właściwe zastosowanie rozwiązań kryptograficznych nie jest łatwym zadaniem i nie każdy webmaster potrafi z nim sobie poradzić. Ich niewłaściwa implementacja może przyczynić się do występowania poważnych luk w bezpieczeństwie. Wielu programistów korzysta też często z przestarzałych algorytmów i pomija istotne aspekty bezpieczeństwa zapominając choćby o rotacji kluczy. Wychodząc naprzeciw tym problemom, Google udostępnił nowe narzędzie kryptograficzne. Keyczar, bo tak właśnie brzmi jego nazwa, jest zestawem narzędzi kryptograficznych, zapewniających wsparcie zarówno dla szyfrowania, jak i uwierzytelniania dla algorytmów symetrycznych lub kluczy publicznych. Aplikacja udostępnia proste API i potrafi wskazywać domyślnie najniebezpieczniejsze miejsca, tagować dane wyjściowe z informacjami o wersjach kluczy, a także oferuje możliwość rotacji kluczy z prostym systemem wersjonowania. Prócz tego w programie znajdziemy opcje związane z automatycznym generowaniem wektorów inicjalizacyjnych oraz podpisami zaszyfrowanymi (ang. ciphertextowymi). Korzystanie z narzędzia wiąże się z koniecznością zaszyfrowania parametru URL przy użyciu klucza symetrycznego. Dotychczas, deweloper musiał zadecydować o wyborze algorytmu, długości klucza, trybu działania, jak również sposobu obsługi wektorów inicjalizacyjnych, rotacji kluczy, czy też ciphertekstu. Keyczar upraszcza całą sytuację, dzięki czemu interakcja ze strony programisty wiąże się z wprowadzeniem zaledwie dwóch linijek kodu, używając Pythona, Javy, oraz – już niebawem – C++. Keyczar funkcjonuje w ramach usługi Google Code i jest dostępny do pobrania pod adresem http://www.keyczar.org/. http://www.techit.pl/

ały przemysł komputery nie byłby tym, czym jest obecnie, gdyby nie technologia, która powstała równo pół wieku temu. Układy scalone, opracowane przez dwóch naukowców, są dziś obecne w każdym sprzęcie elektronicznym i trudno wyobrazić sobie życie bez nich. Dwaj inżynierowie, którzy zaprezentowali pierwsze na świecie układy scalone to Jack Kilby (pracujący wówczas w Texas Instruments) i Robert Noyce (zatrudniony w Fairchild Semiconductor, późniejszy współzałożyciel firmy Intel). Noyce i Kilby pracowali oddzielnie, ale niemal jednocześnie zaprezentowali bardzo podobne do siebie rozwiązania. Z tym, iż Noyce oparł swój wynalazek na krzemie, a Kilby na germanie. Pierwszy mikrochip ujrzał światło dzienne dokładnie 12 września 1958 r. Ten dziwnie wyglądający (jak na dzisiejsze czasy) układ scalony miał wielkość 11,1 na 1,58 mm i jego konstruktorem był Kilby. Obecnie przemysł wytwarzający układy scalone może się pochwalić obrotami rzędu 300 mld USD rocznie. Popularne scalaki pełnią w produktach elektronicznych rolę mózgu oraz układu nerwowego. Są to produkty zawierające miliony tranzystorów, wytwarzane przy użyciu technologii kilkudziesięciu nanometrów, co oznacza iż poszczególne elementy czy ścieżki są na takim układzie oddalone od siebie np. o 60 nm. A warto pamiętać, że nanometr to jedna miliardowa część metra (ludzki włos ma średnicę 10 tys. nanometrów). Czterdzieści lat temu superkomputer mający wydajność zaledwie 1000 dzisiejszych pecetów zajmował kilka dużych pokoi i kosztował bajońskie sumy – ponad 10 mln USD. Wszystko zmieniło się właśnie za sprawą układów scalonych. W latach pięćdziesiątych komputery składały się z dziesiątków tysięcy pojedynczych tranzystorów, diod i rezystorów. To też była swoista rewolucja, ponieważ wcześniej stosowano lampy. Kilby i Noyce doszli więc do wniosku, że tranzystory, rezystory i kondensatory można przecież zintegrować ze sobą w ramach jednego kawałka np. krzemu czy innego materiału. Jak rewolucyjny to był wynalazek niech świadczy fakt, że Kilby zdobył w 2000 r. nagrodę Nobla w dziedzinie fizyki właśnie za wynalezienie układu scalonego. Noyce ma w tej dziedzinie też duże zasługi, opracowując układ scalony oparty na krzemie, który to materiał jest stosowany do dzisiaj. Firma Fairchild (w której pracował Noyce) produkowała w latach pięćdziesiątych tranzystory oparte na krzemie. Stąd pomysł stosowania krzemu do budowania układów scalonych, a nie germanie, jak to zrobił Kilby. Co ciekawe, do

dyskusji o układach scalonych włączył się wtedy Moore (wszyscy chyba znamy sformułowane przez niego prawo), twierdząc, że układ opracowany przez Noyce'a (oparty na krzemie) jest bardziej praktyczny i będzie łatwiejszy do produkowania niż układ oparty na germanie, co okazało się prawdą. Kilby złożył jako pierwszy wniosek o opatentowanie swojego wynalazku, jednak pierwszy patent został przyznany rozwiązaniu opracowanemu przez Noyce'a. Następnie po powtórnym rozpatrzeniu całej kwestii związanej z datami sprawę wygrał Kilby, jednak po wieloletnich przepychankach sądowych ostatecznie patent powrócił do Noyce'a. Na początku nie wszyscy byli przekonani, że układ scalony to dobry pomysł. Wielu znawców przedmiotu argumentowało, że proces produkcji układu scalonego jest tak skomplikowany, że będzie to niemożliwe albo bardzo drogie i nieopłacalne przedsięwzięcie. Po latach widać, jak bardzo się mylili. Tak czy inaczej obie firmy dogadały się w sprawie patentów i po jakimś czasie zaczęły produkować układy scalone. Uważa się, że produkcję pierwszego komercyjnego układu scalonego podjęła firma Fairchild. Firma TI uruchomiła natomiast w 1964 roku produkcję swoich pierwszych kalkulatorów opartych na układach scalonych. Przemysł zbrojeniowy Stanów Zjednoczonych wykorzystał bardzo szybko układy scalone, wprowadzając je do swoich produktów, takich jak np. rakiety balistyczne Minuteman. Z kolei NASA stosowała szeroko scalaki podczas realizacji misji człowieka na Księżyc (program Apollo). Patrząc w przeszłość i oceniając rolę układów scalonych w rozwoju elektroniki, Kilby wypowiedział znamienne słowa podczas odbierania w 2000 r. nagrody Nobla – To tak jakby bóbr i królik przyglądali się potężnej zaporze przedzielającej rzekę i ten pierwszy powiedział do królika – ja jej nie zbudowałem, ale cały pomysł to chyba wzięli ode mnie. Wynalazcy układów scalonych już nie żyją. Noyce zmarł na atak serca w 1990 r. mając 63 lata, a Jack Kilby zmarł na raka w 2005 r. w Dallas (w wieku 81 lat). http://www.itpartner.pl

10

11/2008

Aktualności

Tim Berners-Lee ogłasza powstanie Fundacji WWW

Picasa rozpoznaje twarze
Google dodało funkcję rozpoznawania twarzy do swojego serwisu Picasa Web Albums. Dzięki niej użytkownik dostaje zestaw zdjęć, które według algorytmu rozpoznającego przedstawiają tą samą osobę i może je łatwo otagować, np. imieniem. Dzięki tagom można przeglądać na bieżąco tworzone albumy zawierające zdjęcia danej osoby. Odnajdywanie twarzy na 3 tysiącach zdjęć zajmuje ok. 20 minut. Jak można się było spodziewać, nowa funkcja nie zawsze działa poprawnie. Czasami nie wykryje twarzy na zdjęciu, czasem za twarz uzna coś, co nią nie jest. Wykrywanie działa najlepiej, gdy twarz fotografowanej osoby była skierowana w stronę fotografującego oraz nie występują na niej cienie. Ogólnie jednak mechanizm ten spisuje się bardzo dobrze. Technologię rozpoznawania twarzy Google pozyskało kupując firmę Neven Vision. Serwis Picasa Web Albums wzbogacił się też o funkcję Explore, która pozwala na przeglądanie wszystkich publicznych zdjęć. Nawigować można na podstawie daty, miejsca i popularnych tagów. Przy okazji Google planuje także wydanie Bety trzeciej wersji aplikacji Picasa. Pojawią się w niej takie funkcje jak tworzenie filmów ze zdjęć i muzyki, usuwanie przebarwień skóry oraz efektu czerwonych oczu, ulepszona funkcja kolażu, przeglądarka plików graficznych oraz synchronizacja z serwisem Picasa Web. http://www.cnet.com/

W

wywiadzie dla BBC News, Tim Berners-Lee, twórca sieci WWW, poinformował o powstaniu Fundacji WWW, której jednym z głównych założeń jest opracowanie mechanizmu umożliwiającego oddzielenie miejsc w Internecie, gdzie znaleźć można rzetelne informacje od tych zawierających plotki. Berners-Lee w trakcie rozmowy z dziennikarzami mówił o zmianach, jakie wprowadzić należy w Sieci, by stała się ona bardziej przyjazna i dostępna dla Internautów. Pośród wszystkich poruszonych przez niego aspektów najistotniejszym wydaje się zastosowanie podziału stron i serwisów internetowych w taki sposób, by promować tylko te, które zawierają wiarygodne informacje. Przykładem niepotrzebnej histerii, jaką wywołać mogą plotki rozpowszechnione w Internecie jest według niego historia Wielkiego Zderzacza Hadronów. Powołana przez Bernersa-Lee do życia Fundacja WWW opracować ma złożony mechanizm oznaczania rzetelnych dostawców informacji w Sieci, umożliwiając tym samym wielu organizacjom nadawanie serwisom różnych etykiet, które świadczyłyby o wiarygodności treści. Inną kwestią, nad jaką pracować będzie Fundacja WWW jest ułatwienie dostępu do Internetu mieszkańcom najbiedniejszych rejonów na świecie. Z czasem Sieć stać się ma bardziej przyjazna dla wszelakiego rodzaju urządzeń mo-

bilnych, a z racji tego, że większość osób zamieszkałych wspomniane tereny to analfabeci, Berners-Lee mówił także o dostarczaniu treści w sposób niewymagający umiejętności czytania. Ponadto ważnym elementem działalności Fundacji WWW ma być także zapewnianie neutralności każdemu użytkownikowi Internetu, tak by mógł swobodnie wyrażać swoje zdanie i dokonywać wyborów. http://www.bbc.co.uk/

Microsoft poszerza współpracę z Novellem
Firmy Microsoft i Novell poinformowały o poszerzeniu współpracy na rzecz budowania mostów pomiędzy otwartym i zamkniętym oprogramowaniem. Koncentruje się ona między innymi na umocnieniu oferowanego wsparcia technicznego oraz szkoleń, ale przede wszystkim na zwiększeniu interoperacyjności pomiędzy systemami z rodziny Microsoft Windows Server i SUSE Linux Enterprise Server. Microsoft zobowiązał się do zakupu certyfikatów o wartości stu milionów dolarów, mogących zostać wykorzystanych przez klientów korzystających ze wsparcia technicznego produktów Novella. W ramach nawiązanej pierwotnie na pięć lat, w listopadzie 2006 roku, współpracy, gigant z Redmond nabył wówczas certyfikaty warte 240 mln USD. W ciągu kolejnych 18 miesięcy ponad połowa z nich została wykorzystana. Wśród klientów, którzy skorzystali z oferty korporacji znalazły się takie koncerny jak Wal-Mar Stores, Renault, czy BMW. Zdaniem Kevina Turnera z Microsoftu, celem poszerzonej współpracy jest podołanie wymaganiem klientów, którzy chcą mieć możliwość uruchamiania równocześnie zarówno Windows, jak i Linuksa, a także pomoc w migracji do SUSE Linux Enterprise Server z innych rozwiązań. Inwestycja ma wejść w życie z dniem 1 listopada 2008. Korporacje już teraz wyraziły chęć kontynuacji innych inicjatyw, w takich dziedzinach jak wirtualizacja, systemy zarządzania, zgodności formatów dokumentów oraz technologia Moonlight. http://www.techit.pl/

Najlepsze aplikacje dla Androida wybrane

F

irma Google ogłosiła zwycięzców pierwszego etapu konkursu Android Developer Challange, którego głównym założeniem było napisanie jak najlepszej aplikacji przeznaczonej na platformę Android. Jako najciekawsze aplikacje stworzone przez uczestników konkursu wymienić należy m.in. cab4me, GoCart, czy też TuneWiki. Pierwsza z nich to przydatne rozszerzenie dla telefonów komórkowych za którego pomocą w łatwy sposób znaleźć można najbliższą taksówkę, nie znając nawet dokładnej lokalizacji, w której się znajdujemy. Kolejna aplikacja, GoCart, znacznie ułatwia zakupy. Rejestrując za pośrednictwem wbudowanej kamery kod kreskowy danego produktu, aplikacja informuje użytkownika, gdzie wybrany towar można kupić najtaniej. TuneWiki pozwala na odtwarzanie plików

multimedialnych w oparciu o Social Network, udostępniając tym samym publicznie informacje o odtwarzanych aktualnie plikach. Dzięki temu możliwe jest podglądnięcie czego słuchają inni użytkownicy Androida w lokalizacji, w której aktualnie się znajdujemy. Ogółem nagrodzonych zostało 50 zespołów, których projekty uznane zostały za najlepsze. Pierwsza dziesiątka otrzymała po 270 tys. USD, twórcy kolejnych 10 aplikacji zostali nagrodzeni sumą 100 tys. USD, z kolei wszyscy pozostali otrzymali po 25 tys. USD. Więcej informacji na temat wszystkich nagrodzonych w konkursie aplikacji znaleźć można na stronie ADC Gallery. Warto dodać, iż wszystkie one dostępne będą do pobrania za darmo w serwisie Android Marketplace. http://osnews.pl/

www.sdjournal.org

11

Opis CD

Acrobat 9 Pro na CD

Na dołączonej do tego magazynu płycie znajdziecie ewaluacyjną wersję programu Acrobat 9 Pro w angielskiej wersji językowej. Dodatkowo, aby ułatwić Wam pracę na tym narzędziu zamieściliśy na CD wideotutoriale pokazujące jak korzystać z nowych funkcji i do jakich zastosowań może być przydatna ta aplikacja.

Opis nowości w Acrobat 9
W najnowszej, dziewiątej już wersji oprogramowania, po raz pierwszy wprowadzono bezpośrednią obsługę technologii Adobe Flash, dzięki czemu użytkownicy mogą umieszczać w pliku PDF materiał wideo zgodny z tym popularnym standardem. Odbiorca dokumentu do obejrzenia jego zawartości potrzebuje jedynie bezpłatnego oprogramowania Adobe Reader 9. Acrobat 9 umożliwia także łączenie różnorodnej zawartości w jeden dokument, tzw. pakiet PDF (Portfolio). Pakiety PDF pozwalają na łączenie kilku różnych typów plików multimedialnych — takich jak dokumenty, materiały filmowe i dźwiękowe, a nawet obiekty trójwymiarowe — w jeden skompresowany plik PDF. Użytkownicy mogą zastosować różne układy stron (lub utworzyć własne), aby zintegrować zawartość, określić sposób nawigacji oraz całość oprawić w odpowiednią szatę graficzną. W rezultacie takie dokumenty jak oferty handlowe, dokumenty prawne czy materiały informacyjne do produktu, stają się bardziej urozmaicone i dostosowane do specyficznych potrzeb.

Dodatkowo Acrobat 9 umożliwia wspólną pracę w czasie rzeczywistym na dokumencie PDF. Wykorzystywany jest do tego Acrobat.com – nowy zestaw usług udostępnianych w hostingu, w chwili obecnej dostępny w postaci publicznej wersji beta. Dzięki niemu kilka osób może w tym samym czasie pracować na jednym dokumencie, konsultować zmiany i wprowadzać poprawki. Co więcej, użytkownicy programu Acrobat 9 mogą za pośrednictwem serwisu Acrobat.com zapisywać i udostępniać pliki, wykorzystywać go jako centrum przechowywania danych w ramach przetwarzania formularzy, a także zbierać za jego pomocą komentarze do udostępnionych dokumentów. Acrobat.com oferuje także inne usługi, takie jak: • Adobe ConnectNow – osobisty serwis do konferencji internetowych, pozwalający na współużytkowanie pulpitu, konferencje wideo i audio oraz czat; • Adobe Buzzword – funkcjonalny, internetowy edytor tekstu, który może być wykorzystywany w celu współtworzenia i współużytkowania dokumentów na potrzeby komentowania i recenzji, zapewniający jednocześnie najwyższej jakości wydruki. Dwie wersje programu Acrobat 9 dostępne są też w języku polskim. Są to: Acrobat 9 Standard oraz Acrobat 9 Pro.

Ceny i dostępność
Adobe Acrobat 9 Standard w polskiej bądź angielskiej wersji językowej kosztuje około 1172 złotych netto. Adobe Acrobat 9 Pro w polskiej bądź angielskiej wersji językowej kosztować będzie około 1878 złotych netto. Natomiast Acrobat 9 Pro Extended, dostępny jedynie w wersji anglojęzycznej, to wydatek rzędu 2751 złotych netto.

12

11/2008

Jeśli nie możesz odczytać zawartości płyty CD, a nie jest ona uszkodzona mechanicznie, sprawdź ją na co najmniej dwóch napędach CD. W razie problemów z płytą, prosimy pisać pod adres: cd@software.com.pl

Redakcja nie udziela pomocy technicznej w instalowaniu i użytkowaniu programów zamieszczonych na płytach CD-ROM dostarczonych razem z pismem.

Biblioteka miesiąca

Jericho HTML
Parser i biblioteka narzędziowa HTML
Jericho to prosta, lekka i darmowa biblioteka użyteczna dla wszystkich programistów Java przetwarzających bądź generujących kod HTML. Jericho dostarcza klasy umożliwiające analizę i przekształcanie istniejących dokumentów HTML bądź też generowanie nowych. Wszystko z użyciem minimalnego nakładu pracy ze strony programisty.
Dowiesz się:
• Jak w łatwy sposób, bez używania bezpośrednich operacji na łańcuchach znaków, modyfikować, czytać i generować kod HTML z poziomu aplikacji Java.

Powinieneś wiedzieć:
• Jak programować w językach Java i HTML na poziomie podstawowym.

Poziom trudności

J

ozue wyruszył na bitwę o Jerycho i mury miasta runęły [...] Nie ma to jak stary dobry Jozue i bitwa o Jerycho” – płyną słowa poniekąd religijnej pieśni, która równie dobrze mogłaby być żołnierską przyśpiewką, mruczaną pod nosem podczas ostrzenia mieczy. Pewnie wszyscy znamy krwawą historię o Jerycho w której mury miasta zawaliły się od ryku trąb a potem ludzie Jozuego „wyrżnęli do nogi ostrzem miecza wszystko, co było w mieście, mężczyzn i kobiety, młodych i starych, woły, owce i osły (Joz 6,21; BW). Być może jednak nie wszyscy znamy małą, acz użyteczną bibliotekę Java a tej samej nazwie – Jericho. Z góry nadmieniam, iż nie jest to oprogramowanie służące celom destrukcyjnym lub religijnym krucjatom a zbieżność nazw jest tu taka sama jak w przypadku języka Java i wyspy o identycznej nazwie. No, może nieco większa – twórca biblioteki nazywa się Martin Jericho. Tak więc – wbrew groźnej nazwie – polecam tym razem Czytelnikom bibliotekę łatwą i przyjemną, a przede wszystkim – nader przyjazną. Nie jest to może ogromny połeć oprogramowania, za to jego przydatność – dość wszechstronna dla wszystkich programistów aplikacji internetowych spod znaku Java. Czym dokładnie jest ta biblioteka? W pierwszej kolejności można by
14

powiedzieć, iż jest parserem HTML ale ja użyję tu określenia nieco szerszego – Jericho to biblioteka narzędziowa pozwalająca na łatwe parsowanie a także – sformatowane generowanie kodu HTML. Jej wewnętrzne mechanizmy pozwalają na wygodną współpracę ze scriptletami innych języków, jak JSP, ASP, PHP. W praktyce narzędzie to przyda się programistom na trzech płaszczyznach – przy analizie struktury kodu HTML, podczas konieczności odfiltrowywania fragmentów tekstu z kodu HTML oraz podczas automatycznego generowania stron HTML. Jak nieczytelny lub rozdmuchany jest nierzadko kod automatycznie generowanych stron wie każdy programista WWW. Z zarówno estetycznych jak i praktycznych powodów (choćby debugowanie), chciałoby się mieć nieco więcej porządku w takim kodzie, co właśnie umożliwia opisana tu biblioteka. Kwestia parsowania HTML może być dla niektórych Czytelników zagadnieniem bardziej kontrowersyjnym – przecież HTML (zwłaszcza współczesny, oparty o XHTML) to podzbiór języka XML, dla którego narzędzi, w tym parserów, nie brakuje. Czy nie jest to zatem tworzenie dodatkowych bytów? Otóż nie. Przynajmniej dla miłośników rozwiązań prostych i czytelnych. Jericho jest biblioteką dedykowaną i dla swojej dziedziny, znacznie wygodniejszą w użyciu niż bardziej ogólny parser XML. Pierwsza wersja biblioteki została opublikowana w lutym 2004 roku i od tamtego czasu regularnie się rozwija. Obecnie na stronie internetowej projektu znaleźć można wersję 2.6 wydaną w czerwcu 2008 roku. W obecnym stadium

biblioteka jest stabilna i z powodzeniem może być wykorzystywana w komercyjnych projektach. Oprogramowanie jest rozpowszechniane na zasadzie licencji EPL (Eclipse Public License) oraz LGPL (GNU Lesser General Public License), które pozwalają na jego pełne i nieodpłatne wykorzystywanie w dowolnego typu projektach. Autorzy rozważają wydanie w przyszłości odpowiednika biblioteki dla platformy .NET.

Struktura i możliwości biblioteki
Jericho jest narzędziem łatwym do opanowania i lekkim. Programiści mogą bez obaw o utratę wydajności lub nadmiar zajmowano miejsca dołączać ją do swoich aplikacji. Skompilowana biblioteka zajmuje łącznie około 160kB a na całość składa się zaledwie kilkadziesiąt klas. Ponadto do prawidłowego działania biblioteka nie wymaga użycia żadnych niestandardowych klas zewnętrznych. Wszystkie klasy Jericho umieszczone są w pakiecie au.id.jericho.lib.html. W sferze funkcjonalnej bibliotekę można podzielić na cztery podstawowe moduły: • – narzędzie samo w sobie oraz baza dla pozostałych modułów – pozwala w łatwy i intuicyjny sposób nawigować po drzewiastej strukturze dokumentu HTML; • renderer – narzędzie pozwalające na wyodrębnianie elementów tekstowych z dokumentu HTML, z pominięciem tagów i atrybutów języka. Można tutaj w łatwy sposób odnosić się do pojedynczych elementów strony – np. wartości pól formularzy lub wręcz całościowo skonwertować dokument HTML do czytelnej dla człowieka postaci – z zachowaniem definiowalnych przez programistę reguł formatowania tekstowego; • formatter – komponent dający wsparcie dla formatowania dokumentu HTML; niezwykle użyteczne narzędzie dla wszystparser

11/2008

Jericho HTML

kich programistów generujących dynamicznie strony WWW, którym zależy na czytelnym kodzie wynikowym; • kompresor – jak wyżej, narzędzie przydatne przede wszystkim jako wsparcie dla generowanego kodu HTML; pozwala zmniejszyć jego objętość poprzez usuwanie niepotrzebnych znaków (zwykle nadmiarowe białe znaki). Wbrew pozorom taka operacja potrafi czasem zredukować wielkość pliku wynikowego o kilkadziesiąt procent. Dużym atutem biblioteki jest umiejętność radzenia sobie z dodatkowymi skryptami umieszczonymi wewnątrz kodu. Narzędzie potrafi ignorować tagi specyficzne dla skryptów JSP, PHP, ASP, PSP i Mason. Ponadto istnieje możliwość zarejestrowania dodatkowych tagów, które będą akceptowane przez parser biblioteki. Parser oferowany przez Jericho prezentuje nieco odmienną filozofię niż klasyczne parsery XML i nie operuje bezpośrednio na drzewie tagów lub zdarzeniach przejścia przez kolejne tagi a przypomina bardziej mechanizm zaawansowanego wyszukiwania tekstowego. Dzięki temu plik HTML jest cały czas traktowany jako dokument tekstowy o specyficznym (dowolnym) układzie, a nie jako obiektowa struktura danych i atrybutów. Każdy element dokumentu identyfikowany jest poprzez swoje położenie w nim (wiersz i kolumna początku i końca elementu). Taka forma reprezentacji dokumentu HTML nie pozwala na utratę jego tekstowej natury i pozwala na dowolne a nie tylko globalne operowanie wyglądem dokumentu. Dzięki tekstowemu podejściu biblioteka pozwala na pracę z dokumentami HTML zawierającymi błędy programistów (niezamknięte tagi, błędy w strukturze dokumentu, etc.), co byłoby niemożliwe przy klasycznych parserach XML.

nie tekstowym. Dobrze napisany filtr powinien rozpoznać taką sytuację i wyłączyć kompresję znaków. Pozostawiam to Czytelnikom jako zadanie domowe. Większość kodu z Listingu 1 poświęcona jest pobraniu odpowiedzi z serwletu w postaci tekstu. Sama redukcja jego wielkości danych sprowadza się zaledwie do dwóch kluczowych linii kodu:
Source source =

SourceCompactor compactor =

new Source(wrapper.toString()); new SourceCompactor(source);

Klasa Source reprezentuje źródło dokumentu HTML – może to być plik, URL lub strumień danych. Zawsze pracę z biblioteką rozpoczniemy od utworzenia instancji tej klasy. W wielu wypadkach będzie to też jedyny obiekt, który będzie nam potrzebny, gdyż klasa Source to jednocześnie parser HTML. Z użyciem jej metod możemy przykładowo łatwo przeszukać wskazany dokument. Opisane zostanie to szerzej w dalszej części artykułu. SourceCompactor to narzędzie, które wykonuje za nas całą pracę. Jak widać musimy jedynie wskazać na źródło danych HTML oraz finalnie – wskazać na obiekt Writer, który obsłuży zapis danych wynikowych. W naszym wypadku zapiszemy dane bezpośrednio do wyjścia z filtra:
compactor.writeTo(

działa na zasadzie czarnej skrzynki, wykonując za nas całą pracę. Możemy tu jedynie wpłynąć na sposób generowania nowych linii – metoda setNewLine (String newLine) przyjmuje jako parametr ciąg znaków reprezentujących nową linię. Jeśli wartość nie zostanie przez nas ustalona, biblioteka użyje identycznej reprezentacji nowych linii jak w danych wejściowych (patrz metoda getNewLine() w klasie Source). Ustawiając tę wartość na spację, uzyskamy w wyniku niezbyt czytelny, zapisany w jednej długiej linii. W niektórych przypadkach może to być użyteczne. Powrotu do wartości domyślnych możemy dokonać poprzez wywołanie metody z wartością null.
SourceCompactor

Praca z parserem HTML
Jak wspomniano wcześniej – Jericho nie jest prawdziwym parserem a bardziej – zaawansowanym mechanizmem wyszukiwania tekstowego, zorientowanym na składnię HTML. Tym niemniej programista może odnieść wrażenie, iż (podobnie jak w przypadku DOM) operuje na drzewie obiektów reprezentujących strukturę dokumentu. Wewnętrznie jednak biblioteka wykonuje karkołomne operacje na łańcuchach znaków – i to z użyciem podstawowych mechanizmów standardowej biblioteki Java. Analizując kod biblioteki nie znajdziemy operacji z użyciem wyrażeń regularnych lub budowania złożonego modelu obiektowego przed rozpoczęciem przeszukiwania dokumentu. Biblioteka działa zatem bardzo niskopoziomowo, co czyni ją narzędziem dość wydajnym.

new OutputStreamWriter(out));

Szybki start

Pierwszy program
Czas napisać pierwszy program z użyciem biblioteki. Zaczniemy od niewielkiego przykładu, za to bardzo obrazowego. Zaprezentowany na Listingu 1 kod ukazuje filtr HTTP, który wycina nadmiarowe znaki z wyjścia serwletu (np. pliku JSP). W przypadku kodu JSP używającego dużej ilości scriptletów, zazwyczaj generowana jest bardzo duża ilość białych znaków, które w tym wypadku zostaną usunięte, zauważalnie redukując rozmiar odpowiedzi z serwera aplikacji. Przykład będzie działał z dowolnym serwletem generującym na wyjściu kod HTML. JSP jest najprostszą formą jego zobrazowania. Aby nasza aplikacja mogła poprawnie działać, trzeba jeszcze zadeklarować filtr w deskryptorze aplikacji. Zobrazowano to na Listingu 2. Jak widać program bezpośrednio odwołuje się do serwletów reprezentowanych przez pliki JSP. Uważny Czytelnik z pewnością spostrzegł, że program jest mocno uproszczony i nie rozpatruje sytuacji, kiedy odpowiedź z serwera jest ciągiem binarnym a
www.sdjournal.org

Najlepiej i najszybciej jest uczyć się na przykładach. Biblioteka dostarczana jest waz ze zbiorem kilkunastu przykładowych klas obrazujących jej działanie w różnych aspektach. Aby je uruchomić, musimy oczywiście w pierwszej kolejności pobrać bibliotekę ze strony projektu: http://sourceforge.net/projects/jerichohtml/ Oprogramowanie dystrybuowane jest postaci pojedynczego pliku ZIP z dokumentacją, źródłami i skompilowaną biblioteką wewnątrz. Nas interesować będzie katalog samples/console, zawierający zbiór plików .bat uruchamiających wybrane przykłady. Nie pozostaje zatem nic innego jak uruchomić wybrane skrypty a potem przeanalizować wynikowy ekran wraz ze źródłami programów. W tych ostatnich zabrakło niestety komentarzy. Programiści nieużywający systemu Windows będą musieli uruchomić programy bezpośrednio z linii komend, wpisując z poziomu katalogu samples/console:
java -classpath classes:../../lib/jericho-html-2.6.jar -Djava.util.logging.config.file=lo gging.prop erties ClassName

gdzie ClassName jest nazwą wybranej aplikacji przykładowej. Z ciekawszych programów, którym warto się przyjrzeć na początku są: • • • • Encoding – program odczytujący tryb kodowania znaków dla pliku HTML; przy okazji pobiera też podstawowe informacje o stronie (np. jej tytuł); RenderToText – przekształca plik HTML do sformatowanego pliku tekstowego, czytelnie zaznaczając akapity, listy, etc; DisplayAllElements – analizuje plik HTML i wyświetla listę wszystkich jego elementów oraz ich położenie w pliku; ConvertStyleSheets – program demonstruje odczyt danych i manipulację na strukturach HTML – wyszukuje zewnętrzne style z plików CSS i osadza je bezpośrednio w pliku HTML (jego zmodyfikowana wersja została przedstawiona na listingu 6 i szerzej opisana w niniejszym artykule).

Wszystkie opisane programy operują na przykładowym pliku HTML dostarczanym wraz z biblioteką. W katalogu samples można również znaleźć inny podkatalog – webapps, zawierający plik .war z przykładową aplikacją internetową, którą przed uruchomieniem należy zainstalować pod wybranym serwerem aplikacji.

15

Biblioteka miesiąca
Reprezentacja dokumentu HTML Najmniejszą częścią dokumentu HTML w rozumieniu Jericho jest tag, reprezentowany przez klasę o tej samej nazwie. W rzeczywistości biblioteka rozróżnia (dziedziczący po klasie Tag) tag otwierający (klasa StartTag) i zamykający (EndTag), dzięki czemu łatwo można nawigować między początkami i końcami poszczególnych elementów strony. Obiekty tego typu zawierają informacje jedynie o samym tagu, z pominięciem jego atrybutów i ciała. Dostarczają za to szeregu metod pozwalających zidentyfikować tag lub nawigować pomiędzy związanymi z nim elementami. Większą jednostką od taga jest Element, który reprezentuje fragment kodu HTML ograniczony tagiem otwierającym i zamykającym. Element umożliwia dostęp do tagów wewnętrznych, pozwala no odczyt atrybutów oraz ciał poszczególnych tagów. Można go przyrównać do obiektów typu Node w DOM. Specyficznym typem elementu jest FormControl, który reprezentuje pole formularza HTML. Dedykowane metody pozwalają na odczyt lub zapis wartości pól oraz na manipulację ich atrybutami. Kolejną specyficzną częścią dokumentu HTML są znaki specjalne (zapisane z użyciem znaku &). Za operacje na nich odpowiada klasa CharacterReference a w szczególności – dwie różne klasy dziedziczące po niej – CharacterEntityReference dla znaków posiadających swą nazwę w standardzie HTML (np. &, €) oraz NumericCharacterR eference dla znaków reprezentowanych poprzez ich kod (np. >) Najbardziej nadrzędną jednostką jest cały dokument reprezentowany przez omawianą już klasę Source. Z punktu widzenia możliwości poruszania się po dokumencie, Source przypomina klasę Element. Ponadto zawiera szereg dodatkowych metod, specyficznych dla całego dokumentu HTML. Wszystkie wymienione wyżej elementy dziedziczą po jednej klasie – Segment, która dostarcza zbioru wspólnych metod służących poruszaniu się po dokumencie. Ponadto większość z klas narzędziowych (jak choćby poznany na początku artykułu SourceCompactor) będzie operowała na obiektach typu Segment, zatem nie będzie miało znaczenia, czy do operacji przedstawimy cały dokument, czy np. tylko element formularza. Przeszukiwanie dokumentu Siła tekstowej natury parsera Jericho ujawnia się przy przeszukiwaniu dokumentów HTML. Możemy tutaj bowiem poruszać się zarówno pomiędzy elementami (tagami) dokumentu, jak również dokonywać na nim klasycznych poszukiwań zadanych wycinków tekstu. Ilość opcji wyszukiwania jest spora – rozważmy dla przykładu różne warianty wyszukań zwracających listę wszystkich elementów zgodnych z zadanymi kryteriami dla segmentu nadrzędnego (może to być cały dokument lub tylko jego element): • – zwraca listę wszystkich elementów zawierających się w elemencie, dla którego metoda została wywołana; • findAllElements(String name) – zwraca listę wszystkich elementów oznaczonych tagiem podanym w parametrze metody; • findAllTags(String name) – jak wyżej ale zwraca listę tagów a nie elementów (operacja szybsza i mniej zachłanna w wykorzystaniu pamięci); • findAllStartTags(String name) – jak wyżej ale uwzględnia tylko tagi otwierające; • findAllElements
findAllElements() (String attributeName, String

Listing 1. Przykład użycia klasy SourceCompactor na potrzeby filtru HTTP
package org.sdjournal.jericho; import java.io.*; import javax.servlet.*;

import javax.servlet.http.*;

import au.id.jericho.lib.html.*; public class CompactorFilter implements Filter { throws IOException, ServletException {

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) OutputStream out = response.getOutputStream(); ApplicationResponseWrapper wrapper = chain.doFilter(request, wrapper); new ApplicationResponseWrapper((HttpServletResponse)response);

Source source = new Source( wrapper.toString() ); compactor.writeTo(new OutputStreamWriter(out)); } out.close();

SourceCompactor compactor = new SourceCompactor(source);

public void init(FilterConfig arg0) throws ServletException { } } public void destroy() { }

class ApplicationResponseWrapper extends HttpServletResponseWrapper { private ByteArrayOutputStream output; private CharArrayWriter myOut;

public ApplicationResponseWrapper(HttpServletResponse response) { super(response); output = new ByteArrayOutputStream(); } this.myOut = new CharArrayWriter();

public ServletOutputStream getOutputStream() throws IOException { } return new FilterServletOutputStream(output);

public PrintWriter getWriter() throws IOException { } return new PrintWriter(this.myOut);

public byte[] getData() { }

return output.toByteArray();

public String toString() { } return myOut.toString();

}

– zwraca listę wszystkich elementów podrzędnych, których tagi zawierają zadany atrybut i wartość; • findAllCharacterReferences() – zwraca listę znaków specjalnych w zadanym segmencie; • findFormControls() – zwraca listę elementów formularza HTML w zadanym segmencie; • getChildElements() – zwraca listę bezpośrednich dzieci zadanego segmentu.
11/2008

value, boolean valueCaseSensitive)

16

Jericho HTML

Powyżej przedstawiono jedynie wybrane metody przeszukiwania – nie jest to pełna lista. W przypadku wyszukiwania tekstowego użyteczne będą następujące podstawowe metody: •
subSequence(int endIndex) beginIndex, int

ta dalej metoda getElement. Z użyciem metody getAttributeValue (dostępnej dla obiektów klasy Element ale nie Tag), możemy odczytać wartość poszukiwanego atrybutu (class).

Renderer

Z HTML do tekstu
Częstą praktyką programistyczną jest odfiltrowywanie części tekstu z wnętrza kodu HTML – choćby na potrzeby kanałów RSS, przedstawiania wyników wyszukiwania, etc. Biblioteka Jericho daje pełne wsparcie dla tego procesu, dostarczając dwa różne narzędzia: •
TextExtractor

– zwraca ciąg znaków zawarty pomiędzy wskazanymi indeksami; • charAt(int index) – zwraca pojedynczy znak z zadanej pozycji; • getParseText() – zwraca obiekt typu ParseText , który bezpośrednio reprezentuje tekst kodu HTML i dostarcza całej gamy metod przeszukiwania tekstowego. Zapewne jedną z najczęściej wykonywanych operacji przez programistów będzie przechodzenie całego segmentu element po elemencie. Aby usprawnić ten proces, klasa Segment dostarcza metodę getNodeIterator(), zwracającą iterator przechodzący po wszystkich tagach segmentu. Oprócz standardowych mechanizmów wyszukiwania, otrzymujemy do dyspozycji metody pozwalające na poruszanie się pomiędzy zależnymi od siebie elementami – podobne do tych jak ma to miejsce w DOM. Wyżej wspomniałem już o metodzie getChildElements, zwracającej listę bezpośrednich potomków elementu. W alternatywie mamy również metodę getParentElement, zwracającą obiekt ojca. Dla tagów odnajdziemy metody typu findNextTag i findPreviousTag. Całość pozwala na bardzo łatwe i intuicyjne poruszanie się po dokumencie. Przykład Przykładowa aplikacja prezentująca możliwości parsera została zaprezentowana na Listingu 3. Program pobiera kod HTML zadanej strony (wskazanej w parametrze wywołania programu) i wyszukuje w nim nazwy wszystkich użytych klas CSS. Program w pierwszej kolejności wyszukuje w dokumencie taga body. Ponieważ nie interesuje nas jego pełna zawartość, a jedynie miejsce w dokumencie, gdzie tag się znajduje, posłużyliśmy się tutaj szybszą metodą wyszukującą obiekt typu StartTag (a nie Element). Nazwa taga została została podana z użyciem klasy HTMLElementName, reprezentującej listę nazw wszystkich elementów HTML ale można tu również posłużyć się zwykłym tekstem. Dla uproszczenia załóżmy, że pobieramy stronę HTML o poprawnej strukturze, tak więc możemy oczekiwać tylko jednego taga body – w tej sytuacji skorzystamy z metody findNextStartTag, by pobrać jedynie pierwszy zgodny element a nie całą listę. W rezultacie otrzymaliśmy obiekt typu StartTag, jednak chcemy w jego obrębie poszukiwać obiektów typu Element (metoda findAllElements), która zwróci listę pełnych danych na temat każdego elementu wewnątrz taga body. Bezpośrednie odwołanie się do tej metody jest błędną koncepcją – w pierwszej kolejności musimy bowiem pobrać dla elementu typu Tag jego zawartość (Element). Służy do tego używww.sdjournal.org

– bardziej złożone narzędzie, które pozwala na sformatowanie wynikowego tekstu na podstawie tagów źródłowego kodu HTML. Narzędzie będzie głównie przydatne przy transformacji większych części HTML lub całych stron, dając w efekcie tekst czytelny dla człowieka.

– klasa odfiltrowuje z zadanego segmentu wszystkie znaki specjalne i nazwy tagów, pozostawiając czysty tekst;

TextExtractor Skupmy się w pierwszej kolejności na prostszym narzędziu – TextExtractor, wyodrębniającym tekst spośród kodu HTML. Jak wszystkie narzędzia Jericho, klasa operuje na danych typu Segment. Nową instancję klasy TextExtractor tworzymy z użyciem operatora new, podając w konstruktorze obiekt segmentu lub... wywołu-

Listing 2. Plik web.xml do przykładu z Listingu 1, który definiuje filtr dla wyjścia z plików JSP
<?xml version="1.0"?>

<!DOCTYPE web-app PUBLIC

'-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN' 'http://java.sun.com/j2ee/dtds/web-app_2_2.dtd'> <display-name>SDJ - Jericho</display-name> <filter> <filter-name>Compactor Filter</filter-name>

<web-app>

</filter>

<filter-class>org.sdjournal.jericho.CompactorFilter</filter-class>

<filter-mapping>

<filter-name>Compactor Filter</filter-name> <servlet-name>jsp</servlet-name>

</web-app>

</filter-mapping>

Listing 3. Program demonstrujący przeszukiwanie dokumentu HTML. Aplikacja wypisuje nazwy wszystkich klas CSS użytych na stronie wskazanej w parametrze uruchomienia programu
package org.sdjournal.jericho; import java.net.URL; import java.util.*;

import au.id.jericho.lib.html.*; public class ClassFinder { try {

public static void main(String[] args) { Source source = new Source(new URL(args[0])); Iterator it = source .findNextStartTag(0, HTMLElementName.BODY)

HashSet classes = new HashSet(); while( it.hasNext() ) {

.getElement().findAllElements().iterator();

Element el = (Element)it.next();

String cssClass = el.getAttributeValue("class"); classes.add(cssClass);

if(cssClass != null && !classes.contains(cssClass)) { System.out.println(cssClass);

} catch (Exception e) { } e.printStackTrace();

}

}

}

}

17

Biblioteka miesiąca
jąc metodę getTextExtractor() dla dowolnego segmentu. To ostatnie rozwiązanie pozwala na bardzo szybkie operacje na tekście zawartym w tagach HTML. Zostało to zilustrowane na Listingu 4. Można tam zauważyć, iż dla otrzymanego obiektu typu TextExtractor wywołujemy metodę setIncludeAttributes, która informuje narzędzie o tym, czy atrybuty tagów mają być uwzględniane w generowanym tekście czy nie. Ponieważ metoda settera zwraca referencję do swojego obiektu, wygodnie można tworzyć cały łańcuch operacji. TextExtractor pozwala na bardziej zaawansowane reguły eksportowania tekstu z kodu HTML, wprowadzając dodatkowe mechanizmy filtrowania. W tym celu należy stworzyć własną klasę dziedziczącą po TextExtractor i nadpisać interesujące nas metody. Przykład takiego rozwiązania przedstawiono na Listingu 5. Jak widać obiekt nadpisuje metodę includeElement, która jako parametr pobiera obiekt typu StartTag a zwraca wartość logiczną. Metoda ta będzie wywołana dla każdego taga otwierającego w zadanym segmencie. Jeśli metoda zwróci wartość false, TextExtractor pominie przetwarzanie danego taga i nie zwróci dla niego żadnego tekstu. W przedstawionym przykładzie, program wyszukuje jedynie tagów typu P, których atrybut class jest różny od „info”. Pozostałe elementy segmentu zostaną zignorowane. Na podobnej zasadzie funkcjonuje metoda excludeElement, która zwraca wartość true dla wszystkich elementów, które mają zostać pominięte w generowaniu tekstu. Renderer Renderer jest dużym narzędziem dbającym o generowanie sformatowanego tekstu, który możliwie najwierniej będzie reprezentował tekst opisany językiem HTML. Z punktu widzenia programisty, narzędzie jest czarną skrzynką, którą możemy co najwyżej dostosować do swoich wymagań z użyciem kilku zaledwie parametrów. Przetworzenie całej strony HTML do czystego tekstu zmieści się w dwóch liniach kodu:
Source source=new Source(new URL(url)); System.out.println( source.getRenderer().toString());

dzielający poszczególne kolumny w tabeli (domyślnie tabulator). Każda z wymienionych metod zwraca swój obiekt (this), dzięki czemu łatwo można zbudować łańcuch operacji.

Po takiej operacji otrzymamy tekst, który nie będzie tylko długim ciągiem znaków. Akapity będę od siebie oddzielone wolnymi liniami. Listy będą numerowane lub wypunktowane z użyciem znaku *. Odnośniki będą wyróżnione trójkątnymi nawiasami. Całość będzie prawie przypominać efekt otwarcia strony pod przeglądarką Lynx. Jak widać na przedstawionym kodzie, filozofia dostępu do obiektu Renderer jest identyczna jak w przypadku klasy TextExtractor. Możemy tutaj otrzymać obiekt klasy renderera bezpośrednio z segmentu, poprzez metodę getRenderer lub utworzyć nową instancję klasy z operatorem new, podając w parametrze konstruktora obiekt segmentu. Sterowanie generowaniem tekstu odbywa się za pomocą kilku setterów. Poniżej wymieniono najważniejsze z nich: •
setMaxLineLength(int maxLineLength)

Formatowanie kodu HTML
Za formatowanie kodu HTML odpowiada klasa SourceFormatter. To kolejna z klas narzędziowych biblioteki, która – udostępniając niewielki interfejs, kryje za sobą niemałą funkcjonalność. Klasa nie buduje kodu HTML z czystego tekstu i nie zajmuje się żadną konwersją. Jak każde narzędzie Jericho – oczekuje na wejściu obiektu typu Segment, a więc istniejącego dokumentu HTML (lub jego fragmentu). Jej zadanie sprowadza się więc do ponownego zbudowania pliku HTML, który będzie sformatowany zgodnie ze wskazanymi parametrami. Można tutaj definiować wielkości wcięć, określić znak definiujący koniec wiersza, etc. – całość łudząco przypomina składnię opisanej wcześniej klasy Renderer. Dodatkową metodą, o której warto tu wspomnieć, jest setTidyTags(boolean), która (przy podaniu parametru true) wymusza generowanie tagów zgodnych z XHTML. Zachęcam do poeksperymentowania z klasą SourceFormatter i przedstawionym w pierwszym przykładzie kodem filtru HTTP. Poniżej niewielki przykład demonstrujący, jak w kilku liniach kodu można uporządkować wygląd zadanego pliku HTML:
Source source=new Source(url);

– ustawia maksymalną długość linii, po której nastąpi automatyczne łamanie tekstu; wartość domyślna to 76 ; • setNewLine(String newLine) – ustawia znak reprezentujący koniec linii; domyślanie wartość jest identyczna jak w pliku źródłowym; • setListBullets(char[] listBullets) – ustawia znaki elementów listy UL dla jej poszczególnych poziomów (domyślnie *, o, + #); • setListIndentSize(int listIndentSize) – ustawia wielkość wcięcia dla elementów listy (domyślnie 6); • s e t T a b l e C e l l S e p a r a t o r( S t r i n g tableCellSeparator) – ustawia znak od-

new SourceFormatter(source).setTidyTags(true) .writeTo(new OutputStreamWriter( System.out));

Modyfikowanie kodu HTML
Biblioteka nie byłaby kompletna, gdyby nie pozwalała na modyfikowanie kodu HTML i manipulowanie na jego strukturze. Jak wszystkie inne elementy Jericho – i ten moduł jest logiczny i prosty. Aby móc modyfikować źródłowy kod HTML należy zapoznać się przede wszystkim z klasą OutputDocument, która reprezentuje kod wynikowy. W konstruktorze tej klasy należy podać obiekt typu Source. OutputDocument dostarcza zbioru metod umożliwiających zmiany na kodzie źródłowym. Przede wszystkim są to metody typu replace (z rożnymi typami parametrów wejściowych – od Attributes po Segment), które pozwalają na podmianę w bieżącym dokumencie wybranych jego elementów. Schemat działania często będzie zatem polegał na odczytaniu kawałka kodu dokumentu, wprowadzeniu oczekiwanych poprawek i podmianie elementu w dokumencie. Ponieważ Jericho jest biblioteką do bezpośrednich manipulacji na tekście, istnieje możliwość zastąpienia dowolnej sekwencji znaków (w zadanym położeniu) lub wstrzyknięcia w podanej lokalizacji dowolnego tekstu. Zostało to dobrze zobrazowane w programie przykładowym o nazwie ConvertStyleSheets, dostarczanym wraz z biblioteką (patrz Listing 6, przedstawiający nie11/2008

Listing 4. Przykład użycia narzędzia TextExtractor do wypisania wszystkich linków zawartych w zadanym fragmencie strony
public static void showAllLinks(Segment seg) {

List links = seg.findAllElements(HTMLElementName.A); for(Iterator it=links.iterator(); it.hasNext();) { Element link = (Element)it.next(); System.out.println(link.getTextExtractor() }

.setIncludeAttributes(false).toString());

}

Listing 5. Przykład użycia mechanizmu filtrowania wewnątrz klasy TextExtractor
TextExtractor textExtractor=new TextExtractor(seg) { public boolean includeElement(StartTag tag) { return tag.getName()==HTMLElementName.P

};

}

&& !"info".equalsIgnoreCase(tag.getAttributeValue("class"));

textExtractor.writeTo(new OutputStreamWriter(System.out));

18

Jericho HTML

co zmodyfikowaną wersję programu). Program odnajduje w kodzie HTML deklaracje zewnętrznych stylów CSS a jeśli takie napotka, przenosi zawartość pliku CSS bezpośrednio do wnętrza kodu HTML, zamykając całość tagami style. W orygi-

nalnym kodzie przykładowym, tagi budowane są z użyciem operacji na klasie StringBuffer, poprzez jawne podawanie tekstu taga i konkatenację z atrybutami. Jest to praktyka podatna na błędy i zwyczajnie nieładna, a przecież biblioteka udostępnia

Listing 6. Program dołączający zawartość pliku CSS bezpośrednio do kodu HTML (zmodyfikowana wersja jednego z programów dostarczanych wraz z biblioteką)
import au.id.jericho.lib.html.*; import java.util.*; import java.io.*; import java.net.*; public class ConvertStyleSheets { if (args.length==0) { System.exit(1);

(co prawda bardzo podstawowe) narzędzia, umożliwiające na budowanie kodu tagów w ładniejszy sposób. Służą do tego celu statyczne metody generateHTML w klasach OpenTag i EndTag, zademonstrowane na przykładowym Listingu. Najważniejszym elementem przykładowego programu jest linia:
outputDocument.replace(

startTag,sb.toString());

public static void main(String[] args) throws Exception { System.err.println("Podaj URL lub nazwe wejsciowego dokumentu HTML");

która podmienia kod odwołania do zewnętrznego pliku CSS na uprzednio wygenerowany tekst z tagiem style. Ostatnia linia programu zapisuje nowo wygenerowany kod HTML na wyjściu, z użyciem znanej już nam metody writeTo. Modyfikowanie danych formularzy HTML Modyfikowanie fragmentów kodu HTML z użyciem Jericho polega głównie na bezpośrednich operacjach na tekście, jednak w kwestii modyfikacji danych formularzy HTML, biblioteka udostępnia narzędzia, pozwalające w łatwiejszy sposób na dokonywanie manipulacji. Za całość odpowiedzialne są klasy FormFields i FormField, których metody pozwalają na szybki dostęp do poszczególnych pól formularza HTML (Listing 7). Przedstawiony kod pobiera z podanego źródła listę pól formularza. Metoda clearValues usuwa wszystkie domyślne wartości, natomiast metoda addValue ustawia nową wartość dla zadanego pola (jest to skrót operacji formFields. get("name").addValue("John Smith");). Oprócz manipulacji na wartościach pól formularza, możemy również modyfikować dodatkowe atrybuty, jak na przykład ReadOnly lub Disabled. Całość finalnie musi zostać zapisana w dokumencie wynikowym, z użyciem opisanej wcześniej klasy OutputDocument.

}

String sourceUrlString=args[0];

if (sourceUrlString.indexOf(':')==-1)

URL sourceUrl=new URL(sourceUrlString); Source source=new Source(sourceUrl); StringBuffer sb=new StringBuffer();

sourceUrlString="file:"+sourceUrlString;

OutputDocument outputDocument=new OutputDocument(source); List linkStartTags=source.findAllStartTags(Tag.LINK); StartTag startTag=(StartTag)i.next();

for (Iterator i=linkStartTags.iterator(); i.hasNext();) { Attributes attributes=startTag.getAttributes(); String rel=attributes.getValue("rel"); continue; if (!"stylesheet".equalsIgnoreCase(rel)) String href=attributes.getValue("href"); if (href==null) continue;

String styleSheetContent; try { styleSheetContent=Util.getString(

} catch (Exception ex) { }

new InputStreamReader(new URL(sourceUrl,href).openStream()));

Podsumowanie
Jericho jest typowym przykładem udowadniającym siłę w prostocie. Niewielki, czytelny kod, korzystający jedynie z bibliotek standardowych oraz prosta koncepcja tworzą dość wszechstronne narzędzie programistyczne, które może znaleźć zastosowanie w wielu aplikacjach Java. Na chwilę obecną największą wadą Jericho jest brak wersji biblioteki zgodnej ze składnią Java 5 oraz nazbyt uproszczony mechanizm generacji kodu HTML. Ponadto mimo że narzędzie znalazło zastosowanie w wielu projektach i zdobyło zaufanie programistów, pewnym ryzykiem jest fakt, iż jest to oprogramowanie jednego autora. Przydałaby się grupa programistów bądź instytucja czuwająca nad dalszym rozwojem biblioteki.

continue; // nie konwertuj dla błędnego URLa

sb.setLength(0);

Attribute typeAttr=attributes.get("type");

sb.append(StartTag.generateHTML(HTMLElementName.STYLE, typeAttr.getValue()) : null, false))

typeAttr != null ? Collections.singletonMap(typeAttr.getKey(),

.append("\n").append(styleSheetContent).append("\n") outputDocument.replace(startTag,sb.toString()); .append(EndTag.generateHTML(HTMLElementName.STYLE));

} } }

outputDocument.writeTo(new OutputStreamWriter(System.out));

Listing 7. Przykład modyfikacji danych formularza
FormFields formFields=source.findFormFields(); formFields.clearValues(); formFields.addValue("name","John Smith"); outputDocument.replace(formFields);

DAVID DE ROSIER
Programista-podróżnik. Pasjonat WEB 2.0, estetycznego kodowania i algorytmów szachowych. Zawodowo – specjalista od aplikacji J2EE i MDA w sektorze bankowym. Kontakt z autorem: ddrosier@gmail.com

OutputDocument outputDocument=new OutputDocument(source);

www.sdjournal.org

19

E-commerce

Sklep internetowy w PHP i SQLite
Zaprojektuj i zbuduj w mniej niż godzinę
Gotowych rozwiązań na rynku e-commerce są setki. Znajdziemy gotowe skrypty o funkcjonalności systemów aukcyjnych, sklepów internetowych oraz systemów barterowych. To najczęściej sprawdzone i tanie rozwiązania, regularnie aktualizowane – dlatego skorzystanie z nich najczęściej bywa bardzo kuszące. Jednak czy zawsze uzasadnione? Najczęściej o wiele lepiej stworzyć własną platformę e-commerce. Nie jest to trudne – nam zajmie to 60 minut.
Dowiesz się:
• Jak zaprojektować od podstaw sklep internetowy; • W jaki sposób korzystać z SQLite; • Jak wykorzystać sesje do przechowywania danych użytkownika.

Powinieneś znać:
• Co najmniej podstawy PHP oraz SQL; • Podstawy programowania obiektowego.

Poziom trudności

go wpływu na poziom trudności pracy. Dlatego nasz sklep zbudujemy wykorzystując PHP5 oraz… SQLite.

Przed rozpoczęciem pracy…
… należy zastanowić się nad funkcjonalnością sklepu. Chcemy oczywiście sprzedawać określone produkty – to oczywiste. Zastanówmy się jednak, co dokładnie chcemy przedstawić potencjalnemu nabywcy. Na pewno będzie to nazwa produktu oraz jego opis. Ludzie lubią widzieć, co kupują, wskazane jest więc umieszczenie co najmniej jednego zdjęcia. Część produktów wymaga dokładniejszego sfotografowania, tak więc nie powinniśmy ograniczyć maksymalnej liczby zdjęć. Oczywiście niezbędne jest również uwzględnienie ceny oraz stawkę podatku VAT. W zależności od typu produktów można pomyśleć również nad dodatkowymi polami określającymi jego parametry (dla sklepu z butami warto pomyśleć o polach z rozmiarami, sprzedając dyski twarde warto zaznaczyć ich pojemność) a jeśli znamy stan magazynu możemy również wykorzystać tą informację. Nie ma bowiem sensu pokazywać użytkownikowi towaru, którego nie mamy na stanie, lub który został już raz sprzedany. Produkt powinien

P

owodów, dla których nie warto wdrażać gotowych rozwiązań może być wiele. Dla prostego sklepu internetowego, w którym właściciel chce zaoferować kilka produktów wykorzystanie osCommerce może być nieoptymalne. Dodatkowo modyfikowanie takiej gotowej platformy również nie należy do rzeczy najprostszych – jeśli dostępna jest dokumentacja, wystarczy się z nią zapoznać. Jeśli jednak jej nie ma, pozostaje metoda prób i (niestety najczęściej) błędów. W obu przypadkach potrzebujemy czasu – który możemy poświęcić na stworzenie własnego, dedykowanego rozwiązania. Za chwilę zobaczysz, że w mniej niż 60 minut można zbudować sklep internetowy, który pomimo okazałej nazwy jest po prostu interfejsem pośredniczącym pomiędzy bazą danych a użytkownikiem, wykonującym na niej określone operacje. Struktura takiej bazy najczęściej nawet nie jest bardzo skomplikowana, tak więc można użyć praktycznie dowolnego silnika baz danych. Nie ma to żadne20

zostać również umieszczony w konkretnej kategorii – ułatwi to przeszukiwanie sklepu użytkownikowi. Klient naszego sklepu w przypadku dokonania zakupu powinien przekazać nam dane niezbędne do zrealizowania zamówienia (m.in. imię, nazwisko, adres, dane do faktury, dane wysyłki). Przyjęliśmy więc, że w celu dokonania zakupu konieczne jest posiadanie konta w systemie. Rejestracja powinna być oczywiście bezpłatna, a klient powinien mieć również możliwość samodzielnego usunięcia konta. Warto również pomyśleć o systemie rabatów – pozwoli to zatrzymać klienta oraz uatrakcyjnić cenowo naszą ofertę. Rabat możemy uzależnić od wielu elementów – wielkości zakupów, kodu promocyjnego podanego podczas rejestracji lub przekroczenie określonej wartości wszystkich zakupów od chwili zarejestrowania konta. W naszym sklepie rabat będzie przydzielany ręcznie przez administratora – czytelnik jednak bez większych problemów będzie w stanie dopasować system rabatowy do własnych potrzeb. Ostatnim niezbędnym elementem jest lista zamówień. Zastanówmy się jakie informacje są naprawdę potrzebne do sprawnego obsłużenia klienta. W większości przypadków powinno wystarczyć imię i nazwisko zamawiającego, adres wysyłki, data złożenia zamówienia, stan, data wysłania towarów oraz oczywiście zamówione towary.

Minuta pierwsza – baza danych
Na początku prac zaprojektujemy strukturę naszej bazy danych. Do stworzenia ba11/2008

Sklep internetowy w PHP i SQLite

zy można użyć zewnętrznych narzędzi (np. zewnętrzny SQLite Manager działający jako dodatek do przeglądarki Mozilla Firefox) lub napisanego samodzielnie prostego skryptu w PHP. Wystarczy do tego podstawowa znajomość języka SQL oraz funkcji wbudowanych w PHP służących do komunikacji z bazą sqlite. Gotowy skrypt przedstawiony jest na Listingu 1. Jego działanie jest proste – łączymy się z plikiem bazy danych, oraz wywołujemy 5 zapytań tworzących 5 tabel – tabelę do przechowywania informacji o użytkownikach, produktach, dostępnych kategoriach, oraz dwie tabele do przechowywania informacji o zamówieniach użytkownika. Strukturę utworzonych tabel przedstawia Rysunek 1. Część z was najprawdopodobniej zauważyła, że brakuje pól w których będą przechowywane informacje o zdjęciach produktów.
Listing 1. Skrypt tworzący tabele w bazie danych
<?php

Zamiast tego, zdjęcia będą miały nazwę odpowiadającą unikalnemu polu zawierającemu unikalne ID produktu, znak separatora (podkreślnik) oraz kolejny numer zdjęcia produktu. Pozwoli to na umieszczenie praktycznie nieograniczonej ilości zdjęć. PHP dostarcza nam mechanizm umożliwiający proste sprawdzenie czy plik w określonej lokalizacji istnieje (służy do tego funkcja file_exist()) – dzięki temu nie musimy przechowywać informacji o tym fakcie w bazie danych. Zdziwić może również brak atrybutów AUTOINCREMENT przy tworzeniu bazy. Jest to związane z tym, że w SQLite wszystko jest łańcuchem znaków. Typ kolumny pomaga silnikowi bazy dane te odpowiednio posortować, oraz zwiększa przejrzystość tabel. Autorzy jednak udostępnili substytut atrybutu – wystarczy zadeklarować w tabeli pole INTEGER PRIMARY KEY .

Minuta 10 – obiekty
W kolejnym kroku utworzymy klasy reprezentujące trzy podstawowe typy obiektów które zdefiniowaliśmy na początku artykułu – dla użytkownika, produktu, oraz zamówienia. W każdej klasie oprócz pól charakterystycznych dla bazy danych znajduje się również prywatne pole error – wykorzystamy je do zapisywania informacji o ewentualnym błędzie (na przykład błędzie podczas połączenia z bazą danych, lub nieprawidłowych danych logowania). Przyjmijmy również, że wszystkie funkcje i metody zwracają wartość logiczną – prawdę, gdy realizowana operacja się powiedzie, oraz fałsz gdy wystąpi jakikolwiek błąd. Dzięki temu sprawdzenie poprawności wykonania nawet cyklu operacji jest dziecinnie proste – sprowadza się do wprowadzenia kilku instrukcji warunkowych.

include 'config.php'; if($db = sqlite_open($sqlitePath, 0666, $sqliteerror)) { sqlite_query($db, 'CREATE TABLE "users" ( "users_id" INTEGER PRIMARY KEY , "users_username" TEXT NULL , "users_name" TEXT NULL

, "users_city" TEXT NULL , "users_postcode" TEXT NULL , "users_adress" TEXT NULL , "users_phone" TEXT NULL

, "users_mail" TEXT NULL , "users_dname" TEXT NULL , "users_deliverycity" TEXT NULL , "users_password" TEXT "users_nip" TEXT NULL );');

NULL , "users_deliverypostcode" TEXT NULL , "users_deliveryaddress" TEXT NULL , "users_discount" TEXT NULL , sqlite_query($db, 'CREATE TABLE "products" ("products_id" INTEGER PRIMARY KEY , "products_name" TEXT NULL , "products_

description" TEXT NULL , "products_price" TEXT NULL , "products_tax" INT NULL , "products_count" INT NULL , "products_categoryid" INT NULL );'); TABLE "category" ( "category_id" INTEGER PRIMARY KEY , "category_name" NULL);');

sqlite_query($db, 'CREATE sqlite_query($db, 'CREATE sqlite_query($db, 'CREATE sqlite_close($db); } { }

"order_status" TEXT NULL , "order_sdate" INT NULL );'); NOT NULL );');

TABLE "orders" ( "order_id" INTEGER PRIMARY KEY , "order_userid" INT NULL , "order_date" INT NULL , TABLE "order_products" ( "product_id" INTEGER PRIMARY KEY , "order_id" INT NOT NULL , "op_amount" INT

echo 'Tabele zosta³y utworzone!';

else die('Wystąpił błąd: '. $sqliteerror);

?>

Listing 2. Zawartość pliku config.php
<?php

$sqlitePath = './sklep2.sqlite'; session_start();

function __autoload($class_name) { } ?>

require_once './class/'.$class_name . '.php';

www.sdjournal.org

21

E-commerce

Listing 3a. Fragment klasy user – służącej do obsługi użytkownika
class user { public $id; }

}

public $username; public $password; public $name; public $city;

function checklogin($username, $password) { if($db = sqlite_open($sqlitePath, 0666, $this->error )) { $value = sqlite_array_query($db, "SELECT users_id FROM users WHERE users_username = MD5(".$password.")"); '".$username."' AND users_password = if(sqlite_num_rows($db) == 0) {

public $postcode; public $adress; public $phone; public $mail; public $dname;

public $deliverycity;

public $deliverypostcode; public $deliveryadress; public $discount; public $nip; private $error; function __constuct($id='') { if($id!='') } { }

$this->error = 'Nieprawid³owa nazwa u¿ytkownika sqlite_close($db); lub has³o!';

}

return -1;

return $value['users_id'];

else return 0;

}

$this->load($id); }

function load($id) { if($db = sqlite_open($sqlitePath, 0666, $this->error )) { $value = sqlite_array_query($db, "SELECT * FROM users WHERE users_id = '".$id."'");

function add($username, $password, $name, $city, $postcode, $adress, $phone, $mail, $dname, $deliverycity, $deliverypostcode, { $deliveryadress, $discount, $nip) $this->username = sqlite_escape_string($username); $this->password = sqlite_escape_string($password); $this->name = sqlite_escape_string($name); $this->city = sqlite_escape_string($city);

if(sqlite_num_rows($value) == 0) { $this->error = "Brak u¿ytkownika o podanym id!"; return false;

}

$this->postcode = sqlite_escape_string($postcode); $this->adress = sqlite_escape_string($adress); $this->phone = sqlite_escape_string($phone); $this->mail = sqlite_escape_string($mail); $this->deliverycity = sqlite_escape_ $this->dname = sqlite_escape_string($dname); string($deliverycity); postcode);

$this->id = $value['users_id'];

$this->username = $value['users_username']; $this->password = $value['users_password']; $this->name = $value['users_name']; $this->city = $value['users_city'];

$this->postcode = $value['users_postcode']; $this->adress = $value['users_adress']; $this->phone = $value['users_phone']; $this->mail = $value['users_mail']; $this->dname = $value['users_dname'];

$this->deliverypostcode = sqlite_escape_string($delivery $this->deliveryadress = sqlite_escape_

$this->deliverycity = $value['users_deliverycity']; $this->deliverypostcode = $value['users_ $this->deliveryadress = $value['users_ $this->discount = $value['users_discount']; $this->nip = $value['users_nip']; sqlite_close($db); } { return true; $this->error=''; deliveryadress']; deliverypostcode'];

$this->discount = sqlite_escape_string($discount); $this->nip = sqlite_escape_string($nip); if($this->validate()) { if($db = sqlite_open($sqlitePath, 0666, $this->error { ))

string($deliveryadress);

sqlite_array_query($db, "INSERT INTO users (users_ id, users_username, users_password, users_name, users_city, users_postcode, users_adress, users_phone, users_mail, users_dname, users_deliverycity, users_ deliverypostcode, users_deliveryadress, users_discount, users_nip) VALUES

else return false;

22

11/2008

Sklep internetowy w PHP i SQLite

W naszym systemie skorzystamy z mechanizmu automatycznego ładowania plików z klasami wprowadzonego w piątej wersji PHP. Dlatego klasy, z których będziemy korzystać bezpośrednio w skrypcie musimy umieścić w osobnych plikach o nazwach takich samych jak nazwy klas. Sama funkcja __autoload() umieszczona została w pliku config.php. Plik ten dołączany jest na początku projektu – gwarantuje to, że funkcja będzie dostępna w każdym miejscu skryptu. W pliku tym zdefiniowaliśmy również nazwę pliku z bazą danych oraz wystartowaliśmy mechanizm sesji. Użytkownik Na Listingu 3a i 3b przestawiono fragment klasy reprezentującej użytkownika. Powinna ona dostarczyć nam wszystkich operacji niezbędnych do obsługi użytkownika. Wszystkie pola wyłączając pole $error są publiczne – chcemy mieć bowiem do nich dostęp w każdym miejscu skryptu. Oczywiście możesz utworzyć zmienne prywatne i utworzyć metodę do ich zwracania. Pole error nie powinno być modyfikowane z zewnątrz klasy – dlatego pozostanie prywatne, a dostęp do jego zawartości spoza klasy odbywa się wyłącznie za pośrednictwem metody geterror().

Klasa posiada zdefiniowany jednoparametrowy konstruktor. Podanie parametru nie jest jednak konieczne – jeśli nie zostanie po-

dany, zostanie utworzony pusty obiekt. Jeśli jednak jako parametr podamy id użytkownika, zostanie wywołana metoda load() któ-

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

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

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

�������

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

�������

�������

Rysunek 1. Schemat utworzonej bazy danych

Listing 3b. Fragment klasy user – służącej do obsługi użytkownika
(NULL, ".$this->username.", ".$this>password.", ".$this->name.", ".$this->city.", ".$this->postcode.", ".$this->adress.", ".$this->phone.", ".$this->mail.", ".$this->dname.", ".$this->deliverycity.", ".$this>deliverypostcode.", ".$this".$this->nip.");"); } function validate() { //realizację funkcji validate pozostawiamy czytelnikowi. //funkcja powinna zwróciæ false gdy nie podano wszystkich wymaganych pól } return true;

>deliveryadress.", ".$this->discount.", sqlite_close($db); } { } return true;

function geterror() { } } return $this->error;

else return false;

}

Listing 4. Metoda updatecount() klasy product
function updatecount($id, $newcount) { if($db = sqlite_open($sqlitePath, 0666, $this->error )) { sqlite_array_query($db, "UPDATE products SET products_ count = '".$newcount."' WHERE products_ id = '".$this->id."';"); } sqlite_close($db); } { } return true;

else return false;

www.sdjournal.org

23

E-commerce

Listing 5. Fragment odpowiedzialny za wyświetlenie kategorii oraz spisu towarów
<?php include 'config.php'; $error = ''; $categories = array(); $products = array();

if($db = sqlite_open($sqlitePath, 0666, $error )) { //wybieramy wszystkie dostêpne kategorie $table = sqlite_array_query($db, 'SELECT * FROM category'); foreach($table as $value) { }

$categories[] = array($value['category_id'], $value['category_name']);

//Wyœwietlamy u¿ytkownikowi menu z wyborem kategorii: foreach($categories as $category) { } echo '<a href="list.php?category='.$category[0].'">'.$category[1].'</a><br>'; echo '<div name="categories">';

echo '</div>';

//sprawdzamy, czy u¿ytkownik wybra³ kategorie: if($_GET['category']=='') { } { echo '<div name="message">Witaj w naszym sklepie internetowym! Wybierz interesuj¹c¹ Ciê kategorie!</div>';

else //jeœli tak - pobieramy towary z bazy: $table = sqlite_array_query($db, 'SELECT products_id FROM products WHERE products_categoryid = "'.sqlite_escape_string($_ if(count($table)==0) { } { { GET['category']).'" AND products_count>0;');

echo '<div name="message">Nie znaleziono produktów w kategorii!</div>';

else foreach($table as $value) $products[] = $value['products_id'];

//oraz wyœwietlamy: foreach($products as $id) { echo '<div name="products">';

}

$product = new product($id);

echo '<div name="singleproduct"><a href="details.php?productid='.$product->id.'">'.$product->name.'</a><br> Opis: '.substr($product->description, 0, 150).'<a href="details.php?productid='.$product->id.'">[...] dalej</a></div>'; Cena netto: '.$product->price.' (+ '. $product->tax.') z³ <br>

}

echo '</div>'; } } { } }

sqlite_close($db);

else die('Wyst¹pi³ b³¹d: '. $error);

?>

24

11/2008

Sklep internetowy w PHP i SQLite

ra uzupełni wszystkie pola klasy jego danymi. Oczywiście funkcja może zostać wykonana w dowolnym momencie życia obiektu – możemy więc po prostu utworzyć obiekt i dopiero później uzupełnić pola metodą load(). Klasa zawiera również metodę checkLogin przyjmująca jako argumenty nazwę użytkownika i hasło. Zadaniem tej metody jest sprawdzenie istnienia w bazie użytkownika o podanych danych logowania. Jeśli użytkownik taki istnieje – funkcja zwróci jego id, w przeciwnym wypadku zwróci wartość 0. Funkcja ta będzie wykorzystywana podczas logowania użytkownika do sklepu. W klasie zdefiniowano również metody add() , remove() oraz validate(). Z powodu ograniczonej objętości artykułu, pełen kod klasy znajdziecie na stronie http: //sdjournal.org. Pierwsza metoda ustawia pola klasy zgodnie z wartościami podanymi na parametr oraz zapisuje użytkownika do bazy danych. Metoda jest wykorzystywana przy rejestracji użytkownika. Wykorzystuje ona dodatkowo metodę validate(), która służy do walidacji danych. Możesz w niej sprawdzać, czy dane spełniają przyjęte założenia – na przykład, czy wypełniono wszystkie pola ustalone jako obowiązkowe. Metoda powinna zwracać logiczną prawdę, jeśli dane są wypełnione poprawnie oraz fałsz w przeciwnym wypadku. Ostatnia metoda – służy do usuwania użytkownika którego id podamy jako parametr. Produkty Klasa reprezentująca produkty jest bardzo podobna do klasy user. Również tutaj znajduje się metoda load() , add(), validate() oraz remove(). Ich funkcjonalność jest identyczna – nie ma więc sensu ich szerszego omawiania. Klasa posiada dwie nowe metody służące do uaktualnienia stanu magazynu. Pierwsza – updatecount() przedstawiona na Listingu 4 służy do zaktualizowania dostępnej liczby egzemplarzy towaru o określonym ID. Druga – decreasecount() zmniejsza ilość dostępnych produktów o jeden. Kod całej klasy products znajduje się na stronie: http://sdjournal.org Zamówienia Nieco bardziej skomplikowana jest klasa do obsługi zamówień. Związane jest to z tym, że zamówienia przechowujemy w dwóch tabelach w bazie – w jednej przechowujemy informacje o zamówieniu (numer, datę złożenia, datę realizacji) a w drugiej identyfikatory zamówionych towarów oraz ich ilość. Kolejnym problemem jest nieznana ilość typów towarów – nie możemy przewidzieć ile rzeczy zostanie przez użytkownika nabytych. Dlatego nie możemy wprowadzić określonej ilości pól w klasie. Konieczne więc jest wykowww.sdjournal.org

rzystanie jakieś struktury danych. Niestety, w chwili obecnej PHP nie obsługuje list czy kolejek – trzeba je implementować samodzielnie. Sytuacja ma się jednak zmienić – w PHP od wersji 5.3 mają zostać zaimplementowane podstawowe struktury danych (m.in. lista, kolejka, stos oraz kopiec). W chwili pisania artykułu dostępna była jednak jedynie

wersja PHP 5.1alpha1 – dlatego do przechowywania informacji o produktach w zamówieniu wykorzystaliśmy rozwiązanie mniej subtelne – zwykłą tablicę. Elementami tablicy są obiekty typu orderProduct. Definicję tej klasy umieściliśmy w tym samym pliku co klasa order – nie jest to błąd. Bezpośrednio do tej klasy powinny odwoływać się

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

������

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

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

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

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

�������

�������

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

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

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

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

�������

�������

Rysunek 2. Struktura klasy order Listing 6. Wyszukiwanie obrazków danego produktu
//pobieramy długość identyfikatora ID produktu $length = strlen(trim($_GET['productid'])); //otwieramy katalog images if($dir = opendir('./images/')) { //pobieramy nazwy wszystkich plików while (false !== ($file = readdir($dir))) { //porównujemy pierwsze znaki if (substr($file, 0, ($length+1)) == trim($_GET['productid'])."_") { } echo '<img src="./images/'.$file.'">';

} }

closedir($dir);

25

E-commerce
tylko instancje klasy order(), a jakiekolwiek odwołanie powinno być możliwe wyłącznie przez pole z tablicą obiektów w tej klasie. Sama klasa orderProduct składa się z czterech pól – zawierającego id produktu, ilość zamówionych egzemplarzy oraz pole omówionego typu product w którym przechowywaListing 7. Dodawanie produktów do koszyka
<?php

ne są informacje o produkcie. Struktura klasy order może wydawać Ci się skomplikowana. Jeśli tak rzeczywiście jest, spójrz na Rysunek 2. Powinien on wyjaśnić wszelkie niejasności. Oczywiście klasa posiada również metody load(), add(), remove(), validate() o

funkcjonalności identycznej jak w poprzednich klasach. I to wszystko! Choć może ciężko w to uwierzyć, to klasy które stworzyliśmy wystarczą do stworzenia w pełni funkcjonalnego sklepu. Za chwilę zobaczysz, w jaki sposób umiejętnie manipulując utworzonymi obiektami (zarówno polami jak metodami) stworzymy w pełni funkcjonalny sklep internetowy!

include 'config.php'; //jesli nie utworzono wczesniej obiektu w koszyku: if(!isset($_SESSION['order'])) { } $_SESSION['order'] = new order();

Minuta 30 – wystawa
Czas zabrać się za kod właściwy. Na początek stworzymy naszą wystawę – stronę, która prezentować będzie klientowi dostępne produkty wraz z krótkim opisem oraz ich ceną. Po wybraniu produktu klient powinien zobaczyć dokładny opis, wraz ze zdjęciami oraz linkiem umożliwiającym dodanie produktu do wirtualnego koszyka.

//jeœli nie podano iloœci kupowanych produktów, wyœwietlamy formularz. if($_POST['amount']!='') { //dodajemy towar. $_SESSION['order']->addproduct($_POST['productid'], $_POST['amount']); header("location:list.php"); } { exit;

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

else ?>

<form method="POST">

<input type="hidden" name="productid" value="<?php echo $_GET['productid'];?>"> Chce kupiæ <input type="text" name="amount" value="1"> sztuk.<br> <input type="submit" value="Dodaj do koszyka">

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

</form> } <?php

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

?>

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

Listing 8. Dodanie zamówienia do bazy danych
<?php include 'config.php';

//sprawdzamy, czy u¿ytkownik jest zalogowany if(isset($_SESSION['user']->id)) { header("location:login.php"); exit;

���

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

}

//uzupe³niamy dane zamówienia $_SESSION['order']->userid = $_SESSION['user']->id; $_SESSION['order']->date = now(); $_SESSION['order']->status = ''; $_SESSION['order']->add();

���

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

//kasujemy zawartoœæ koszyka unset($_SESSION['order']); //przekierowujemy klienta na stronê z podziêkowaniami header("location:thanks.html"); exit; ?>

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

Rysunek 3. Proces zakupów

26

11/2008

Sklep internetowy w PHP i SQLite

Spis towarów… …będzie pierwszą rzeczą którą zobaczy klient po wejściu do naszego sklepu. Dodatkowo będzie to najprawdopodobniej strona która będzie najczęściej wyświetlana. Dlatego należy zadbać, aby była czytelna. Nie powinniśmy więc przeładowywać jej mało przydatnymi informacjami – wystarczy wyświetlić nazwę, początek opisu oraz cenę – to właśnie nią kieruje się większość użytkowników. Oczywiście informacje wyświetlane w naszym sklepie są tylko przykładem – ostateczny wygląd strony zależy od Czytelnika. Listing 5 przedstawia gotowy skrypt. Na początku łączymy się z bazą – jeśli połączenie się nie uda, wykonywanie skryptu zostanie przerwane. Po połączeniu z bazą pobieramy z bazy danych wszystkie kategorie oraz tworzymy tablicę dwuwymiarową w której przechowujemy pary – nazwa kategorii oraz jej unikalny identyfikator numeryczny. Dane te wyświetlamy w bloku <div> o nazwie categories. Umożliwi to prostą zmianę wyglądu sekcji (i całego sklepu) przy użyciu zewnętrznego arkusza stylów. Przy wyświetlaniu strony należy sprawdzić, czy klient wybrał już kategorie. Ponieważ informacja o kategorii przesyłana jest jako parametr w adresie, wystarczy sprawdzić wartość tej zmiennej. Jeśli użytkownik niczego nie wybrał – wyświetlamy komunikat powitalny zachęcający do obejrzenia naszej oferty. Jeśli kategoria jest wybrana – pobieramy z bazy danych identyfikatory produktów należących do tej kategorii oraz tworzymy obiekt klasy products , który wykorzystując metodę load() wypełnia wszystkie pola klasy danymi produktu, które następnie są wyświetlane. Szczegóły produktu Po wybraniu interesującego produktu klientowi powinny wyświetlić się dokładniejsze informacje – między innymi pełen opis, cena oraz wszystkie dostępne zdjęcia. Wyświetlenie danych przedmiotu nie powinno Ci już sprawić żadnego problemu – również tutaj tworzymy nowy obiekt typu product podając jako parametr id projektu przesyłane w adresie. Trudniejsze może wydawać się wyświetlenie wszystkich zdjęć produktu. Kod realizujący to zadanie przedstawiony jest na Listingu 6. Przypomnijmy – przyjęliśmy, że obrazki produktu o określonym id mają nazwę: id_ (numer). Używając funkcji opendir() oraz

readdir() otwieramy folder ze zdjęciami i szu-

kamy plików, które rozpoczynają się od tych znaków. Jeśli warunek ten jest spełniony – wyświetlamy zdjęcia na stronie. Ponownie, ze względu na ograniczoną objętość artykułu, po pełen kod skryptu odsyłamy na http://sdjournal.org

Minuta 45 – koszyk zakupów
Jednym z najbardziej charakterystycznych rzeczy w sklepach internetowych są niewątpliwie koszyki. To one będą przechowywać informację o produktach, które klient zdecydował się kupić (zarówno o samym produkcie jak i ilości zamówionych egzemplarzy). Poprawne skonstruowanie koszyka jest bardzo ważne – w koszyku nie mogą pojawić się zakupy kogoś innego, nie mogą one również zniknąć. Podstawowa zasada jest więc prosta – należy zagwarantować każdemu klientowi własny koszyk. Można to oczywiście zrobić na wiele (lepszych lub gorszych) sposobów. Koszyk każdego klienta może być plikiem przechowywanym w jednym z folderów sklepu. Może być również wpisem w bazie danych. W obu przypadkach należałoby wybrać pewną unikalną cechę klienta, która stanowiłaby jego identyfikator. Pewnie część czytelników zaproponowałaby, aby takim identyfikatorem był adres IP komputera z którego korzysta użytkownik. Niestety adresu nie możemy wykorzystać – istnieją rozwiązania, które umożliwiają współdzielenie adresu IP pomiędzy wieloma komputerami (najpopularniejsze to proxy oraz NAT). Jeśli dwóch naszych klientów korzystałoby z takiej sieci nie jesteśmy w stanie rozróżnić ich koszyków. Innym rozwiązaniem jest wykorzystanie mechanizmu ciastek (cookies) do przechowania informacji o zawartości koszyka. Rozwiązanie to jest jednym z lepszych, choć również nie jest pozbawione wad. Nie możemy bowiem zagwarantować, że każdy nasz klient będzie miał włączoną obsługę ciastek w przeglądarce. Co prawda odsetek takich ludzi jest coraz mniejszy, jednak nie oznacza to, że ktoś z tej grupy nie będzie chciał skorzystać z sklepu. Odrzucamy to rozwiązanie również z innego powodu – w PHP od dawna istnieje mechanizm nie posiadający wspomnianych wcześniej wad. Mowa oczywiście o sesjach, których zasada działania jest połączeniem zasad metod wcześniej wymienionych. Dla każdego użytkownika generowany jest plik, w którym przechowywać możemy dane. Dodatkowo każdy użytkownik posiada unikalny identyfikator sesji (PHPSESSID) który pozwala na przyporządkowanie plików konkretnym użytkownikom. Identyfikator ten jest przesyłany pomiędzy podstronami wykorzystując ciastka, lub – jeśli przeglądar-

ka nie obsługuje Cookies – dodając do adresu parametr. Jednak najlepsze w tym rozwiązaniu jest to, że nie musimy w ogóle przejmować się szczegółami implementacji tego mechanizmu – wszystko załatwia PHP. Jedyne o co musimy zadbać, to wystartowanie mechanizmu sesji – realizujemy to funkcją session_start(). W plikach sesyjnych możemy przechowywać dowolny typ danych, mogą to być proste zmienne, tablice, a nawet obiekty – ograniczają nas wyłącznie nasze potrzeby oraz wyobraźnia. My do budowy koszyka wykorzystamy utworzoną wcześniej klasę order, która przechowuje informacje o zamówieniu. W rzeczywistości będziemy korzystać tylko z pola orderproducts, które jest tablicą zamówionych obiektów. Aby dodać nowy produkt do koszyka stworzyliśmy dodatkową metodę – addproduct(). Przyjmuje ona 2 parametry – ID dodawanego towaru oraz jego ilość. Gdy klient złoży zamówienie, wystarczy uzupełnić obiekt danymi zamówienia i wywołać metodę add() która doda zamówienie do bazy danych. Oczywiście, możemy to wykonać tylko wtedy, gdy klient jest zalogowany – jeśli nie, przekierowujemy go na odpowiednią stronę. Cały proces dokonywania zamówienia przedstawiony jest na Listingu 8.

Podsumowanie
Właściwie mamy już działający sklep. Klient może przeglądać oferowane przez nas produkty, dodać je do koszyka i ostatecznie jeśli zdecyduje się na zakup – zamówić je. Oczywiście, nie jest to pełna funkcjonalność sklepu – powinieneś stworzyć jeszcze moduł dla obsługi sklepu, który będzie wyświetlał złożone zamówienia, umożliwiał tworzenie kategorii oraz dodawanie towaru. Nie powinno to jednak sprawić Ci już najmniejszego problemu – wystarczy wykorzystać metody load() oraz add() z odpowiedniej klasy. Jeśli jednak nie będziesz czegoś pewien – zachęcamy do przejrzenia kodu pełnego skryptu, umieszczonego na stronie http://sdjournal.org. Kod jest dosyć szeroko skomentowany, stanowi więc dosyć dobre uzupełnienie niniejszego artykułu.

GRZEGORZ HIBNER
Autor jest studentem Politechniki Poznańskiej i pracownikiem firmy zajmującej się consultingiem IT. Z PHP związany jest od pierwszych wersji PHP4. Interesuje się szeroko pojętym programowaniem (PHP, C/C++, C#, JAVA), bazami danych oraz zarządzaniem projektami. Kontakt z autorem: grzegorz.hibner@gmail.com

W Sieci
• • http://www.php.net http://www.sqlite.org

www.sdjournal.org

27

E-commerce

Wydajny, elastyczny i przyjazny CMS
Poznajemy Textpattern cz.1
TXP nie jest tak popularny jak np. Joomla. Nie posiada tak rozbudowanej listy plugin'ów i dodatków. Mniej znany, nie oznacza jednak gorszy czy też mniej wydajny. Stanowi ciekawą alternatywę i chociażby tylko ze względu na to warto poszerzyć horyzonty i przyjrzeć się rozwiązaniu bliżej. Niniejszy artykuł pełni rolę wprowadzenia.
Dowiesz się:
• Zdobędziesz podstawową wiedzę na temat CMS Textpattern; • Dowiesz się jak zainstalować i przygotować TXP do pracy, skonfigurować podstawowe i zaawansowane opcje.

Powinieneś wiedzieć:
• Znać podstawy XHTML, CSS i PHP; • Posiadać podstawową wiedzę na temat serwerów WWW oraz witryn internetowych zbudowanych w oparciu o system CMS; • Orientować się w tematyce budowy wydajnych stron WWW.

Zalecany jest również serwer Apache od wersji 1.3 lub 3.0 z włączonym modułem wsparcia dla przyjaznych linków (clean URLs) mod_rewriter. Po szczegółowe informacje odnośnie wymagań warto zajrzeć na domową stronę projektu http://www.textpattern.com. W dalszej części zakładam, iż posiadamy zainstalowane, skonfigurowane i działające środowisko dla TXP. Licencjonowanie TXP jest darmowym rozwiązaniem open source objętym licencją GNU GPL (General Public License). Oznacza to, że możemy zarówno w celach komercyjny jak i prywatnych wykorzystywać, dystrybuować i modyfikować CMS. Należy pamiętać, iż zewnętrzne rozwiązania zwiększające funkcjonalność TXP, plugin'y, dodatki itp. mogą być objęte odrębnymi warunkami licencyjnymi. Od wersji 4.1 planowane jest objęcie TXP licencją BSD (Berkley Software Distrybution). Zgodnie z zasadami licencji Textpattern nadal pozostanie darmowym rozwiązaniem. Zasady licencji BSD czynią zasady korzystania nawet bardziej liberalnymi. Proces instalacji Ściągamy paczkę instalacyjną z witryny projekt. Rozpakowaną zawartość kopiujemy do wybranego katalogu naszego serwera w obrębie którego powstawać będzie nasza witryna np. http: //localhost/cms W oknie przeglądarki wpisujemy adres naszej lokalizacji wskazując na podkatalog textpattern, http://localhost/cms/textpattern/. Pojawia się ekran powitalny na którym musimy dokonać wyboru domyślnego języka. TXP posiada wsparcie dla języka polskiego, jednak wybierzmy język angielski. Uczyni to zdobytą wiedzę bar11/2008

Poziom trudności

T

extpattern to darmowy, elastyczny, elegancki, łatwy w użyciu system zarządzania treścią. Informację taką znajdziemy na oficjalnej stronie projektu i chyba jest to najtrafniejsza definicja której słuszności mam nadzieję dowiodę. Owszem, jest wiele innych systemów CMS, które możemy objąć podobną definicją. Dlatego warto wspomnieć o tym co odróżnia Texpattern (w skrócie TXP) od innych systemów zarządzania treścią. Podobnie jak inne znane rozwiązanie tego typu TXP wykorzystuje PHP, XHTML, arkusz CSS oraz bazę danych MySQL. Tak jak inne systemy zarządzania treścią może wykorzystać TXP do budowy witryny firmowej, portalu korporacyjnego czy prywatnego bloga. Różnice odnajdziemy kiedy rozpoczniemy pracę nad budową własnej witryny w oparciu o prezentowane rozwiązanie. Wiele z systemów CMS z którymi się spotkałem oferowało możliwość łatwego wprowadzania treści, dodawania artykułów oraz podstron. Nie będąc zawodowym webmasterem użytkownik, po zainstalowaniu i wstępnym skon28

figurowaniu, mógł cieszyć się własną witryną WWW. Dla szukających szybkiej i w miarę bezbolesnej metody na zaistnienie w Sieci to znakomite rozwiązanie, które porównałbym do mieszkania w stanie pod klucz. Po odmalowaniu, wyłożeniu wykładziny, umeblowaniu możemy cieszyć się własnym kątem. TXP natomiast przedstawiłbym jako mieszkanie w stanie surowym, w którym możemy zdecydować o ilość i układzie pokoi, budowie ścianek działowych, lokalizacji pomieszczeń. TXP oferuje większą swobodę. Dostajemy solidny i stabilny szkielet na którym realizujemy naszą wizję. W minimalnym stopniu ograniczona jest wolność twórcza. Dzięki zastosowaniu przejrzystej składni opartej o charakterystyczne znaczniki, dokonanie zmian odbywa się w intuicyjny i prosty sposób.

Instalacja
Do prawidłowej instalacji, TXP wymaga działającej platformy LAMP w postaci tria serwerów – WWW, PHP i MySQL. Minimalne wymagania to PHP w wersji 4.3 lub wyższej wraz z obsługą MySQL (mysql extension) i XML (XML extension) , serwera baz danych MySQL w wersji 3.23 lub wyższej. Rekomendowane jest posiadanie PHP od wersji 4.4.1 lub od wersji 5.0.2 oraz MySQL w wersji 4.2.7 lub wyższej.

Wydajny, elastyczny i przyjazny CMS

dziej uniwersalną, poza tym większość dokumentacji dostępna jest w języku angielskim. W następnym oknie musimy podać nazwę użytkownika MySQL, hasło, adres serwera MySQL oraz nazwę istniejącej bazy danych (proponuję stworzyć wcześniej pustą bazę np. z wykorzystaniem phpMyAdmin). Możemy również wprowadzić ścieżkę do instalacji (Site path) oraz adres URL (Site URL). Pozostawiam domyślne wartości bez zmian i przechodzimy dalej (Next). W oparciu o wprowadzone dane zostaje automatycznie wygenerowany skrypt konfiguracyjny. Zaznaczamy cały kod, za pomocą np. notatnika tworzymy plik config.php i wklejamy kod. Zapisany plik przesyłam na serwer do podkatalogu textpattern. Jeśli wykonaliśmy wszystko poprawnie, po kliknięciu przycisku I did it ukaże się kolejne okno w którym wprowadzamy dane o administratorze (Publisher). Podajemy pełną nazwę użytkownika, login, hasło oraz istniejący adres email. Po kliknięciu na przycisk Next zostanie utworzona odpowiednia struktura. Wstrzymujemy oddech i naszym oczom ukazuje się informacja o pomyślnej instancji. Możemy zalogować się do webowego interfejsu użytkownika. GUI zorganizowane jest w postaci paneli lub też zakładek – Content, Presentation, Admin, View Site. Pod każdą z zakładek kryją się dodatkowe panele ze szczegółowymi opcjami konfiguracyjnymi. Przejdźmy do zakładki Admin. Pierwszym krokiem jest wykonanie diagnostyki instalacji. Panel podzielony jest na dwie części w pierwszej Preflight check otrzymujemy ostrzeżenia zebrane po wstępnym sprawdzeniu instalacji. W oknie Diagnostyki info znajdują się szczegółowe dane dotyczące m.in. konfiguracji serwera WWW, zainstalowanych modułów serwera, ustawień lokalnych itd.

podczas normalnej pracy z witryną np. konfiguracja, zamiany ustawień, modyfikacja treści. Oba statusy powodują wyświetlanie informacji o czasie budowy poszczególnych podstron, ilości wysłanych zapytań MySQL oraz zużyciu pamięci. W trybie Debugging wszystkie napotkane podczas budowania witryny tagi widoczne są również w postaci kodu XHTML. Status Live to publikacja w trybie normalnego użytkowa-

nia, ustawiamy kiedy chcemy aby nasz projekt ujrzał światło dzienne. Use textile – opcja definiuje domyślny edytor TXP. Textile jest ciekawym rozwiązaniem znacznie upraszczającym budowę treści zgodnej z XHTML. Edytor wykorzystuje uproszczoną składnię dzięki czemu szybko możemy dodać treść, która będzie prezentowana w postaci poprawnego kodu XHTML. Pseudokod jest automatycznie formatowany do właściwej postaci.

Rysunek 1. Strona powitalna

Konfiguracja
Panel konfiguracyjny podzielony jest na trzy części Basic, Advanced, Langugae. W zakładce Language mamy możliwość zdefiniowania używanego języka, wyboru języków dodatkowych z dostępnej listy, a także instalacji pliku zewnętrznego. Basic zawiera opcje podstawowej konfiguracji. Definiujemy Site name (nazwa witryny), Site slogan (motto), Site URL (domyślny katalog instalacyjny), strefę czasową Time Zone, automatyczną zmianę czasu letni/zimowy, format daty używany przez TXP Data format, oraz format daty którą opatrzone będą dodawane przez nas artykuły. Production status pozwala zdefiniować jeden z trzech stanów w który aktualnie znajduje się witryna. Debugging umożliwia identyfikację problemów z funkcjonowaniem szablonu, plugin'ów lub dodanych skryptów. Testing to tryb wykorzystywany
www.sdjournal.org
Rysunek 2. Konfiguracja dostępu do bazy danych

Rysunek 3. Wygenerowany skrypt konfiguracyjny

29

E-commerce
Ustawienie opcji na Convert linebreaks ignoruje wszystkie znaczniki poza znacznikiem przełamania wiersza. Leave text untouched wyłącza opcje autofrmatowania. Accept commnets? Włączenie/wyłączenie opcji umożliwiającej użytkownikom zamieszczanie komentarzy. Po ustawieniu na Yes, na ekranie pojawiają się dodatkowe opcje definiujące sposób zamieszczania komentarzy. W niniejszym artykule pominąłem omawianie szczegółów związanych z publikacją komentarzy. Po zapisaniu konfiguracji podstawowej przechodzimy do konfiguracji opcji zaawansowanych – Advanced. Opcje konfiguracyjne podzielone są na kilka części. Omówię te najważniejsze. Admin • Image directory – definiuje domyślny katalog do którego będziemy zaciągać zdjęcia i ilustracje; • File directory path – definuje ścieżkę do katalogu przechowywania zaciągniętych plików; • Use ISO-8859-1 encoding in e-mails sent (default is UTF-8) – zmiana kodowania w generowanych wiadomościach e-mail. Style • Use raw editing mode by default? Ustawienie opcji na Yes spowoduje, że do edycji arkusza stylów wykorzystywany będzie edytor z wyłączonym autoformatowaniem, praca będzie odbywała się z surowym kodem. Do dyspozycji mamy również edytor organizujący arkusz stylów do postaci tabeli, grupującej selektory i klasy w przejrzystą formę. Aby użyć edytora Textpattrern zmieniamy opcje na No. Publish Najważniejsze z punktu widzenia prawidłowego i bezpiecznego funkcjonowania witryny są opcje zawarte w sekcji Publish.
Rysunek 4. Wprowadzenie danych użytkownika

Rysunek 5. Ekran logowania

Rysunek 6. Konfiguracja opcji podstawowych

• Prevent widowed words in article titles? Włączenie opcji zapobiega powstawaniu jednowyrazowych linii w tytułach artykułów. Jeśli TXP wykryje, iż w tytule wystąpi przełamanie wiersza pomiędzy przedostatnim, a ostatnim wyrazem automatycznie zostaje dodany odpowiedni znacznik XHTML. Dwa ostanie wyrazy będą traktowane jako jeden; • Artricle use excerpts? Definiuje czy artykuły będę opatrzone skrótami tzw. zajawkami których rozwinięcie stanowi właściwy artykuł; • Allow from override? Kiedy opcja jest włączona możemy wybranym artykułom nadać odmienny format bez konieczności separowania poprzez umieszczania w osobnych sekcjach; • Send „lats-Modified” header? Włączenie opcji powoduje, że do przeglądarki odwiedzającego wysłane zostaje zapytanie o wersje witryny przechowywanej w cash'u. Jeśli witryna nie zmieniła się Textpattern nakazuje przeglądarce korzystanie z wersji znajdujące się w cash'u. Rozwiązanie pozwala ograniczyć czas ładowania witryny oraz zmniejszyć zapotrzebowanie na przepustowość łącza klienta; • Attach titles permalinks? Zaznaczenie powoduje, że Textpattern tworzy przyjazne linki w oparciu o nazwę artykułu. Opcja wymaga włączonej obsługi przyjaznych linków; • Ping Textpattern? Zaznaczenie umożliwia powiadomienie zespołu Textpattern.com o fakcie istnienia i działania naszej witryny w Sieci;
11/2008

30

Wydajny, elastyczny i przyjazny CMS

• Ping ping-o-matic.com? Wysyłanie powiadomień do wyszukiwarek o aktualizacji strony za pośrednictwem serwisu http:// pingomatic.com/; • Logs expire after how many days? Wyrażony w dniach okres przechowywania logów o odwiedzających w bazie danych TXP; • Maximum URL length (in characters). Definiuje maksymalną długość adresów URL. Przydatna opcja zabezpieczająca witrynę przed atakami typu przeładowanie bufora przy użyciu ekstremalnie długich linków; • Use plugins? Włączenie obsługi plugin'ów. Warto wyłączyć w przypadku konieczności identyfikacji problemów z funkcjonowaniem witryny; • Use admin-side plugins? Włączenie/wyłączenie plugin'ów interfejsu administratora. • Allow PHP in pages? Włączenie funkcjonalności umożliwi użycie kodu PHP w szablonie witryny po umieszczeniu w znacznikach <txt:php>...</txp:php>; • Allow PHP in articles? Opcja nie zalecana ze względów bezpieczeństwa. Umożliwia stosowanie kodu PHP w treści arty-

kułów, co jest wbrew postulatowi o oddzieleniu warstwy logicznej od warstwy prezentacji; • Allow raw PHP? Zalecane jest wyłączenie funkcjonalności. Rozwiązanie przydatne w sytuacji upgrade witryny z wersji wcześniejszych, gdzie kod PHP stosowany był jawnie w treści artykułów. Dodawanie nowego użytkownika Przejdźmy do zakładki Users. Oprócz zmiany danych dodanego wcześniej administratora (nazwa, email, nowe hasło, uprawnienia) mamy możliwość dodania nowych użytkowników o zróżnicowanych prawach dostępu. • Publisher – użytkownik o pełnych uprawnieniach. Może tworzyć, edytować i usuwać artykuły, a także zarządzać komentarzami i odnośnikami. Publisher może zmienić status artykułów, konfigurację witryny, zarządzać sekcjami i artykułami oraz zarządzać użytkownikami; • Managing Editor – posiada podobne uprawnienia co Publisher za wyjątkiem

tworzenia, usuwania i edycji uprawnień innych użytkowników; Copy Editor – może modyfikować artykuły, odnośniki, komentarze użytkowników witryny, ponadto posiada uprawnienia do zmiany szablonu i formularzy; Staff Writer – tworzy, edytuje, publikuje i usuwa artykuły. Może zaciągać ilustracje i zdjęcia; Freelancer – może tworzyć i edytować artykuły oraz zmieniać ich status. Publikacja wymaga jednak akceptacji użytkownika o roli Managing Editor lub Publisher; Designer – odpowiada za kreację wyglądu witryny. Posiada pełen dostęp do szablonu oraz stylów CSS. Nie może jednak zmieniać publikowanej treści.

Pozostałe panele Zakładka Visitor Logs nie wymaga szerszego omówienia. Mamy możliwość przeglądania zebranych logów, filtrowania zawartości i szczegółowego wyszukiwania informacji o odwiedzających. Plugins umożliwia instalację dodatków. Proces instalacji jest specyficzny i polega na wklejeniu odpowiedniego kodu w polu Install plugin i zaciągnięciu na serwer (Upload). Bardzo ciekawą funkcjonalność oferuje zakładka Import. Mamy możliwość importowania zawartości witryn opartych o inne platformy. W wersji 4.0.6 Textpattern wspiera import z systemów Movable, WordPress, b2 i Blogger. Importowaną treść możemy przypisać do odpowiednich sekcji oraz nadać wybrany status. Nieco rozczarowuje brak popularnych systemów CMS.

Podsumowanie
Mam nadzieję, że Textpattern zainteresował Cię drogi Czytelniku. Zapoznałeś się z procesem instalacji oraz szczegółowej konfiguracji. Wspólnie udało się nam stworzyć szkielet, na którym zbudujemy witrynę. W następnej części ożywimy nasz projekt dodając treść, zmieniając domyślny wygląd poprzez edycję szablonu i arkusza CSS. Zainstalujemy wybrany plugin i skonfigurujemy witrynę na nasze potrzeby.

Rysunek 7. Konfiguracja opcji zaawansowanych

W Sieci
• http://www.textpattern.com – strona domowa projektu

KRYSTIAN RAJSKI
Autor interesuje się tworzeniem aplikacji webowych oraz technologiami internetowymi. Związany z grupą ProgInn. Na co dzień pracuje jako Software Test Engineering w firmie ADVA Optical Networking. Kontakt z autorem: krajski@p-innovations.com, http://www.p-innovations.com

Rysunek 8. Dodawanie użytkowników

www.sdjournal.org

31

Programowanie PHP

Opensource-owe platformy blogowe
Porównanie oparte o PHP i bazy danych
W przeciągu ostatnich lat blogi internetowe zjednały sobie wielką popularność wśród użytkowników internetu. Przestały być tylko i wyłącznie formą pamiętników a stały się miejscem wymiany zdań pomiędzy różnymi środowiskami jak choćby programistów.
Dowiesz się:
• O najpopularniejszych platformach blogowych napisanych w PHP; • O ich obsłudze, możliwościach i porównaniu z rozwiązaniami konkurencyjnymi.

Powinieneś wiedzieć:
• Powinieneś mieć wiedzę na temat zarządzania systemami CMS (instalacja systemów, obsługa panelów); • Powinieneś znać PHP i umieć konfigurować bazy danych MySQL.

Poziom trudności

W

iele firm (np. Microsoft) zaczęło wykorzystywać platformy blogowe jako formę kontaktu z klientem, kontaktu, choć częściowo anonimowego, jednak bardziej przyjaznego. Równocześnie wraz z tym boomem rozwinęło się PHP i stało powszechnie stosowanym językiem programowania w aplikacjach internetowych. Naturalnym było, więc, że wiele platform blogowych powstało właśnie w oparciu o niego i zazwyczaj w sprzężeniu z systemem baz danych MySQL. W temacie artykułu podkreśliłem właśnie techniki (PHP + bazy danych), na jakich omawiane w artykule blogi bazują. Powodem tego jest fakt, że konkurencyjne rozwiązania (Perl, RubyOnRails) również oferują darmowe, opensource-owe platformy blogowe (odpowiednio MovableType, Typo etc.). We wstępie chciałbym jeszcze wytłumaczyć powody wybrania omawianych platform. Wordpress i Texpattern są zapewne wielu czytelnikom doskonale znane, jeśli nie z praktyki to chociażby ze słyszenia. Dwie ostatnie aplikacje wybrałem ze względu na to, iż pracują w trybie Multi – Users (MU), co pozwala na prowadzenie wielu niezależnych
32

blogów w oparciu o jedną platformę. Jako, że temat jest obszerny przy omawianiu każdego ze skryptów chciałbym skupić się na rzeczach podstawowych i najważniejszych a więc kwestia związana z łatwością i intuicyjnością zarządzania blogiem, sposobem tworzenia własnych them-ów (sposoby szablonowania), dostępność plugin-ów (rozszerzeń), dokumentacja aplikacji oraz wsparcie techniczne.

Wordpress (wersja 2.3.2)
Poczynając od instalacji a na zarządzaniu kończąc można śmiało powiedzieć, że Wordpress jest skryptem zarówno stabilnym jak i przyjaznym użytkownikowi. Zarówno grafika panelu administracyjnego jak i jego filozofia czynią go bardzo łatwym w opanowaniu i intuicyjnym w zarządzaniu. Co ważne, a o czym pisałem na wstępie, dostosowanie panelu administracyjnego do obsługi w ojczystym języku jest łatwiejsza niż strony frontowej, nawet dla osób nieznających PHP. Rozwijanie możliwości bloga przez wgrywanie własnych them-ów czy plugin-ów również nie przysparza najmniejszych problemów. Dodatkową zaletą jest obszerna i prosta możliwość konfiguracji systemu. Wordpress został zaprojektowany tak, że doskonale nadawać się może nie tylko jako skrypt typowo blogowy, ale również jako bardzo dobry CMS do prowadzenia małych i średnich stron internetowych.

Them-y Wordpress jak wszystkie omawiane w tym artykule skrypty posiada system szablonów możliwych do łatwej instalacji. Osoby, które nie mają wiedzy, a które nie chcą korzystać z domyślnych, po instalacji mogą pobrać setki, wiele them-ów. Skupię się jednak na omówieniu kwestii technicznej pracy z szablonami tego skryptu. Wordpress nie korzysta z systemu szablonów takiego jak Smarty, bądź HTML_Template_IT (parser klas Pear). Odbija się to lekko na wydajności gdyż mechanizmy cache-owania w wymienionych wcześniej systemach znacznie przyspieszają przetworzenie i wyświetlenie widoków. Kolejnym bardzo poważnym mankamentem jest kwestia tego, że wiele słów zaszytych jest na stałe w szablonie. Takie rozwiązanie uniemożliwia łatwą internacjonalizację strony frontowej i wymaga ręcznej edycji. Włączenie mechanizmu cache-owania możliwe jest przez instalacje dodatkowych rozszerzeń jak plugin WP-Cache. Plugin-y Domyślnie po instalacji mamy możliwość korzystania z dwóch dostarczonych domyślnie plugin-ów. Zamiast jednak opisywać przykładowe z nich, tak w tym skrypcie jak i pozostałych chciałbym się skupić bardziej na teoretycznych kwestiach. Jak wiadomo by napisać własne rozszerzenie, potrzebna jest znajomość, co najmniej PHP. Co jednak jest jeszcze bardzo ważne to dokumentacja gotowego skryptu, oraz tutoriale, pomagające deweloperom w pisaniu własnego plugin-a. W przypadku Wordpress-a, nie można mieć żadnych zastrzeżeń w tych względach. Na oficjalnej stronie projektu, umieszczono bardzo wiele informacji na temat rozwoju własnych rozszerzeń a także, co jest ogromnym ułatwieniem, można
11/2008

Porównanie opensource-owych platform blogowych

tam znaleźć API przygotowane właśnie pod tym kątem. Osoby nieznające PHP, mają szeroki wachlarz dostępnych rozszerzeń, dostępnych całkowicie za darmo a oferujących duże możliwości rozszerzenia swojego bloga o dodatkową funkcjonalność. Wsparcie techniczne i dokumentacja Tak jak pisałem już w poprzednich paragrafach wsparcie techniczne dla opisywanego skryptu nie pozostawia dla mnie nic do życzenia. Podobnie ma się sytuacja z techniczną dokumentacją (API). Dzięki ogromnej popularności Wordpress-a osoby nieznające języka angielskiego, dzięki dobremu suportowi w wielu krajach nie miałyby żadnego problemu z pracą z tym skryptem. Zalety • stabilność skryptu; • intuicyjność i przyjazność środowiska pracy nawet dla niezaawansowanych użytkowników; • możliwość pisania własnych them-ów z samą znajomością PHP (dodatkowo też API); • nieduże wymagania (dla omawianej wersji: PHP 4.2, MySQL 4.0, opcjonalnie mod _ rewrite włączony na serwerze) systemowe oraz lekkość skryptu; • duża popularność a co za tym idzie bardzo dobre wsparcie techniczne i dokumentacja, duże możliwości rozwoju skryptu zarówno przez początkujących jak i zaawansowanych użytkowników; • możliwość wykorzystania jako pełnego CMS-a. Wady • co może wydać się niekonsekwencją, jednak ze względu na dużą popularność wiele dostępnych rozszerzeń jest niestabilnych i napisanych na niskim poziomie; • brak dobrego sposobu internacjonalizacji frontu strony; • sposób szablonowania ze względu na czytelność oraz wydajność; • obsługa tylko i wyłącznie systemu baz danych MySQL; • wiele plugin-ów wykorzystujących JavaScript korzysta z metod niezgodnych z wytycznymi DOM level 1 i 2, oraz specyfikacji języka JavaScript (ECMAScript) opracowanego przez organizację ECMA; • Wordpress pracujący w trybie MU jest niestabilny, dlatego wyłączyłem jego opis i skupiłem się na możliwościach trybu dla jednego użytkownika.

intuicyjnym. Mimo, że na oficjalnej stronie projektu opisywany jest jako CMS a nie platforma blogowa, wydaje się jednak, że został stworzony z myślą o tym drugim przeznaczeniu. Co prawda możliwości konfiguracyjne skryptu są bogate niemniej, dotyczą one przede wszystkim właśnie ustawień związanych z prowadzeniem bloga. To, co na pewno jest istotną kwestią i wiele osób może zachęcić, to możliwość wyboru języka zarówno instalacji jak i prowadzenia bloga już w pierwszym kroku konfiguracji skryptu. Dla osób myślących o wykorzystaniu go tylko i wyłącznie jako skrypt blogowy i niemyślących o dalszym rozwoju swojej strony, najpoważniejszym mankamentem wydawać się może tylko ubogi edytor tekstowy WYSIWYG służący do wprowadzania i edycji wpisów.
Tabela 1. Zestawienie platform Wordpress Wymagania platformy PHP 4+ MySQL

Them-y Textpattern dysponuje dość różnym podejściem do systemu szablonów. Na stronie, twórcy zaznaczają, że skrypt nie posiada takowego systemu jak większość pozostałych skryptów. Podejściem przypomina bardziej serwisy blogowe jak http://www.blox.pl czy http://www.blogger.com, ze względu na wewnętrzny system znaczników. Jest to rozwiązanie ciekawe i wydajne, jednak poważnym ograniczeniem jest fakt, braku pełnej ingerencji w widoki, bez dokładniejszego poznania struktury skryptu. Edycja them-ów możliwa jest z poziomu panelu administracyjnego, gdzie tak jak napisałem możemy ingerować zarówno w strukturę HTML/XHTML jak i arkusze CSS. Dla Textpattern-a, dostępb2evolution PHP 4+ MySQL Pełna możliwość edycji szablonów LifeType PHP 4+ MySQL Pełna możliwość edycji szablonów z ograniczeniami spowodowanymi systemem Smarty

Textpattern PHP 4+ MySQL System szablonowania ciągle nie jest w fazie końcowej i trwają nad nim prace

Sposób szablono- Pełna możliwość wania edycji, jednak w przypadku chęci dostępu do całkowitego formatowania przez autora wymaga znajomości choćby podstaw PHP Importowanie danych z innych platform obsługa importu z ponad 20 innych platform

b2, Blogger, MoObsługa między vable Type, Word- innymi: Wordpress Press, Movable Type, Blogger, LiveJournal duży skrypt/dość szybki czas wykonania niewielki skrypt/ szybki czas wykonania

Brak

Rozmiar skryptu/ prędkość wykonywania *

średni skrypt/ średni czas wykonania

duży skrypt/ średni czas wykoanania (możliwość włączenia cache-owania dzięki szablonom Smarty) Dobra obsługa przyjaznych URLi, istnieją plugin-y do optymalizacji Średnie grono użytkowników, przede wszystkim osoby o zaawansowanej wiedzy o PHP i administracji/ ograniczone wspracie w językach poza angielskim/ obszerna dokumentacja XHTML 1.0 Strict

Optymalizacja pod silniki wyszukiwarek

Dobra obsługa przyjaznych URLi, wiele plugin-ów przydatnych do optymalizacji Bardzo wiele użytkowników/ wsparcie w wielu językach, również wsparcie komercyjne/ bardzo dobra dokumentacja

Dobra obsługa przyjaznych URLi, istnieją plugin-y do optymalizacji Dość duże grono użytkowników/ ograniczone wspracie w językach poza angielskim/ obszerna dokumentacja

Dobra obsługa przyjaznych URLi, istnieją plugin-y do optymalizacji Średnie grono użytkowników, przede wszystkim osoby o zaawansowanej wiedzy o PHP i administracji/ ograniczone wspracie w językach poza angielskim/ obszerna dokumentacja XHTML 1.0 Transitional Tak Tak

Społeczność/ wsparcie/ dokumentacja

Domyślny format wyjściowy danych Edytor WYSIWYG

XHTML 1.0 Transitional Tak

XHTML 1.0 Transitional Tak

Tak Tak

Textpattern (wersja 4.0.6)
Poczynając od instalacji jak i zarządzaniu samego panelu Textpattern również jest skryptem
www.sdjournal.org

Obsługa kanałów Tak Tak informacyjnych RSS/Atom * testy przeprowadzone przy użyciu rozszerzenia Xdebug

33

Programowanie PHP
nych jest wiele gotowych tematów, z których niektóre znaleźć można w odnośnikach na końcu artykułu. Plugin-y Decydując się na pracę z Textpattern-em z jednej strony możemy być zaskoczeni lekkością skryptu, jego minimalizmem i łatwą obsługą, z drugiej możliwościami, jakie daje przy prowadzeniu bloga. Właśnie dzięki plugin-om, o bardzo dużych możliwościach jest to osiągalne. W momencie powstawania artykułu na równoległej do strony http://www.textpattern.com witrynie http://www.texpattern.org można było znaleźć prawie pięćset rozszerzeń i plugin-ów dla opisywanego skryptu. Osoby zainteresowane pisaniem własnych dodatków, również dostępnych jest wiele tutoriali i dobra dokumentacja skryptu. Również ciekawą kwestią jest sposób pracy z plugin-ami opierający się też o autorski dla Textpattern-a system znaczników/tagów. Więcej informacji na ten temat można znaleźć w linkach na końcu artykułu. Wsparcie techniczne i dokumentacja Na oficjalnej stronie skryptu, możemy znaleźć odnośniki do pełnej dokumentacji stworzonej przez użytkowników i twórców Textpattern-a, która została nazwana TextBook i zawiera wszystkie niezbędne informacje zarówno dla początkujących jak i zaawansowanych użytkowników. Dokumentacja w dniu powstawania artykułu dostępna była w kilkunastu językach (bez języka polskiego). Na temat Texpattern-a została napisana również książka: Textpattern, Solutions, która jest uznana za oficjalną dokumentację dostępną w formie książkowej. Pozycja ta jest w pełni dostępna i możliwa do nabycia w internecie. Zalety • stabilność skryptu; • intuicyjność i przyjazność środowiska nawet dla niezaawansowanych użytkowników; • lekkość skryptu; • zaawansowane możliwości jako skrypt blogowy; • wiele dostępnych them-ów i plugin-ów; • szeroki zakres języków instalatora dla panelu i bloga; • bogata dokumentacja i duża ilość artykułów poświęconych Textpattern-owi; • ze względu na strukturę kodu, skrypt jest bardzo wydajny i szybki. Wady • mniejsza popularność w porównaniu do Wordpress-a również jeśli chodzi o zaplecze programistyczne; • obsługa tylko i wyłącznie systemu baz danych MySQL;
34

• wbrew oficjalnemu opisowi skrypt nie posiada bogatych możliwości jako CMS i nadaje się raczej na platformę blogową; • mocno strukturalny kod co w pewien sposób ogranicza możliwość rozwoju w szybki i łatwy sposób; • brak dobrego systemu szablonowania o pełnych możliwościach.

mniejszą ilość informacji do znalezienia w internecie. Wsparcie techniczne i dokumentacja Niestety, jak pisałem na początku, po pojawieniu się dość poważnego problemu nie uzyskałem pomocy. Mimo iż b2evolution wydaje się wyjątkowo wielojęzycznym skryptem to dokumentacja choć dobrze przygotowana, dostępna jest zaledwie w dwóch językach w tym oczywiście w języku angielskim. Ocena powyższa jak powiedziałem opiera się mniej na własnym doświadczeniu, bardziej na informacjach przeczytanych w internecie. To samo dotyczy listy zalet i wad jakie przedstawiam. Zalety • możliwość pisania własnych them-ów z samą znajomością PHP (dodatkowo API); • duże możliwości administracyjne; • jak na specyfikę przeznaczenia (tryb MU) duża ilość them-ów i plugin-ów; • czytelna i bogata dokumentacja; • popularność w swojej kategorii; • możliwość obsługi kilku systemów baz danych. Wady • mała popularność w porównaniu z platformami dla trybów blogowych przeznaczonych dla jednego użytkownika; • brak dobrego wsparcia na oficjalnym forum suportu przy bardziej skomplikowanych zagadnieniach; • niewiele informacji w języku innym niż angielski; • duży brak kompatybilności pomiędzy wersjami.

b2evolution (wersja 2.4.0)
Tak jak w pozostałych platformach tak i w przypadku b2evolution instalacja jest bardzo prosta i przebiega w trybie graficznym. Ze względu na tryb MU jako główne przeznaczenie tego skryptu, panel administracyjny jest już jednak dużo bardziej zaawansowany. Niestety po zainstalowaniu pojawia się problem z polskimi znakami. Mimo, że w wykazie dostępnych kodowań i języków znajduje się język polski niestety nawet po jego wybraniu blog niepoprawnie interpretował polskie znaki. Na oficjalnym forum suportu również nie udało mi się znaleźć rozwiązania, stąd opis poniższych możliwości opieram na dyskusjach jakie znalazłem w internecie oraz dokumentacji skryptu. Przeglądając panel administracyjny w pierwszym momencie, można mieć duże problemy z ogarnięciem wszystkich jego możliwości. Zagłębiając się dalej, łatwo jednak od razu rozpoznać ogromne możliwości jakie daje b2evolutions. Można stwierdzić, że duży nacisk położono na bezpieczeństwo skryptu choćby po tym jak wiele opcji zarządzania uprawnieniami użytkowników oferuje panel. Oczywiście poza wieloma możliwościami ustawień samego trybu MU przez administratora również wiele ustawień dotyczy samego sposobu prowadzenia konkretnego bloga. Them-y System szablonów b2evolution spośród 4 opisywanych tu platform najbliższy jest podejściu jakie oferuje Wordpress. Różnicą na pewno jest użycie słownika do łatwiejszej internacjonalizacji strony frontowej. Tutaj jednak znów natrafiłem na problem, mimo ustawienia jakiegokolwiek z dostępnych języków, zarówno front strony jak i panel administracyjny nie zareagowały na zmienione ustawienia. Plusem jest spora ilość darmowych them-ów do ściągnięcia z oficjalnej strony platformy. Plugin-y W przypadku plugin-ów, b2evolution również oferuje na swojej stronie duży wybór. Podzielone są zarówno kategoriami jak i wersjami wydania. Co bardzo ważne dokumentacja wspomagająca tworzenie własnych rozszerzeń jest bardzo szczegółowa. Brak natomiast jest dobrych tutoriali, a względna popularność platformy (tryb MU), powoduje również znacznie

LifeType (wersja 1.2.5)
LifeType jest skryptem wymagającym zdecydowanie większej wiedzy w porównaniu zarówno z Wordpress-em jak i Texpattern-em. Choć miałem raczej opisywać ogólnie pewne aspekty a nie wnikać w szczegóły chciałbym jednak podsunąć pewne rozwiązanie dla osób instalujących skrypt po raz pierwszy. Otóż w pliku wizard.php, czyli skrypcie instalacyjnym bloga w linii siódmej znajduje się następujący zapis: set_time_limit (5 * 3600), zapobiega on samoczynnemu wykonywaniu się poszczególnych czynności w czasie instalacji jeżeli trwają powyżej określonego czasu. Instalowałem LifeType-a lokalnie oraz na serwerze firmy home.pl w obydwu przypadkach zapis ten niestety powodował zatrzymanie procesu instalacji w momencie tworzenia i wypełniania tabel w bazie. Polecam więc zakomentowanie tej linii. Przechodząc do panelu administracyjnego użytkownik z prawami administratora za11/2008

Porównanie opensource-owych platform blogowych

pewne szybko zwróci uwagę na to, że autorzy skryptu główny nacisk, jeśli chodzi o możliwości konfiguracyjne postawili na zarządzanie możliwościami bloga przez administratora dając mu wiele opcji. Z tych najważniejszych ale i kierowanych do osób z pewnym doświadczeniem wymienię np. możliwości ustawienia cache-owania zarówno szablonów Smarty (system szablonowania LifeType-a), cache-owania przez HTTP, czy ze względów bezpieczeństwa uniemożliwienie edycji i tworzenia skryptów PHP właśnie w szablonach jak i w samym skrypcie. Jeśli natomiast chodzi o możliwości konfiguracyjne samego bloga i kwestie, które najbardziej powinny zainteresować przeciętnego użytkownika, LifeType oferuje tylko te podstawowe, co dla wielu użytkowników może okazać się zniechęcające. Dodatkowo, w wersji, którą opisuję nie ma zarówno spolszczenia dla frontu jak i panelu administracyjnego, szczegóły jednak opiszę poniżej. Them-y LifeType co napisałem we wstępie korzysta z szablonów Smarty. Nie chciałbym wnikać i skupiać się na wadach i zaletach tego podejścia, gdyż nie tego dotyczy artykuł i wiele na ten temat zostało już napisane. W przypadku użytkowników nieposiadających doświadczenia w architekturze Smarty, wykonanie własnego them-u nie powinno jednak przysporzyć większych trudności. Konstrukcja nie jest skomplikowana i łatwo (posiadając choć podstawową wiedzę z programowania w PHP) można na zasadzie porównania z domyślnym szablonem wykonać swój własny. Dodatkowym atutem jest użycie w szablonach mechanizmu słownika (i18n) przez co spolszczenie można dokonać dodając odpowiedni plik do folderu z tłumaczeniami a następnie ustawić go z poziomu panelu administracyjnego. Użycie szablonów Smarty umożliwia ustawienie dla nich wielu opcji, jak choćby system cache-owania, o którym pisałem powyżej. Jeśli chodzi o gotowe szablony dedykowane blogowi niestety na oficjalnej

stronie jest ich bardzo niewiele i również w internecie ciężko jest znaleźć takowe. Plugin-y Jak pozostałe skrypty, LifeType posiada dobrą dokumentację dla osób chcących wykonać własne rozszerzenia. API skryptu jest udokumentowane w pełni (nie w języku polskim), brak natomiast szerszej sekcji z tutorialami odnośnie budowy plugin-ów. Podobnie jak w przypadku them-ów, tak i jeśli chodzi o plugin-y dla LifeType-a nie ma ich wielu, natomiast bez problemu można znaleźć te najbardziej powszechne jak chociażby chmura tagów lub ograniczenie dostępu do bloga osobom nieupoważnionym przez weryfikację hasłem. Wsparcie techniczne i dokumentacja Mimo dobrej dokumentacji w języku angielskim, ze względu na popularność zarówno oficjalne forum skryptu jak i informacje możliwe do znalezienia w internecie mogą zniechęcić wielu użytkowników do rozpoczęcia pracy z LifeType-m. Zdecydowanie jest on przeznaczony dla osób posiadających wiedzę zarówno jeśli chodzi o PHP jak i administrację CMSami. Na stronach w języku polskim próżno szukać jakichkolwiek informacji na temat skryptu, w języku angielskim jak wspomniałem sytuacja jest podobna. Rozwiązaniem pozostaje w tym względzie poświęcenie się lekturze wiki jak i dokumentacji API w przypadku chęci poważnych zmian podstawowej funkcjonalności skryptu. Wady • nieduża ilość gotowych them-ów oraz plugin-ów; • dokumentacja przede wszystkim w języku angielskim; • niewiele tutoriali oraz artykułów dotyczących LifeType-a; • nieduże możliwości administracyjne samym blogiem; • obsługa tylko i wyłącznie systemu baz danych MySQL.

Zalety • stabilność skryptu; • dobra dokumentacja skryptu (język angielski); • w swojej klasie nie posiada dużej konkurencji; • duży nacisk postawiony na bezpieczeństwo; • bogate możliwości dla administratora (system zarządzania blogami oraz użytkownikami); • system szablonów oparty na Smarty.

Podsumowanie
Powyższy artykuł napisany został z zamiarem przedstawienia czytelnikom najpopularniejszych systemów blogowych wraz z ich docelowym przeznaczeniem, stąd też celowe rozgraniczenie na systemy napisane dla trybu single/multi user/s. Oczywiście istnieje dużo alternatywnych rozwiązań i platform takich jak np. Serendipity czy boastMachine, które jednak ze względu na popularność celowo ominąłem. Tekst ma być podpowiedzią dla osób, które stojąc przed wyborem instalacji jakiegoś rozwiązania chciałyby mieć ogólne spojrzenie na możliwości prezentowane przez poszczególne platformy, dlatego też celowy podział przy każdym opisie na kwestie najważniejsze w pracy z opisanymi systemami. Warto podkreślić jednak, że podobnie jak w przypadku CMS-ów, kierując się wyborem jakiegoś rozwiązania najlepiej jest dobrać skrypt w oparciu o docelowe wymagania stawiane przez klienta bądź użytkownika. Niekoniecznie więc decyzja na instalację bardzo rozbudowanej platformy blogowej będzie słuszną decyzją w przypadku kiedy użytkownik oczekuje prostoty, lekkości i intuicyjności a duża część dostępnych możliwości nie będzie wykorzystana. Dlatego właśnie warto czasem rozważyć decyzję wyboru chociażby bardzo popularnego Wordpress-a na rzecz lekkiego i bardzo przyjaznego Textpattern-a. Z drugiej strony programiści bądź webmasterzy mający wykonać serwis blogowy dla wielu użytkowników, powinni dobrze zapoznać się z platformami b2evolution i LifeType ze względu na różnorodność opcji administracyjnych. Artykuł nie miał na celu zasugerowania lepszego rozwiązania, a wszystkie opisane platformy mają zarówno rzesze zwolenników jak i przeciwników. Zakończeniem artykułu są linki do stron związanych z omówionymi w tekście zagadnieniami.

W Sieci
• • • • • • • • • • • http://www.problogger.net/archives/2006/02/15/choosing-a-blog-platform/ – tekst poświęcony wyborowi platformy blogowej (EN); http://www.siteground.com/choose_blog_tool.htm – porównanie platform blogowych (EN); http://txpmag.com/article/textpattern-versus-wordpress – porównanie platform Wordpress i Textpattern (EN); http://asymptomatic.net/blogbreakdown.htm – porównanie wielu platform blogowych (EN); http://www.ojr.org/ojr/images/blog_software_comparison.cfm – porównanie wielu platform blogowych (EN); http://unblogbar.com/software/ – porównanie wielu platform blogowych (DE); http://www.weblogmatrix.org/ – porównanie wielu platform blogowych (EN); http://wordpress.org/ – oficjalna strona platformy Wordpress (EN); http://textpattern.com/ – oficjalna strona platformy Textpattern (EN); http://b2evolution.net/ – oficjalna strona platformy b2evolution (EN); http://lifetype.net/ – oficjalna strona platformy LifeType (EN).

LECH ALBRZYKOWSKI
Autor od kilku lat zajmuje się programowaniem aplikacji internetowych oraz wdrażaniem systemów CMS. Kontakt z autorem: albrzykowski@gmail.com

www.sdjournal.org

35

Testowanie oprogramowania

SAP GUI Scripting API
Automatyzacja czynności w SAP GUI
SAP GUI Scripting API to interfejs pozwalający na emulowanie każdej czynności jaką może wykonać użytkownik w środowisku SAP GUI. Dzięki jego użyciu można zautomatyzować czynności powtarzalne, ale również uzyskać dostęp do SAP GUI z poziomu innych aplikacji, np. Windows Scripting Host.
Dowiesz się:
• W jaki sposób tworzyć skrypty automatyzujące czynności użytkownika w SAP GUI; • W jaki sposób połączyć SAP GUI z aplikacją MS Office.

Powinieneś wiedzieć:
• Czytelnik powinien posiadać dobrą orientację w posługiwaniu się SAP GUI, czynności bądź transakcje SAP jakie będą miały zostać zautomatyzowane; • Czytelnik powinien znać podstawy programowania w języku skryptowym typu JavaScript lub JScript.

Poziom trudności

N

iemiecki producent oprogramowania SAP tworzy szeroką gamę komplementarnych rozwiązań do informatycznego wsparcia procesów biznesowych. Poszczególne elementy systemu wydzielane ze względu na biznesowy obszar ich zastosowania określane są mianem modułów. W celu zapewnienia kompatybilności i spójności poszczególnych modułów całość napisana jest w dedykowanym języku programowania ABAP lub w Javie, który to język programowania posiada niekwestionowaną pozycję na rynku języków programowania systemów biznesowych. W obu przypadkach oprogramowanie uruchamiane jest na dedykowanych serwerach. Serwery funkcjonują w kilku wersjach w rozróżnieniu na konkretne infrastruktury systemu operacyjnego i bazy danych, które stanowią szkielet danej wersji konfiguracji serwera. Rozbudowany system aplikacji biznesowych SAP można również podzielić na część transakcyjną (moduły odpowiadające różnym procesom przedsiębiorstwa) oraz część szeroko rozumianego raportowania – Business Intelligence. Struktura aplikacji SAP wyraźnie rozgranicza warstwę przechowywania danych (Oracle, MaxDB, MS SQL Server), warstwę wykonywania logiki biznesowej (ABAP, J2EE) oraz warstwę interfejsu użytkownika (SAP GUI for Windows, SAP
36

GUI for Java, dostęp przez przeglądarkę internetową dla aplikacji z interfejsem webowym). Artykuł poniższy opisuje pokrótce SAP GUI Scripting API (dalej SGS), skryptowe API dostępu do funkcjonalności SAP GUI. Wszystkie odniesienia dotyczą SAP GUI for Windows 7100.1.5.1033. Głównym celem przyświecającym powstaniu SGS było stworzenie narzędzia emulującego działania użytkownika. SGS zapewnia taką właśnie funkcjonalność wykonania każdego działania, jakie może podjąć użytkownik w interakcji z systemem za pomocą SAP GUI. Działania dostępne przez SGS to: • użycie/aktywacja elementów SAP GUI (np. wybranie pozycji menu, naciśnięcie przycisku); • zapisanie czynności wykonanych przez użytkownika do postaci skryptu; • logowanie informacji systemowych do pliku. Przykładowe zastosowania SGS: • testy wydajności (symulowanie aktywności wielu użytkowników); • automatyzowanie powtarzalnych czynności (zarówno administratorów jak i użytkowników systemu); • łączenie SAP GUI z aplikacjami zewnętrznymi. Porównaniem mogącym dać zupełnie nowym użytkownikom pewien obraz SGS w SAP GUI, może być JavaScript i przeglądarka internetowa.

Przy czym SGS nie umożliwia dokonywania z poziomu SGS jakichkolwiek zmian w samym GUI np. dodawania nowych elementów ekranu. Skrypty są wykonywane w SAP GUI, a niewiele można z SAP GUI zrobić bez podłączenia się do serwera aplikacji i otwarcia sesji. Dlatego do poznania SGS i wypróbowania przykładowego kodu będzie potrzebna instalacja zarówno SAP GUI jak i samego serwera aplikacji. SAP udostępnia wersje testowe swojego sytemu, które można pobrać ze strony http://sdn.sap.com, do czego wymagana jest rejestracja. Z sekcji Downloads > SAP NetWeaver Main Release można pobrać SAP NetWeaver 7.0 ABAP Trial Version. SAP GUI można pobrać z ftp://ftp.sap.com/pub/sapgui/, gdzie znajdują się obie wersje SAP GUI dla Windows oraz Java. Należy zwrócić uwagę na to, że oprogramowanie skali SAP Netweaver ma duże wymagania sprzętowe, które podane są na stronie pobierania. Kolejnym krokiem jest instalacja. Uruchamiana jest poprzez otwarcie w przeglądarce internetowej prezentacji w formacie html, w której wszystkie kroki są przejrzyście opisane. Przed uruchomieniem instalatora warto zwrócić uwagę na kwestie dotyczące długości nazwy komputera oraz zawartość plików services oraz hosts z katalogu %windir%/system32/drivers/etc/. Dodatkowo, w przypadku, gdy nasz komputer nie posiada adresu IP innego niż 127.0.0.1, konieczne jest zainstalowanie Microsoft Loopback Adapter. Szczegóły można znaleźć w instrukcji instalacji. Po instalacji i uruchomieniu serwera SAP Netweaver oraz SAP GUI, aby móc połączyć się z serwerem, należy zainstalowany system dodać do listy systemów w zakładce Systemy w SAP Logon. W polu opis wpisać można np. NSP, w polu Serwer aplikacji nazwę albo adres IP komputera na którym serwer jest uruchamiany, Numer systemu to dla wersji testowej 00, ID systemu to NSP. Jeśli wszystko zostało wykonane zgodnie z instrukcją instalacji i serwer został uruchomiony, po dwukrotnym kliknięciu na nowo dodanej pozycji NSP w SAP Logon, SAP GUI otworzy się na ekranie logowania do systemu.
11/2008

SAP GUI Scripting API

Po zainstalowaniu obsługa SGS nie jest domyślnie aktywowana w ustawieniach serwera SAP Netweaver. Do wyboru są dwie możliwości uruchomienia obsługi SGS po stronie serwera – tylko dla bieżącej sesji uruchomienia serwera lub zapisać to ustawienie aktywne dla wszystkich nowo uruchamianych sesji serwera. W pierwszym przypadku należy użyć transakcji rz11 wybierając parametr sapgui/user_scripting. Ostatnia pozycja Current value ma wartość FALSE. Należy kliknąć na niej i wybrać z paska narzędziowego przycisk Change Value. Następnie po wpisaniu wartości TRUE w polu New value należy kliknąć ikonę dyskietki, aby zapisać zmiany. W środowisku produkcyjnym koniecznym może być zaznaczenie również opcji Switch on all servers. Do kolejnego uruchomienia, dla wszystkich nowych sesji użytkownika w bieżącej sesji serwera, SGS jest już aktywne. Takie rozwiązanie jest praktyczne, jeśli w standardowym trybie nie udostępnia się SGS użytkownikom, a chce tylko jednorazowo wykonać czynności administracyjne lub testy nie wymagające wielokrotnego uruchamiania serwera SAP Netweaver. Jeśli jednak SGS ma być dostępne po restarcie serwera SAP Netweaver, należy wprowadzić wpis aktywujący obsługę SGS w pliku profilu serwera. Plik profilu uruchomieniowego serwera zawiera parametry uruchomieniowe serwera. W systemie testowym plikiem profilu jest: %nazwa_serwera, domyślnie NSP%_DVEBMGS00_%nazwa_komputera_na_którym_uruchomiony_jest_serwer% znajdujący się w katalogu: %katalog_instalacji, domyślnie c:\SAP%\ %nazwa_serwera, domyślnie NSP%\SYS\profile. Za pozycją rdisp/myname dopisujemy w nowej linii: sapgui/user_scripting = TRUE. Po wprowadzeniu tej zmiany, każda nowo uruchomiona sesja serwera będzie obsługiwać SGS. Po wykonaniu opisanych dotąd czynności system jest gotowy do używania w nim SAP GUI Scripting API. Skrypty SGS można uruchamiać po zalogowaniu poprzez kliknięcie pierwszego od prawej przycisku ustawień layout’u (Alt+F12) i wybraniu Script Recording and Playback, a następnie poprzez kliknięcie zielonego przycisku odtwarzania, aby wybrać w wyświetlonym oknie plik skryptu do wykonania. Wybranie pliku podwójnym kliknięciem albo po zaznaczeniu go kliknięcie przycisku OK rozpoczyna wykonanie zapisanego w pliku skryptu. Aby rozpocząć nagrywanie wykonywanych czynności klika się w tym samym oknie na czerwony przycisk nagrywania. Po kliknięciu przycisku More można wpisać ścieżkę do pliku, w jakim zostaną zapisane czynności wykonywane przez użytkownika w trakcie działania rejestratora skryptów. Zarówno podczas nagrywania, jak i wykonywania skryptu, w prawym dolnym rogu okna SAP GUI aktywny jest czerwono-biały wskaźnik działania skryptu, który podczas normalnego użytkowania SAP GUI również widoczny, ale nieaktywny. Krótki przegląd możliwości zastosowania i składni kodu SGS przedstawiony zostanie powww.sdjournal.org

niżej na przykładzie zautomatyzowania exportu wyników raportu SAP Query. Jako, że SAP Query oferuje kilka formatów, do jakich można eksportować wyniki raportów, w przykładzie wybrano bezpośredni eksport do pliku tekstowego, który dobrze nadaje się do późniejszego użycia w aplikacjach zewnętrznych. Przykładowy skrypt napisany jest przy założeniu, że będzie on wykonywany bez potrzeby ingerencji użytkownika, a więc potrzebne będzie wpisanie hasła i nazwy użytkownika. W przykładzie te dane wpisane są do kodu, co może być dozwolone w środowisku systemu deweloperskiego, jednak ze względów bezpieczeństwa w zastosowaniach produkcyjnych, lepiej zastosować monit o te dane np. przy użyciu elementu InputBox. Pierwszą czynnością, jaką należy wykonać w celu uruchomienia skryptu SGS, jest przygotowanie środowiska uruchomieniowego dla skryptu, a więc uruchomienie SAP GUI. Pojawia się zatem okazja wykorzystania możliwości użycia SGS w połączeniu z Windows Scripting Host (WSH) i zautomatyzowania również tej operacji kodem zawartym w jednym, rozpoznawalnym przez WSH pliku vbs. W celu zawarcia całego kodu w jednym pliku aplikacja SAP Logon uruchamiana jest przez WSH. Tworzony jest obiekt silnika WSH, a wywołanie metody Run uruchamia SAP Logon przez otwarcie domyślnie tworzonego podczas instalacji skrótu na pulpicie. Do momentu wystartowania SAP Logon nie można odwołać się do silnika SGS, dlatego na potrzebny na to czas, zależny od wydajności systemu, na którym SAP GUI jest używane, należy skrypt uśpić. Po uruchomieniu SAP Logon tworzone są kolejno obiekty aplikacji, silnika, połączenia oraz sesji. Połączenie definiowane jest przez podanie nazwy wpisu dla połączenia z listy w SAP Logon. Po zainicjalizowaniu tych obiektów można się już odwoływać do elementów sesji i ekranu SAP

GUI. Okno jest maksymalizowane, co jest przydatne do zapewnienia zawsze tej samej widoczności, ponieważ SGS może się odwoływać tylko do widocznych elementów, jest to istotne np. przy późniejszym odwoływaniu się do pozycji wyświetlanych list. Na końcu w pola tekstowe wpisywane są nazwa i hasło użytkownika, a całość zatwierdzana klawiszem Enter powodując zalogowanie użytkownika w systemie. W celu odwoływania się do elementów ekranu użyta jest metoda findById(). W zależności od rozdzielczości ekranu, na którym uruchomione zostało SAP GUI, zmienia się ilość widocznych elementów. Jeśli element nie jest widoczny na ekranie SGS nie może się do niego odwołać, co powoduje powstanie wyjątku. Np. przy wysokiej rozdzielczości widocznych jest 25 linii raportu, przy niższej rozdzielczości już tylko 12, więc nie można odwoływać się do wiersza 25. Należy zwrócić na to uwagę, jeśli skrypty mogą być uruchamiane przy innej rozdzielczości ekranu. Podana powyżej metoda zdefiniowania obiektu sesji i odwoływania się do elementów ekranu ułatwia późniejsze bezpośrednie użycie kodu generowanego przez rejestrator skryptów. Kolejność wywoływania obiektów składających się na ekran SAP GUI, do którego elementów odwołuje się skrypt jest następująca: Aplikacja>Połączenie>Sesja. Aplikacją jest uruchomiony SAP Logon, dlatego zawsze istnieć będzie tylko jeden taki obiekt. Połączenie z serwerem aplikacji jest otwierane poprzez zalogowanie się w SAP GUI. Domyślna maksymalna ilość połączeń do sesji serwera wynosi 200 i nie jest proporcjonalnie dystrybuowana między użytkowników. Dlatego w teorii jeden użytkownik mógłby otworzyć do 200 sesji na serwerze. Oddzielną sesją w rozumieniu tego artykułu, określane jest każde otwarte okna SAP GUI. W każdej sesji można wykonywać niezależnie różne od siebie różne transakcje. Dla jednego połączenia można utworzyć maksymalnie pięć sesji. Dlatego

Listing 1. Uruchomienie SAP Logon oraz zalogowanie użytkownika do systemu
Set WshShell = WScript.CreateObject("WScript.Shell") ‘tworzymy obiekt do ‘uruchamiamy SAP GUI

odwoływania się do silnika WSH poprzez skrót na pulpicie

WshShell.Run("""d:\profiles\All Users\Desktop\Sap Logon.lnk""") WScript.Sleep(5000) Dim objSapGui

‘usypiamy skrypt na czas uruchomienia SAP GUI

Set objSapGui = GetObject("SAPGUI") Dim objScriptingEngine Set objScriptingEngine = objSapGui.GetScriptingEngine Set session = objConnection.Children(0) ‘kolejno obiekt silnika SGS ‘połączenia ‘oraz sesji ‘wpisanie nazwy uzytkownika ‘wpisanie hasła ‘wybór języka sesji

Set objConnection = objScriptingEngine.openConnection("NSP") session.findById("wnd[0]").maximize

‘maksymalizuje główne okno

session.findById("wnd[0]/usr/txtRSYST-BNAME").text = "bcuser" session.findById("wnd[0]/usr/txtRSYST-LANGU").text = "EN" session.findById("wnd[0]").sendVKey 0

session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = "minisap"

‘wysłanie użycia klawisza Enter

Listing 2. Uruchomienie transakcji sq01
session.findById("wnd[0]/tbar[0]/okcd").text = "/nsq01" session.findById("wnd[0]").sendVKey 0

37

Testowanie oprogramowania
przy domyślnych ustawieniach, możliwe jest teoretycznie otwarcie tysiąca okien SAP GUI i wykonywanie w każdym z nich, innej transakcji. Uruchamianie transakcji można wykonywać poprzez rozwinięcie drzewa menu i wybranie odpowiedniego jego elementu, ale dużo praktyczniejszym z punktu widzenia zastosowania w SGS sposobem jest wpisywanie kodu transakcji do pola komend i wysłanie do GUI procedury wciśnięcia klawisza Enter. Tak więc, aby już po zalogowaniu uruchomić transakcję tworzenia raportów ad hoc SAP ABAP Query, użyty zostanie kod z Listingu 2. Najpierw kod transakcji wpisywany jest do okna komend, a następnie wysyłane naciśnięcie klawisza Enter, do uruchomienia wpisanej transakcji. Poprzedzanie nazw transakcji znakiem /n umożliwia uruchamiania tej samej transakcji wielokrotnie w jednej sesji, jeśli np. zamierzamy wywołać po kolei kilka kwerend w tej samej sesji. W celu zapewnienia kontroli dostępu, raporty SAP Query przypisane są do specjalnych grup użytkowników SAP Query. Dlatego, aby na ekranie transakcji sq01 odwołać się do określonej kwerendy należy dla każdego nowego połączenia wybrać docelową grupę użytkowników. Wybór ten będzie zapamiętany do zamknięcia danego połączenia. Jeśli uruchomimy transakcję sq01 w nowej sesji dla tego samego połączenia, wyświetlony zostanie katalog kwerend dla ostatnio wybranej grupy użytkowników. Wybranie przycisku wyświetlenia listy grup użytkowników, wywołuje nowe okno modalne zawierające listę grup. Dla zautomatyzowania tego wyboru, użyta zostaje funkcja filtra, który zawęża wyświetlane pozycje do jednej konkretnej nazwy grupy. Kolejno, wywoływane jest wybranie i podwójne kliknięcie na pierwszy wiersz listy, co powoduje zmianę wyświetlanej listy kwerend na listę dla grupy /SAPQUERY/QD. Dzięki wyszukiwaniu elementu ekranu po jego wartości, zapewnia się dostęp bez względu na to, czy w nowo otwartym oknie wyboru szukany element jest widoczny, ponieważ po zastosowaniu filtra wyświetlana jest tylko jedna, właściwa dla dalszego wykonania skryptu wartość. Po wybraniu grupy użytkowników wyświetlona zostaje lista dostępnych kwerend. Do pola nazwy kwerendy skrypt wprowadza nazwę kwerendy i uruchamia z wcześniej zapisanym wariantem. Pojawia się okno wyboru nazwy wariantu, do którego skrypt wstawia zapisaną w kodzie nazwę. Wybór zatwierdzany jest klawiszem Enter, a następnie poprzez wybór klawisza F8, kwerenda zostaje uruchomiona z wybranym wariantem. W wariancie dla transakcji można zapisać wiele ustawień. W powyższym przykładzie wariant zawiera wybranie z opcji Output format – File store z podaniem ścieżki, czyli zapisu wyniku kwerendy do pliku. Po wykonaniu zapytania, wyświetla się okno, w którym jeszcze raz można zmienić ścieżkę do pliku. W tym samym oknie dokonuje się formaty pliku w jakim zapisane mają być wyniki. W przykładzie pozostawiony zostaje domyślny wybór DAT, jedynie dodatkowo zaznaczane jest pole With column heeaders. Zapisuje to w pierwszym wierszu pliku nazwy kolumn, co np. ułatwia późniejsze użycie pliku jako tabeli połączonej w MS Access. Ostatnia linia kodu zatwierdza zapisanie danych. Po wykonaniu wszystkich czynności w SAP GUI w celu zamknięcia wszystkich otwartych dla wykonania skryptu sesji użyta zostaje transakcja /nex. Powoduje to zamknięcie sesji bez pytania o potwierdzenie tego wyboru. Wywołanie kwerendy SAP Query z poziomu transakcji sq01 umożliwia testowanie ich wykonania użytkownikom je tworzącym, jeszcze zanim dla zapytania zostanie utworzona nowa transakcja dodana do menu użytkownika końcowego. Ponadto, umożliwia to późniejsze użycie tego samego kodu, do wywoływania różnych kwerend poprzez użycie funkcji i przekazywanie nazw kwerendy i wariantu w jej parametrach. Użycie SAP GUI Scripting wymaga dobrej znajomości systemu od strony użytkownika, dlatego jest to narzędzie, które można polecić użytkownikom kluczowym, pracownikom pierwszej i drugiej linii wsparcia, osobom, które potrzebują wykonać różnego rodzaju czynności administracyjne z poziomu SAP GUI. Do sprawnego rozumienia i edycji kodu przydatna jest znajomość podstaw programowania, np. w JavaScript. Możliwość łączenia w jednym pliku kodu SGS z WSH umożliwia łatwy dostęp do SGS z poziomu każdej aplikacji mającej również możliwość wywołania skryptu WSH. Ta właściwość umożliwia na przykład uruchamianie skryptów SGS poprzez Zaplanowane zadania Windows, z makr aplikacji Microsoft Access lub z pliku batch w linii komend Windows. Dostarcza to dużą elastyczność w dostępie do SAP GUI z innych aplikacji przy dopasowywaniu rozwiązań do wymagań konkretnej sytuacji.

Listing 3. Użycie filtra w celu ograniczenia ilości wpisów na liście wyboru
session.findById("wnd[0]/tbar[1]/btn[19]").press session.findById("wnd[0]").sendVKey 19 session.findById("wnd[1]/tbar[0]/btn[29]").press

session.findById("wnd[2]/usr/subSUB_DYN0500:SAPLSKBH:0600/cntlCONTAINER1_FILT/ session.findById("wnd[2]/usr/subSUB_DYN0500:SAPLSKBH:0600/cntlCONTAINER1_FILT/ session.findById("wnd[2]/usr/subSUB_DYN0500:SAPLSKBH:0600/btn600_BUTTON").press LOW").text = "/SAPQUERY/QD" LOW").caretPosition = 12 shellcont/shell").doubleClickCurrentCell shellcont/shell").selectedRows = "0"

Podsumowanie
SGS, jak każdy skrypt, jest narzędziem użytecznym we wszystkich sytuacjach, w których występują czynności powtarzalne, a których złożoność czyni je pracochłonnymi lub podatnymi na błędy użytkownika. Może się okazać bardzo przydatne dla osób tworzących szkolenia, ponieważ pozwala na stworzenie interaktywnych tutoriali. Dla programistów jest to otwarcie dostępu do SAP GUI do wykorzystania w zewnętrznych aplikacjach. Dokumentacja SAP GUI Scripting dostępna jest przy wybranym domyślnym katalogu instalacji SAP GUI w pliku Program Files/SAP/FrontEnd/ SAPgui/SAPguihelp/SAPGUIScripting.chm. Można w nim znaleźć dobrze ustrukturyzowaną i łatwo dostępną, popartą przykładami dokumentację API.

session.findById("wnd[3]/usr/ssub%_SUBSCREEN_FREESEL:SAPLSSEL:1105/ctxt%%DYN001session.findById("wnd[3]/usr/ssub%_SUBSCREEN_FREESEL:SAPLSSEL:1105/ctxt%%DYN001session.findById("wnd[3]/tbar[0]/btn[0]").press

session.findById("wnd[1]/usr/cntlGRID1/shellcont/shell").selectedRows = "0"

session.findById("wnd[1]/usr/cntlGRID1/shellcont/shell").doubleClickCurrentCell

Listing 4. Uruchomienie kwerendy w transakcji sq01 z wariantem zapisującym wyniki bezpośrednio do pliku
session.findById("wnd[0]/usr/ctxtRS38R-QNUM").text = "NAZWA_KWERENDY" session.findById("wnd[0]/tbar[1]/btn[17]").press session.findById("wnd[1]/usr/ctxtRS38R-VARIANT").text = "NAZWA_WARIANTU" session.findById("wnd[1]/usr/ctxtRS38R-VARIANT").caretPosition = 4 session.findById("wnd[1]").sendVKey 0 session.findById("wnd[0]").sendVKey 8

session.findById("ses[0]/wnd[1]/usr/chkRSAQDOWN-COLUMN").selected = true session.findById("ses[0]/wnd[1]/tbar[0]/btn[0]").press

Listing 5. Zamykanie sessji bez potwierdzenia wylogowania
session.findById("wnd[0]/tbar[0]/okcd").text = "/nex" session.findById("wnd[0]").sendVKey 0

ROMAN GRYZOWSKI
Autor od 3 lat zajmuje się programowaniem VBA, a od 2 pracuje jako kluczowy użytkownik systemu SAP MM-SD. Kontakt z autorem: rg@whereto.pl

38

11/2008

Testowanie oprogramowania

IBM Rational Data Architect
Pierwsze kroki...
Wyobraźmy sobie sytuację, w której musimy stworzyć oprogramowanie dla biblioteki. Chcąc wywiązać się z zadania musimy zaprojektować system, który będzie spełniał wymagania stawiane przez naszego zleceniodawcę. Z pomocą przychodzi nam Rational Data Architect, który jest narzędziem służącym do tworzenia zarówno prostych, jak i bardzo złożonych modeli bazodanowych.
Dowiesz się:
• Czym jest IBM Rational Data Architect; • W jaki sposób tworzyć modele baz danych za pomocą IBM Rational Data Architect; • W jaki sposób konfigurować połączenie z bazą (bazami danych); • Jak generować modele baz danych na serwerach bazodanowych;

Powinieneś wiedzieć:
• Czym jest model logiczny oraz model fizyczny bazy danych; • Znać podstawową składnię języka SQL; • Znać podstawy konfiguracji serwerów bazodanowych.

Poziom trudności

W

celu głębszego poznania funkcjonalności Rational Data Architect przed instalacją tego narzędzia powinniśmy zainstalować serwer bazodanowy, na którym będziemy przeprowadzać testy na modelach, oraz wykonywać zapytania SQL. W moim przypadku serwerami bazodanowymi, na których będę działał są DB2 v.9.5 Express-C oraz SQL Server 2005 Express Edition. Rational Data Architect w najnowszej wersji dostępny jest do pobrania za darmo ze strony IBM, do której odnośnik znajduje się części W Sieci. W moim przypadku jest to wersja v7.0. Proces instalacji Rational Data Architect jest prosty i intuicyjny. Oczywiście mamy możliwość samodzielnego ustawienia poszczególnych parametrów, ale na potrzeby rozpoznania tego narzędzia wystarczy nam instalacja z domyślną konfiguracją. Po uru40

chomieniu Rational Data Architect ukaże się środowisko graficzne dobrze znane dla osób, które wcześniej pracowały na eclipsie. Interfejs jest bardzo przyjazny i intuicyjny dla użytkowników tego narzędzia. W zasadzie nie jest wymagana żadna dodatkowa konfiguracja. Po zakończeniu procesu instalacji Rational Data Architect jest gotowy do pracy.

Tworzenie modelu logicznego
W celu rozpoczęcia prac nad oprogramowaniem dla naszej uniwersyteckiej biblioteki musimy stworzyć projekt całego systemu. Jednym z jego elementów będzie model logiczny, który wyrazi nam tabele, oraz relacje między nimi, dające zrealizować się w każdym Systemie Zarządzania Bazą Danych (SZBD). W celu rozpoczęcia prac nad modelem powinniśmy otworzyć nowy projekt (File-> New-> Data Design Project), w ramach którego będziemy tworzyć modele bazodanowe i nie tylko. Mamy możliwość stworzenia modelu logicznego na kilka sposobów – jednym z nich jest stworzenie pustego modelu (File-> New-> Logical Data Model). Po skorzystaniu z tej opcji zostanie otwarty obszar ro-

boczy – widoczny na Rysunku 1 – na którym stworzymy model logiczny bazy danych biblioteki. Po prawej stronie opisywanego obszaru naszym oczom ukazuje się zakładka Palette, w której znajdują się kontrolki służące do modelowania diagramów. Podstawowe kontrolki odkryją się po zaznaczeniu opcji Data. Znajdują się tu między innymi kontrolki takie jak encja i relacja, które są najczęściej wykorzystywanymi elementami przy tworzeniu diagramów związków encji. Dodatkowo dla każdej kontrolki możemy ustawić interesujące nas opcje w obszarze Properties, domyślnie znajdującym się poniżej naszego obszaru roboczego. Wiedząc gdzie znajdują się podstawowe funkcje Rational Data Architect możemy przystąpić do modelowania bazy danych biblioteki. Aby stworzyć encję, bądź relację wystarczy przeciągnąć interesującą nas kontrolkę na obszar roboczy. Na potrzeby testów stworzymy niewielki model składający się z kilku encji – Dokument (DokumentID, Tytul, ISBN, AutorID, WydawcaID) połączonej w relacji wiele-do-wielu z encjami Autor (AutorID, Imie, Nazwisko), Wydawca (WydawcaID, Nazwa) oraz w relacji jeden-do-wielu z encją Egzemplarz (EgzemplarzID, Ilosc_egz). Przedstawiony powyżej model nie odzwierciedla rzeczywistych potrzeb bibliotek, ale nam do testów w zupełności wystarczy. Schemat ten widoczny jest na Rysunku 2.

Tworzenie modelu fizycznego
Mając gotowy model logiczny pójdźmy krok dalej i stwórzmy model fizyczny bazy danych.
11/2008

IBM Rational Data Architect – pierwsze kroki

I tutaj ponownie Rational Data Architect daje nam szereg możliwości tworzenia owych modeli. Podobnie jak w przypadku modelu logicznego możemy stworzyć nowy model fizyczny postępując analogicznie do sposobu opisanego przeze mnie powyżej. Ścieżka, pod którą znajdziemy kreator modelu fizycznego to File-> New-> Phisical Data Model. Tutaj ponownie pojawia się nam zakładka Palette po prawej stronie ekranu, na której znajdują się kontrolki, które wykorzystamy do stworzenia modelu fizycznego od zera. Bardzo ciekawą opcją jest możliwość generowania modelu fizycznego z istniejącego już modelu logicznego. Nie jest to żadna nowinka wśród oprogramowania służącego do modelowania baz danych, ale zaskakująca jest prostota z jaką przebiega cały ten proces. Powstanie modelu odbywa się w sposób niemal natychmiastowy i aby tego dokonać nie jest nam potrzebna żadna specjalistyczna wiedza, tak jak to jest w przypadku niektórych produktów konkurencyjnych. Po prostu wybieramy z menu opcję Data-> Transform-> Phisical Data Model. Pojawi się nam nowe okno, w który ustawiamy paramtery ułatwijące nam późniejszą pracę na modelach. Jedną z największych zalet Rational Data Architect jest to, że współpracuje nie tylko z produktami firmy IBM, ale również z niemal wszystkimi najpopularniejszymy serwerami bazodanowymi, do których możliwe jest podłączenie za pomocą sterownika JDBC. W związku z tym, że każdy serwer bazodanowy charakteryzuje się różnymi typami danych, Rational Data Architect ma wprowadzone słowniki typów danych, które wybieramy przy generowaniu modelu fizycznego. W tej sytuacji w zależności od naszych wymagań wybieramy słowniki typów danych odpowiadające naszym potrzebom. W moim przypadku jest to DB2 UDB. Po przebrnięciu przez proces konfiguracji naszego nowego modelu fizycznego zatwierdzamy wszystkie ustawienia przyci-

skiem Finish i po chwili mamy gotowy model fizyczny. Korzystając z tej samej funkcji możemy również uaktualnić istniejący model fizyczny o zmiany, które wprowadziliśmy w modelu logicznym. W tej chwili jedyne co musimy z nim zrobić, to poukładać encje wedłgu na-

szego uznania. Oczywiście Rational Data Architect posiada funkcję, która się tym zajmuje, ale nie zawsze działa ona tak, jak byśmy tego chcieli. W sposób analogiczny wykorzystując funkcję transformacji do modelu logicznego (Data> Transform-> Logical Data Model) możemy wy-

Rysunek 2. Obszar roboczy dla modelu logicznego

Rysunek 1. Starter instalacji Rational Data Architect

Rysunek 3. Konfiguracja połączenia z SQL Server 2005

www.sdjournal.org

41

Testowanie oprogramowania
generować model logiczny z istniejącego schematu fizycznego. Innym sposobem tworzenia modelu fizycznego jest funkcja inżynierii odwrotnej (Reverse Engeneering), która pozwala nam na pobranie modelu fizycznego istniejącej bazy danych z serwera baz danych. Aby tego dokonać musimy skonfigurować połączenie z bazą danych. wym przyciskiem myszy folder Connections a następnie wybrać opcję New Connection... Po wykonaniu powyższych wskazówek otworzy się nam okno kreatora połączeń. Teraz musimy skonfigurować wszystkie niezbędne ustawienia. Zacznijmy od nadania nazwy. Rational Data Architect ustawia domyślną nazwę dla połączenia, ale zaleca się jego zmianę. Następnie wybierzemy serwer bazy danych, z którym chcemy się połączyć (pole Select a database manager). W moim przypadku jest to SQL Server 2005. W polu User ID wprowadzamy nazwę użytkownika serwera baz danych. Następnie podajemy hasło podanego użytkownika w polu Password. W polu Database wpisujemy nazwę bazy danych, z którą chcemy się połączyć oraz podajemy host. W przypadku, gdy serwer znajduje się na tym samym komputerze, na którym zainstalowany jest Rational Data Architect w polu host wpisujemy localhost. Konieczne jest również wpisanie numeru portu, na którym serwer baz danych nasłuchuje połączeń. Na ogół serwery bazodanowe mają domyślnie przypisany numer portu. Ostatnią rzeczą, którą należy zrobić jest podanie ścieżki dostępu do sterownika JDBC w polu Class location. Gdy podamy wszystkie niezbędne dane powinniśmy skorzystać z opcji Test Connection aby sprawdzić, czy wprowadzone przez nas informacje są poprawne. Jeśli test nie zwróci nam żadnego błędu, wówczas zatwierdzamy ustawienia przyciskiem Finish. W tej chwili powinniśmy mieć gotowe połączenie z bazą danych, do którego odnośnik znajduje się w widoku Database Explorer. Chcąc nawiązać połączenie z serwerami baz danych wspieranych przez firmę IBM sprawa jest dużo łatwiejsza, mianowicie większość danych wypełniona zostaje automatycznie. Nie musimy również dostarczać sterownika JDBC dla bazy danych, gdyż Rational Data Architect go posiada. Rational Data Architect dając możliwość nawiązania połączenia z serwerami baz danych otwiera przed nami olbrzymie możliwości. Jakie możliwości daje nam możliwość nawiązania połączenia? Generowanie, aktuali-

Nawiązanie połączenia z bazą danych
Aby nawiązać połączenie z bazą danych musimy w widoku Database Explorer zaznaczyć pra-

Rysunek 4. Widok na mapowane modele bazodanowe

W Sieci
• • • • • http://www.ibm.com/developerworks/downloads/r/rda/ – Rational Data Architect w wersji trial http://www-306.ibm.com/software/data/db2/express/download.html – DB2 9.5 Express-C http://www.microsoft.com/sql/downloads/trial-software.mspx#EZC – SQL Server 2005 Express Edition http://www.microsoft.com/downloads/details.aspx?FamilyID=c243a5ae-4bd1-4e3d-94b8-5a0f62bf7796&displaylang=en – SQL Server 2005 Management Studio Express Edition http://msdn.microsoft.com/en-us/data/aa937724.aspx – JDBC dla SQL Server 2005

Konfiguracja połączenia z SQL Server 2005
W celu nawiązania połączenia Rational Data Architect z SQL Server-em 2005 potrzebny będzie nam sterownik JDBC dla SQL Server 2005. Na pierwszym etapie skonfigurujemy serwer bazodanowy. W tym celu musimy uruchomić narzędzie, które zostało zainstalowane wraz z serwerem bazy danych SQL Server Configuration Manager (domyślnie znajduje się w Start-> Programy-> Microsoft SQL Server 2005-> Configuration Tools). Z wyświetlonej listy wybieramy opcję TCP/IP. W tym miejscu konieczne jest uaktywnienie możliwości nawiązania połączenia z serwerem bazodanowym, więc przy polu ENABLE wybieramy z listy YES, a następnie przechodzimy do zakładki IP Addresses, gdzie podamy port, w którym SQL Server będzie nasłuchiwał połączeń. Domyślnym portem dla SQL Server 2005 jest 1433. Zatwierdzamy wprowadzone zmiany klikając na Apply. Kolejnym ważnym elementem przy nawiązywaniu połączenia jest wybór sposobu logowania się do serwera bazodanowego. Logowanie nie może odbyć się za pomocą Windows Authentication. Musimy uaktywnić użytkownika sa (domyślne konto dla administratora bazy danych), lub stworzyć nowego użytkownika. Mając skonfigurowany SQL Server 2005 możemy nawiązać połączenie z nim za pomocą Rational Data Architect w sposób opisany w części Nawiązanie połączenia z bazą danych.

42

11/2008

IBM Rational Data Architect – pierwsze kroki

zacja modeli baz danych na serwerach, pobieranie modeli z serwerów, mapowanie źródeł, synchronizacja modeli, kojarzenie odrębnych źródeł danych, odszukiwanie podobieństw w modelach, w sytuacji, kiedy nie istnieje fizyczna implementacja relacji pomiędzy nimi, analiza modeli i źródeł danych pod kątem zgodności ze standardami korporacyjnymi stworzonymi w ramach Rational Data Architect(!). Wymieniłem tylko najistotniejsze zalety płynące z możliwości połączenia z bazą danych. Ich lista jest dużo dłuższa.

pować stworzony przez nas model z modelem znajdującym się na serwerze baz danych, konieczne jest użycie funkcji Reverse Engineering w celu pobrania modelu do Rational Data Architect. Aby wykonać mapowanie modeli w obrębie jednego projektu w menu wybieramy opcję File-> New-> Mapping Model. Prawdopodobnie na etapie poznawania narzędzia Rational Data Architect funkcja ta nie znajdzie zastosowania więc postanowiłem, że nie będę jej dogłębnie analizował.

Mapowanie modeli
Mapowanie modeli ma na celu umożliwienie nam porównania różnych źródeł danych między sobą, znalezienie powiązania w źródłach danych, oraz przeprowadzenie szczegółowej analizy porównawczej modeli. Rysunek 4 obrazuje nam sposób w jaki wyglądają dwa przykładowe mapowane modele bazodanowe. Abyśmy mogli wykonać mapowanie modeli, konieczne jest umieszczenie źródeł danych w jednym projekcie. Aby ma-

Wykonywanie poleceń SQL za pomocą RDA
Rational Data Architect posiada wbudowane narzędzie służące do tworzenia poleceń SQL. Można uzyskać dostęp do niego na wiele sposobów, włączając dostęp bezpośrednio z panelu Database Explorer. Na potrzeby artykułu wykorzystałem połączenie z SQL Server-em 2005. Aby wykonać polecenie SQL musimy wykonać następujące kroki:

• prawym przyciskiem myszy klikamy na połączeniu z bazą danych w panelu Databse Explorer i wybieramy opcję New SQL Statement; • w oknie, które się otworzy po wykonaniu polecenia z punktu pierwszego wpisujemy nazwę polecenia oraz jego typ (SELECT, INSERT, itp.); • po wykonaniu poleceń z powyższych punktów otworzony zostanie edytor, w którym podajemy polecenie SQL, oraz dodajemy tabele (poprzez klikniecie prawym przyciskiem myszy na widoku Tables i wybranie opcji Add Tables), na których będziemy operować; • podajemy polecenie SQL i aby je wykonać używamy funkcji znajdującej się w: Run > Run SQL. Narzędzie służące do tworzenia poleceń SQL w Rational Data Architect posiada szeroki wachlarz możliwości przy budowaniu zapytań SQL, oraz operacji na wynikach zapytań. Wszystko to powoduje, że Rational Data Architect jest narzędziem wielofunkcyjnym służącym nie tylko do tworzenia modeli baz danych, ale również do ich testowania.

Podsumowanie
Rational Data Architekt jest narzędziem, które dzięki swoim funkcjom pozwala na drastyczną redukcję czasu pracy nad modelami baz danych. Narzędzie to zbudowane w oparciu o open source-ową platformę eclipse nie tylko posiada przyjazne użytkownikom środowisko graficzne, ale również pozwala na zsynchronizowanie pracy architektów tworzących projekty oprogramowania nie tylko bazodanowych. Wystarczy dodać kolejne wtyczki do elipsa i osoby odpowiedzialne za różne elementy powstawania projektu oprogramowania mogą wymieniać się efektami swojej pracy ciągle korzystając z tego samego narzędzia. Rational Data Architect jest jak szwajcarski scyzoryk przy zarządzaniu modelami baz danych. Czy to znaczy, że RDA może wszystko? Nie. Szwajcarski scyzoryk, również nie może, ale możliwości, które dają te dobrze zorganizowane narzędzie pozwalają na odnalezienie zastosowania w niemal każdej sytuacji.

Rysunek 5. Widok narzędzia służącego do wykonywania poleceń SQL

Współpraca Rational Data Architect z serwerami baz danych
Rational Data Architect w swojej pełnej funkcjonalności współpracuje z: • • • • • • • • • • • Cloudscape® DB2 for iSeries® DB2 for Linux®, UNIX®, and Windows® DB2 for z/OS® Derby Informix® Dynamic Server Microsoft SQL Server Enterprise MySQL Oracle Sybase Adaptive Server Enterprise Teradata

SZYMON GRUSZEWSKI
Autor jest studentem na wydziale informatyki w Polsko-Japońskiej Wyższej Szkole Technik Komputerowych w Warszawie. Odbył praktyki w firmie IBM Polska, których tematem było rozpoznanie narzędzia Rational Data Architect. Kontakt z autorem: szymon.gruszewski@gmail.com
43

www.sdjournal.org

Testowanie oprogramowania

Bezpieczne partycjonowanie
Systemy wielordzeniowe QNX
W dzisiejszych czasach praktycznie każdy wbudowany system podłączony jest fizycznie lub bezprzewodowo do świata zewnętrznego. Taka łączność sieciowa pozwala użytkownikom na zdalne monitorowanie i sterowanie oraz pozwala systemom pobierać nowe oprogramowanie i treści wtedy, kiedy jest to konieczne.
Dowiesz się:
• Co to jest technologia partycjonowania? • Jak optymalnie wykorzystywać czas CPU w systemach wieloprocesorowych? • Jak tworzyć bezpieczne systemy?

Powinieneś wiedzieć:
• Co to jest system wbudowany? • Na czym polega przetwarzanie współbieżne?

Poziom trudności

N

iestety, łączność opisana powyżej sprawia, że systemy są narażone na infiltrację przez rosnącą rzeszę cyber-terrorystów oraz szantażystów. W rzeczywistości, złośliwi hakerzy pokonali już wiele różnych systemów SCADA, systemów kontroli HVAC, urządzeń przenośnych oraz systemów bezpieczeństwa nuklearnego przy użyciu wirusów, ataków DoS (zablokowanie usług) oraz innych programów sieciowych. Aby opanować takie ataki wielu projektantów systemów skierowało się do bezpiecznego partycjonowania. Mówiąc krótko technologia ta pozwala projektantom wyizolować procesy oprogramowania na wirtualne części lub partycje oraz alokować predefiniowane zapasy pamięci lub czasu CPU do każdej partycji. System operacyjny może wtedy wykorzystywać te zapasy, a co za tym idzie chronić procesy w którejkolwiek partycji przed fałszywym lub złośliwym monopolizowaniem zasobów wymaganych dla tych procesów w innych partycjach – Rysunek 1. Przy pomocy partycjonowania zasobów, projektant systemu może wyizolować procesy oprogramowa44

nia w osobne partycje oraz alokować zagwarantowany zapas pamięci oraz czasu CPU do każdej z partycji. W wyniku tego, złośliwe lub źle napisane procesy nie będą mogły zmonopolizować zasobów niezbędnych dla innych procesów Partycjonowanie może również ochronić przed problemami z wydajnością i niezawodnością, które nieuchronnie pojawiają się podczas integrowania wielu podsystemów. Projektant staje często przed problemem połączenia dowolnej liczby podsystemów opracowanych na miejscu z podsystemami i elementami od zewnętrznych dostawców oprogramowania. W trakcie fazy integracji wszystkie te podsystemy łączą się i rozpoczynają współzawodnictwo o zasoby, co często skutkuje nieoczekiwanymi zachowaniami systemu. Podsystemy, które prawidłowo funkcjonowały w izolacji, teraz pracują wolno lub w ogóle odmawiają pracy. Rozwiązanie takich kwestii związanych z zasobami jest skomplikowanym i czasochłonnym zadaniem. Po zidentyfikowaniu głównej przyczyny projektant systemu musi żonglować priorytetami różnych podsystemów, lub co gorsze ponownie wdrożyć logikę podsystemu, aby uzyskać pożądane zachowanie. Proces ten może z łatwością przedłużyć realizację projektu o dodatkowe tygodnie lub miesiące. Partycjonowanie odpowiada na te problemy na etapie projektowania, pozwalając projektan-

tom systemów alokować predefiniowane zasoby dla każdego z podsystemów. Kiedy rozpoczyna się testowanie podsystemu, opracowujący go może ograniczyć partycję podsystemu do alokowanego zapasu zasobów oraz może testować podsystem w symulowanych warunkach pesymistycznych. Dzięki temu może on rozwiązać potencjalne kwestie związane z wydajnością oraz rywalizacją o CPU we wczesnym etapie, w dużym stopniu upraszczając następna fazę integracji systemu.

Skalowanie partycji w procesorach wielordzeniowych
Do dziś partycjonowanie stosowano prawie wyłącznie w środowiskach procesorów jednordzeniowych. Jednakże, przy rosnącej popularności procesorów wielordzeniowych, producenci potrzebują sposobu na wdrożenie partycji w dwóch, czterech, ośmiu i większej liczbie rdzeni procesowych. W tym jest wyzwanie. W środowisku procesorów pojedynczych, program planujący RTOS alokuje pojemność CPU do każdej partycji. W idealnej sytuacji program planujący RTOS może po prostu rozszerzyć ten koncept na wszyst���������� ��������� ���������� ����������

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

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

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

Rysunek 1. Schemat partycjonowania zasobów

11/2008

kie rdzenie procesowe w systemie wielordzeniowym. Niestety, wiele Systemów Operacyjnych Czasu Rzeczywistego (RTOS) nie zapewnia tej możliwości, w dużej mierze z powodu ich ograniczonych możliwości w zakresie przetwarzania wieloprocesorowego. RTOS (System Operacyjny Czasu Rzeczywistego) może obsługiwać jeden lub większą liczbę następujących modeli przetwarzania wieloprocesorowego: • Asymetryczne Przetwarzanie Wieloprocesorowe (AMP) — traktuje każdy rdzeń jako odrębny CPU. Osobny RTOS działa na każdy rdzeń, wymuszając na projektancie systemu statyczną konfigurację pamięci, przerwań oraz innych współdzielonych zasobów systemowych. Aplikacje działające na danym rdzeniu mogą wykorzystywać wyłącznie zasoby, które zostały statycznie skonfigurowane dla tego rdzenia; • Symetryczne Przetwarzanie Wieloprocesorowe (SMP) — pojedynczy RTOS zarządza wszystkimi rdzeniami. RTOS zarządza współdzielonymi zasobami systemowymi, pozwalając im na wykorzystanie przez którąkolwiek z aplikacji działających na którymkolwiek rdzeniu. Dodatkowo, RTOS może dynamicznie planować wszelkie procesy na którymkolwiek rdzeniu, umożliwiając pełne wykorzystanie CPU. Podejście to nie tylko upraszcza rozbudowę, ale również oferuje większą elastyczność podczas wykorzystywania bezpiecznych partycji w środowiskach wielordzeniowych; • Ograniczone Przetwarzanie Wieloprocesorowe (BMP) — rozszerza SMP poprzez umożliwienie projektantowi powiązać wszelkie procesy (oraz wszystkie wątki z nimi powiązane) z określonym rdzeniem. Podejście to łączy w sobie sterowanie AMP oraz uproszczone programowanie oraz większą skalowalność SMP. Z natury AMP nie jest w stanie odpowiedzieć na wymagania przetwarzania związane z rdzeniami wielokrotnymi. Z tego powodu wszelkie partycje w AMP są ograniczone do rozmiaru pojedynczego rdzenia, do 100%. W SMP oraz BMP, z drugiej strony, RTOS posiada całkowity obraz systemu, co pozwala mu na wykorzystanie całkowitej pojemności CPU procesora wielordzeniowego (np. wszystkich rdzeni) do partycjonowania. Projektanci systemu mogą w wyniku tego elastycznie mapować partycje na wiele rdzeni w dowolny sposób, odpowiedni do wymogów systemowych — oraz niezależnie od ograniczeń procesora. Na przykład, na Rysunku 2, Bezpieczna Partycja 1 rozciąga się na dwa rdzenie CPU, podczas gdy inne partycje pracują na pojedynczych rdzeniach. Elastyczność ta umożliwia projektantom systemów dostosowywać rozwój platformy, zarówno w oprogramowaniu jak i w sprzęcie. Na przykład, wprowadzanie nowych funkcjonalności oprogramowania do aplikacji może nadwerężyć partycję do poziomu, w którym pojedynczy rdzeń CPU nie będzie już w stanie poradzić sobie z obciążeniem przetwarzania. W takim przypadku, partycje można łatwo rozszerzyć, aby obejmowała dwa rdzenie. Migracja do nowej platformy sprzętowej może również wymagać zmian w zasobach partycji, co z kolei spowoduje potrzebę zawarcia wielu rdzeni w partycji.

O firmie QNX Software Systems

QNX Software Systems, międzynarodowa firma należąca do Harman International, jest liderem w przemyśle technologii wbudowanych systemów operacyjnych czasu rzeczywistego. Konstrukcje QNX® Neutrino® RTOS oraz QNX Momentics® oparte na komponentach tworzą najbardziej niezawodną i skalowalną ramę do budowy innowacyjnych i wysoce wydajnych systemów wbudowanych. Światowe firmy takie jak Cisco, DaimlerChrysler, General Electric, Lockheed Marti oraz Siemens zależne są od technologii QNX oraz routerów sieciowych, sprzętu medycznego, układów telematycznych dla motoryzacji, systemów bezpieczeństwa i obrony, robotów przemysłowych oraz innych aplikacji. Założona w 1980, firma QNX Software Systems posiada swoja siedzibę główną w Ottawie, Kanada, i dystrybuuje produkty do ponad 100 krajów na całym świecie.

www.sdjournal.org

45

Testowanie oprogramowania
Jeśli partycja wymaga dedykowanego rdzenia CPU, projektant systemu może zastosować ograniczone przetwarzanie wieloprocesorowe, aby ta i wyłącznie ta partycja była uruchamiana na tym rdzeniu. wielka pracę. Na przykład, jeśli w partycji alokowano 30% CPU, będzie ona zawsze wykorzystywała 30%, nawet jeśli w danej chwili potrzebuje tylko 10%. To podejście stało-cyklowe marnuje cenne (i dostępne) cykle CPU i uniemożliwia systemowi radzenie sobie z zapotrzebowaniem impulsowym. Inne aplikacje najlepiej wykorzystują takie jałowe cykle poprzez dynamiczną alokację do partycji, co może przynieść korzyści z dodatkowego czasu przetwarzania. Takie podejście daje nam bardziej czuły system oraz eliminuje kosztowną przebudowę związaną z podejściem stało-cyklowym.

Tworzenie systemów, które przetrwają
Żadna, nawet największa liczba przeprowadzonych testów nie jest w stanie w pełni wyeliminować wirusów lub potencjalnych dziur w skomplikowanym systemie, jak również żaden test nie jest w stanie przewidzieć każdego zagrożenia, na które może napotkać system. Projektanci systemów oraz twórcy oprogramowania muszą, w rezultacie zaadoptować technologie, które zawierają błędy w oprogramowaniu oraz inne zagrożenia i szybko je naprawić. W prawidłowy sposób wdrożone, partycjonowanie może zapewnić taką ochronę oraz skalowanie ze zwiększającą się liczbą rdzeni procesora. W wyniku takiej ochrony, zarówno procesory pojedyncze jak i systemy wielordzeniowe mogą: • zawierać blokadę ataków; • zawierać wadliwe podsystemy, które powodują obciążenie CPU lub wyczerpanie pamięci; • zapewniać gwarantowany czas CPU dla procesów przeprowadzających diagnostykę systemu oraz odzyskiwanie danych; • zapewniać zagwarantowany czas CPU dla interfejsów użytkownika (idealne dla systemów, w których gwarantowany dostęp zdalny jest wymogiem kluczowym); • integrować podsystemy od różnych producentów oraz dostawców przy jednoczesnym uniknięciu typowych w takich sytuacjach konfliktów zasobów, które utrudniają integrację. Co istotne, dobrze wdrożony plan partycjonowania nie wymaga zmian kodów w istniejących aplikacjach i umożliwia projektantom pracę zgodnie z tym samym planem i priorytetami zadań jak dotychczas. Dzięki adaptacyjnemu partycjonowaniu QNX, projektant systemu może na przykład uruchomić istniejące aplikacje i usługi systemowe w partycjach a program planujący systemu operacyjnego zapewni, że każda partycja otrzyma swoje alokowane zasoby. W ramach każdej partycji, program planujący rozdysponuje wątki zgodnie z tradycyjnymi zasadami priorytetowego szeregowania z wywłaszczeniem.

Maksymalne wykorzystanie CPU
Schemat partycjonowania powinien również być elastyczny w sposobie zarządzania zasobami CPU. Niektóre wdrożenia ściśle wymuszają zasoby CPU w każdej sytuacji, aby każda z partycji zużywała w całkowite zasoby, nawet w przypadku, gdy ma do wykonania nie-

���

���

���

���

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

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

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

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

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

�����

�����

�����

�����

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

Rysunek 2. W modelach symetrycznego i ograniczonego przetwarzania wieloprocesorowego, partycje mogą w sposób elastyczny rozciągać się na różne rdzenie

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

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

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

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

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

�����������

�����������

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

���

���

���

W Sieci
���� ����

��� ���

��� ���

�� ���

http://www.qnx.com

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

�����������

�����������

�����������

KERRY JOHNSON, QNX SOFTWARE SYSTEMS
Kontakt z autorem: kjohnson@qnx.com

Rysunek 3. Inteligentne partycjonowanie, opatentowane przez QNX Software Systems, narzuca czas CPU dla budżetu partycji, kiedy system jest obciążony. Niewykorzystany czas CPU jest dynamicznie alokowany do partycji w sytuacji niepełnego obciążenia

ROMAIN SAHA, QNX SOFTWARE SYSTEMS
Kontakt z autorem: rsaha@qnx.com

46

11/2008

Testowanie oprogramowania

Joomla 1.5
Nowości
21 stycznia, w dwa i pół roku po pierwszym głównym wydaniu Joomla! (miało to miejsce 16 września 2005 roku) zespół projektantów udostępnił społeczności z radosnym komunikatem długo oczekiwane wydanie drugie. Od tego momentu ukazało się pięć kolejnych aktualizacji, eliminujących zauważone błędy, wnoszących dziesiątki drobniejszych poprawek i udoskonaleń.
Dowiesz się:
• Jakie zmiany wprowadzono do wersji 1.5.

Powinieneś wiedzieć:
• Podstawy użytkowania Joomla 1.0.

sy tcpdf, zapewniając atrakcyjniejsze dokumenty i ograniczając częste wcześniej problemy z kodowaniem znaków, czy obsługą niektórych formatów graficznych. Łatwiejsza lokalizacja rozszerzeń Nowe rozwiązania w językowej warstwie Joomla! już w najbliższej przyszłości będą zapewne skutkować szybszą polonizacją rozszerzeń. Już teraz mamy do czynienia ze znacznie częstszymi próbami lokalizacji nowości, niż miało to miejsce w przypadku rozszerzeń dla Joomla 1.0. Problemem może być wprawdzie utrzymanie pewnych standardów, zapewnienie wysokiej jakości tłumaczeń, ale sam proces stał się bardzo łatwy. Wystarczy zainstalować specjalny komponent TranslationManager. Komponent wyświetla na zapleczu frazy języka witryny i zaplecza, które wystarczy przetłumaczyć i zapisać, by korzystać w swoim Joomla! i ewentualnie udostępnić społeczności. Ustawienia Ustawienia lokalne w Joomla 1.0 definiowano w Konfiguracji globalnej. W Joomla 1.5 nie znajdziemy w globalnych ustawieniach takich opcji. Kod języka i kod kraju ustawiane są teraz przez plik językowy – jezyk.xml (np. pl-PL.xml). Wewnątrz znacznika locale można umieścić wiele ciągów ustawiających lokalizację. System wybiera spośród nich automatycznie jedno, odpowiednie do konfiguracji serwera. Jeśli zatem mamy problemy z umiejscowieniem, takie jak niepoprawne wyświetlanie daty, można – razem z administratorem serwera sprawdzić i zmodyfikować wpisy w znaczniku locale.

Poziom trudności

• zachowano zgodność wsteczną z poprzednimi wydaniami Joomla!, komponentami, szablonami, modułami i innymi dodatkami.

Uniwersalność i lokalizacja

P

rzystosowanie Joomla!, którego początki sięgają przecież 2001 roku do zmieniającej się natury internetu i nowoczesnych technologi sieciowych wymagało gruntownej przebudowy kodu, wzbogacenia użyteczności i uproszczenia interfejsu użytkownika. Jak poprzednio, nowe wydanie Joomla! zapewnia użytkownikom i projektantom wygodny i łatwy w użyciu szkielet publikacji treści w witrynach internetowych wszelkiego typu. W Joomla! 1.5: • istotnie zwiększono funkcjonalność – zarówno użyteczność, jak i wykonalność (ang. manageability), skalowalność i wydajność, zostawiając daleko w tyle oryginalne Mambo; • zapewniono obsługę dowolnego języka – dwubajtowe kodowanie utf (język japoński!), obsługa tekstów w językach z pisownią od prawej (np. arabski, farsi i hebrajski); • rozwinięto zdolność integracji z aplikacjami zewnętrznymi przez usługi sieciowe i zdalne uwierzytelnianie, np. lekki protokół dostępu do usług katalogowych (LDAP); • udoskonalono technikę dodawania treści, szablony i formy prezentacji, aby zapewnić obsługę standardów dostępności i użyteczności dla dowolnych odbiorców; • zbudowano nowoczesny, prostszy i elastyczny szkielet projektowy dla komponentów i innych rozszerzeń;
48

Dla polskich użytkowników Joomla! 1.0 nie jest zbytnią nowością w pełni zlokalizowany interfejs Joomla 1.5 – zarówno witryny, jaki zaplecza. Wielu użytkowników Joomla 1.0 w Polsce nie było i nie jest nawet świadomych faktu, że oryginalny Joomla! przemawia na zapleczu tylko w języku angielskim. W UTF-8 W Joomla 1.5 problem lokalizacji rozwiązano gruntownie i definitywnie. Dla wydawców polskiego Joomla! skończył się problem z tygodniami pracy potrzebnej na dokonanie niezbędnych zmian w skryptach. Do nowego wydania trzeba co najwyżej dotłumaczyć kilka nowych fraz w plikach językowych. Zmianą najważniejszą jest zapewnienie pełnej obsługi przez Joomla 1.5 standardu UTF, a więc wielobajtowego kodowania znaków. W efekcie Joomla 1.5 stał się projektem w pełni uniwersalnym, obsługującym dowolny język, w tym języki z kierunkiem pisma od prawej do lewej czy języki, w których stosowane jest pismo morfosylabiczne (chiński, japoński). Doskonalszy PDF Dostosowanie do standardu UTF pozwoliło również lepiej niż dotychczas rozwiązań problem generowania dokumentów PDF. W miejsce stosowanego w poprzednim wydaniu Joomla! skryptu free-PDF skorzystano z obsługującej UTF kla-

Zarządzanie rozszerzeniami
Oznaczenie komponentów, modułów, dodatków, szablonów i pakietów językowych jednym terminem – rozszerzenia, to najdrobniejsza ze zmian. Przede wszystkim uproszczono proces instalacji.
11/2008

Nowy Joomla 1.5 i nowe w Joomla!

W wydaniach sprzed Joomla 1.5 trzeba było dobrać rodzaj instalatora do typu rozszerzenia. W Joomla 1.5 instalatorowi dodano inteligencji, w rezultacie sprytnie sam rozpoznaje rodzaj instalowanego rozszerzenia. Użytkownik nie musi się już martwić o poprawny wybór – po prostu wskazuj rozszerzenie, a resztę pracy wykonuje instalator. Rozwiązano często doświadczane kłopoty na serwerach Linuksowych i Uniksowych, a spowodowane ograniczeniami praw dostępu do plików i bezpiecznym trybem działania PHP. Jak wiadomo, bezpieczny tryb ogranicza PHP do możliwości wykonywania operacji tylko na tych plikach lub folderach, których właściciel jest tożsamy z używanym przez PHP (zwykle jest to użytkownik 'apache'). Normalnie pliki tworzone są albo przez Joomla!, albo podczas transmisji przez FTP. W Joomla 1.5 dodano obsługę protokołu FTP przez rdzeń systemu. Kombinacja akcji PHP na plikach i włączona obsługa FTP przez Joomla! umożliwia bezproblemowe działanie przy włączonym safe mode. Włączenie FTP umożliwia operację na plikach (np. instalację rozszerzeń lub zmiany w pliku konfiguracyjnym) bez konieczności dokonywania zmian praw zapisu dla katalogów i plików. Takie rozwiązanie znacznie ułatwia życie administratorowi i zwiększa bezpieczeństwo witryny.

Zarządzanie artykułami
Wprawdzie nie dokonano bodaj najbardziej oczekiwanej zmiany – możliwości przypisywania artykułów do wielu kategorii tudzież tworzenia wielopoziomowego systemu kategorii, ale i w sferze zarządzania artykułami zmiany są znaczące. Sposób obsługi został uproszczony, stając się jeszcze bardziej intuicyjnym, niż był w Joomla 1.0. Czytaj więcej Zrezygnowano z formalnego podziału artykułów na część wstępną i tekst główny. W konsekwencji w edytorze artykułów mamy zamiast dwóch jedno pole na cały tekst. Oczywiście, nie zrezygnowano jednak z możliwości wyodrębniania zapowiedzi i właściwego tekstu. Wszak zapowiedzi są niezwykle użytecznym sposobem prezentacji artykułów w przeglądach (zwanych dawniej blogami). Teraz jednak, aby podzielić artykuł na zapowiedź i tekst główny, używamy markera Czytaj więcej. Można przy tym wpisać odpowiednie polecenie, ale wygodniej zastosować przycisk wstawiający marker, umieszczony pod edytorem. W miejscu wstawienia znacznika pojawi się czerwona przerywana linia, oddzielająca wstęp artykułu od całości. O obsługę podziału na stronach witryny zadba nowy dodatek (ang. plg_readmore). Warto przy tym wspomnieć, że w przypadku migracji danych ze starszych stron, nie będzie to powodować żadnych problemów. Nowe rozwiązanie jest w pełni zgodne z poprzednimi. Nieprzypisane zamiast statycznych W wydaniach sprzed Joomla 1.5 istniał specyficzny typ artykułu nazywany materiałem statycznym. Ewolucja jego właściwości następowww.sdjournal.org

wała już w kolejnych wydaniach Joomla 1.0. Początkowo taki materiał można było udostępnić jedynie przez publikację odnośnika w menu, nie można go było udostępnić w przeglądach artykułów ani w modułach typu Popularne czy Nowości. Chociaż z czasem stało się to możliwe, artykuł statyczny nadal różnił się od zwykłego, dynamicznego – nie można go było przenieść do kategorii, a tym samym udostępnić w przeglądzie czy na liście artykułów w kategorii. Odmienność typu wiązała się w Joomla 1.0 z dwoma różnymi procedurami tworzenia artykułów i materiałów statycznych. Wspomniana wcześniej rezygnacja z formalnego podziału artykułów na część wstępną i tekst główny rozwiązała również kwestię materiałów statycznych. Redakcję obu typów artykułów obsługuje jedna, taka sama procedura. A dawne materiały statyczne są teraz po prostu artykułami nieprzypisanymi do żadnej kategorii. W efekcie – jeśli potrzebujemy umieścić w witrynie statyczny artykuł, jak statyczną, niezmienną stronę HTML, możemy to uczynić – redagujemy nowy artykuł w taki sam sposób, jak standardowy i zamiast przypisać go do konkretnej sekcji i kategorii, wybieramy na liście możliwości opcję Nieprzypisany. W każdym jednak momencie nieprzypisany artykuł możemy umieścić w dowolnej kategorii i sekcji, co w Joomla 1.0. możliwe nie było, a także każdy artykuł przypisany do kategorii i sekcji możemy przekształcić w nieprzypisany materiał statyczny. Ilustrowanie artykułów Unowocześniony sposób zarządzania obrazkami zaowocował również istotnymi zmianami w sposobie ilustrowania artykułów. W Joomla 1.0 ilustrowanie artykułów obsługiwał specjalny, niezbyt intuicyjny dodatek (mosimage). Co prawda, samo stosowanie dodatku osobom nauczonym, jak go używać kłopotu nie sprawiało, ale jeśli ktoś nie doczytał, jak to się robi, miał problem. W Joomla 1.5 – podobnie jak w Joomla 1.0 wstawiamy ilustracje do artykułów za pomocą przycisku Wstaw obraz, ale teraz polecenie to otwiera specjalny edytor, umożliwiający zarówno wybór obrazka, jak i opis jego właściwości. Co więcej – w Joomla 1.0 nie można było umieścić w artykule obrazka, który nie został przesłany na serwer przed przystąpieniem do pisania artykułu. W Joomla 1.5 jest to, oczywiście, możliwe. Podgląd artykułu i inne usprawnienia W Joomla 1.0 redagowany artykuł można było podejrzeć dopiero po zapisaniu go w bazie danych. W Joomla 1.5 podgląd możliwy jest już po napisaniu pierwszych słów, a więc w każdym momencie. Usprawniono również podział długich artykułów na strony i generowanie spisu treści artykułów wielostronicowych. Przycisk Podziel stronę wywołuje teraz okno, w którym podajemy parametry podziału – tytuł nowej strony oraz inną nazwę umieszczaną w spisie treści. Poprzednio ko-

nieczne było ręczne wpisanie markera wraz z odpowiednimi atrybutami. W Joomla 1.0 dysponowaliśmy jednym edytorem wizualnym – TinyMce. Wprawdzie możliwe było doinstalowanie innych edytorów, ale trzeba to było uczynić, jeśli TinyMCE nie spełniał naszych oczekiwań. Joomla 1.5 udostępnia dwa edytory wizualne, obok TinyMCE – XStandard Lite. Edytor ten oferuje wprawdzie znacznie mniej funkcji, ale zapewnia większą zgodność generowanego kodu ze standardami XHTML niż TinyMCE. W Joomla 1.5 na dobre zagościła też możliwość wyboru przez użytkowników uprawnionych do współtworzenia witryny własnego edytora. Parametry globalne Obowiązujących w całej witrynie, podstawowych ustawień prezentacji artykułów w Joomla 1.0 dokonywaliśmy w edytorze konfiguracji globalnej witryny. W Joomla 1.5 edytor tych ustawień przeniesiono w bardziej naturalne miejsce – do menedżera artykułów. W każdym bądź razie tak sądzili projektanci. W rezultacie użytkownicy Joomla! 1.0 zastanawiają się często, gdzie się te ustawienia podziały. A kryją się w przyborniku menedżera artykułów (strona Wszystkie artykuły), pod ikoną Preferencje. Takie rozwiązanie wynika nie tylko z woli uproszczenia interfejsu, ale także z rozwiniętych w Joomla 1.5 możliwości zarządzania rozszerzeniami. W Joomla 1.0 parametry globalne można było zdefiniować w zasadzie tylko dla treści zarządzanych przez komponent Artykuły (Content). W Joomla 1.5 można ustawiać parametry globalne także dla niektórych komponentów i modułów. W przybornikach na stronach menedżerów tych rozszerzeń również znajdziemy ikonę Preferencje (być może w następnych polskich wydaniach użyjemy określenia Ustawienia lub Parametry). Za pierwszym przemawia jego polski rodowód, za drugim spójność terminologiczna.

Projektowanie menu
Spore udoskonalenia przyniosła w Joomla 1.5 obsługa menu. Zmiany, pozornie drobne, mają jednak charakter wręcz rewolucyjny. Zmiana najtrudniej dostrzegalna Zmiana najmniej widoczna, najtrudniej dostrzegalna, a najbardziej rewolucyjna wynika z konsekwentnego zastosowanego w Joomla 1.5 wzorca projektowego MCV (Model-KontrolerWidok). Pozwala on projektantom witryn na stosunkowo łatwe zaprojektowanie własnych sposobów prezentacji treści, innych niż widoki domyślne. W efekcie spora już w Joomla 1.0 ilość typów pozycji menu w Joomla 1.5 jest praktycznie nieograniczona. Każdy może wzbogacać oferowaną domyślnie paletę o nowe, odpowiednie dla konkretnej witryny rozwiązania. Po umieszczeniu skryptów definiujących nowe widoki wśród skryptów szablonu, pojawią sie one w zestawie typów pozycji menu do wyboru.
49

Testowanie oprogramowania
Trzy kliknięcia Nie chodzi tu o dotarcie po 3 kliknięciach do poszukiwanej treści, ale o tworzenie nowej pozycji menu w Joomla 1.5. Dodajemy je dosłownie za pomocą trzech kliknięć – w pierwszym wybieramy w przyborniku polecenie Utwórz, w drugim wskazujemy zakres treści (artykuły, komponent, łącze zewnętrzne), w trzecim widok – sposób prezentacji (typ pozycji), po czym trafiamy na stronę edytora pozycji, gdzie wystarczy jedynie uściślić zakres treści i ewentualnie zdefiniować dodatkowe parametry prezentacji. Pozycja domyślna Domyślna startowa pozycją menu w Joomla 1.0 musiała być pierwszą pozycją w głównym menu witryny. Joomla 1.5 zapewnia w tej mierze pełną swobodę – domyślną pozycją menu, wskazującą na stronę startową witryny, wywoływaną po wpisaniu w przeglądarce adresu witryny może być dowolna pozycja w dowolnym menu. W każdym też momencie można ją zmienić. Zmiana typu bez usuwania W Joomla 1.0 takiej możliwości nie było w ogóle. Raz ustalonego typu pozycji menu zmienić się nie dało. Jedynym wyjściem było usunięcie takiej nieodpowiadającej nam pozycji i stworzenie nowej. W Joomla 1.5 wystarczy prosty zabieg – w edytorze pozycji menu naciskamy przycisk Zmień typ, a następnie dokonujemy odpowiednich ustawień. Walory tego rozwiązania można poznać tak naprawdę dopiero w trakcie migracji z Joomla 1.0 do Joomla 1.5. Kto już przechodził ten proces, wie, ze podczas migracji tracimy – niestety – wszystkie połączenia pozycji menu z nierdzennymi komponentami. Dzięki możliwości zmiany typu menu po doinstalowaniu komponentów przywrócenie połączeń w różnych menu witryny przebiega łatwo, bez zbędnego stresu. Zwolenników standardów dostępności interesuje zapewne, na ile zmodyfikowano kod, który w Joomla 1.0 preferował stosowanie do rozmieszczania treści obciążających kod i łącza, a przy tym wysoce niedostępnych tabel. Gorszą wiadomością jest ta, że tabele w kodzie pozostały. Nie zdecydowano się na pełne wykorzystanie doświadczeń projektu a8e. Ale jest i dobra wiadomość, którą się już dzieliliśmy. Proces generowania kodu HTML został przeniesiony do odrębnych skryptów, które mogą być swobodnie modyfikowane przez projektantów bez ingerencji w rdzenny kod. W efekcie każdy projektant witryny może skutecznie wyeliminować z kodu wszystkie niepotrzebnie zastosowane tabele, zastępując je rozwiązaniami w pełni korzystającymi z możliwości CSS. Istotą rozwiązania jest mechanizm podmiany skryptów rdzenia Joomla! skryptami szablonu. Przykład takiego rozwiązania dołączono, oczywiście, do oficjalnego wydania Joomla 1.5. Zainteresowanych odsyłamy do przejrzenia skryptów szablonu Beez, zwłaszcza tych umieszczonych w katalogu /templates/beez/html. Znajdziemy tam wzorcowe skrypty widoków dla rdzennych komponentów i modułów (contact, content, poll, search, user, weblinks). Można je wykorzystać we własnych rozwiązaniach projekowych. tów spoza zespołu Centrum Projektu nie znajdziemy jeszcze w Sieci zbyt wielu, ale jaskółki w tym przypadku dość szybko uczynią wiosnę.

Kompatybilność z 1.0 i rozszerzeniami
Projektanci Joomla 1.5 uczynili wszystko, co możliwe, aby zachować w maksymalnym stopniu wsteczną zgodność z Joomla 1.0, a tym samym i z rozszerzeniami stworzonymi dla Joomla 1.0. Zastosowane w Joomla 1.5 rozwiązania projektowe, oparte na obiektowym PHP z natury rzeczy wymagają rozszerzeń napisanych wedle nowego wzorca projektowego. Natywnych rozszerzeń dla Joomla 1.5 jest już sporo (niestety, niewiele spolonizowanych), ale nie na tyle, by można zupełnie zrezygnować z opracowanych dla Joomla 1.0, zwłaszcza że zastosowanie alternatywnych rozwiązań pociąga za sobą koszty migracji danych, a projektanci dawnych rozszerzeń albo porzucili swoje dawne rozwiązania, albo publikują nowsze wersje na licencjach komercyjnych. W Joomla 1.5 można korzystać z rozszerzeń projektowanych dla Joomla 1.0 (komponentów, modułów, szablonów, dodatków) w specjalnym trybie – trybie zgodności wstecznej. Uaktywnienie trybu jest proste – wystarczy włączyć odpowiedni dodatek, wybierając w menu zaplecza ->Dodatki -> System : Spuścizna (Plugins -.System – Legacy). Zdarzyć się może, że włączenie trybu zgodności wstecznej nie rozwiąże jednak problemów z dawnymi rozszerzeniami. Na nic zda się narzekanie na niedobrych projektantów, co to nie przewidzieli kilka lat temu, jakie możliwości i wymagania będzie mieć Joomla! w roku 2008, 2009 i następnych. Jeśli jakieś starocie ma miejsce w muzeum, poradzić się nie da. Trzeba poszukać nowszych rozwiązań. Szczególnie dotyczy to komponentów stworzonych jeszcze dla Mambo, wymagających rejestrowania zmiennych globalnych. Nawet usilne próby bez zasadniczych zmian w kodzie nie przywrócą im życia.

Otwartość
Cechą umieszczającą Joomla 1.5 w ścisłej czołówce najnowocześniejszych rozwiązań współczesnej informatyki jest jego otwartość i łatwość integracji z innymi systemami. W porównaniu z Joomla 1.0, które pod tym względem również przodowało wśród innych CMS (systemów zarządzania witrynami ineternetowymi), w Joomla 1.5 dokonano niemalże skoku o pokolenie wzwyż. Mechanizmy integracji oparto na znanym już z poprzedniej wersji, ale rozbudowanym typie rozszerzenia nazwanych obecnie dodatkami lub wtyczkami. Zmiana ich nazwy nie jest ucieczką od przypominających związek z Mambo mambotów czy krócej botów, ale podkreśla istotną zmianę ich roli. W Mambo i w Joomla 1.0 boty umożliwiały dodawanie funkcji, których zadaniem było przetwarzanie treści (np. osadzanie obrazków i ich parametrów, paginacja materiałów wielostronicowych). W Joomla 1.5 dodatki (kalka językowa – wtyczki do najpiękniejszych nie należy, ale popularyzowana przez nas od lat nazwa dodatki może budzić nieporozumienia) mogą poszerzać funkcjonalność Joomlowego frameworka. W dystrybucji 1.5 znajdujemy kilka takich dodatków, m.in.: • upoważnienie – LDAP: obsługujący uwierzytelnianie do usługi sieciowej LDAP; • upoważnienie – OpenID: obsługujący identyfikację za pomocą OpenID; • upoważnienie – GMail: obsługuje integrację z usługami sieciowymi Gmail; • XML-RPC - Blogger API: obsługuje interfejs oprogramowania XML-RPC Blogger. Przykładów praktycznego wykorzystanie tych i innych dodatków oferowanych przez projektan-

Szablony graficzne
O najistotniejszej zmianie już wspominaliśmy: konsekwentne rozdzielenie warstwy aplikacji, warstwy danych i warstwy prezentacji – zastosowanie modelu MCV – otworzyło nowe możliwości przed projektantami szaty graficznej. W Joomla 1.0 o mechanizmach personalizacji szablonów można było raczej pomarzyć. Oczywiście, stosując specjalne skrypty, projektanci udostępniali użytkownikom pewne możliwości dostosowania szablonu do swoich preferencji. Teraz te możliwości wzrosły w sposób w zasadzie nieograniczony. Skrypt konfiguracyjny szablonu może posiadać sekcję parametrów definiujących opcjonalne rozwiązania różnych kwestii – rozmiarów strony, układu jedno- lub wielokolumnowego, rozmieszczenia elementów, kolorystyki, wielkości czcionki. Oczywiście, nie wystarczy samo zdefiniowanie możliwości wyboru – szablon trzeba odpowiednio zaprogramować. Jest to jednak działanie niezwykle proste – najczęściej wystarczy zdefiniowanie odpowiednich arkuszy stylów dla poszczególnych opcji.
50

Podsumowanie
Stworzenie doskonałej witryny ze wszystkimi funkcjami, jakie sobie wymarzysz, może wymagać czasu i zaangażowania. Ale ze społecznością Joomla!, wsparciem projektantów oraz dzięki licznym rozszerzeniom tworzonym dla Joomla! 1.5, jest to jak najbardziej możliwe. Możesz również tworzyć własne rozszerzenia i udostępniać je ku uciesze całej społeczności.

STEFAN WAJDA
Stefan Wajda [Zwiastun] jest liderem PCJ!, koordynatorem Zespołu Tłumaczy i Dokumentacji akredytowanym przy Translation Work Group projektu Joomla!, wydawcą witryn PCJ, autorem w pełni zlokalizowanych wersji Mambo i Joomla!, komponentów josDirectory i josResource. Spolonizował ponad 150 rozszerzeń dla Joomla!, opublikował w Internecie około 600 artykułów poświęconych wszystkim aspektom Joomla! Kontakt z autorem: zwiastun@zwiastun.net

11/2008

XML

Spring 2 Schema
Własne przestrzenie nazw w Spring 2.x
Ten artykuł wprowadzi Cię szybko w podstawowe techniki tworzenia własnych przestrzeni nazw XML Schema dla plików konfiguracyjnych Spring IOC. Autorzy Spring Framework pisząc o dobrym oprogramowaniu promują zasadę DRY (Don't Repeat Yourself) – wyraźnie widać to w mechanizmie rozszerzania konfiguracji XML kontenera Springa.
Dowiesz się:
• Jak za pomocą własnej przestrzeni nazw XML stworzyć najprostsze rozszerzenia składni plików konfiguracyjnych XML dla Spring Framework w wersji 2.x.

Powinieneś wiedzieć:
• Podstawowa znajomość języka Java oraz konfiguracja kontenera Inversion Of Control dla Spring Framework 2.x za pomocą plików XML; • Wskazana jest również minimalna wiedza z zakresu języka XML oraz API programowej obsługi kontenera Spring IOC.

Poziom trudności

w dalszym ciągu działają w wersji 2.0 Springa (ze względu na słynne umiłowanie kompatybilności wstecz przez jego autorów), jakkolwiek zalecaną formą konfiguracji XML jest teraz XML Schema.

S

Motywacja
Nie trzeba nawet specjalnie zachęcać do stosowania nowej definicji plików konfiguracyjnych XML, gdyż oferuje nam ona rozliczne korzyści o których użytkownicy DTD mogą tylko poma-

pring jest popularnym frameworkiem IOC (Inversion Of Control) dla języka Java. Oferuje on kilka sposobów konfiguracji aplikacji oraz wstrzykiwania zależności, jednak najbardziej popularną techniką uzyskiwania tych celów jest konfiguracja w pliku XML. Jak powszechnie wiadomo XML oferuje czytelną, hierarchiczną strukturą prezentowanych przez siebie informacji, które to m.in. zapewniły mu rolę niepisanego standardu konfiguracji aplikacji webowych. XML jednakże cechuje się również tendencją do gadatliwości tzn. do konieczności opisywania zawartych w nim danych za pomocą dużej ilości tekstu. Programiści używający Springa w wersji niższej niż 2.0 skazani byli na używanie dość ograniczonego zestawu narzędzi redukujących rozmiar plików konfiguracyjnych XML oraz zjawiska tzw. XML hell (np. stosowanie dziedziczenia definicji beanów lub automatycznego wiązania). Na szczęście twórcy Springa od wersji 2.0 swojego frameworka dodali możliwość konfiguracji aplikacji za pomocą plików XML zdefiniowanych nie tylko zgodnie z DTD, ale i mechanizmem XML Schema. Oczywiście stare konfiguracje napisane pod kątem DTD
52

rzyć. Zaliczyć do nich należy głównie usprawnione uzupełnianie składni w edytorach XML dostępnych w popularnych IDE oraz zestaw dodatkowych przestrzeni nazw włączonych do dystrybucji Springa począwszy do wersji 2.0. W szczególności predefiniowane przestrzenie nazw okazują się być przydatne w codziennej pracy – pozwalają one m.in. na zastąpienie rozbudowanych definicji fabryk typu FieldRetrievingFactoryBean, ListFactoryBean lub TransactionProxyFactoryBean ich kompaktowymi odpowiednikami wyrażonymi za pomocą określonej przestrzeni nazw. Twórcy Springa nie poprzestali na szczęście na dostarczeniu nam zestawu predefiniowanych przestrzeni nazw, ale udostępnili również mechanizm do samodzielnego tworzenia tychże. Nie muszę chyba wspominać o tym jak bardzo konfiguracja naszej aplikacji zyska na czytelności po zastosowaniu elementów oraz atrybutów własnej konstrukcji, dostosowanych do

Listing 1. Szkielet konfiguracji kontenera Springa oparty na XML DTD
<!-- Stara konfiguracja --> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" <beans>

"http://www.springframework.org/dtd/spring-beans-2.0.dtd"> </beans>

Listing 2. Szkielet konfiguracji kontenera Springa oparty na XML Schema
<!-- Nowa konfiguracja --> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/ </beans> beans/spring-beans-2.0.xsd">

11/2008

Spring 2 Schema

naszych konkretnych potrzeb. Zysk ten będzie widoczny w szczególności jeżeli planujemy wielokrotne wykorzystywanie naszego kodu w aplikacjach używających np. pisanej przez nas biblioteki. W artykule tym chciałbym właśnie przedstawić podstawowe techniki rozszerzania możliwości konfiguracyjnych XML w Springu.

Listing 3. Przykład użycia komponentu z własnej przestrzeni nazw
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:myns="http://www.foo.com/customSchema" xsi:schemaLocation="

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

Migracja na nowy styl konfiguracji
Przejście na nowy styl konfiguracji jest bardzo proste. Wystarczy zamienić w istniejących plikach konfiguracyjnych parę pierwszych linijek dokumentu. Migracja zaprezentowana na Listingu 2 jest niemalże bezbolesna. Niemalże, gdyż istnieje parę (dosłownie parę) szczegółów konfiguracji które zostały uznane przez twórców Springa za przestarzałe (deprecated) i które należy w związku z tym dostosować do nowej konfiguracji opartej na XML Schema. Do szczegółów tego typu należy np. atrybut singleton elementu <bean>, który w nowej konfiguracji powinien zostać zamieniony na atrybut scope (ze względu na wprowadzenie mechanizmu rozszerzalnych zasięgów w nowszych wersjach Springa).

http://www.springframework.org/schema/beans http://www.springframework.org/schema/ http://www.foo.com/customSchema http://www.foo.com/customSchema.xsd"> <myns:bar id="bar" value="barValue" /> </beans> beans/spring-beans-2.0.xsd

Listing 4. Kod przykładowego komponentu Bar
package foo; public class Bar {

// wartość komponentu private String value; public Bar(String value) { } this.value = value;

@Override

public String toString() { } return value;

Witaj przestrzenio – przypadek użycia
Na początku spróbujemy napisać jak najszybciej najprostszą przestrzeń nazw z jednym elementem. Na potrzeby przykładów minimalnych zawartych w tym artykule załóżmy, że pracujemy dla firmy Foo i naszym zadaniem jest stworzenie elementu XML który pozwoli nam na bardziej efektywne używanie komponentu Bar w aplikacjach korzystających ze sprzedawanej przez nas biblioteki. Wyobraźmy sobie, że docelowo nasz klient chciałby konfigurować swoją aplikację za pomocą komponentu Bar w następujący sposób – Listing 3. Oczekujemy, że powyższa konfiguracja utworzy w kontenerze instancję klasy Bar o id równym bar oraz wartości prywatnej właściwości value równej barValue. Sam komponent Bar wygląda następująco – Listing 4. Schemat kroków Klasyczny schemat kroków wykonywany podczas tworzenia własnej przestrzeni nazw to kolejno: • napisanie dokumentu XSD; • stworzenie parserów dla nowych elementów lub atrybutów XML; • zaprogramowanie własnej klasy typu NamespaceHandler, która pozwoli nam na zmapowanie parserów i dekoratorów do określonych elementów i atrybutów XML; • dodanie do wynikowej aplikacji lub biblioteki meta-danych potrzebnych Springowi. W kolejnych sekcjach opiszę szerzej każdy z tych kroków.
www.sdjournal.org

}

Listing 5. Dokument XML Schema definiujący przykładową przestrzeń
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://www.foo.com/customSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://www.foo.com/customSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xsd:import namespace="http://www.springframework.org/schema/beans" /> <xsd:element name="bar"> <xsd:complexType> <xsd:complexContent>

<xsd:extension base="beans:identifiedType"> </xsd:extension>

<xsd:attribute name="value" type="xsd:string" use="required" />

</xsd:schema>

</xsd:element>

</xsd:complexType>

</xsd:complexContent>

W Sieci
• • • • • • http://springframework.org – Strona projektu Spring Framework http://static.springframework.org/spring/docs/2.5.x/api – Spring 2.5 API http://static.springframework.org/spring/docs/2.5.x/reference/xsd-config.html – Konfiguracja oparta na XML Schema w Spring 2.5 http://static.springframework.org/spring/docs/2.5.x/reference/extensible-xml.html – Własna przestrzeń nazw wg Spring 2.5 Reference http://www.w3.org/XML/Schema – XML Schema http://www.w3.org/ – DOM XMl DOM

53

XML
Dokument XSD Dokument XML Schema pozwoli nam określić składnię naszej przestrzeni nazw, czyli m.in. jaListing 6. Przykładowy parser komponentu Bar
package foo;

kie elementy oraz atrybuty są w niej dopuszczalne, a jakie nie. Schema uwzględnia również informacje o tym jakie typy danych zawarte są

import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.w3c.dom.Element; @Override

import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; public class BarParser extends AbstractSingleBeanDefinitionParser { // Oczekujemy instancji klasy Bar protected Class<Bar> getBeanClass(Element element) { } return Bar.class;

w poszczególnych elementach i atrybutach naszej przestrzeni oraz czy są one obowiązkowe. Interesujący nas schemat mógłby mieć następującą postać – Listing 5. Tematyka tworzenia definicji XML Schema jest poza zakresem tego artykułu. Ograniczę się zatem do podsumowania, że zdefiniowaliśmy właśnie element o nazwie bar zawierający jeden (wymagany) atrybut o nazwie value. Element ten dziedziczy również po identyfikowalnym typie Springa, co w praktyce oznaczna tyle, że również implicite dziedziczy atrybut id. Następnym krokiem zbliżającym nas do działającej przestrzeni nazw będzie zmapowanie elementu XML zdefiniowanego powyżej do Javy. Parser elementu Aby przekonwertować element XML do instancji zarejestrowanej w kontenerze musimy napisać parser implementujący interfejs org.spring
framework.beans.factory.xml.BeanDefiniti onParser.

@Override

protected void doParse(Element element, BeanDefinitionBuilder builder) { // Odczytaj wartość atrybutu // } String value = element.getAttribute("value"); builder.addConstructorArgValue(value);

i dodaj ją jako argument konstruktora wynikowej instancji

}

Listing 7. Handler mapujący przykładowy element 'bar' do wybranego parsera
package foo; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; public class BarNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() {

// zarejestruj instancję parsera dla // elementów <bar/> z tej przestrzeni nazw registerBeanDefinitionParser("bar", new BarParser());

}

}

Listing 8. Zawartość pliku META-INF/spring.handlers
http\://www.foo.com/customSchema=foo.BarNamespaceHandler

Listing 9. Zawartość pliku META-INF/spring.schema
http\://www.foo.com/customSchema.xsd=foo/foo.xsd

Listing 10. Kod minimalnego komponentu 'Bar' rozszerzonego o listę swoich potomków
package foo; import java.util.List; public class Bar { private String value;

Klasy implementujące wspomnianego interfejsu służą do analizy pojedynczego elementu XML znajdującego się bezpośrednio między elementami <beans></beans>, wraz z ew. podelementami znajdującymi się wewnątrz naszej definicji. Nasz konkretny element <bar> jest raczej prosty tzn. nie zawiera zagnieżdżonych elementów i zwróci tylko jedną instancję (klasy Bar) do rejestracji w kontrolerze. Ograniczmy się zatem do dziedziczenia z klasy AbstractSingle BeanDefinitionParser – Listing 6. Klasa BeanDefinitionBuilder jest jedną z najważniejszych klas programowej obsługi kontenera Springa. Temat ten zasługuje na co najmniej parę osobnych artykułów, tak więc ograniczę się tylko do podania informacji, że klasa ta służy do programowego tworzenia instancji klasy przeznaczonej do rejestracji w kontenerze. W tym konkretnym przykładzie chcemy, aby nowy obiekt klasy Bar został stworzony za pomocą jednoargumentowego konstruktora.

Zarejestrowanie elementu w NamespaceHandler
Instancje interfejsu org.springframework.bean s.factory.xml.NamespaceHandler służą do łączenia przestrzeni nazw z parserami elementów oraz atrybutów XML. Sam NamespaceHandler nie wykonuje logiki związanej z analizą elementów i atrybutów XML, ponieważ całą logikę związaną z czytaniem dokumentu XML zawarliśmy w poprzednim kroku (w definicji parsera). NamespaceHandler oferuje parę metod pozwalających na interakcję z nim w określonych momentach jego cyklu życia, jakkolwiek na nasze skromne potrzeby zainteresujemy się jedynie bezargumentową metodą init() wywoływaną w momencie inicjalizacji handlera. W powyższym przykładzie (Listing 7) zmapowaliśmy parser napisany w poprzednim kroku do elementu XML <bar>. W miażdżącej większości przypadków jeden handler bę11/2008

private List<Bar> children; public Bar(String value) { } this.value = value;

@Override

public String toString() { } return value;

public void setChildren(List<Bar> children) { } this.children = children;

public List<Bar> getChildren() { } return children;

}

54

Spring 2 Schema

dzie mapował wiele parserów i/lub dekoratorów –nie implementujemy wielu handlerów dla jednej przestrzeni nazw. Jak wspomniałem wcześniej nasze potrzeby względem handlera są bardzo skromne – dlatego właśnie dziedziczymy z klasy org.springframework.
beans.factory.xml.NamespaceHandlerSupp ort.

Listing 11. Przykład użycia zagnieżdżonego komponentu
<myns:bar id="bar" value="parent"> <myns:bar value="child1"> </myns:bar> </myns:bar> <myns:bar value="grandChild" />

Dzięki wspomnianej klasie pomocniczej możemy nadpisać metodę init() interfejsu oraz nie martwić się o logikę związaną z rejestracją parsera. Meta-dane dla Springa Ostatnim krokiem jest dodanie do korzenia ścieżki klas naszej aplikacji lub biblioteki folderu META-INF wraz z plikami spring.handlers oraz spring.schemas – Listing 8 i Listing 9. Jak widać pierwszy z nich mapuje URI przestrzeni nazw na napisany przez nas wcześniej handler – tą metodą Spring wie których parserów powinien użyć dla poszczególnych elementów i atrybutów w określonej przestrzeni nazw. Drugi zaś wskazuje fizyczną lokalizację pliku XSD z definicją naszej przestrzeni – w tym konkretnym przypadku plik z definicją powinien znajdować się w pakiecie foo i nazywać się foo.xsd. Pragę zwrócić uwagę na konieczność poprzedzania znaków dwukropka w obydwu plikach znakiem backslash (ze względu na fakt, że nie tylko znak równości, ale i dwukropek są poprawnymi symbolami końca klucza w plikach właściwości Javy).

<myns:bar value="child2" />

Listing 12. Uaktualniony dokument XML Schema uwzględniający zagnieżdżanie elementów
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://www.foo.com/customSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.foo.com/customSchema"

elementFormDefault="qualified" attributeFormDefault="unqualified"> <xsd:element name="bar"> <xsd:complexType> <xsd:choice minOccurs="0" maxOccurs="unbounded"> </xsd:choice> <xsd:element ref="bar" />

<xsd:attribute name="id" type="xsd:ID" /> </xsd:complexType>

<xsd:attribute name="value" use="required" type="xsd:string" />

</xsd:element> </xsd:schema>

Listing 13. Parser elementu 'bar' uwzględniający rekurencję
package foo; import java.util.List;

import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element;

Zagnieżdżanie elementów – rozszerzony przypadek użycia
Powyższy przykład jest nieco prosty, gdyż zakłada że sparsowany element XMLa zarejestruje tylko jedną instancję określonej klasy w kontrolerze. Jeżeli chcielibyśmy rekurencyjnie parsować i rejestrować zagnieżdżone elementy XML powinniśmy stworzyć parser dziedziczący po czymś potężniejszym niż AbstractSi ngleBeanDefinitionParser – tą klasą jest np. AbstractBeanDefinitionParser. Wyobraźmy sobie, że nasz przypadek użycia rozszerzymy w następujący sposób – otóż nasz potężny komponent Bar został rozszerzony o listę swoich dzieci (dla uproszczenia przykładu również instancji klasy Bar) – Listing 10. Przykładowy scenariusz konfiguracji drzewa komponentów Bar w pliku XML mógłby wyglądać następująco – Listing 11. Powyższa zmiana konfiguracji pociąga za sobą oczywiście konieczność aktualizacji dokumentu XML Schema – Listing 12. Poza schematem XML w stosunku do poprzedniego przykładu zmianie uległby w zasadzie tylko sam parser – Listing 13. Powyższy parser mógłby dziedziczyć po klasie AbstractSingleBeanDefinitionParser i dalej zwracać wynik zgodny z zadanym scenariuszem, jakkolwiek dziedziczenie po Abstrac tBeanDefinitionParser pozwala na jego nieco czytelniejszą implementację.
www.sdjournal.org

import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;

public class BarParser extends AbstractBeanDefinitionParser { protected AbstractBeanDefinition parseInternal(Element element, // Stwórz budowniczego definicji elementu BeanDefinitionBuilder barBuilder = BeanDefinitionBuilder barBuilder.addConstructorArgValue(element.getAttribute("value")); // Wyszukanie dzieci elementu określonego typu List<Element> childElements = DomUtils.getChildElementsByTagName( if (childElements != null) { element, "bar"); .rootBeanDefinition(Bar.class); ParserContext parserContext) {

// Dodanie potomków do listy zarządzanej przez kontener ManagedList children = new ManagedList(childElements.size()); for (Element e : childElements) { // Rekurencja

} } } }

children.add(parseInternal(e, parserContext));

barBuilder.addPropertyValue("children", children);

return barBuilder.getBeanDefinition();

55

XML Własne atrybuty – przypadek użycia
Ostatnim istotnym przypadkiem użycia jest dodanie własnego atrybutu do dowolnego elementu w pliku konfiguracyjnym – Listing 14. Załóżmy, że chcemy aby podczas parsowania elementu oznaczonego atrybutem myns:bar (o dowolnej wartości) na konsoli pojawiała się wartość licznika wskazującego ile elementów oznaczonych identyczną wartością znaleziono dotychczas w kontenerze. Zmiany w implementacji Jak łatwo się domyśleć na pierwszy ogień pójdzie aktualizacja schematu XML – Listing 15. Podobnie jak w przypadku własnych elementów, dla nowego atrybutu również musimy napisać własny parser. Możemy to wygodnie zrobić poprzez implementację interfejsu BeanDefinitionDecorator – Listing 16. Tym razem będziemy również musieli zmodyfikować BarNamespaceHandler. Wynika to z faktu, iż tym razem nie rejestrujemy parsera definicji beana, a tylko tzw. dekorator, czyli mniejszy parser służący do modyfikacji lub wzbogacania wybranego fragmentu definicji. Oczywiście wyświetlanie informacji o tym którą z kolei definicję oznaczoną konkretną wartością parsuje kontener, jest w realnym świecie średnio przydatne, jakkolwiek dostęp do parametrów BeanDefinitionHolder oraz ParserContext daje nam możliwość manipulacji kolejno definicją dekorowanego elementu (możemy również zwrócić całkowicie nową instancję zamiast modyfikować istniejącą) oraz całym rejestrem kontenera. Niestety ze względu na ograniczony rozmiar niniejszego artykułu jestem zmuszony przemilczeć szczegóły dotyczące możliwości programowej manipulacji definicjami beanów oraz zawartością kontenera.

Listing 14. Przykład użycia atrybutu XML z własnej przestrzeni nazw
<bean class="java.lang.String" myns:bar="barValue" > </bean> <constructor-arg value="someValue"/>

Listing 15. Dokument XML Schema dla minimalnego atrybutu
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://www.foo.com/customSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.foo.com/customSchema"

elementFormDefault="qualified" attributeFormDefault="unqualified"> <xsd:attribute name="bar" type="xsd:string" /> </xsd:schema>

Listing 16. Parser minimalnego atrybutu z własnej przestrzeni
package foo; import java.util.HashMap;

import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Attr; import org.w3c.dom.Node; public class BarParser implements BeanDefinitionDecorator { @Override

import org.springframework.beans.factory.xml.BeanDefinitionDecorator;

HashMap<String, Integer> counters = new HashMap<String, Integer>(); public BeanDefinitionHolder decorate(Node node, // odczytaj wartość atrybutu // sprawdź wartość licznika if (i == null) { } i = 0;

BeanDefinitionHolder holder, ParserContext ctx) {

Podsumowanie
W niniejszym artykule poznaliśmy podstawowe sposoby rozszerzania możliwości konfiguracyjnych plików XML w Springu za pomocą własnych przestrzeni nazw. Znając sposoby na analizę elementów XML najwyższego poziomu (wraz z ich ew. zagniżdżeniami) oraz atrybutów XML możemy rozpocząć tworzenie własnych przestrzeni nazw, które przy minimalnej znajomości XML DOM oraz API programowej manipulacji zawartością kontenera IOC Springa pozwolą nam na napisanie w pełni funkcjonalnych mapowań dla naszych komponentów. Tematyka tego artykułu powinna w szczególności zainteresować osoby dostarczające dla innych firm programistycznych gotowe rozwiązania oparte na Springu ze względu na zminimalizowanie wiedzy wymaganej przez klienta do poprawnego stosowania naszych komponentów.

String value = ((Attr) node).getValue(); Integer i = counters.get(value);

// zwiększ licznik counters.put(value, ++i); // wyświetl wynik return holder; System.out.println(value + ": " + i); }

}

Listing 17. Handler mapujący parser do atrybutu 'bar'
package foo; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; public class BarNamespaceHandler extends NamespaceHandlerSupport { @Override

HENRYK KONSEK
Autor pracuje na stanowisku projektanta JEE w warszawskiej firmie Artegence. Udziela się również jako administrator serwisu javablackbelt.com. W wolnym czasie interesuje się swoją Anią oraz m.in. psychiatrią oraz dobrymi technologiami. Kontakt z autorem: http://www.hekonsek.pl lub hekonsek@gmail.com.

public void init() { } }

registerBeanDefinitionDecoratorForAttribute("bar", new BarParser());

56

11/2008

Kasa dla webmastera

LinkLift
Koniec z reklamą kontekstową
Internecie królują systemy reklamy kontekstowej. W oparciu o treść witryny, wyświetlane są odpowiednie reklamy z takich serwisów jak Google AdSense, czy AdKontekst Wirtualnej Polski. Zarobki z takich reklam są jednak stosunkowo niewielkie, stąd istnieje zapotrzebowanie na inne formy reklamy. Gwarantowany zarobek oferuje nowy wchodzący do Polski LinkLift.
Dowiesz się:
• Jak dodatkowo zarobić na reklamie; • Dlaczego era reklamy kontekstowej może się kończyć.

Powinieneś wiedzieć:
• Jak umieścić kod PHP na swojej stronie.

Z kim wchodzimy w interesy Poziom trudności
LinkLift został założony w 2006 roku w Niemczech, zaś swym zasięgiem obejmuje już Francję, Włochy, Hiszpanię i Polskę. Firma zatrudniła także polskich administratorów, dzięki czemu można otrzymać odpowiedź na każde pytanie w ciągu kilku dni. Należy podkreślić, że są to osoby pomocne i cierpliwe – pomogą nawet w instalacji skryptu na własnej platformie.

Z

biegiem czasu formy reklamy w Internecie rozwinęły się. Początkowo dostępne były jedynie reklamy tekstowe lub graficzne, płaciło się zaś za ilość wyświetleń. Następnie prym zaczęły wieść reklamy robione we flashu, a wraz z nimi przyszło płacenie niezależne od ilości wyświetleń, lecz od ilości kliknięć w reklamę. Niektórzy posunęli się jeszcze dalej – korzyści otrzymywało się jedynie, jeśli użytkownik kliknął w reklamę na naszej stronie, a następnie zarejestrował się na witrynie reklamowanej lub kupił z niej jakiś produkt, bądź zamówił usługę (taka forma reklamy jest dostępna także w Google AdSense jako tzw. skierowania). Rezultatem takich praktyk było obniżenie się zarobków webmasterów do tego stopnia, że reklama na witrynie średnio poczytnej zaczęła być dyskusyjna – czy jest ona jeszcze opłacalna. W tej sytuacji odważniejsze serwisy wyszły naprzeciw wymaganiom twórców stron i wprowadziły reklamy płatne za czas wyświetlania, nie zaś za ilośc odsłon lub kliknięć. Pionierskim serwisem tego typu w Polsce jest LinkLift.
58

Wycena linku
LinkLift oferuje jedynie odnośniki tekstowe, podobnie jak do niedawna Google AdSense. Zarejestrować w serwisie możemy się przez stronę http://www.linklift.pl/ ?ref=a1267774449. Następnie, jeśli chcemy oferować przestrzeń reklamową na naszej stronie, zgłaszamy ją do serwisu. W ciągu tygodnia (zazwyczaj dużo krócej) zostanie ona zweryfikowana przez administratorów i podana zostanie wycena jednego linku tekstowego. LinkLift oferuje umieszczenie do dziesięciu linków tekstowych na jednej stronie, przy czym możemy określić, w której części strony będą one wyświetlane – w nawigacji, części głównej strony, lub stopce. Określamy także kategorię strony i, czy reklamy będą widoczne na pojedynczej stronie, czy także na wszystkich jej podstronach. W zależności od tych ustawień, możemy oszacować wycenę jednego linku (Rysunek 1). Pomoże w tym poręczny kalkulator na witrynie LinkLiftu. Jeśli po akceptacji

strony i wyceny będziemy chcieli zmienić te dane, będzie to możliwe (ręczna zmiana wyceny jest właśnie wdrażana, lecz można o nią poprosić administratora). Sam algorytm wyceny uwzględnia takie czynniki, jak tematyka strony, pozycja linków na stronie, liczba sprzedanych linków, liczba linków zewnętrznych, wiek strony, ilość linków zwrotnych i sąsiedztwo oraz przynależność do określonej branży. Osoba chcąca umieścić swoją reklamę, będzie mogła przeglądać dostępne przestrzenie reklamowe, wraz ze statystykami strony m.in. w Yahoo, DMOZ i Alexa Rank. Podane są także Page Rank strony oraz Page Rank i ilość stron linkujących do danej, także bardzo szczegółowe statystyki, które powodują, że znajomość dokładnego adresu nie jest potrzebna (jeśli zezwolimy, będzie on widoczny).

Instalacja skryptu
Serwis współpracuje ze stronami stworzonymi w PHP, Perlu, WordPressie, Joomli, Dru-

Rysunek 1. Kalkulator pomagający oszacować wartość jednego linka

11/2008

LinkLift – pewny zarobek na reklamie

palu, Xoops, Serendipity oraz Joggerze. Ten ostatni jest polskim systemem blogowania, który został dodany ekskluzywnie na potrzeby polskich bloggerów – widać więc, że firma rozwija się prężnie i nie pozostaje obojętna na potrzeby rynku. Wybierając którąś z powyższych opcji, szybko skonfigurujemy nasz skrypt, który wystarczy wkleić do szablonu naszej strony. Nadszedł czas na główną zaletę LinkLiftu – brak inwazyjności. Niby Google AdSense oferuje także linki tekstowe, jednak według swojego szablonu, którego nie można zmieniać, co często jest bardzo irytujące. Reklama wyświetlana przez linklift ma przykładową strukturę:
<a href=”http://blog.eldoras.com” rel=”nofollow”>Blog autora</a>

Pierwsi klienci
Dopóki pierwszy klient nie zamówi u nas reklamy, będzie wyświetlana domyślna (darmowa). Dla strony o Page Rank 0 (czyli nowej w Internecie) cena wyjściowa to około 4zł - 7zł za jednego linka tekstowego. Jeśli ktoś zdecyduje się wykorzystać naszą przestrzeń reklamową, zostaniemy poinformowani o tym mailem. W ciągu 24 godzin możemy zaakceptować lub odrzucić propozycję reklamy z oferowaną przez zleceniodawcę wyceną. Po tym czasie link jest automatycznie akceptowany na okres 30 dni. Ceny podawane na witrynie są cenami netto (z racji oferowanych usług w różnych krajach o różnych stawkach podatkowych) – w Polsce otrzymujemy 70% wartości podanej na witrynie. Wszystkie płatności w serwisie są realizowane przez PayPal, który jest w pełni dostępny w Polsce. Minimalna kwota do wypłaty to 60zł.

• 25 zł plus bonus promocyjny w wysokości 5 zł za Advertiser Lead ; • 25 zł plus bonus promocyjny w wysokości 5 zł za Publisher Lead . Należność za Advertiser Lead przysługuje, gdy reklamodawca (ang. advertiser) zamówi linki tekstowe o wartości minimum 120 zł. Należność za Publisher Lead przysługuje, gdy skierowany reklamobiorca (ang. publisher) udostępni swoją stronę w serwisie przez minimum miesiąc (bez przerw).

Reklamujemy naszą stronę
Oczywiście, możemy także wykupić przestrzeń reklamową u innych użytkowników systemu. Po wpłaceniu pierwszych pieniędzy na konto przez PayPal, otrzymujemy dodatkowe 60zł na kupno przestrzeni reklamowych.

I tyle! Żadnych dodatkowych znaczników, całość możemy dowolnie modyfikować pod kątem wyglądu i rozmieszczenia. Pełna swoboda. Na Rysunku 2 widać reklamy LinkLiftu (czerwona obwódka) i Google AdSense (zielona obwódka) w akcji – jedna linijka LinkLiftu zawiera 4 reklamy, które idealnie komponują się ze stroną, podczas gdy Google AdSense jest wyraźnie bardziej inwazyjne. Należy podkreślić, iż LinkLift nie jest reklamą kontekstową, więc może występować równolegle z reklamami Google AdSense. Reklamy LinkLiftu mają w swoim kodzie rel=”nofollow”, dzięki czemu nie są przez wyszukiwarki traktowane jak linki wychodzące, które obniżają nasz Page Rank – zapobiega to wykorzystaniu systemu przez reklamodawców do podwyższenia swoich pozycji w wyszukiwarkach przez zwiększenie ilości stron do nich linkujących.

Program partnerski
Jak każdy porządny system reklamowy (poza Google AdSense), tak też LinkLift oferuje Program Partnerski. Do wyboru mamy całą gamę linków graficznych i tekstowych, które możemy umieścić na naszej witrynie. Wynagrodzenie można otrzymać za: • polecenie naszej strony użytkownikowi, który zarejestruje się jako reklamodawca i dokona zakupu linku tekstowego ("Advertiser Lead") lub ; • polecenie strony użytkownikowi, który zarejestruje się i zostanie zaakceptowany jako reklamobiorca ("Publisher Lead"). Partner otrzymuje wynagrodzenie w wysokości:

Podsumowanie
Z usług LinkLiftu często korzystają użytkownicy blogosfery, czyli autorzy witryn o Page Rank 3 – 6. Osoby te mnóstwo czasu spędzają w Internecie i są świetnie obeznane w systemach reklamowych. LinkLift zdobył ich zaufanie i sprawdza się bardzo dobrze, dlatego polecamy go wszystkim, którym nie odpowiadają dotychczasowe formy reklamy. Zasady są proste – płacimy za reklamę na miesiąc i przez miesiąc ona widnieje na danej stronie. Prostota to kolejny plus LinkLiftu.

Rysunek 3. Estetyczna strona porządnego systemu LinkLift

KRZYSZTOF TRYNKIEWICZ
Krzysztof Trynkiewicz studiuje Informatykę na Uniwersytecie Jagiellońskim. Od wielu lat zajmuje się tworzeniem witryn w technologii PHP i Flash oraz publicystyką. Obecnie rozwija kilka równoległych projektów autorskich dostępnych na witrynie http://blog.eldoras.com Kontakt z autorem: chris.trynkiewicz@gmail.com

Rysunek 2. Porównanie reklam Google AdSense i LinkLiftu

www.sdjournal.org

59

Narzędzia programistyczne

Plugin
Wielokrotne wykorzystanie sprawdzonych narzędzi
Tworzenie aplikacji, składa się zarówno z tych bardziej twórczych, jak i bardziej odtwórczych prac. Mimo wszelkich naszych starań tworzenia wedle zasady DRY (z ang. DRY – Don't Repeat Yourself), ile razy zdarza się, że dla tej samej funkcjonalności powielamy i dostosowujemy ten sam kod w różnych elementach aplikacji lub pomiędzy różnymi aplikacjami.
Dowiesz się:
• Efektywnie wykorzystywać pluginy w swojej pracy; • Stworzyć własny plugin; • Wykorzystywać istniejące pluginy to szybkiego tworzenia aplikacji.

Powinieneś wiedzieć:
• Jak stworzyć projekt w symfony; • Posiadać doświadczenie w tworzeniu aplikacji; • Posiadać doświadczenie w obiektowym PHP.

lub w wersji 1.1:
<cd mojprojekt

<symfony plugin:install nazwapluginu

Dokładną informację, jak należy zainstalować potrzebny plugin do określonej wersji Symfony, możemy podejrzeć na stronie pluginu, w zakładce Installation.

Poziom trudności

N

a początek zaprezentuję najczęściej wykorzystywane pluginy w Symfony, których jest w chwili pisania artykułu ponad 200. Następnie stworzymy prosty dodatek do wysyłania maila (ang. plugin) w symfony, bez dodatkowego nakładu naszej pracy.

Pluginy w Symfony
W Symfony jeden z największych walorów możemy odnaleźć w liczbie i różnorodności pluginów. Obecnie z ponad 200 pluginów możemy np. szybko stworzyć prosty CMS, Blog czy Forum, podłączyć do naszej aplikacji bezpieczny mechanizm autoryzacji i autentyfikacji sfGuardPlugin, czy łatwo podczepić AJAXowe biblioteki. Wszystkie z nich tworzone są bezpłatnie przez społeczność Symfony i znajdziemy je na stronie: http://www.symfony-project.org/plugins/ Każdy plugin posiada dostępny kod źródłowy, który budowany jest zgodnie z przyjętą w Symfony strukturą, dzięki czemu łatwo się nam w nim odnaleźć. Wśród dostępnych pluginów można między innymi znaleźć: • sfSimpleCMSPlugin – prosty CMS do zarządzania treścią i strukturą strony; • sfGuardPlugin – autoryzacja i zarządzanie użytkownikami oraz uprawnieniami;
60

• sfThumbnailPlugin – tworzenie miniaturek zdjęć; • sfControlPanelPlugin – interfejs do zarządzania Symfony z poziomu przeglądarki; • sfLightboxPlugin – łatwe wykorzystywanie skryptu AJAX-owego Lightbox2; • sfSslRequirementPlugin – wprowadzenie kodowania SSL dla akcji; • sfPropelActAsNestedSetBehaviorPlugin – wdrożenie algorytmu nested set zintegrowanego z obiektami Propela; • sfPokaYoke – walidacja formularzy po stronie klienta. Zmiany warto śledzić na bieżąco, gdyż pluginy cały czas są tworzone i rozwijane. Przy korzystaniu z projektów, warto jest zainteresować się licencją, zgodnie z którą jest wydawany plugin. Licencję pluginu można znaleźć na stronie pluginu na http://symfony-project.com oraz w głównym katalogu pluginu, w pliku LICENSE. Zdecydowana większość z nich jest wydawana na licencji MIT, tak jak i samo symfony, w związku z czym bez przeszkód możemy je wykorzystywać również w celach komercyjnych.

Rozpoczęcie pracy
Do rozpoczęcia pracy potrzebujemy oczywiście utworzonego projektu Symfony. Poszczególne kroki tworzenia projektu dokładnie przedstawiliśmy na początku prezentacji multimedialnej. Jak stworzyć plugin, zaprezentowaliśmy na płycie dołączonej do Software Developer’s Journal 7/2008. W związku z tym, że sam plugin był tworzony ponad pół roku temu, niektóre wykorzystane w nim techniki są już wycofywane. Aby nasz plugin był zgodny z symfony 1.0 należy włączyć parametr compat_10 w pliku konfiguracyjnym config/settings.yml naszej aplikacji. Jest tam również kod źródłowy pluginu. Poniżej omówimy zawartość płyty oraz pokażemy, w jaki sposób można ją rozbudowywać.

Struktura pluginu
Sporym ułatwieniem jest, zorganizowanie struktury katalogów i plików pluginu, w bardzo podobny sposób co struktura naszej aplikacji. Dzięki temu bez problemu możemy odnaleźć się w jego zawartości. Łatwo jest również przenieść istniejącego moduł w naszej aplikacji, aby funkcjonował jako osobny moduł. Struktura plików przedstawiona została na Listingu 1. Pamiętaj – aby po każdej zmianie struktury pluginu zalecane jest czyszczenie cache projektu komendą symfony cc. Postaramy się przedstawić najważniejsze elementy struktury i podać przykłady informacji, jakie można w nich zawrzeć.
11/2008

Instalacja pluginu
Najczęściej pluginy wymienione na Symfony Plugins zostały przygotowane jako paczki PEAR, dlatego możemy je zainstalować, podając w Symfony 1.0 polecenie:
<cd mojprojekt

<symfony plugin-install nazwapluginu

Plugin

Moduły
Moduły umieszczamy w katalogu modules/. Nasz prezentacyjny plugin posiada moduł (ang. Modules) sfMailForm. W zależności od potrzeby, każdy moduł może zawierać cztery katalogi: • actions – definiujący dostępne akcje dla modułu; • config – określający specyficzną konfigurację samego modułu; • templates – widoki dla modułów zwracane po wywołaniu akcji; • validate – formularze sprawdzania wprowadzanych danych przez formularze. W praktyce przyjęło się tworzenie dodatkowego katalogu lib/ zawierającego klasę z wszystkimi , akcjami (Listing 1). W pliku actions.class.php pozostawia się jedynie rozszerzenie do klasy z katalogu lib/ (Listing 2). Takie rozwiązanie zostało zastosowane w przykładowym pluginie.

Zadania do uruchomienia z linii komend
Nowe zadania (ang. Tasks) tworzone w pluginie zawieramy w katalogu data/tasks/. Każde zadanie umieszczamy w oddzielnym pliku, który powinien zawierać wywołanie funkcji pake_desc oraz pake_task, a także funkcję
Listing 1. Struktura plików pluginu
nazwaPluginu/ config/ *schema.yml config.php

wywołującą zadanie (zainteresowanych odsyłam do Listingu 4).

Tworzenienie pluginu jako paczki PEAR
Aby nasz plugin można było instalować za pomocą komendy symfony plugin:install musi on

# plik ze schematem bazy danych # specyficzna konfiguracja dla pluginu

data/

generator/

sfPropelAdmin/ template/ skeleton/

nazwaSzablonu/

#

skórka dla admin generatora

fixtures/ lib/ *.yml

Konfiguracja pluginu
Konfigurację dla pluginu definiujemy config/ w katalogu pluginu. Może ona składać się z dwóch elementów: • konfiguracji dla naszego pluginu – plik config.php; • struktury bazy danych – plik schema.xml lub schema.yml. W pliku konfiguracyjnym config.php możemy elastycznie odwoływać się do konfiguracji naszej aplikacji i dowolnie dopisywać lub modyfikować wprowadzone wartości. Przykładowo możemy stworzyć przyjaźniejszy adres wysyłania formularza na /wyslij zamiast / sfmailForm/submit (przykład na Listingu 2). W pliku definicji struktury bazy danych (plik schema.yml lub schema.xml) tworzymy konfigurację – podobnie jak w całym projekcie. Wyjątkiem jest zawarcie w pliku informacji o pakiecie (przykład na Listingu 3). Stworzona schema będzie bez problemu wykrywana przez wywoływanie komendy z prefiksem propel. Na Listingu 3 znajduje się przykład pliku schema.yml, zawierający tabelę sfMailform_ archive, która będzie zapisywać dane wprowadzone w naszym przykładowym formularzu. Po skonfigurowaniu pliku czeka nas jeszcze tylko dobre skonfigurowanie pliku databases.yml w naszym projekcie oraz budowa modelu Propela, SQL-a i stworzenie struktury w bazie danych (np. za jednym zamachem komendą symfony propel-build-all).

# testowe informacji do bazy danych # miejsce na nasze klasy # pomocniki # model danych, generowany z propela # zadania do uruchomienia w pasku komend # nazwa tworzonego modułu

*.php

helper/ model/ task/ *.php *.php Task.class.php

modules/

nazwaModulu/ actions/ config/

module.yml view.yml security.yml *.php

templates:

validate: *.yml

Listing 2. Przykład wykorzystania konfiguracji w pliku config.php
$r = sfRouting::getInstance(); // pobranie instancji odpowiedzialnej za przekierowania

$r->prependRoute('submit', '/wyslij', array( 'module' => 'sfMailForm', 'action' => 'submit') // dopisanie czytelniejszego adresu // z /sfMailForm/submit na /wyslij

);

Listing 3. Przykładowa schema.yml z encją gromadzącą informacje z wprowadzonych danych z formularzy
propel: _attributes: { package: plugins.sfMailFormPlugin.lib.model } klas pluginu)

Dane do testów (fixtures)
Dane do testów umieszczamy w plugine w katalogu data/fixtures/. Wywoływanie ładowania danych wykonujemy komendą symfony propel-load-data. Zawieramy tutaj dane, które chcielibyśmy umieścić w bazie danych, tak aby nasz plugin działał poprawnie.
www.sdjournal.org
sfMailForm_archive: id: attributes:

# deklaracja informacji o pakiecie (miejscu zapisu

{ phpName: pluginMailForm } { type: longvarchar }

content:

created_at:

61

Narzędzia programistyczne
mieć zdefiniowany w głównym katalogu plik package.xml. Plik ten zawiera w odpowiednio przygotowanym formacie XML-owym wszystkie potrzebne informacje o pluginie. Opiszę wszystkie możliwe do zastosowania znaczniki wraz z przykładowymi wartościami dla naszego pakietu. • •
<name>: imię i nazwisko; <user>:

instance"

//pear.php.net/dtd/tasks-1.0

xsi:schemaLocation="http: http:// http:

pear.php.net/dtd/tasks-1.0.xsd //pear.php.net/dtd/package-2.0

pear.php.net/dtd/package-2.0.xsd">.

http://

Z ele-

mentów poniżej mamy: • •
<name>:

Możliwe znaczniki
Główny znacznik w pliku package.xml zawiera <?xml version="1.0" encoding="UTF-8"?>, a pod nim mamy informację o pakiecie:
<package version="2.0" xmlns="http://pear.php.net/ dtd/package-2.0" //pear.php.net/dtd/tasks-1.0" packagerversion="1.4.1" xmlns:tasks="http:

xsi="http://www.w3.org/2001/XMLSchema-

xmlns:

• • •

nazwa pluginu; w naszym przypadku: sfMailFormPlugin; <channel>: informacja na jakim serwerze znajduje się paczka (w przypadku paczek dostępnych na symfony-project.org, będzie to: plugins.symfony-project.org); <summary>: krótki opis o samym pluginie; <description>: dłuższy opis; <lead>: informacja o liderze projektu:

• • • •

Listing 4. Przykładowa budowa zadania mailform-raport
<?php /** * Raport o statystykach wypełniania formularza *//

* plik: /plugins/sfMailFormPlugin/data/tasks/sfMailFormRaport.php pake_desc('raport o statystykach do administratora – przeslanie na adres e-mail'); pake_task('mailform-report', 'project_exists'); pake_alias('mailreport', 'mailform-report'); /** // możliwość używania skrótu „mailreport”

• •

* Funkcja wywoływana przy uruchomieniu zadania * @param pakeTask $task * @param Array $args */ function run_mailform-report($task, $args) { if (!count($args)) { } throw new Exception('Podaj proszę adres e-mail, na który ma przyjść raport');

// ... // .. }

$emial = $args[0];

// miejsce na kod wyciągający dane z bazy i wysyłający mail z raportem

nazwa użytkownika (w przypadku gdy jest to projekt na symfonyproject.org, będzie to login do zarządzania projektami); • <email>: poprawny adres e-mail lidera; • <active>: informacja czy osoba nadal pracuje nad tym projektem (wartości: yes lub no); <date>: data ostatniej poprawki w paczce (np.: 2008-12-31); <time>: czas ostatniej poprawki w paczce (np.: 23:59:00); <version>: informacje o wydanej wersji: • <release> i <api>: numer wydania; <stability>: informacja o stabilności wydania; • <release> i <api>: słowna informacja o stabilności (np. stable, beta, alpha); <license uri=”xxx”>: informacja o nazwie licencji wraz z odesłaniem do strony z jej treścią podawaną w atrybucie uri; <notes>: miejsce na dodatkowe komentarze; <contents>: lista zamieszczonych plików: • <dir name=”xxx”>: nazwa katalogu podawana w atrybucie name; • <file role=”data” name=”xxx”>: nazwa pliku (atrybut name); • <dependencies>: zależności występujące przy naszej paczce: • <php>: zależność od wersji PHP (np. ze znacznikiem <min>5.2.0</ min>, umożlwi instalację, gdy na ser werze znajdować będzie się wersja 5.2.0 lub wyższa); • <pearinstaller>: zależność od wersji PEAR; • <package>: zależność od innych paczek symfony: • <name>: nazwa paczki; • <channel>: informacja o ser werze, na którym paczka się znajduje; • <min>: minimalna wersja paczki; • <max>: maksymalna wersja paczki;

PIOTR PLENIK, FIRMA TEAMLAB
Współzałożyciel firmy TeamLab.pl, specjalizującej się w wytwarzaniu oprogramowania klasy enterprise. Zawodowo zajmujący się tworzeniem oraz rozwojem aplikacji dla biznesu, typu CMS i CRM. W wolnym czasie redaktor serwisu www.symfony.pl. W PHP programuje 2000 r., w frameworku symfony od 2006 r.. Administrator portalu dla Organizacji Pozarządowych – www.ngo.pl. Absolwent ostatniego roku Polsko-Japońskiej Wyższej Szkoły Technik Komputerowych. Interesuje się zarządzaniem projektami biznesowymi oraz open source, programowanie (PHP, ASP.NET, Java) oraz bazy danych (MS SQL, PostgreSQL, MySQL). Kontakt z autorem: piotr.plenik@teamlab.pl, strona http://www.teamlab.pl

Rysunek 1. Schemat utworzonej bazy danych

62

11/2008

Plugin

Poprawnie stworzony plugin zawsze powinien mieć plik LICENSE, opisujący warunki jego używania. Zalecane jest również dodanie pliku README zawierającego np. historię zmian, działanie pluginu, jak instalować, itd.

Podsumowanie
Wiele rozszerzeń dla symfony już powstało – są gotowymi pluginami, łatwymi do instalacji, aktualizacji czy odinstalowania z naszej aplikacji. Tworzenie nowych pluginów o do-

wolnej funkcjonalności jest równie proste jak tworzenie nowych bibliotek PEAR i umożliwiających ponowne wykorzystywanie pomiędzy różnymi aplikacjami.

Listing 5. Przykład zawartości paczki package.xml dla pluginu w symfony
<?xml version="1.0" encoding="UTF-8"?> </dir>

<package packagerversion="1.4.6" version="2.0" xmlns="http:

//pear.php.net/dtd/package-2.0" xmlns: tasks="http://pear.php.net/dtd/tasks1.0" xmlns:xsi="http://www.w3.org/ 2001/XMLSchema-instance" xsi:

<dir name="task"> <!-- tasks --> <file role="data" name="sfSampleTask.class.php" />

</dir>

schemaLocation="http://pear.php.net/

<dir name="validator"> <!-- validators --> php" /> <file role="data" name="sfSampleValidator.class. </dir>

dtd/tasks-1.0 http://pear.php.net/dtd/ tasks-1.0.xsd http://pear.php.net/dtd/ package-2.0 http://pear.php.net/dtd/ <name>sfPrzykladowyPlugin</name> package-2.0.xsd">

</dir>

<channel>plugins.symfony.pl</channel>

<dir name="modules">

<summary>przykładowy plugin w symfony</summary>

<dir name="sfSampleModule">

<description>To jest przykładowy plugin w symfony, w celu pokazania zawartosci package.xml</ description>

<file role="data" name="actions/ <file role="data" name="config/security.yml" /> tions.class.php" /> actions.class.php" />

<lead>

<file role="data" name="lib/BasesfSampleModuleAc <file role="data" name="templates/ </dir> indexSuccess.php" />

<name>Piotr PLENIK</name> <user>jupeter</user> <active>yes</active> <email>piotr.plenik@teamlab.pl</email>

</lead>

</dir>

<date>2008-01-01</date> <time>12:53:01</time> <version>

<dir name="web">

<dir name="css">

<!-- stylesheets --> <file role="data" name="sfSampleStyle.css" />

<release>1.0.0</release> <api>1.0.0</api>

</dir>

</version>

<dir name="images"> <!-- images --> <file role="data" name="sfSampleImage.png" />

<stability>

<release>beta</release> <api>beta</api>

</stability>

<license uri="http://www.symfony-project.org/license">MIT <notes>-</notes> <contents> <dir name="/"> license</license>

</contents>

</dir>

</dir>

</dir>

<dependencies> <required> <php>

<file role="data" name="README" /> <dir name="config"> <!-- model -->

<file role="data" name="LICENSE" />

</php>

<min>5.2.0</min>

<pearinstaller>

</dir>

<file role="data" name="schema.yml" />

</pearinstaller> <package>

<min>1.4.1</min>

<dir name="data">

<name>sfGuardPlugin</name> <min>1.1.13</min> <max>1.1.15</max>

<dir name="fixtures"> <!-- fixtures --> <file role="data" name="fixtures.yml" />

<channel>pear.symfony-project.com</channel>

</dir>

</dir>

<dir name="lib">

<dir name="model">

</dependencies> <phprelease /> </package> <changelog />

</required>

</package>

<exclude>1.1.14</exclude>

<!-- model classes --> <file role="data" name="sfSampleClass1.php" /> <file role="data" name="sfSampleClass2.php" />

www.sdjournal.org

63

Programowanie urządzeń mobilnych

Programowanie gier dla Symbian OS
Budujemy grę!
W poprzednim artykule Czytelnicy mieli okazję przebrnąć przez gąszcz stosunkowo zawiłych szczegółów dotyczących programowania aplikacji pod Symbian OS. W rezultacie powstał prosty szkielet gry. W niniejszej części cyklu zajmiemy się tematem znacznie ciekawszym – odejdziemy (chwilowo) od niskopoziomowych zagadnień systemowych i zrobimy to co Tygrysy lubią najbardziej – zbudujemy grę!
Dowiesz się:
• Jak zaprojektować architekturę prostej gry i jak zaimplementować ją pod system operacyjny Symbian; • Jak zaprojektować i zaimplementować silnik gry oparty na przyrostach czasu; • Jak oprogramować menu gry.

Powinieneś wiedzieć:
• Jak się programuje w języku C++; • Co to jest pętla gry; • Jak działa szkielet aplikacji opisany w poprzedniej odsłonie cyklu.

Poziom trudności

J

est to bardzo trafne pytanie, które powinna zadać sobie każda osoba planująca stworzyć grę komputerową. Zakładam, że wielu z czytelników SDJ-ta, będących z przyczyn oczywistych programistami, odpowiedziałaby: nie ma na co czekać, bierzemy się za kodowanie!. Takie podejście jest właśnie przyczyną upadku wielu przedsięwzięć związanych z produkcją gier. Otóż to od czego zawsze powinno zaczynać się tworzenie gry, to opracowanie jej koncepcji. Ponieważ temat projektowania gier (ang. game design), chociaż bardzo ciekawy, nie pokrywa się z tematem niniejszego artykułu – pójdziemy na łatwiznę i zaczerpniemy pomysł na naszą aplikację z klasyki polskiej myśli kreatywnej w dziedzinie komputerowej rozrywki. Opisywana w niniejszym artykule gra – LaserQuest – bazuje na koncepcji logicznej gry pt. Lasermania, wydanej pierwotnie na ośmiobitowe Atari przez Laboratorium Komputerowe Avalon. LaserQuest imple64

mentuje podstawowy podzbiór funkcjonalności oryginalnej Lasermanii – szczegółowy opis koncepcji gry, do którego lektury gorąco namawiam przed przejściem do kolejnej części artykułu, znajduje się w ramce zatytułowanej LaserQuest: skrócony podręcznik użytkownika.

Gotowi...? Zaczynamy!
Punktem wyjścia do naszych rozważań będzie szkielet aplikacji opracowany w poprzedniej odsłonie niniejszego cyklu. Dla porządku przypomnę, że szkielet ten oferuje nam:
• • •

implementację pętli gry; obsługę zdarzeń klawiatury; podstawową obsługę przerwań (utrata i uzyskanie focusa).

Pierwszym zadaniem – być może niespecjalnie twórczym, aczkolwiek niezbędnym – jest dostosowanie istniejącego szkieletu do wymogów naszego projektu. Wbrew pozorom – zmienia się wiele rzeczy – nazwa aplikacji, UI, identyfikator zasobów, autor itd. Oczywiście można pokusić się o ręczne przerabianie kodu, ale podejście takie jawnie gwałci zasadę DRY (ang. Don't Repeat

Yourself). Czytelników niezaznajomionych z tą zasadą zapraszam do lektury wspaniałej książki pt. Pragmatyczny Programista autorstwa Andrew Hunta i Davida Thomasa. Tym, którzy mimo wszystko zdecydują się podjąć tę żmudną pracę, gwarantuję wiele niezapomnianych emocji związanych z próbami uruchomienia programu. Tych, którzy wolą bardziej pragmatyczne podejście namawiam na zautomatyzowanie tego procesu. Ja do wygenerowania szkieletu projektu LaserQuest wykorzystałem proste narzędzie o nazwie Template-2-Text (w skrócie t2t). T2t to prosty silnik renderowania tekstu na bazie zadanych szablonów. To co wyróżnia to narzędzie od całego zestawu innych, podobnych rozwiązań, to możliwość generowania całego drzewa katalogów na bazie drzewa szablonowego, możliwość wykorzystania zmiennych szablonowych w nazwach plików oraz automatyczny mechanizm wykrywania tych zmiennych w celu pobrania ich od użytkownika. Aby dostosować nasz szkielet aplikacji do wymagań t2t, skopiowałem go do oddzielnego katalogu i zmodyfikowałem nazwy i zawartości plików. Rozważamy plik GameSkeletonApplication.cpp (Listing 1). W nowej odsłonie plik ten będzie miał nazwę [%PROJECT-NAME%]Application.cpp. Jak się można łatwo domyśleć, tag o strukturze '[%NAZWA%]' oznacza zmienną, która przy generowaniu tekstu na bazie zadanego szablonu zostanie podmieniona na konkretną wartość. Zawartość szablonu [%PROJECT-NAME%]Application.cpp przedstawiona jest na Listingu 2. Analizując plik szablonu można zauważyć takie zmienne jak – [%PROJECT-NAME%]
11/2008

Programowanie gier dla Symbian OS

(nazwa

projektu), [%AUTHOR%] (autor), (kontaktowy adres email autora) oraz [%UID%] (unikalny identyfikator aplikacji). W podobny sposób przekształcone zostały pozostałe pliki projektu GameSkeleton. Narzędzie t2t oraz szablon szkieletu gry są dostępne do pobrania z witryny SDJ. Po skonfigurowaniu narzędzia (patrz Ramka Konfiguracja narzędzia t2t) wystarczy wywołać komendę:
[%EMAIL%] t2t -d GameSkeletonS60 LaserQuest

należy ustawić dodatkowo opcję Self sign sis file. Osoby zainteresowane szczegółami podpisywania aplikacji zapraszam do Ramki Jak podpisać aplikację dla Symbian OS?. Po takich zabiegach konfiguracyjnych wystarczy wybrać opcję Build Project i spokojnie czekać aż w podkatalogu sis projektu pojawi się podpisana paczka instalacyjna LaserQu-

est.sisx. Kwestia przetransportowania paczki z grą na telefon jest mocno zależna od posiadanego systemu. W większości przypadków wykorzystuje się w tym celu sieć Bluetooth – należy przy tym pamiętać o włączeniu odbiornika Bluetooth w telefonie i ustawianiu jego widoczności dla innych urządzeń (między innymi dla komputera z którego będzie-

Listing 1. Zawartość pliku GameSkeletonApplication.cpp
// // // // // // // #include "GameSkeletonApplication.h" #include "GameSkeletonDocument.h" AUTHOR(S): Rafal Kocisz <rafal.kocisz@gmail.com> FILE NAME: GameSkeletonApplication.cpp

W dalszej kolejności narzędzie poprosi o wartości kolejnych zmiennych – UID, AUTHOR , RESOURCE-ID, VENDOR , EMAIL oraz PROJECTNAME po czym wygeneruje w bieżącym katalogu podkatalog LaserQuest z odpowiednią zawartością. Bardziej dociekliwi Czytelnicy mogą w tej chwil zadać pytanie – skąd mam wziąć UID aplikacji? Dla nich właśnie przygotowałem specjalną Ramkę o tytule podobnym do przedstawionego wyżej pytania.

const TUid KUidGameSkeletonApp = { 0xA000958F }; CApaDocument* CGameSkeletonApplication::CreateDocumentL() { return ( static_cast< CApaDocument* >( }

LaserQuest – pierwsze wyjście z mroku
Tytuł niniejszego podpunktu brzmi nieco tajemniczo, czy wręcz złowieszczo. Skąd taka nazwa? Sprawa jest prosta. W punkcie tym opiszemy sposób uruchomienia nowo wygenerowanej aplikacji na telefonie. Dlaczego już teraz? Otóż – na nieszczęście programistów – program działający idealnie pod emulatorem urządzenia, na realnym sprzęcie ma szansę działać zupełnie niepoprawnie. Wynika to z istnienia szeregu subtelnych różnic pomiędzy tymi dwoma środowiskami. Zasada jest prosta – im dłużej będziemy odwlekać uruchomienie aplikacji na telefonie, tym większe jest prawdopodobieństwo wystąpienia takich błędów i tym większe będą koszty ich znalezienia. Aby uruchomić naszą grę na urządzeniu musimy wykonać następujące kroki – zbudować binarną wersję aplikację przeznaczoną do uruchomienia na telefonie, wygenerować instalator i podpisać go oraz przetransportować powstałą paczkę instalacyjną na telefon. Pierwsze dwa kroki można zautomatyzować przy pomocy środowiska Carbide. W tym celu należy przestawić aktualną konfigurację na Phone Release (GCCE) a następnie kliknąć prawym przyciskiem na nazwie projektu w panelu Project Explorer i wybrać zakładkę Carbide.c++ -> Carbide Build Configurations -> SIS Builder (Rysunek 1). Po wciśnięciu przycisku Add możemy skonfigurować sposób budowania aplikacji (Rysunek 2). Kluczową rolę odgrywa tutaj plik LaserQuest.pkg (można go znaleźć w podkatalogu sis projektu) opisujący dokładnie sposób generowania paczki instalacyjnej. Do zawartości tego pliku wrócimy w kolejnych podpunktach. Oprócz wpisania nazw generowanych plików
www.sdjournal.org

CGameSkeletonDocument::NewL( *this ) ) );

TUid CGameSkeletonApplication::AppDllUid() const { } return KUidGameSkeletonApp;

// Eof

Listing 2. Zawartość szablonu [%PROJECT-NAME%]Application.cpp
// // // // // // // #include "[%PROJECT-NAME%]Application.h" #include "[%PROJECT-NAME%]Document.h" AUTHOR(S): [%AUTHOR%] <[%EMAIL%]> FILE NAME: [%PROJECT-NAME%]Application.cpp

const TUid KUid[%PROJECT-NAME%]App = { [%UID%] }; CApaDocument* C[%PROJECT-NAME%]Application::CreateDocumentL() { return ( static_cast< CApaDocument* >(

}

C[%PROJECT-NAME%]Document::NewL( *this ) ) );

TUid C[%PROJECT-NAME%]Application::AppDllUid() const { } return KUid[%PROJECT-NAME%]App;

// Eof

65

Programowanie urządzeń mobilnych
my wysyłać paczkę). Paczka instalacyjna pojawia się jako nowa wiadomość w skrzynce odbiorczej. Po jej otwarciu automatycznie rozpoczyna się proces instalacji. Po jego pomyślnym zakończeniu pozostaje jedynie uruchomić aplikację. W naszym przypadku otrzymujemy znajomy z poprzedniej części cyklu czarny ekran z mrugającym przyjaźnie licznikiem FPS. Kolejny etap naszych zmagań zakończył się sukcesem!

Listing 3. Definicja klasy CLaserQuestGame
class CLaserQuestGame : public CBase public: {

enum TMode { EMenu, EPlay }; static CLaserQuestGame* NewL( CLaserQuestGame(

const TLaserQuestKeyState& aKeyState ); const TLaserQuestKeyState& aKeyState );

~CLaserQuestGame();

Architektura gry
Dobrneliśmy wreszcie do momentu kiedy można zacząć myśleć o tym, co nas najbardziej interesuje – mowa tu oczywiście o implementacji zawartości gry. Zanim przejdziemy do kodowania, wypada zastanowić się nad architekturą naszego rozwiązania. Rozwiązanie, które zdecydowałem się zastosować w przypadku projektu LaserQuest, to drzewiasta hierarchia obiektów reprezentujących poszczególne składniki gry. W hierarchii tej wyróżniać będziemy kilka poziomów. Na szczycie hierarchii umieszczony zostanie obiekt reprezentujący grę jako całość – w naszym przypadku obiekt ten będzie reprezentowany przez klasę CLaserQuestGame. Obiekt ten będzie odpowiedzialny za integrację warstwy gry z warstwą szkieletu aplikacji oraz za zarządzanie trybami gry. Obiekty reprezentujące wspomniane tryby stanowić będą kolejną warstwę w naszej hierarchii. W naszym przypadku wyróżnimy dwa rodzaje trybów – tryb menu (klasa CLaserQuestGameMenuMode) oraz tryb rozgrywki (klasa CLaserQuestGamePlayMod e). Tryb gry, to według prezentowanego tu zamysłu, maszyna stanów określająca, co się w danej chwili z grą dzieje. Dla przykładu – tryb rozgrywki (CLaserQuestGamePlayMode) przechowuje i zarządza takimi informacjami jak poziom etapu gry, warunki jej zakończenia itd. Tryb gry może z kolei przechowywać obiekt reprezentujący silnik określonej części rozgrywki. W przypadku LaserQuest wyróżnimy tylko jeden silnik, reprezentowany przez klasę CLaserQuestGameBoardEngine. Obiekt silnika – w naszym przypadku stanowiący liść hierarchii – reprezentować będzie planszę na której odbywa się faktyczna rozgrywka. W tym miejscu zaimplementowna będzie mechanika gry oraz reguły nią sterujące. Gwoli jasności należy w tym miejscu mocno podkreślić, że przedstawiona tu hierarchia bazuje na kompozycji (to znaczy – obiekty wchodzące w jej skład zawierają siebie nawzajem), a nie na dziedziczeniu. To co łączy klasy opisujące obiekty na poszczególnych poziomach to wspólna koncepcja przetwarzania oparta na dwóch metodach – Draw() oraz Update(). Zadaniem pierwszej z tych metod jest renderowanie danego składnika, druga odpowiada za uaktualnianie oraz obsługę ewentualnych przejść pomiędzy sta11/2008

void Draw( CBitmapContext& aGc ) const; void Update( TInt64 aDt ); TBool ExitFlag() const { return iExitFlag; } private:

void ConstructL();

void UpdateMenuMode( TInt64 aDt ); void UpdatePlayMode( TInt64 aDt ); const TLaserQuestKeyState& iKeyState; TMode iMode; CLaserQuestGamePlayMode* iPlayMode; CLaserQuestGameMenuMode* iMenuMode; TBool iExitFlag;

}; // class CLaserQuestGame

Listing 4. Definicja metody Draw() w klasie CLaserQuestContainer
void CLaserQuestContainer::Draw( CBitmapContext& aGc ) const { aGc.Reset();

aGc.SetBrushColor( KRgbBlack ); aGc.DrawRect( Rect() ); iGame->Draw( aGc );

aGc.SetBrushStyle( CGraphicsContext::ESolidBrush );

TBuf< KFpsMessageMaxLength > fpsMessage; iFpsCounter->Fps() );

fpsMessage.Format( KFpsMessageFormatString, aGc.UseFont( iEikonEnv->NormalFont() ); aGc.SetPenColor( KRgbWhite ); aGc.DrawText( fpsMessage,

TPoint( KFpsMessagePosX,

aGc.DiscardFont(); }

KFpsMessagePosY ) );

Listing 5. Definicja metody Update() w klasie CLaserQuestContainer
void CLaserQuestContainer::Update( TInt64 aDt ) { iGame->Update( aDt ); if ( iGame->ExitFlag() ) { if ( iAppUi != NULL ) { } iAppUi->Exit(); }

}

66

Programowanie gier dla Symbian OS

nami gry (czytaj: przekazywania kontroli pomiędzy poszczególnymi składnikami). W przypadku programowania bardziej skomplikowanych gier warto zastanowić się nad zbudowaniem szkieletu gry opartego na powyższej koncepcji – tak aby raz zaprogramowaną funkcjonalność można było wykorzystać w przyszłości. Można by dla przykładu stworzyć bazową klasę reprezentującą składnik gry (np. CLaserQuestGameEntity) i z niej dziedziczyć klasy bazowe reprezentujące poszczególne składniki hierarchii. W przypadku LaserQuest – aby nie zaciemniać tematu – zbudujemy opisaną wyżej hierarchię w sposób bezpośredni. Warto w tym miejscu zatrzymać się na chwilę i zwrócić uwagę na zastosowaną konwencję nazewnictwa klas w naszym projekcie. Ponieważ przy programowaniu aplikacji C++ dla Symbian OS nie stosuje się zazwyczaj przestrzeni nazw, dlatego zdecydowałem się nadawać wszystkim klasom reprezentującym składniki gry nazwy rozpoczynające się prefiksem CLaserQuestGame. Podejście takie pozwala w łatwy sposób odróżniać klasy szkieletu aplikacji od klas reprezentujących samą grę. Warto w tym punkcie poruszyć jeszcze jedną kwestię natury architektonicznej. Podejrzewam, że wielu purystów projektowania obiektowego obruszy się widząc w jednej klasie metody odpowiedzialne za przetwarzanie i renderowanie swojej zawartości. Słyszę niemalże jak padają groźnie pytania pokroju – a co z separacją warstwy logiki od warstwy prezentacji?! Odpowiedź jest prosta – w przypadku programowania gier rzadko zachodzi ku temu potrzeba. Co więcej – w grach komputerowych warstwa logiki często łączy się z warstwą prezentacji (np.: badanie kolizji pomiędzy obiektami występującymi w grze na zasadzie badania zawartości sprite'ów) i czasami wprowadzanie takiego podziału jest sztuczne i powoduje niepotrzebny narzut. W takich sytuacjach warto jest stosować zasadę Brzytwy Ockhama – nie mnóżmy niepotrzebnych bytów (czytaj: klas) jeśli nie ma po temu rzeczywistej potrzeby. Co więcej – nasza koncepcja wcale nie kłóci się z ideą separacji wspomnianych warstw. Po prostu użyliśmy do tego innego narzędzia – zamiast umieszczać te funkcjonalności w różnych klasach, umieściliśmy je w różnych funkcjach. Dodatkowo, fakt iż metoda Draw() posiada modyfikator const jest dodatkowym gwarantem, iż wspomniane warstwy nie będą się przeplatać. W kolejnych podpunktach opiszę szczegółowo kolejne klasy w przedstawionej tu hierarchii. Schemat hierarchii przedstawiony jest na Rysunku 3.

Rysunek 1. Narzędzie do konfiguracji procesu budowania aplikacji

Listing 6. Definicja metody Draw() w klasie CLaserQuestGame
void CLaserQuestGame::Draw( CBitmapContext& aGc ) const { switch ( iMode ) { case EMenu: iMenuMode->Draw( aGc ); break; case EPlay: iPlayMode->Draw( aGc ); break; default: break; } }

Listing 7. Definicja metody Update() w klasie CLaserQuestGame
void CLaserQuestGame::Update( TInt64 aDt ) { switch ( iMode ) { case EMenu: UpdateMenuMode( aDt ); break; case EPlay: UpdatePlayMode( aDt ); break; default: break; } }

Konfiguracja narzędzia t2t
• •

Aby skonfigurować narzędzie t2t (pod systemami z rodziny Windows) należy podjąć następujące kroki: rozpakować archiwum z narzędziem do wybranego podkatalogu; ustawić zmienną środowiskową %T2T _ HOME% , przypisać jej nazwę wybranego podkatalogu i dodać ją do zmiennej %PATH% .

Gra zamknięta w obiekcie
W niniejszym podpunkcie opiszę interfejs oraz implementację klasy CLaserQuestGame,
www.sdjournal.org

Po takich zabiegach konfiguracyjnych (zakładając, że w systemie dostępny jest interpreter języka Perl) narzędzie t2t można uruchomić z dowolnego miejsca w systemie wpisując z linii poleceń komendę t2t. Po uruchomieniu tej instrukcji bez żadnych argumentów wyświetlona będzie lista poleceń narzędzia wraz z prostą instrukcją obsługi opatrzoną przykładami.

67

Programowanie urządzeń mobilnych
która, jak wspomniałem wyżej, reprezentuje grę jako całość. Klasa ta jest – niejako z powołania – punktem styku silnika gry oraz opisanego w poprzednim odcinku szkieletu aplikacji. Na początek przyjrzyjmy się definicji klasy (plik LaserQuestGame.h w podkatalogu inc katalogu projektu; paczkę z kodem źródłowym do niniejszego artykułu można pobrać z witryny SDJ). Definicja klasy przedstawiona jest na Listingu 3. Prześledźmy na początek publiczne składniki interfejsu tej klasy. Statyczna metoda NewL(), konstruktor oraz prywatna metoda ConstructL() stanowią część mechanizmu dwufazowej konstrukcji obiektów (ang. two-phase construction). Osoby planujące na poważnie zająć się programowaniem natywnych aplikacji dla Symbian OS powinny zapoznać się z tym mechanizmem – tak samo jak z mechanizmem stosu czyszczącego (ang. cleanup stack). Obydwa mechanizmy opisane są w Ramce zatytułowanej Stos czyszczący oraz dwufazowa konstrukcja obiektów w Symbian OS. W tym punkcie zakładamy, że metoda NewL() przejmuje rolę konstruktora klasy. Destruktor klasy uchował się na szczęście od Symbianowych dziwactw i nadal pozostaje zwykłym destruktorem. Metody Draw() i Update() mają szczególne znaczenie. Do Draw() przekazywany jest kontekst bitmapy reprezentującej tylny bufor aplikacji. Z kolei Update() otrzymuje przyrosty czasu pomiędzy poszczególnymi iteracjami pętli gry. Znaczenie publicznej metody ExitFlag() opiszę w dalszej części tego podpunktu. Obiekt klasy CLaserQuestGame jest przechowywany i tworzony w obiekcie kontenera (klasa CLaserQuestContainer, pliki LaserQuestContainer.h/cpp). Tworzenie obiektu gry zrealizowane jest w metodzie CLaserQuestContainer::ConstructL():
iGame = CLaserQuestGame::NewL( iKeyState );

Listing 8. Definicja metody CLaserQuestGame::UpdateMenuMode()
void CLaserQuestGame::UpdateMenuMode( TInt64 aDt ) { iMenuMode->Update( aDt ); if ( iMenuMode->IsFireKeyPressed() ) { switch ( iMenuMode->ActiveOption() ) { case CLaserQuestGameMenuMode::EExit: { iExitFlag = ETrue; break; } {

case CLaserQuestGameMenuMode::EStart: iMode = EPlay; break; } }

iPlayMode->Reset();

}

}

Listing 9. Definicja metody CLaserQuestGame::UpdatePlayMode()
void CLaserQuestGame::UpdatePlayMode( TInt64 aDt ) { iPlayMode->Update( aDt ); if ( iPlayMode->MenuKeyPressed() ) { iMode = EMenu; }

iMenuMode->Reset(); }

LaserQuest – skrócony podręcznik użytkownika

Jak wspomniano we wstępie artykułu, LaserQuest to gra logiczna, bazująca na Lasermanii. Rozgrywka LaserQuest odbywa się na dwuwymiarowej planszy podzielonej na równomierne pola, wypełnionej przeróżnymi elementami. Elementy występujące w grze to: • • • • • • • emiter lasera, czyli urządzenie generujące wiązkę skondensowanego światła; ściany absorbujące promień lasera; ściany odbijające promień lasera; ruchome lustra odbijające promień lasera; czujniki układu alarmowego; teleport do kolejnej planszy; pojazd sterowany przez gracza.

Warto zwrócić uwagę na to, w jaki sposób do obiektu gry przekazywany jest stan klawiatury. Prywatna składowa iKeyState prze-

Zadaniem gracza jest zniszczenie wszystkich czujników układu alarmowego i wejście do teleportu prowadzącego do następnej planszy. Czujniki można niszczyć promieniem lasera. W praktyce oznacza to, że gracz musi w taki sposób manipulować ruchomymi częściami planszy (lustrami) aby nakierować odbijający się promień lasera na kolejne czujniki, a gdy zostaną one zniszczone – dotrzeć do teleportu. Wspomniane manipulacje wykonywane są za pomocą sterowanego joystickiem pojazdu, który można wykorzystać do przesuwania luster. W niniejszym odcinku cyklu logika otaczająca główny silnik gry jest bardzo uboga, aczkolwiek kompletna. Po uruchomieniu gry użytkownik ma do dyspozycji proste menu z dwoma opcjami – Start i Exit. Opcja pierwsza powoduje przejście do testowej planszy i rozpoczęcie rozgrywki. Opcja druga powoduje natychmiastowe opuszczenie aplikacji. Po rozpoczęciu rozgrywki gracz ma następujące opcje. Może sterując pojazdem próbować rozwiązać planszę – jeśli mu się to uda, to rozgrywka zostanie zakończona i gra przejdzie ponownie do trybu menu. Gracz może wrócić do wspomnianego trybu w dowolnym momencie rozgrywki – wciskając prawy softkey. Jeśli w trakcie rozgrywki gracz uzna, że znalazł się w położeniu bez wyjścia, to może zrestartować grę przy pomocy lewego softkey'a. Rysunek 2. Narzędzie do konfiguracji procesu budowania paczki instalacyjnej programu

68

11/2008

Programowanie gier dla Symbian OS

chowywana jest w klasie CLaserQuestGame jako referencja do stałej. Idea tej decyzji projektowej polega na tym, iż mając referencję do zmiennej reprezentującej stan klawiatury wszelkie dotyczące jej zmiany (wykonywane na poziomie klasy CLaserQuestContainer) będą widoczne w klasie CLaserQuestGame. Referencję tę możemy oczywiście przekazać dalej – tak aby obiekty niżej w hierarchii również mogły śledzić stan klawiatury. Wykorzystanie referencji do stałej daje nam gwarancję, że nikt nie popsuje wartości składowej iKeyState (tylko klasa CLaserQuestContainer ma prawo ją uaktualniać, wszyscy inni mogą ją tylko czytać). W rezultacie – stosując takie podejście – możemy badać stan klawiatury na zasadzie bezpośredniego odpytywania (ang. key polling), a nie na zasadzie notyfikacji (ang. key event notification). Innymi słowy – to obiekt zainteresowany stanem klawiatury pyta o jej stan, w odróżnieniu od sytuacji gdy obiekt śledzący stan klawiatury informuje o zmianach wszystkich zainteresowanych. Stosowanie pierwszego podejścia w przypadkach pisania prostych gier znacznie ułatwia oprogramowywanie warstwy logiki. Kolejne miejsca w których podpinamy nasz silnik gry to metody Draw() i Update() w klasie CLaserQuestContainer (Listingi 4 i 5). W przypadku metody CLaserQuestContainer::Draw() stosujemy proste podejście – wystarczy w odpowiednim miejscu wywołać funkcję Draw() na obiekcie iGame. Zawartość metody Update() jest trochę bardziej skomplikowana. Problem z tą metodą polega na tym, że oprócz komunikacji przebiegającej w dół hierarchii (w tym konkretnym przypadku mowa jest o wywołaniu iGame->Update( aDt )) musimy również odczytać wiadomość wędrującą w górę hierarchii – obiekt reprezentujący grę powiadamia swojego rodzica (czyli klasę CLaserQuestContainer) o tym, że gdzieś w jej wnętrzu zapadła decyzja o zakończeniu działania aplikacji. Aby przekonać się o tym, kontener sprawdza odpowiednią flagę w silniku gry. Nasi znajomi puryści projektowania obiektowego mogliby tym razem zauważyć, że alternatywą dla tego rozwiązania mógłby być wzorzec projektowy znany pod nazwą Obserwatora, bazujący na wywoływaniu funkcji zwrotnych. Owszem – jest to alternatywa warta rozważenia, aczkolwiek w przypadku niewielkich gier zastosowanie prostego odpytywania jest zwyczajnie prostsze. Żądanie zakończenia gry trzeba przekazać jeszcze o jeden poziom wyżej, do obiektu klasy CLaserQuestAppUi. W tym celu trzeba było zmodyfikować kod szkieletu i przekazać wskaźnik na wspomniany obiekt do kontenera (patrz: nowa składowa iAppUi w klasie
www.sdjournal.org

kontenera). Wywołanie łatwia sprawę.

CLaserQuestContainer::Update finalnie za-

iAppUi->Exit()

w

Omówienie mechanizmu interakcji na linii silnik gry – pętla gry mamy za sobą. Wróćmy ponownie do implementacji silnika i przeana-

Listing 10. Definicja klasy CLaserQuestGameMenuMode
class CLaserQuestGameMenuMode : public CBase public: {

enum TOption { EStart, EExit };

static CLaserQuestGameMenuMode* NewL( CLaserQuestGameMenuMode(

const TLaserQuestKeyState& aKeyState ); const TLaserQuestKeyState& aKeyState );

~CLaserQuestGameMenuMode(); void Reset();

void Draw( CBitmapContext& aGc ) const; void Update( TInt64 aDt ); TOption ActiveOption() const

TBool IsFireKeyPressed() const private:

{ return iActiveOption; }

{ return iIsFireKeyPressed; }

void ConstructL();

const TLaserQuestKeyState& iKeyState; TOption iActiveOption; CFbsBitmap* iTitle; CFbsBitmap* iStart; CFbsBitmap* iExit; TLaserQuestPeriod

CFbsBitmap* iActiveStart; CFbsBitmap* iActiveExit; iMenuOptionsTransitionDelayPeriod;

TBool iIsFireKeyPressed;

}; // class CLaserQuestGameMenuMode

Listing 11. Definicja zasobu LaserQuestMenu.mbm w pliku LaserQuest.mmp
START BITMAP LaserQuestMenu.mbm SOURCEPATH ..\gfx HEADER TARGETPATH resource\apps SOURCE c24 LaserQuestMenuExit.bmp

SOURCE c24 LaserQuestMenuExitActive.bmp SOURCE c24 LaserQuestMenuStart.bmp SOURCE c24 LaserQuestMenuTitle.bmp SOURCE c24 LaserQuestMenuStartActive.bmp END

Listing 12. Zawartość wygenerowanego automatycznie pliku nagłówkowego LaserQuestMenu.mbg
// LaserQuestMenu.mbg // Generated by BitmapCompiler // Copyright (c) 1998-2001 Symbian Ltd. // enum TMbmLaserquestmenu { EMbmLaserquestmenuLaserquestmenuexit, All rights reserved.

EMbmLaserquestmenuLaserquestmenuexitactive, EMbmLaserquestmenuLaserquestmenustart, EMbmLaserquestmenuLaserquestmenutitle }; EMbmLaserquestmenuLaserquestmenustartactive,

69

Programowanie urządzeń mobilnych
lizujmy wewnętrzne mechanizmy jego działania. Jak wspominałem wcześniej, gra LaserQuest składa się z dwóch podstawowych trybów – menu oraz rozgrywki. Podział ten uwzględniony jest w klasie CLaserQuestGame. W enumeracji CLaserQuestGame::TMode zdefiniowane są dwie wartości reprezentujące wspomniane tryby – EMenu oraz EPlay. Informacja o tym jaki jest aktualny tryb gry przechowywany jest w składowej iMode. Jeśli zajrzymy do implementacji metod CLaserQuestGame: :Draw() oraz CLaserQuestGame::Update() (Listingi 6 i 7) to zauważymy, że są one zaimplementowane na bazie instrukcji switch. Instrukcje te delegują zadania do obiektów reprezentujących poszczególne tryby gry w zależności od wartości zmiennej iMode. W przypadku metody Draw() sytuacja jest prosta – wystarczy wywołać metodę Draw() dla obiektu reprezentującego aktywny tryb gry. W przypadku metody Update() należy dodatkowo obsłużyć komunikację zwrotną – kod odpowiedzialny za to zadanie umieszczony jest w metodach UpdateMenuMode() oraz UpdatePlayMode() (Listingi 8 i 9). W UpdateMenuMode() oprócz wywołania metody Update() na obiekcie iMenuMode, sprawdzamy czy użytkownik podjął jakąś akcję związaną z tym trybem. W tym celu wykorzystujemy metody – IsFireKeyPressed() oraz ActiveOption() stanowiące część publicznego interfejsu klasy CLaserQuestGameMenuMode. Pierwsza metoda zwraca wartość ETrue w przypadku gdy w trybie menu wykryto wciśnięcie przycisku fire. Po wykryciu takiej sytuacji, przy pomocy drugiej metody – ActiveOption() – pobierany jest identyfikator opcji, która jest na dany moment aktywna i na tej podstawie podejmowane są kolejne akcje – bądź to ustawienie flagi wyjścia z programu, bądź przejście do trybu rozgrywki. W przypadku UpdateMenuMode() dzieje się podobnie – tyle, że do obsłużenia jest tylko jedna możliwość – powrót z trybu rozgrywki do trybu menu. W jaki sposób tryby gry kontrolują swój stan – o tym już za moment. Na początek sprawdzimy...

Listing 13. Fragment definicji metody CLaserQuestGameMenuMode::ConstructL() – wczytywanie bitmapy
void CLaserQuestGameMenuMode::ConstructL() { iTitle = new ( ELeave ) CFbsBitmap(); User::LeaveIfError( iTitle->Load( KLaserQuestMenuMbmFilePath,

// ...

EMbmLaserquestmenuLaserquestmenutitle ) );

Listing 14. Definicja stałej określającej ścieżkę dostępu do pliku mbm
#ifdef __WINS__ _LIT( KLaserQuestMenuMbmFilePath, #else

"z:\\resource\\apps\\LaserQuestMenu.mbm" );

_LIT( KLaserQuestMenuMbmFilePath, #endif // __WINS__

"c:\\resource\\apps\\LaserQuestMenu.mbm" );

Listing 15. Fragment definicji metody CLaserQuestGameMenuMode::Draw()
void CLaserQuestGameMenuMode::Draw( CBitmapContext& aGc ) const {

aGc.BitBlt( TPoint( KTitlePosY, KTitlePosY ), iTitle, iTitle->SizeInPixels() );

// ... }

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

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

...co w menu piszczy
����������������������� �����������������������

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

Rysunek 3. Schemat architektury gry LaserQuest

Po zapoznaniu się ze szczegółami implementacji obiektu reprezentującego grę jako całość, czas przyjrzeć się klasom reprezentującym obiekty z drugiej warstwy hierarchii – mowa tu o warstwie trybów gry. Na początek przyjrzymy się prostszej z dwóch klas występujących w LaserQuest – CLaserQuestGameMenuMode. Przeanalizujmy Listing 10, na którym znajduje się definicja wspomnianej klasy. Duża część interfejsu klasy wygląda znajomo – wiele metod w tej klasie było wykorzystywane w obiekcie klasy CLaserQuestGame. To co na pewno rzuca się w oczy to zestaw wskaźników do obiektów klasy CFbsBitmap. Tak, tak – wreszcie dotarliśmy do miejsca gdzie narysujemy coś więcej niż czarny pro11/2008

70

Programowanie gier dla Symbian OS

stokąt czy informacja o liczniku FPS. Menu w naszej grze jest na tyle proste, że nie warto rozbijać go na mniejsze klasy. Gdyby było inaczej, to zapewne architektura tej części gry byłaby o wiele bardziej złożona; oprogramowanie skomplikowanych interfejsów użytkownika w grach to jednak temat na oddzielny, wcale niekrótki artykuł. W przypadku LaserQuest klasa CLaserQuestGameMenuMode jest odpowiedzialna za obsługę menu oraz za jego renderowanie. Przyjrzyjmy się jak zostało to zrealizowane. Klasa CFbsBitmap służy w Symbian OS do reprezentacji specjalnie spreparowanej bitmapy. Bitmapy takie są w procesie budowania aplikacji przetwarzane dedykowanym narzędziem (bmconv), a następnie pakowane w pliki z rozszerzeniem mbm. Tak spreparowane paczki bitmap są następnie dołączone do instalatora aplikacji i stanowią integralną ich część. Nagrodą, którą programista otrzymuje za uporanie się z całym tym galimatiasem jest możliwość synchronicznego wczytania bitmapy na podstawie automatycznie wygenerowanego identyfikatora (zapisanego jako enumeracja w nagłówkowym pliku z rozszerzeniem mbg). Brzmi skomplikowanie? Cóż – niestety – po części tak jest. Prześledźmy jak w praktyce wygląda proces przygotowania bitmap reprezentujących menu gry LaserQuest. Jako że ponoć jeden obraz wart jest tysiąca słów, zapraszam Czytelników do zapoznania się z Rysunkiem 4, na którym pokazane jest menu gry LaserQuest. Obraz menu składa się z kilku bitmap wyświetlonych na czarnym tle. Bitmapy te są reprezentowane przez następujące składowe w klasie CLaserQuestGameMenuMode: iTitle (tytuły gry), iStart (napis Start), iExit (napis Exit), iActiveStart oraz iActiveExit (podświetlone napisy Start i Exit). Bitmapy zostały narysowane w zwykłym edytorze grafiki i zapisane w podkatalogu gfx projektu LaserQuest. W dalszej kolejności zmodyfikowano odpowiednio plik definicji projektu (mmp) dodając fragment pokazany na Listingu 11. W definicji określone są źródłowa i docelowa ścieżka dla zasobów oraz lista bitmap, które składają się na paczkę LaserQuestMenu.mbm. To, na co warto zwrócić uwagę, to specyfikacja formatu piksela dołączona do każdego elementu we wspomnianej liście. W naszym przypadku używamy wartości c24, która oznacza, iż każdy piksel w docelowej bitmapie reprezentowany jest przez 24 bity. Na tym kończy się praca programisty związana z przygotowaniem bitmap – pozostałą częścią procesu przygotowania pliku mbm zajmuje się łańcuch budowania aplikacji. W tym momencie warto wspomnieć, że Carbide oferuje wygodne, wizualne narzędzie wspomagające dołączanie bitmap do projekwww.sdjournal.org

tu i zwalniające programistę z ręcznego modyfikowania plików mmp. Aby dostać się do

wspomnianego narzędzia należy otworzyć plik mmp w eksploratorze projektu, a następ-

Listing 16. Definicja metody CLaserQuestGameMenuMode::Update()
void CLaserQuestGameMenuMode::Update( TInt64 aDt ) { iMenuOptionsTransitionDelayPeriod.Update( aDt ); if ( iMenuOptionsTransitionDelayPeriod.Passed() ) { if ( iKeyState & KKeyUp || iKeyState & KKeyDown ) { switch ( iActiveOption ) { case EStart: iActiveOption = EExit; break; case EExit: iActiveOption = EStart; break; iMenuOptionsTransitionDelayPeriod.Reset( } KOneSecondInMicroSeconds / 5 ); }

}

if ( iKeyState & KKeyFire ) { } iIsFireKeyPressed = ETrue; }

Listing 17. Definicja klasy TLaserQuestPeriod
class TLaserQuestPeriod public: {

TLaserQuestPeriod( TInt64 aPeriod = 0 ) void Reset( TInt64 aPeriod ) void Update( TInt64 aDt ) TBool Passed() const { iPeriod = aPeriod; } : iPeriod( aPeriod ) { }

{ if ( iPeriod > 0 ) { iPeriod -= aDt; } } { return iPeriod <= 0; }

private: };

TInt64 iPeriod; // In microseconds.

Skąd mam wziąć UID dla aplikacji Symbian OS?

UID w kontekście Symbian OS, to unikalny w skali światowej identyfikator aplikacji. Utrzymywaniem puli i przydzielaniem UID-ów zajmuje się firma Symbian – producent Symbian OS. Nie każda aplikacja musi mieć unikalny UID – np. do celów testowych można wykorzystywać jeden UID wielokrotnie, jednakże należy mieć świadomość, że gdy zainstalujemy na jednym telefonie dwie różne aplikacje z identycznym UID-em to efekty będą nieprzewidywalne (czytaj: coś się na pewno popsuje). Z tego względu – wszystkie aplikacja pretendujące do uzyskania certyfikacji Symbian Signed (jeden z podstawowych wymogów przy rozpowszechnianiu aplikacji komercyjnych) muszą posiadać swój własny UID. Generalnie, osoby planujące udostępnić swoją aplikację na publicznym forum (niekoniecznie w trybie komercyjnym – może to być równie dobrze aplikacja oferowana na zasadach Open Source) powinna postarać się o taki numer. Aby uzyskać UID na własne potrzeby trzeba zarejestrować się na stronie Symbian Signed (https://www.symbiansigned.com). Po pomyślnej rejestracji należy przejść do zakładki My Symbian Signed a następnie wybrać z bocznej belki opcje UIDs i Request. Dalej należy postępować według przedstawionych instrukcji. Zamówione UID-y odbiera się za pomocą poczty elektronicznej.

71

Programowanie urządzeń mobilnych
nie wybrać zakładkę Sources. Przyjrzymy się teraz jak obsłużyć nasze bitmapy z poziomu kodu źródłowego. W tym celu dobrze jest zajrzeć do pliku LaserQuestGameMenuMode.cpp. Na początku należy dołączyć plik nagłówkowy zawierający definicję enumeracji z identyfikatorami bitmap:
#include <LaserQuestMenu.mbg>

Listing 18. Definicja metody CLaserQuestGameBoardEngine::ComputeNextVehicleMovePosX()
TInt CLaserQuestGameBoardEngine::NextVehicleMovePosX( TDirection aDir ) const {

static const TInt KDir2Dx[] = { -1, 1, 0, 0 }; return iVehiclePosX + KDir2Dx[ aDir ]; }

Stos czyszczący oraz dwufazowa konstrukcja obiektów w Symbian OS

Pisząc aplikacja C++ dla Symbian OS nie da się uniknąć mechanizmu stosu czyszczącego i idiomu dwufazowej konstrukcji. W tym miejscu opiszę obydwa mechanizmy tak, aby Czytelnik był w stanie zrozumieć prezentowane kody źródłowe i w pewnym ograniczonym zakresie stosować je przy budowaniu własnych gier. Czytelników zainteresowanych szczegółowym zgłębieniem tej dziedziny wiedzy odsyłam do książki Symbian OS Explained autorstwa Jo Stichbury. Drugi, trzeci oraz czwarty rozdział tej książki stanowią w mojej opinii najlepsze dostępne wprowadzenie to tematyki opisywanej bardzo pobieżnie w niniejszej Ramce. Potrzeba wprowadzenia stosu czyszczącego oraz dwufazowej konstrukcji obiektów wzięła się z tego, iż kompilatory używane do budowania aplikacji pod pierwotne wersje systemu Symbian nie obsługiwały sytuacji wyjątkowych. Na dzień dzisiejszy sytuacja ta może bawić, aczkolwiek na ówczesne czasy (początek lat 90) taka była rzeczywistość. Jako, że Symbian OS miał być systemem dedykowanym dla urządzeń mobilnych o mocno ograniczonych zasobach, to jego autorzy byli zmuszeni wprowadzić spójny i przekrojowy system zabezpieczeń przed gubieniem tych zasobów. W tej sytuacji opracowano alternatywny mechanizm obsługi wyjątków w postaci funkcji User::Leave() oraz makra TRAP. Rozważając temat w kategoriach języka C, mechanizmy te odpowiadają bibliotecznym funkcjom setjmp() i longjmp(). W kontekście sytuacji wyjątkowych języka C++, funkcja User::Leave() działa podobnie jak instrukcja throw, zaś TRAP pełni rolę bloku catch . Jednakże wbudowany mechanizm wyjątków C++ oferuje coś więcej – mowa tu oczywiście o automatycznym wywoływaniu destruktorów po pojawieniu się sytuacji wyjątkowej co – przynajmniej w teorii – zapobiega powstawaniu luk w zasobach. Pomijając szereg subtelnych zagrożeń, mechanizm wyjątków C++ stanowi stosunkowo wygodne narzędzie do obsługi nieprzewidzianych sytuacji w programie. W tym kontekście, symbianowy stos czyszczenia stanowi brakujący składnik mechanizmu obsługi wyjątków. Niestety – ze względu na oczywiste ograniczania (jest to w końcu tylko biblioteka próbująca imitować mechanizmy wbudowane w język) – programiści są zmuszeni ręcznie zarządzać obiektami znajdującymi się na takim stosie. To z kolei ciągnie za sobą fakt, iż tylko wybrane klasy mogą ze stosem czyszczenia współpracować – mowa tu o obiektach dziedziczących z klasy CBase. Analizując przedstawione w poszczególnych Listingach nagłówki klas Czytelnik może się łatwo przekonać, iż zasadniczo wszystkie klasy reprezentujące silnik LaserQuest dziedziczą z CBase (stąd też bierze się konwencja zakładająca dodawanie klasom prefiksów – z góry wtedy wiadomo, że klasy o nazwach rozpoczynających się na C reprezentują obiekty przechowujące zasoby). W tym miejscu dochodzimy do genezy problemu na które remedium stanowić ma idiom dwufazowej konstrukcji obiektów. Chodzi o to, że wbudowany konstruktor obiektów klasy C nie może rzucać wyjątków (tj. wywoływać operacji leavującej). Jeśli przyjrzymy się dowolnej klasie przechowującej zasoby (np. dynamicznie alokowane obiekty reprezentujące bitmapy) to zauważymy, że operacje związane z ich alokacją mają nazwy zakończone sufiksem L . To oznacza właśnie, iż operacje te mogą bezpośrednio lub pośrednio wywołać operację User::Leave(). Z drugiej strony, alokacja pamięci jest sama w sobie operacją potencjalnie leavującą. W tej sytuacji – zakładając iż konstruktor klasy może wywoływać operację User::Leave(), przy dynamicznej alokacji obiektu mielibyśmy do czynienia z dwoma takimi operacjami wywołanymi pod rząd. A jest to sytuacja niedopuszczalna, gdyż po wykonaniu pierwszej z operacji leavujących należy bezzwłocznie umieścić wskaźnik do zaalokowanego zasobu oraz umieścić na stosie czyszczenia (przy pomocy wywołania CleanupStack::PushL()). Aby obejść ten problem stosuje się prosty chwyt – wszystkie potencjalnie leavujące operacje związane z konstrukcją obiektu umieszcza się w metodzie ConstructL(), którą należy wywołać ręcznie po uprzednim włożeniu wskaźnika do zaalokowanego obiektu na stos czyszczenia. Proces ten można ukryć przed użytkownikiem umieszczając opisane wyżej operacje w statycznej metodzie klasy, nazywanej według przyjętej konwencji NewL() lub NewLC(),. Metody te zastępują wbudowany konstruktor, tak że obiekt można zkonstruować w następujący sposób:
iMenuMode = CLaserQuestGameMenuMode::NewL( iKeyState );

Plik ten jest generowany automatycznie w trakcie budowania aplikacji i można go znaleźć w katalogu z systemowymi nagłówkami SDK. Plik nagłówkowy dla zasobu LaserQuestMenu.mbm w przypadku rozważanej aplikacji wygląda tak jak przedstawiono na Listingu 12. Wczytywanie bitmap reprezentujących menu zrealizowane jest w metodzie ConstrutL() klasy CLaserQuestGameMenuMode. Przyjrzyjmy się fragmentowi tej metody (Listing 13). Na początek należy stworzyć przy pomocy operatora new obiekt reprezentujący bitmapę. W drugim kroku – przy pomocy metody CFbsBitmap::Load() wczytujemy zawartość bitmapy z pliku mbm. Oprócz identyfikatora bitmapy podajemy również ścieżkę dostępu do pliku mbm. Ścieżka ta zdefiniowana jest jako stała tekstowa na początku pliku LaserQuestGameMenuMode.cpp (Listing 14). Z racji tego, że ścieżki dostępu do pliku mbm są różne w środowisku emulatora i na urządzeniu, dlatego do wyboru właściwej zastosowałem instrukcję warunkową preprocesora. Dla ścisłości należy dodać, iż zmienna __WINS__ jest definiowana automatycznie w momencie budowania aplikacji w wersji działajacej pod emulatorem, co – mam nadzieję – finalnie rozjaśnia sprawę. Niestety, podejście takie nie rozwiązuje do końca naszego problemu. Chodzi konkretnie o to, że ścieżka będzie niepoprawna w sytuacji gdy zainstalujemy aplikację na karcie pamięci (o ile takowa jest dostępna w telefonie). Sytuację tę można obsłużyć sprawdzając w czasie wyko-

W ramach ćwiczenia zachęcam wszystkich Czytelników do przeanalizowania dołączonych źródeł projektu i zbadania implementacji opisanych powyżej mechanizmów w praktyce. Rysunek 4. Menu gry LaserQuest

72

11/2008

Programowanie gier dla Symbian OS

nania programu miejsce jej instalacji i dynamicznie budując ścieżkę dostępu. Wrócę do tego tematu w kolejnych odsłonach niniejszego cyklu. Wracając jeszcze do zawartości Listingu 13, warto zwrócić uwagę na użycie konstrukcji User::LeaveIfError(). Funkcja ta powoduje rzucenie symbianowego wyjątku w sytuacji kiedy operacja wczytywania zawartości bitmapy z jakichś przyczyn się nie powiedzie. Voila! Jedyne co nam pozostało to wyświetlenia bitmapy, co też czynimy w funkcji CLaserQuestGameMenuMode::Draw() (Listing 15). Rysowanie bitmapy zrealizowane jest przy pomocy operacji szybkiego kopiowania fragmentu pamięci zaimplementowanego jako metoda CBitmapContext::BitBlt(). Warto też podkreślić, iż zgodnie z dobrym zwyczajem programistycznym unikamy tak zwanych magicznych numerów zapisanych bezpośrednio w kodzie źródłowym, a w zamian za to wykorzystujemy stałe (KTitlePosY, KTitlePosY). Patrząc z szerszej perspektywy, należy uwypuklić fakt, iż w tym miejscu również idziemy na pewne uproszczenie. Otóż przy profesjonalnej produkcji gier rozłożenie elementów ekranu realizuje się – w miarę możliwości – w sposób niezależny od wyświetlacza. W naszym przypadku, zamiast stałej powinniśmy wykorzystać raczej wartość wyliczaną, bazującą na takich parametrach jak szerokość i wysokość ekranu urządzenia (pobieranych w czasie działania programu). W prezentowanym przykładzie zakładam, że wyświetlacz ma stałe rozmiary (240x320 pikseli). Przeanalizujemy teraz jak działa metoda CLaserQuestGameMenuMode::Update() (Listing 16). Wspomniana metoda sprawdza stan klawiatury i ustawia odpowiednie flagi. To co ewidentnie rzuca się w oczy to wykorzystanie składowej iMenuOptionsTransitionDelay Period. Składowa ta jest zdefiniowana w klasie CLaserQuestGameMenuMode w następujący sposób:
TLaserQuestPeriod

użytkownik nie byłby w stanie kontrolować tego procesu. Kończąc niniejszy podpunkt warto zwrócić uwagę na metodę CLaserQuestGameMenuMode ::Reset(). Metoda ta stanowi pewną architektoniczną konwencję – jest ona wykorzystywana do resetowania stanu obiektu, co jest bardzo przydatne w momencie kiedy przechodzimy pomiędzy trybami gry lub restartujemy tryb gry (będzie napisane więcej na ten temat w kolejnym podpunkcie). Wizualny efekt naszych wysiłków związanych z oprogramowaniem menu gry przedstawiony jest na Rysunku 4.

Rozgrywkę czas zacząć!
Kolejny tryb gry, zaimplementowany w ramach klasy CLaserQuestGamePlayMode reprezentuje rozgrywkę. Tryb ten – na ten moment – dostarczony jest nieco na wyrost. Aczkolwiek jego wprowadzenie daje

nam wysoki poziom elastyczności architektury w kontekście kolejnych etapów implementacji gry. Kiedy w następnych odcinkach cyklu będziemy rozszerzać LaserQuest o obsługę wczytywania kolejnych plansz czy system zapisywania stanu gry – tryb ten będzie bardzo przydatny. W bieżącej fazie projektu nie ma się w tym miejscu specjalnie o czym rozpisywać. Praktycznie wszystkie operacje w tym trybie polegają na delegowaniu zadań do silnika planszy. To, na co warto zwrócić uwagę, to mechanizm restartu rozgrywki zaimplementowany w metodzie Update(), z wykorzystaniem wspomnianej wcześniej metody Reset(). Metoda CLaserQuestGamePlayMode::Draw() w przyszłości również będzie bardziej interesująca – umieścimy tam kod odpowiedzialny za wyświetlanie aktualnego numeru planszy oraz statystyk gry, a także napisów reprezentują-

iMenuOptionsTransitionDelayPeriod;

Użyta powyżej klasa TLaserQuestPeriod reprezentuje okres czasu wyrażony w milisekundach, a także oferuje proste operacje do zliczania tego okresu na podstawie przyrostów czasu (Listing 17). Obiekt tej klasy wykorzystywany jest w metodzie Update() w celu wprowadzenia opóźnienia przy zmianach opcji w menu. Gdyby ta funkcjonalność zaimplementowana była bez opisanego mechanizmu to, ze względu na fakt, iż wspomniana funkcja wywoływana jest około 30 razy na sekundę, opcja w menu zmieniałby się tak szybko, że
www.sdjournal.org

Rysunek 5. Przechodzenie fragmentów wiązki lasera przez elementy planszy

73

Programowanie urządzeń mobilnych
cych opcje przypisane do softkey'ów (restart gry i powrót do menu). modelowania planszy wykorzystałem zwykłą tablicę liczb całkowitych. Aczkolwiek, diabeł – jak zwykle – tkwi w szczegółach. Pierwsza rzecz – rozmiar planszy – 14 na 18 pól, z czego tak naprawdę wykorzystane jest tylko 12 na 16 pól. Zewnętrzny obszar to strefa tak zwanych wartowników (ang. sentinels). Wykorzystanie wartowników to dość prosty zabieg pozwalający uniknąć wstawiania kłopotliwych i podatnych na błędy warunków brzegowych. Przy programowaniu logiki planszy często zachodzi potrzeba sprawdzenia tego co znajduje się na polu o indeksie i + 1, lub co gorsza – wstawienia tam nowej wartości. Jeśli nie skorzystamy z wartowników, to w podobnych sytuacjach musimy posiłkować się dodatkowymi warunkami, które zazwyczaj mocno zaciemniają kod. O błąd naruszenia pamięci w takich warunkach nietrudno... Korzystając z wartowników mamy gwarancję, że przy takich operacjach wyjście poza bufor tablicy nam nie grozi, gdyż wszystkie algorytmy działające na planszy operują na jej wewnętrznym otoczonym warstwą ochronną. Druga sprawa, to reprezentacja poszczególnych składników planszy. A jest tego trochę – puste pole, ściana, ściana-lustro, lustro ruchome, emiter promienia laserowego czy wreszcie sama wiązka lasera – to tylko niektóre elementy rozgrywki. Pomysł na upakowanie tego wszystkiego w jednej tablicy jest następujący. Wartość zero oznacza wartownika. Wartości mniejsze od zera oznaczają kolejne elementy planszy. Wartość jeden oznacza pole puste. Wartości powyżej jeden to maski bitowe określające jaka część wiązki lasera przechodzi przez dane pole. Warto w tym miejscu zauważyć, że puste pole planszy może zawierać cztery fragmenty wiązki – w różnych konfiguracjach. Idea ta jest przedstawiona na Rysunku 5, gdzie każdy fragment wiązki przedstawiony jest oddzielnym kolorem (zielony – EBeamUpperLeft, niebieski – EBeamUpperRight, czerwony – EBeamBottomLeft oraz żółty – EBeamBottomRight). Innymi słowy – jeśli dane pole ma wartość większą od jeden, to zakładamy, że jest to puste pole przez które przechodzą fragmenty wiązki lasera. Aby przeprowadzić przez dane pole wiązkę, możemy skorzystać z operacji bitowych. Na przykład wyrażenie:
iCurrentGridData[ 6 ][ 4 ] |=

Laserowa łamigłówka
I oto dotarliśmy do implementacji upragnionego silnika planszy. Monolityczna klasa CLaserQuestGameBoardEngine stanowi niewątpliwie serce naszej aplikacji – tutaj zaimplementowano mechanikę działania gry. Tym razem podarujemy sobie zamieszczanie Listingu zawierającego pełną definicję klasy – skupimy się na jej publicznym interfejsie oraz zapoznamy się z wybranymi szczegółami jej wewnętrznej implementacji. W tym podpunkcie Czytelnik znajdzie wiele odniesień do plików projektu, a w szczególności do dwóch z nich – LaserQuestGameBoardEngine.h oraz LaserQuestGameBoardEngine.cpp. Z tego względu, sugerowane jest zaopatrzenie się w paczkę z kodami źródłowymi projektu przed rozpoczęciem czytania niniejszego podpunktu. Przypominam, że wspomniana paczka dostępna jest do pobrania na witrynie SDJ. Publiczny interfejs klasy reprezentującej planszę gry, czyli punkt styku pomiędzy silnikiem LaserQuest, a obiektem reprezentującym tryb rozgrywki, nie zadziwia niczym niezwykłym. Ponownie widzimy tu takie metody jak Draw(), Update() czy Reset(). Uwagę należy zwrócić za to na metodę IsSolved(). Metoda ta odpowiada na pytanie, czy nasza laserowa łamigłówka została pomyślnie rozwiązana. Przypominam, że według opisanych wcześniej założeń, warunkiem zakończenia gry jest zniszczenie wszystkich umieszczonych na planszy sensorów i dojście do pola oznaczonego jako wyjście. Prawdziwa mechanika LaserQuest – zgodnie z zasadą ukrywania informacji – zamknięta jest w metodach stanowiących niepubliczny interfejs klasy. Zanim jednak przejdziemy do opisu tej mechaniki, zbadamy jaka struktura danych reprezentuje planszę gry. Dla większości Czytelników nie będzie zapewne wielkim zaskoczeniem, iż do

EbeamBottomRight;

dodaje do pola o określonych indeksach (x=6 i y=4) fragment wiązki znajdujący się w jego dolnym prawym rogu. W tym miejscu warto zauważyć, iż plansza gry przechowywana jest w dwóch wersjach – jedna w postaci oryginalnej i druga – zawierająca modyfikacje wprowadzone w trakcie gry. Podejście takie ułatwia implementację mechanizmu restartu, który w przypadku LaserQuest jest nieodzowny, jako że gracz poprzez niewłaściwe przesuwanie luster może doprowadzić do sytuacji, w której ukończenie planszy jest niemożliwe. Kolejnym ciekawym aspektem związanym z implementacją mechaniki gry jest emisja lasera. Na początek warto zauważyć, że emiter zaimplementowany w grze może działać w 8 konfiguracjach (jest w stanie wysyłać promień lasera na 8 sposobów). Wspomniana konfiguracja opisana jest przez pozycję emitera na planszy, aktywny bok (tj. bok z którego emitowany jest promień lasera) oraz orientację promienia (lewo- lub prawostronną). Poszczególne konfiguracje pracy emitera pokazane są na Rysunku 6, przy czym wiązki lasera o orientacji lewostronnej zaznaczone są kolorem zielonym, zaś prawostronnej – białym. Kluczową rolę w implementacji silnika odgrywa funkcja TrackBeam(). Funkcja ta odpowiada za śledzenie wiązki lasera od momentu wyjścia z emitera aż do chwili, kiedy trafi ona w materiał, który nie jest w stanie jej odbić. Algorytm ten korzysta intensywnie z tablic przejść (ang. lookup tables) opisujących zmiany fragmentów wiązki dla różnych kon-

Erratra

Nikt nie ma patentu na nieomylność. W tym miejscu opisane są usterki, które wkradły się do poprzedniej części artykułu. Do implementacji metody CGameSkeletonContainer::OnTick() wkradł się drobny aczkolwiek znaczący błąd. Chodzi konkretnie o fragment kodu w którym obliczany jest przyrost czasu pomiędzy kolejnymi iteracjami pętli gry:
TInt64 dt = iTickStart.Int64() - iTickStop.Int64();

Przy tak skonstruowanym zapisie przyrosty przekazywane do metody CGameSkeletonContainer: :Update() są ujemne... Drugi błąd polega na zastosowaniu zbyt ogólnego kontekstu graficznego w metodzie CGameSkeletonContainer::Draw(). Uważni czytelnicy zauważą, iż w projekcie LaserQuest jako kontekst graficzny przekazywany jest obiekt klasy CBitmapContext, w odróżnieniu do CGraphicsContext używanego w przypadku projektu GameSkeleton. Problem polega na tym, iż ten drugi nie oferuje kluczowej przy programowaniu gier operacji szybkiego kopiowania bitmap (BitBlit). Warto w tym miejscu podkreślić iż poprawki opisanych usterek zostały zaaplikowane w przykładowych kodach źródłowych są dostępne na witrynie SDJ. Rysunek 6. Konfiguracje pracy emitera

74

11/2008

Programowanie gier dla Symbian OS

figuracji wejściowych i żonglując przyrostami określa drogę wiązki, na której pozostawia ślad przy użyciu odpowiednich operacji bitowych. Osoby zainteresowane szczegółami implementacji tego algorytmu zapraszam do przeanalizowania kodów źródłowych. To na co chciałbym zwrócić jeszcze raz uwagę, to wykorzystanie tablic przejść. Ta użyteczna technika pozwala niejednokrotnie uczynić dany fragment kodu krótszym i czytelniejszym, toteż gorąco polecam stosowanie jej przy konstruowaniu swoich własnych aplikacji. Jako przykład stosowania tej technik mogę podać implementację pomocniczej metody CLaserQuestGameBoardEngine: :ComputeNextVehicleMovePosX(), przedstawioną na Listingu 18. Wspomniana metoda oblicza wartość składową na osi X dla kolejnej pozycji pojazdu kierowanego przez gracza przy zadanym kierunku. W implementacji funkcji korzystamy z faktu, iż enumeracje opisujące kierunki ruchu przyjmują wartości z zakresu od 0 do 3. Biorąc to pod uwagę, wykorzystujemy wartość kierunku jako indeks w tablicy przejść zawierającej odpowiednie przyrosty na osi X. Ten sam efekt można by uzyskać stosując operację switch do obsługi kolejnych wartościach enumeracji, aczkolwiek przedstawione rozwiązanie wydaje się być bardziej proste, eleganckie i jednocześnie – kompaktowe. Oprócz struktur danych opisujących rozgrywkę, silnik planszy przechowuje cały szereg bitmap wykorzystywanych do renderowania składników gry. W przypadku kafli (ang. tiles), czyli statycznych składników planszy sytuacja jest prosta – poszczególne bitmapy przechowywane są w tablicy:
CFbsBitmap* iTileBitmaps[ KLaserQuestTileBi tmapCount ];

Analizując kod źródłowy silnika warto zwrócić uwagę na makro TILE _ ENUM _ VAL _ 2 _ TILE _ BITMAP _ INDEX , które w sprytny sposób odwzorowuje wartości enumeracji identyfikujących poszczególne kafle na indeks w tablicy z odpowiadającymi im bitmapami. Nieco bardziej złożone struktury danych wykorzystywane są przy animacji. Jako przykład można podać tu dwuwymiarową tablicę służącą do przechowywania klatek animacji pojazdu którym steruje gracz:
CFbsBitmap* iVehicleFrames[ KLaserQuestVehi [ KLaserQuestVehicleFrameBitmapCount ]; cleFrameCount ]

Podsumowanie
Tak oto kończymy drugi odcinek cyklu artykułów o programowaniu gier przeznaczonych dla Symbian OS. Niestety – mój ambitny plan opisany w podsumowaniu z poprzedniego odcinka – spalił na panewce – wiele z obiecanych wtedy zagadnień zmuszony byłem przenieść do kolejnego odcinka. Głównym tego powodem stało się ograniczenie wielkości artykułu. Z drugiej strony – staram się traktować prezentowane zagadnienie bardzo poważnie, opisując niełatwy proces tworzenia gier od podszewki i zahaczając o szczegóły pomijane często w publikacjach o podobnej tematyce. Mam nadzieję, iż prezentacja cyklu tworzenia gry – od początku do końca – z uwzględnieniem form przejściowych, da pełniejszy pogląd na to zagadnienie. Na sam koniec – zgodnie z tradycją chciałbym zaproponować Czytelnikom zadanie domowe. Proponuję, korzystając z dołączonego do niniejszego artykułu szablonu szkieletu aplikacji oraz narzędzia t2t, stworzyć własny projekt i zaimplementować prostą grę o tematyce podobnej do tej, którą reprezentuje LaserQuest (dobrymi przykładami tego rodzaju gier są takie tytuły jak Sokoban czy Boulder Dash). Osoby, które zdecydują się na taki krok, zachęcam również do rozwijanie obranego projektu na bazie technik opisywanych w kolejnych odcinkach niniejszego cyklu – w myśl starego porzekadła, które w zawodzie programisty sprawdza się jak nigdzie indziej – nie zrozumiesz dopóty, dopóki nie zrobisz tego sam. Na koniec chciałbym wymienić osoby, które dzięki swoim wnikliwym recenzjom przyczyniły się do znacznej poprawy jakości niniejszego artykułu. Wspomniane osoby to: Dawid de Rosier, Jacek „Noe” Cybularczyk oraz Piotr Buła. Chciałbym również tradycyjnie podziękować mojej ukochanej żonie – Oli, za cierpliwość, którą mi nieustannie okazuje.

Pierwszy wymiar tablicy odpowiada numerom klatek animacji zaś wymiar drugi – poszczególnym kierunkom ruchu. Zarówno rysowanie jak i uaktualnianie zawartości planszy przebiega w kilku etapach – niektóre z nich aktywowane są jedynie w specyficznych przypadkach – tak na przykład dzieje się z animacją zanikającego sensora. Aby zwiększyć czytelność kodu starałem się grupować metody i składowe w grupy tematyczne. Niestety, w przypadkach takich jak silnik gry LaserQuest, gdzie mamy do oprogramowania zestaw mocno powiązanych i przenikających się reguł gry, ciężko jest uniknąć monolitycznych klas. Zresztą LaserQuest jest i tak projektem stosunkowo nieskomplikowanym – sama Lasermania stanowiąca jego pierwowzór zawiera o wiele szerszy zestaw reguł rozgrywki powiązanych z dodatkowymi typami elementów występujących na planszy gry. Czytelników zainteresowanych szczegółami implementacji silnika zapraszam do analizy kodu źródłowego. Tych mniej cierpliwych zachęcam do obejrzenia Rysunku 7, na którym przedstawione są efekty działania opisanych wyżej mechanizmów.

Gra w kieszeni
Nadszedł czas aby przetestować naszą grę w jej docelowym środowisku. Procedura budowania paczki instalacyjnej jest identyczna do tej opisanej na początku artykułu. Czytelników, którzy są szczęśliwymi posiadaczami komórek Nokia z serii S60 3rd Edition, zapraszam do przetestowania LaserQuest. Mam nadzieję, że rozwiązanie przykładowej planszy (ściągniętej zresztą z oryginalnej Lasermanii) nie sprawi nikomu dużego problemu. Już po kilku minutach grania widać jest, że grze bardzo dużo brakuje do finalnej postaci. Nadal brakuje dźwięku, obsługi wielu plansz, czy wykrywania orientacji ekranu. Do aspektów tych wrócimy w kolejnych odsłonach cyklu, a teraz czas na...

RAFAŁ KOCISZ
Rafał Kocisz pracuje na stanowisku Dyrektora Technicznego w firmie Gamelion, wchodzącej w skład Grupy BLStream. Rafał specjalizuje się w technologiach związanych z produkcją oprogramowania na platformy mobilne, ze szczególnym naciskiem na tworzenie gier. Grupa BLStream powstała, by efektywniej wykorzystywać potencjał dwóch szybko rozwijających się producentów oprogramowania – 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 testowaniu gier. Kontakt z autorem: rafal.kocisz@game-lion.com

Rysunek 7. Plansza gry

www.sdjournal.org

75

Wywiad

Na fali zmian
Informacja to najcenniejszy zasób w firmie. EMC wie, jak sprawić aby ten zasób generował zyski - dzięki integracji sprzętu, oprogramowania i usług.
Bartosz Stebnicki
Software Developer's Journal: Proszę na początek powiedzieć naszym Czytelnikom kilka słów o sobie – kiedy rozpoczął Pan pracę w firmie EMC i z jakimi problemami zetknął się Pan pracując na obecnym stanowisku? Bartosz Stebnicki: W EMC pracuję już 8 lat i przez ten czas stawiłem czoła wielu wyzwaniom. Firma w tym czasie zmieniała się i rozwijała dynamicznie – od oferującej pojedynczy produkt do potężnej korporacji, która proponuje klientom kilkadziesiąt produktów. Miałem dużą przyjemność uczestniczyć w procesie rozwoju firmy, ale wymagało to także dużego wysiłku i sporego nakładu pracy. W tym czasie dokonaliśmy kilku akwizycji, pojawiali się w EMC nowi ludzie, firma zwiększała się obroty i rozrosła się z kilku do kilkudziesięciu zatrudnionych osób. SDJ: Czy wprowadził Pan jakieś rewolucyjne zmiany przejmując dowodzenie firmą na rynku polskim? Bartosz Stebnicki: Oczywiście wprowadziliśmy szereg istotnych zmian, ale raczej nie nazwałbym ich rewolucyjnymi. Na pewno pojawiło się kilka zmian w związku z postępującymi akwizycjami. Rozpoczęliśmy ekspansję na nowe rynki i otworzyły się przed nami kolejne możliwości. Tak więc w polskim oddziale EMC pojawiły się nowe obszary działania i możliwości rozwoju. Wprawdzie nie nastąpiła rewolucja, ale odnotowaliśmy bardzo szybki i harmonijny wzrost. SDJ: EMC swoje usługi oraz produkty kieruje głównie do klientów biznesowych. Czy macie Państwo także roz76

wiązania dla indywidualnych użytkowników? BS: Podjęliśmy już pewne kroki w tym kierunku: EMC przejęło firmę Iomega, która oferuje produkty dla rynku konsumenckiego. 10 lat temu zaczynaliśmy działania od współpracy z największymi firmami, naszymi klientami były m.in. PKO BP czy TP S.A. Później nasze produkty stawały się coraz bardziej powszechne. Myślę więc, że za jakiś czas produkty EMC można będzie nabyć nawet w sieciach handlowych, takich jak Carrefour czy Media Markt. SDJ: Które z produktów w bogatej ofercie EMC cieszą się największą popularnością i najlepiej się sprzedają? BS: Strukturę naszej firmy tworzą cztery główne działy odpowiadające specyfice produktów i usług : storage, oprogramowanie m.in. Documentum i Legato, trzecia część firmy to produkty związane z bezpieczeństwem i wreszcie czwarta – wizualizacja i rozrywka. Można nas przyrównać do 4-silnikowego samolotu. Obecnie każdy z wymienionych działów osiąga wyśmienite wyniki. SDJ: Czy dostrzega Pan już odpowiedni potencjał kadrowy do otwarcia centrum inżynierskiego EMC, czy woli nadal korzystać z usług podwykonawców takich, jak S4E? Na odpowiedź na to pytanie czeka jeden z naszych Czytelników. BS: Firma EMC świadczy usługi dedykowane i zauważyliśmy, że ich sprzedaż zwiększa się dużo szybciej niż sprzedaż licencji czy sprzętu. Natomiast nie planujemy obec11/2008

Wywiad
nie otwarcia centrum projektowego. Oferujemy usługi serwisowe, wdrożeniowe i na nich głównie skupiamy naszą uwagę na chwilę obecną. SDJ: Czy planujecie wprowadzenie takich usług jak otwarte szkolenia? Czy myślicie o przeprowadzaniu wykładów – czy to na uczelniach, czy za pośrednictwem jakiegoś centrum szkoleniowego? BS: Tak mamy takie plany. Dotychczas szkolenia były organizowane przez nasze polskie biuro, ale istniała także możliwość skorzystania ze szkoleń zagranicznych. Jednak w związku z szybko rosnącą liczbą klientów zamierzamy poszerzyć ofertę szkoleń przede wszystkim dla użytkowników naszych produktów. Ale chcemy również szerzej zaistnieć na uczelniach, gdzie specjaliści EMC mogliby przekazywać swoją wiedzę studentom. Mamy nadzieję, że działania te przyniosą za kilka lat korzyści nie tylko naszej firmie, ale też całemu rynkowi. Nasze podejście jest długoterminowe i podejmujemy wyzwania, które nie są obliczone jedynie na szybki, natychmiastowy efekt. SDJ: Jak ocenia Pan udział produktów EMC w polskim rynku pamięci masowych ? BS: To zależy, o jakim segmencie tego rynku mówimy. Na rynku dużych przedsiębiorstw jest to około 70%, a kilka procent w przypadku firm zaliczanych do SMB. SDJ: Czy w ramach swoich systemów operacyjnych korzystacie też z otwartego oprogramowania? BS: Z otwartego oprogramowania nie, aczkolwiek naszą dewizą jest otwartość naszych produktów na inne technologie. Oferowane przez nas rozwiązania współpracują z różnymi systemami operacyjnymi, jak np. systemy firm IBM, HP, ale też z systemem Linux – są to zatem systemy otwarte. SDJ: Proszę opowiedzieć o Państwa sukcesach na obszarze Data Center. Jakie macie osiągnięcia w tej materii. BS: Oprócz tradycyjnej gałęzi storage'owej, gdzie – tak jak wspomniałem – jesteśmy obecni u większości dużych klientów, uczestniczyliśmy również w projektowaniu oraz budowie kilku dużych centrów danych w Polsce. Nie chciałbym jednak podawać ich nazw. SDJ: Jak będzie wyglądać przyszłość w sektorze Data Center? BS: Myślę, że bez wykorzystania Data Center już wkrótce ciężko będzie nam się
www.sdjournal.org

obejść. Powstaje też pytanie, jakie to będzie Data Center? Można bowiem myśleć o ofercie outsourcingu, a więc wynajęciu powierzchni, gdzie stawiamy swój własny sprzęt, albo o ofercie szerszej i bardziej złożonej jak udostępnianie samej powierzchni dyskowej z gwarancją bezpieczeństwa i odpowiednio wysokiej wydajności. Taką usługę oferuje EMC – posiadamy duże możliwości i wydajną infrastrukturę, z której korzysta klient. Sądzę, że właśnie w tym kierunku będzie zmierzać sektor Data Center. SDJ: Jakie rozwiązania związane z bezpieczeństwem danych oferuje EMC? W jaki sposób archiwizowane i zabezpieczane są dane w oferowanych przez firmę rozwiązaniach. Jakie gwarancje daje EMC, że świadczone przez firmę usługi są w pełni bezpieczne? BS: Problem bezpieczeństwa widzimy bardzo szeroko, rozpatrujemy go na kilku poziomach – od płaszczyzny sprzętowej, gdzie same macierze są skonstruowane w sposób zapewniający ochronę danych i minimalizujący ryzyko ich utraty, poprzez przeniesienie danych do chronionej lokalizacji i ochronę dostępu do tych danych (tutaj korzystamy z rozwiązań RSA), aż po fizyczne zabezpieczanie danych – czyli odpowiednio chroniony budynek. Dzięki temu powstaje w pełni bezpieczna infrastruktura, przechowująca zaszyfrowane dane i zapewniająca dostęp do nich tylko upoważnionym osobom. SDJ: Czy Państwa centrum danych jest zlokalizowane gdzieś blisko czy korzystacie z zewnętrznej lokalizacji? BS: Usługa, którą zaczęło świadczyć EMC nosi nazwę Mozy i dotyczy zarówno rynku konsumenckiego, jak i rynku dużych klientów, infrastruktura na jej potrzeby, jest zlokalizowana poza granicami Polski. SDJ: Kilka tygodni temutemu miało miejsce otwarcie EMC Signature Solution Center w siedzibie firmy Wola Info. Jakie korzyści dla firmy EMC będzie miało otwarcie takiego centrum w Polsce? BS: Wspólnie z firmą Wola Info tworzymy centrum testowe. To miejsce, gdzie klienci mogą praktycznie zapoznać się z posiadaną przez nas, bardzo bogatą infrastrukturą, składającą się z serwerów firm trzecich, bibliotek taśmowych, macierzy dyskowych, przełączników i jeszcze kilku innych elementów. To centrum daje klientom możliwość przetestowania funkcjonalności i wydajności aplikacji bez konieczności sprowa-

dzania sprzętu bądź dalszego wyjazdu. Myślę, że daje to naszym klientom ogromne korzyści. SDJ: Jakie jest w samej firmie EMC podejście do bezpieczeństwa informacji? W jaki sposób firma zabezpiecza się przed wypływem informacji oraz przed atakami z zewnątrz? BS: Oczywiście wdrożyliśmy odpowiednie procedury, sprzęt i oprogramowanie jak firewall czy antywirusy. Jednak przede wszystkim staramy się uświadamiać użytkowników, co należy robić, a czego nie w zakresie bezpieczeństwa. Tu bowiem dostrzegamy największe ryzyko. I myślę tu nawet o tak prostych rzeczach jak blokowanie komputera odchodząc od biurka czy zmienianie haseł jak też nie pozostawianie na biurku ważnych dokumentów i korzystanie z niszczarki. Są to więc kwestie często mniej związane z IT a bardziej z kulturą pracy. O IT troszczy się nasza korporacja. SDJ: A czy zanotowaliście Państwo kiedyś próby włamań hakerów np. na stronę internetową korporacji? BS: Obawiam się, że gdy odpowiem przecząco, to takie próby się rozpoczną. Jednak dotychczas nie zanotowaliśmy takiego typu zdarzeń. Być może nikt nie uznał nas za firmę będącą atrakcyjnym celem podobnych ataków. SDJ: A jak ocenia Pan pisma dla profesjonalistów, takie jak Linux+ , SDJ, lub Haking9 – czy pisma te faktycznie docierają do specjalistów i gwarantują podnoszenie ich umiejętności? BS: Znam doskonale wszystkie te pisma i przyznam, że poziom szczegółowości zagadnień tam poruszanych jest wysoki. Jest to niewątpliwie świetne źródło informacji dla specjalistów. SDJ: Na koniec chcielibyśmy poznać Pana spostrzeżenia na temat rozwoju rynku IT w Polsce. Czy polski rynek nie potrzebuje obecnie silnego impulsu? Czy nie zostajemy gdzieś w tyle za rynkami europejskimi? BS: Polski rynek rozwija się i dojrzewa w szybkim tempie. Ale nie jest też tak, że my tylko staramy się dogonić innych, gdyż w wielu dziedzinach dorównujemy już bądź nawet wyprzedzamy inne rozwinięte rynki europejskie. Potencjał jest zatem olbrzymi. SDJ: Dziękujemy za rozmowę.

77

KLUB PRO
Jeżeli Twoja firma jest prenumeratorem Software Developer’s Journal za comiesięczną dopłatą 50 PLN +VAT możesz dodatkowo otrzymać reklamę. Wystarczy tylko, aby profil Twojej firmy pokrywał się z naszym magazynem. Wyślij do nas: logo firmy, dane kontaktowe i informację o firmie Reklama przez 12 kolejnych numerów tylko za 600 PLN +VAT. Jeżeli nie posiadasz jeszcze prenumeraty możesz ją zamówić w atrakcyjnej cenie. Dla nowych prenumeratorów specjalna oferta – 690 PLN.

Oferta skierowana dla firm

sdj@software.com.pl tel. 22 427 36 91 pren@software.com.pl http://buyitpress.com
Opera Software
Opera Software’s vision is to deliver the best Internet experience on any device. We are offering browser for PC/desktops and embedded products that operates across devices, platforms and operating systems. Our browser can deliver a faster, more stable and flexible Internet experience than its competitors. http://www.opera.com

Skontaktuj się z nami:

Architektury systemów IT

Twórca frameworków JUVE i serwera aplikacji AVAX oferuje usługi, doradztwo, rozwiązania do tworzenia nowoczesnych, dużych systemów i rozwiązań informatycznych/internetowych, integrujące architektury ery post-J2EE/.NET, wykorzystujące MDD/MDA dla dziedzin – bankowość, telekomunikacja, handel, e-commerce, ERP/Workflow/ CRM, rozwiązania internetowe, portalowe. www.mpsystem.com mpsystem@mpsystem.com

FRONTLINE STUDIOS

Frontline Studios – amerykańsko-polski twórca gier konsolowych oraz PC – szuka utalentowanych koderów (bardzo dobra znajomość C/C++; Java, Delphi, UML), doświadczonych grafików (2D, 3D) oraz zespołów developerskich. Oferujemy długoterminową pracę nad poważnymi projektami. Nie przegap tej okazji! kadry@frontstudios.com

Future Processing

Future Processing to dynamiczna firma technologiczna działająca na globalnym rynku oprogramowania. Jesteśmy zespołem wysokiej klasy specjalistów posiadających wiedzę i doświadczenie niezbędne do realizacji ambitnych projektów informatycznych. Jeśli programowanie to Twoja pasja dołącz do nas! (możliwość pracy zdalnej). http://www.future-processing.pl

Kei.pl

Kei.pl działa na rynku usług hostingowych od 2000 roku. Do naszych zadowolonych Klientów z dumą możemy zaliczyć wiele przedsiębiorstw sektora MSP, instytucji oraz osób prywatnych. W ofercie Kei.pl znajdują się pakiety hostingowe, a także usługi dla wymagających Użytkowników – platformy e-Biznes oraz serwery fizyczne. http://www.kei.pl

KLUB PRO
StatConsulting TTS Company Sp. z o.o.

StatConsulting to firma o znaczącej pozycji na rynku usług analitycznych oraz Data Mining. Nasza oferta obejmuje m.in. modele scoringowe, rozwiązania Fraud Detection oraz modelowanie ryzyka. Tworzymy także własne rozwiązania informatyczne na potrzeby projektów Data Mining, Data Quality, zarządzania ryzykiem itd. http://www.statconsulting.com.pl

Sprzedaż i dystrybucja oprogramowania komputerowego. Import programów na zamówienie. Ponad 200 producentów w standardowej ofercie. Chcesz kupić oprogramowanie i nie możesz znaleźć polskiego dostawcy? Skontaktuj się z nami – sprowadzimy nawet pojedyncze licencje. http://www.OprogramowanieKomputerowe.pl

Transition Technologies S.A.

Firma w branży high-tech od 1991. Producent oprogramowania dla przemysłu (ponad 350 referencji z instalacji na całym świecie). Usługi z zakresu: hurtownie danych i Business Intelligence, rozwiązania eBusiness, optymalizacja, integracja danych, aplikacji oraz procesów biznesowych, portale korporacyjne, consulting i outsourcing usług IT, zaawansowana automatyka cyfrowa. http://www.tt.com.pl

EPRO

Naszą misją jest projektowanie najwyższej jakości dedykowanych systemów IT, które cechuje wysoka niezawodność, wydajność, ergonomiczność i intuicyjność w obsłudze oraz administracji. Głównym elementem oferty EPRO jest oprogramowanie sklepu internetowego oraz identyfikacja wizualna. tel. 085 743 66 38 http://www.epro.com.pl

IT SOLUTIONS

IT SOLUTIONS

Wdrożenia i szkolenia z zakresu: • SQL Server • SharePoint Services • MS Project / Server • Tworzenie aplikacji w technologii .NET http://www.itsolutions.biz.pl marcin.pytlik@itsolutions.biz.pl

Softline rozwiązania mobilne

Wiodący producent systemów mobilnych, dostawca aplikacji użytkowych dla biznesu (Symbian OS, Windows Mobile, J2ME ) zaprasza do współpracy. Zostań naszym partnerem. Dołącz do zespołu. http://www.softline.com.pl

Proximetry Poland Sp. z o.o.

Proximetry Poland Sp. z o.o. jest polskim oddziałem amerykańskiej firmy Proximetry Inc. – dostawcy systemów zarządzania sieciami bezprzewodowymi opartymi na technologiach WiFi i WiMAX. Naszą misją jest dostarczenie klientom rozwiązań poprawiających jakość usług (QoS) dostarczanych drogą radiową. Dołącz do najlepszych i zostań członkiem naszej ekipy! http://www.proximetry.com

SWD Software Sp. z o.o

System operacyjny czasu rzeczywistego RTOS QNX. Oficjalny dystybutor w Polsce. Zakres działalności: lokalizacja produktów QNX, dostawy sprzętu i oprogramowania, doradztwo przedsprzedażowe, wsparcie techniczne, certyfikowane szkolenia, opracowania na zamówienie. http://www.swdsoft.pl

Roczna prenumerata

250,Software Developer’s Journal (poprzednio Software 2.0) jest miesięcznikiem głównie dla programistów, którzy liczą, że dostarczymy im gotowe rozwiązania, oszczędzają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.

tylko

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

Zamówienie prenumeraty
Prosimy wypełniać czytelnie i przesyłać faksem na numer: 00 48 22 244 24 59 lub listownie na adres: Software-Wydawnictwo Sp. z o. o. ul. Bokserska 1 02-682 Warszawa Polska E-Mail: pren@software.com.pl Przyjmujemy też zamównienia telefoniczne: 0048 22 427 36 91 0048 22 427 36 79 0048 22 427 36 50 Jeżeli chcesz zapłacić kartą kredytową, wejdź na stronę naszego sklepu internetowego www.buyitpress.com. Imię i nazwisko ............................................................................... Nazwa firmy..................................................................................... Dokładny adres .............................................................................. ......................................................................................................... Telefon ............................................................................................ E–mail ............................................................................................. ID kontrahenta ................................................................................ Numer NIP firmy ............................................................................. Fax (wraz z nr kierunkowym) .........................................................

□ automatyczne przedłużenie prenumeraty

Prenumerujesz – zyskujesz
l

l l l

oszczędność pieniędzy szybka dostawa prezenty bezpieczna płatność ność on–line

Tytuł
Software Developer’s Journal (1 płyta CD) – dawniej Software 2.0

Ilość Od Ilość zama- numeru nume- wianych pisma rów prenume- lub mierat siąca

Cena

12

180*/ 250 PLN

* cena prenumeraty rocznej dla osób prywatnych

W NASTĘPNYM NUMERZE SOFTWARE DEVELOPER’S JOURNAL 12/2008 168

SYSTEMY OPERACYJNE
Technologia Adobe Flash w systemach wbudowanych

SZTUCZNA INTELIGENCJA
Miary entropii w sztucznej ewolucji programów komputerowych

PROGRAMOWANIE JAVA
Obliczenia numeryczne w programach komputerowych

PROGRAMOWANIE PHP
Zaawansowana obróbka grafiki w PHP

NOWE ARTYKUŁY W DZIAŁACH
Biblioteka miesiąca Testowanie oprogramowania
I WIELE INNYCH ARTYKUŁÓW, KTÓRYCH NIE MOŻESZ PRZEOCZYĆ!

W spr

zedaż y

od 18 listop ada

Redakcja zastrzega sobie możliwość zmiany zawartości pisma.
11/2008

82

You're Reading a Free Preview

Pobierz
scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->