92

Software Developer's Journal 01/2007 PL

Embed Size (px)

DESCRIPTION

Tematy numeru:* GWT – WEB 2.0 na maksa* Rozszerzenia środowiska bazodanowego Kexi* Progress Software Progress Sonic ESB– tworzenie usług w środowiskuProgress Sonic Workbench* Magic eDeveloper– zadaniowe podejście do programowania* Quartz – zarządzanie zadaniami w J2SE/J2EE* e-Poltax* Business Process Execution Language* Aplikacje Java w telewizji interaktywnej

Citation preview

Page 1: Software Developer's Journal 01/2007 PL
Page 2: Software Developer's Journal 01/2007 PL
Page 3: Software Developer's Journal 01/2007 PL
Page 4: Software Developer's Journal 01/2007 PL

4

Spis treści

www.sdjournal.org Software Developer’s Journal 01/2007

Aktualności 6

Opis CD 12

Sprostowanie 23

Tam byliśmy 24

Wywiad z Dave'em Chappelem 68

Kasa dla programisty 72

Algorytmy: Licytacja 74

Felieton 86

Księgozbiór 87

Zapowiedzi 90

Noworoczne postanowieniaHo ho ho zaczęło wydobywać się z naszego redakcyjnego serwera. Wzbu-dziło to w nas niejaką konsternację, ale nie do takich rzeczy jesteśmy przy-zwyczajeni. Dochodzące nie wiadomo skąd dźwięki dzwoneczków też nie dały nam specjalnie do myślenia. Przemykające to tu to tam grupki rado-snych kolędników obudziły w nas lekkie podejrzenia. Ale pewności nabrali-śmy dopiero kiedy jedna z koleżanek wpadła do redakcji z okrzykiem Świą-teczne wyprzedaże!!!

No tak, to właśnie nadeszła TA pora. Trzeba sie sprężyć i wymyślić coś ekstra. Komisja złożona z najszacowniejszych członków naszej małej społecz-ności po spędzeniu nocy na selekcjonowaniu genialnych i megakreatywnych pomysłów stwierdziła co następuje:

l Primo – Z okazji Świat Bożego Narodzenia naszym czytelnikom wszyst-kiego co najlepsze! Howgh!

l Secundo – Świątecznego bonusa w postaci 8 dodatkowych stron! Howgh!l Tertio – Stały i niezwykle interesujący- brand new-dział Kasa dla Progra-

misty, a w nim same smaczności. Możliwości jakie oferują polskie firmy informatyczne swoim pracownikom. Doświadczenia programistów, którzy przeszli od hobby do zawodowstwa. Odsłona pierwsza: wywiad z Marci-nem Kuciębą – Software Developer Manager Centrum Rozwoju Oprogra-mowania Sabre w Krakowie. Howgh!

Żeby dopieścić Wasz zmysł estetyczny zmieniliśmy design płytek. Ponadto, uroczyście przyrzekamy, i niech nas to i owo, jeśli zełgaliśmy, nadal ciężko pracować i oddać w Wasze ręce płytkę z czytelnym i łatwym w obsłudze indeksem. Howgh!

DO SIEGO ROKU!!!

Magdalena [email protected]

1/2007 (145)

Miesięcznik Software Developer’s Journal (12 numerów w roku)jest wydawany przez Software-Wydawnictwo Sp. z o. o. Dyrektor wydawniczy: Jarosław SzumskiRedaktor naczelny: Sylwia Pogroszewska [email protected]: Magdalena Filip [email protected] redaktora: Katarzyna Kober [email protected] produkcji: Marta Kurpiewska [email protected] graficzne: Robert Zadrożny [email protected]ład i łamanie: Robert Zadrożny [email protected] okładki: Agnieszka MarchockaOpracowanie CD: Aurox Core Team [email protected] aktualności: Rafał KociszTłumaczenie: Rafał KociszKorekta: Piotr OzaistStali współpracownicy: Stefan TuralskiBetatesterzy: K. Boguś, K. Kokosa, Ł. Lechert, Ł. Witczak, M. Cylke, M. Mucha, R. ZacharczykDział reklamy: [email protected]: Marzena Dmowska [email protected] tel.: (22) 887 14 44Nakład: 6 000 egz.

Adres korespondencyjny: Software-Wydawnictwo Sp. z o. o., ul. Bokserska 1, 02-682 Warszawawww.sdjournal.org [email protected] tel. (22) 887 10 10

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

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

Płyty CD dołączona do magazynu przetestowano programem AntiVirenKit firmy G DATA Software Sp. z o.o.Redakcja używa systemu automatycznego składu

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

Pismo ukazuje się w następujących wersjach językowych: polskiej , angielskiej .

Page 5: Software Developer's Journal 01/2007 PL

5www.sdjournal.orgSoftware Developer’s Journal 01/2007

Biblioteka Miesiąca Quartz – zarządzanie zadaniami w J2SE/J2EE 16Piotr AniołaPiotr przedstawi otwartą bibliotekę wspomagającą harmonogramowanie zadań, którą można zintegrować z dowolną aplikacją J2EE lub J2SE. Pokaże nam jak budować proste i złożone harmonogramy.

Aplikacje Biznesowee-Poltax 26Janusz GanczarskiJanusz przedstawi w artykule budowę i funkcjonowanie aplikacjii elekronicz-nych na podstwie elektronicznych formularzy rozliczeń podatkowych (PIT) systemu e-Poltax.

Business Process Execution Language 36Piotr SkrobiszPiotr zapozna nas z podstawami i najczęściej używanymi elementami języka Oracle Business Process Execution Language.

Programowanie w JavaAplikacje Java w telewizji interaktywnej 44Tomasz KuprowskiTomasz przedstawi w artykule wykorzystanie Javy w telewizji interaktywnej. Pokaże w jaki sposób napisać zananą wszystkim grę Snake.

WarsztatyGWT – WEB 2.0 na maksa 50David de RosierDavid roztoczy przed nami kuszące możliwości Google Web Toolkit. Opisze prace z projektami GTW, pisanie własnych komponentów oraz transfer kodu Java na JavaScript.

Bazy DanychRozszerzenia środowiska bazodanowego Kexi 60Jarosław StaniekJarek przedstawi rozszerzenia środowiska Kexi, które to narzędzie przekłada łatwość tworzenia i rozwijania aplikacji bazodanowych nad bogactwo zaawan-sowanych opcji.

Kluby techniczneProgress Software Progress Sonic ESB 78– tworzenie usług w środowisku Progress Sonic WorkbenchArtykuł przybliży pojęcia związane z usługami ESB oraz zaprezentuje w jaki sposób stworzyć nową klasę usług przy uzyciu Progress Sonic Workbench.

Magic eDeveloper 80– zadaniowe podejście do programowaniaArtykuł przybliży ideę stosowania zdarzeniowego podejścia do programowania.

Page 6: Software Developer's Journal 01/2007 PL

6

www.sdjournal.orgAktualności

www.sdjournal.org Software Developer’s Journal 01/2007

Microsoft nawiązuje współpracę z Zend TechnologiesMicrosoft zawarł porozumienie z Zend Technolo-gies – firmą odpowiedzialną za rozwijanie języka PHP. Współpraca między obydwoma firmami ma opierać się przede wszystkim na podejmowaniu działań mających na celu zwiększenie integra-cji języka PHP z takimi platformami jak Win-dows Server 2003 oraz Windows Server code-name Longhorn. Owocem tego przedsięwzięcia ma stać się również wzbogacenie funkcjonalno-ści języka w odniesieniu do technologii Micro-softu. Jak dotychczas Zend skupiał uwagę jedy-nie na rozwiązaniach otwartych, przez co PHP był dedykowany głównie do współpracy z ser-werem Apache. W momencie zawarcia poro-zumienia, firmy zadeklarowały zmodyfikować i usprawnić swoje produkty w taki sposób, aby jeszcze lepiej mogły one ze sobą współpra-cować. Microsoft ma stworzyć między innymi nowy składnik FastCGI dla wbudowanego w Windows Server 2003 serwera IIS, który zin-tegruje IIS i PHP. Składnik ten będzie dostępny na stronie www.iis.net dla użytkowników Win-dows XP, Windows Server 2003, Windows Vista oraz Widnows Server codename Longhorn. Zend będzie z kolei opracowywał w swoim labo-ratorium nowe wersje PHP oraz przygotowy-wał je do działania na platformie serwerowej Microsoft. Planowane jest także dostosowanie produktów Zend Technologies (między innymi Zend Core) do współpracy z Windows Server, aby zoptymalizować działanie aplikacji PHP oraz przeprowadzać testy wydajnościowe. Jak widać plany są bardzo ambitne, oraz co ważne – korzystne dla obu stron: Microsoft zdobędzie nowych odbiorców dla swoich produktów, zaś Zend może liczyć na zwiększone zainteresowa-nie językiem PHP w gronie użytkowników plat-formy Windows Server System. http://betanews.com/

OpenBSD 4.0Pojawiła się kolejna stabilna wersja dystrybucji typu UNIX z rodziny BSD: OpenBSD 4.0. System ten powstał powstał w 1995 roku jako efekt roz-łamu w zespole NetBSD. Nowe OpenBSD to już 20 wydanie na płycie CD (21 udostępnio-ne jest na serwerach FTP). Autorzy są bardzo dumni z tej dystrybucji miedzy innymi dlatego, że przez 10 lat istnienia systemu odnotowano tylko jedną dziurę w standardowym instalatorze. W wersji 4.0 znajdziemy pokaźną listę popra-wek, aktualizacji i nowości, z którymi można szerzej zapoznać się na przeznaczonej po temu witrynie internetowej (http://www.openbsd.org/plus40.html). Przedstawiona jest tam lista wprowadzonych zmian w stosunku do ostatniej stabilnej odsłony systemu oznaczonej numerem 3.9. Najnowszą wersję OpenBSD można pobrać ze strony twórców.http://www.openbsd.org/

Google CodeJam 2006 zakończoneZakończył się tegoroczny konkurs programi-styczny Code Jam organizowany przez Google. Zwyciężył dwudziestojednoletni Petr Mitrichev z Rosji, drugie miejsce zdobył Ying Wang z USA, trzeci był Andrey Stankevich, także z Rosji. Nagroda za pierwsze miejsce wyniosła 10 tysię-cy dolarów, osoby które zajęły miejsca od dru-giego do dziesiątego dostały o połowę mniej. Tegoroczna, czwarta edycja Code Jam zgroma-dziła 21 tysięcy uczestników z ponad stu krajów. Tysiąc osób zakwalifikowało się do dwuetapo-wych rozgrywek, z czego setka przeszła do ści-słego finału, który odbył się w siedzibie firmy w Nowym Jorku. Uczestnicy w zależności od wła-snych preferencji programowali w języku Java, C++, C#, Python lub VB.NET.http://www.google.com/

Firefox 2

Po długim i burzliwym okresie oczekiwania Mozilla wypuściła stabilną wersję swojej sztandaro-

wej, otwartej przeglądarki Firefox, ozna-czonej wersją 2.0. Nowy Lisek w porów-naniu do poprzedniej wersji (1.5.0.7) wnosi całkiem sporo nowości. Pierw-sze, co rzuca się w oczy to odświeżony interfejs użytkownika i nowa domyślna skórka. Prócz tego mamy do dyspozy-cji wbudowaną ochronę przed stronami służącymi do kradzieży danych poprzez podszywanie się pod inne witryny (na przykład banków czy systemów aukcyj-nych). Firefox może weryfikować strony z wewnętrzną listą lub odpytywać Go-ogle. Wbudowana wyszukiwarka posia-da teraz funkcję podpowiedzi (działają-cą obecnie tylko w przypadku Google, Yahoo! i Answers.com), automatycznie uzupełniającą wpisywane przez nas fra-zy, uproszczono także dodawanie no-wych wyszukiwarek. Poprawiono obsłu-gę kart, każda karta posiada przycisk zamykania, dostępna jest też wygodna lista wszystkich otwartych kart. Z menu Historia mamy także dostęp do ostat-nio zamkniętych kart. Domyślnym za-chowaniem przeglądarki jest otwiera-nie stron w nowej karcie zamiast w no-wym oknie. W przypadku awarii przeglą-darki mamy możliwość przywrócenia se-sji, czyli otwartych stron, tekstu wpisa-nego w formularzach i aktualnie pobie-ranych plików. Bezpośrednio z poziomu przeglądarki możemy podglądać kana-ły RSS i sprawdzać pisownię w polach tekstowych (także po polsku). Mene-dżer zakładek rozszerzony został o tak zwane mikro-podsumowania, czyli za-kładki w których zamiast tytułu wyświe-tlają się na bieżąco aktualizowane dane z treści strony. Nowy Firefox obsługuje także język skryptowy JavaScript w wer-sji 1.7. Jak można przeczytać na blo-gu Mike'a Beltzner – dewelopera Fire-foxa – wersja 2.0 przeglądarki w ciągu pierwszych 24 godzin od wypuszczenia w wersji stabilnej została pobrana po-nad 2 miliony razy. Daje to średnią przekraczającą 30 ściągnięć na sekun-dę. Wynik ten jest bardzo dobry; dla porównania największy konkurent Fi-refox 2.0 – Internet Explorer 7 w cią-gu pierwszych 4 dni od premiery odno-tował trochę ponad 3 mln pobrań. Jest to zapewne ciekawy materiał do analizy i przemyśleń – więcej na ten temat moż-

na przeczytać w blogu Beltznera. Prze-glądarka Mozilla Firefox 2.0 przebojowo weszła na rynek, niestety, pojawiły się też problemy rzucające cień na ten suk-ces. Dla przykładu serwis listvine.com wymienia powody, które mogą postawić migrację z wersji 1.5 na 2.0 pod zna-kiem zapytania. Wielu użytkownikom nie spodobał się nowy interfejs, który uznano za mało ergonomiczny. Funk-cje antyphishingowe są dosyć proste a ponadto mogą stanowić zagrożenie dla prywatności. Często pojawiają się problemy z kompatybilnością istnieją-cymi dodatkami. Firefox 2.0 na skutek wycieku pamięci potrafi zajmować du-żą ilość RAMu. Problem ten był często zgłaszany przed wydaniem wersji final-nej. Występują problemy z obsługą CSS co przeszkadza w wyświetlaniu niektó-rych stron. Firefoksowi 2.0 zdarza się zawiesić w losowych momentach. Użyt-kownicy narzekają też na problemy z hi-storią, a także, gorszą niż w wersji 1.5, obsługą RSS. Z kolei SecurityFocus po-daje, że krytyczna dziura wykryta przez Michała “lcamtufa” Zalewskiego istnie-je nadal w Firefoksie 2.0 mimo, że za-łatano ją w Firefoksie 1.5.0.5. Przykła-dy te, a także szybko wykrywane dziury w Internet Explorerze pokazują, jak trud-nym zadaniem jest obecnie tworzenie przeglądarek. Nie wystarczy samo prze-twarzanie kodu HTML; trzeba wspierać wiele standardów, rozszerzeń a przy tym cały czas pamiętać o bezpieczeństwie. Wygląda na to, że chwilą wydania Fire-Fox 2.0 i Internet Explorera 7.0 wojna przeglądarek rozgorzeje na nowo, zaś jej wyniki będą zależeć głównie od szyb-kości wydawania łatek na dziury i błędy zgłaszane przez użytkowników.

http://www.slashdot.org/http://www.beltzner.ca/mike/http://listvine.comhttp://www.securityfocus.com

Page 7: Software Developer's Journal 01/2007 PL

www.sdjournal.org

Microsoft walczy z piractwem na aukcjachFirma Microsoft rozpoczęła akcję przeciwko osobom sprzedającym nielegalne oprogramowa-nie na internetowych aukcjach. Przygotowano już 50 pozwów, z czego 15 złożono w Stanach Zjed-noczonych, 10 w Niemczech i Holandii, a po pięć we Francji i Wielkiej Brytanii. Dodatkowe sprawy zostały złożone także w Polsce, Argentynie, Australii, Belgii i Korei. Akcja przeciwko aukcjom jest kolejnym krokiem szeroko zakrojonej kampa-nii przeciwko piratom. Według szacunków organi-zacji Business Software Alliance, około jedna trze-cia instalowanego oprogramowania jest nielegal-na. Z przeprowadzonych przez Microsoft testów wynika, że prawie połowa aukcji sprzedających programy firmy Microsoft oferuje nielegalne opro-gramowanie. Firma Microsoft ostrzega też, że w wielu przypadkach sprzedawane produkty są zarażane wirusami, trojanami i innymi szkodni-kami. Od czerwca 2005 roku ponad 500 milio-nów użytkowników uruchomiło na swoich kompu-terach narzędzie do sprawdzania legalności (Win-dows Genuine Advantage). Spośród nich, 21 pro-cent systemów zostało zidentyfikowane jako nie-legalne. http://www.cnet.com/

Vista za droga dla producentów komputerówGigant z Redmond wyraził sprzeciw wobec sprze-dawania przedsiębiorstwom domowych wersji systemów operacyjnych. Sprzedawcy sprzętu komputerowego w celu minimalizacji kosztów proponują klientom zakup tańszej, ale wystar-czającej do prowadzenia małej firmy, domowej wersji oprogramowania. Różnica cenowa między domową i biurową wersją systemu operacyj-nego Windows XP waha się od 25 do 50 USD. W przypadku nowej Visty, różnica ta ma być dużo wyższa, bo sięgająca aż 100 USD. W ofercie firmy Microsoft znajdą się trzy wersje domowe oraz dwie biurowe nowego systemu. Producent oprogramowania zapowiedział, że będzie kładł większy nacisk na odpowiednie dopasowanie danej wersji do jego zastosowania. Microsoft zamierza zlikwidować lukę rynkową, powodo-waną przez próbujących obniżyć koszty sprzętu sprzedawców i wymusić dostarczanie biurowych wersji oprogramowania do firm, a wersji domo-wych do prywatnych użytkowników. http://www.4press.pl/

Ubuntu 6.10 Edgy Eft

Zgodnie z zapowiedziami ukazała się kolejna wersja najpopularniej-szej dystrybucji Linuksa – Ubun-

tu 6.10 Edgy Eft. Nowe Ubuntu to przede wszystkim nowa wersja środowiska GNO-ME (2.16), oba projekty są ściśle ze so-bą związane, można pokusić się o stwier-dzenie, że to właśnie w tym systemie GNO-ME najlepiej prezentuje swoje możliwo-ści. Pierwszą rzucającą się w oczy nowo-ścią jest odświeżony wygląd ikon systemo-wych, a także poprawa szybkości działania środowiska i wchodzących w jego skład narzędzi. Nowe GNOME lepiej zarządza energią, co w laptopach pozwala na dłuż-szą pracę na baterii, a dodatkowo w pane-lu ustawień dostępny jest wykres, z które-go łatwo można zorientować się na ile pra-cy starczy prądu. Nowe narzędzie Baobab pozwoli usprawnić kontrolę wolnego miej-sca na dysku. Osoby niewidome z pewno-ścią ucieszą się z nowego czytnika ekra-nowego Orca używającego technologii AT-SPI. Przeglądarka WWW Epiphany posia-da funkcję sprawdzania pisowni w polach tekstowych, a wbudowana nagrywarka płyt CD ma już możliwość bezpośredniego na-grywania DVD. Odnośnie kwestii specy-ficznych dla Ubuntu to dla wydania Edgy Eft przygotowano nowy schemat graficz-ny, obejmujący wygląd środowiska, okna logowania, tapetę, skórkę dla Firefoksa, a także ekran pokazywany podczas star-tu systemu. W nowym Ubuntu znajdziemy domyślnie zainstalowany system notatek Tomboy, program do zarządzania zdjęcia-mi F-spot, nową wersję rozbudowanego

R E K L A M A

klienta poczty Evolution (2.8.0), pakiet biu-rowy OpenOffice 2.0.4 RC2 i betę komu-nikatora Gaim 3.1. Do dyspozycji mamy także najnowszą wersję przeglądarki Fire-fox 2.0. Jedną z istotniejszych zmian w no-wym Ubuntu jest Upstart. Jest to nowocze-sny zamiennik procesu init, który mówiąc w dużym uproszczeniu odpowiada za uru-chamianie wszystkich innych procesów w systemie. Init jest rozwiązaniem wywodzą-cym się jeszcze z czasów początków Linuk-sa i mimo wielu poprawek niezbyt dobrze radzi sobie na przykład z dynamicznie pod-łączanymi urządzeniami. Ubuntu jest pierw-szym systemem w którym został wdrożony Upstart. Najnowszą wersję Ubuntu Edgy Eft 6.10 można pobrać ze strony twórców. Kolejne Ubuntu (wersja 7.04) ma ukazać się 19 kwietnia 2007, będzie nosiło nazwę The Feisty Fawn.

http://www.ubuntu.com/https://wiki.ubuntu.com/EdgyReleaseNotes/http://kubuntu.org/http://www.edubuntu.org/

Page 8: Software Developer's Journal 01/2007 PL

8

www.sdjournal.orgAktualności

www.sdjournal.org Software Developer’s Journal 01/2007

Więzienie i grzywny za torrentyJak donosi serwis CDRInfo.pl, po raz pierwszy w historii do więzienia trafiła osoba za prowa-dzenie strony z plikami torrent. Mimo, iż strona nie zawierała żadnych plików naruszających prawa autorskie, a tylko pliki z informacją skąd je pobrać sąd uznał administratora winnym. Wyrok to 5 miesięcy więzienia plus 5 miesięcy dozoru domowego i 3.000 grzywny dla 23-let-niego Granta Stanleya z USA. Stanley przyznał się do winy. Jest jednym z trzech oskarżonych w wyniku akcji FBI i MPAA. Podobna sprawa ma równolegle miejsce w Finlandii. W ciągu trzech miesięcy roku 2004 za pomocą strony Finreac-tor użytkownicy wymienili 29.625 terabajtów danych. 16.000 gier, 136.000 filmów, 274.000 albumów z muzyką... Czterech administratorów strony Finreactor przyznało się do winy. Zosta-li ukarani grzywnami w wysokości 60.000 dola-rów każdy. Kolejnych 21 administratorów zosta-ło uznanych winnymi przez sąd w Finlandii. Będą musieli zapłacić odszkodowania w wysokości 700.000 dolarów. Sprawy kolejnych osób nadal się toczą – oskarżonych zostało łącznie 32 administratorów fińskiej strony. http://cdrinfo.pl/

MTS 2006Zakończył się Microsoft Technology Summit 2006 – największa tegoroczna konferencja tech-niczna Microsoft w Polsce, kierowana do specja-listów IT i programistów. Dla wszystkich, którzy nie mieli okazji uczestniczyć w tym wydarzeniu osobiście organizatorzy przygotowali transmisje na żywo w Internecie, z wybranych sesji konfe-rencji. Podczas tegorocznej, drugiej już edycji konferencji Microsoft Technology Summit, odbyło się 114 sesji technicznych i 9 bizneso-wych pokrywających aż 9 obszarów tematycz-nych, stanowiących przekrój przez wszystkie technologie Microsoftu. Sesje były prowadzone przez 86 najlepszych ekspertów z Polski i zagra-nicy. Wśród prelegentów byli między innymi Rafał Łukawiecki (ekspert w dziedzinie bezpie-czeństwa IT, wybrany najlepszym wykładowcą konferencji jak IT Forum i TechEd 2005), oraz Fred Baumhardt – wybitny konsultant do spraw bezpieczeństwa firmy zatrudniony w Microsof-cie. W konferencji uczestniczyło ponad 2500 osób. Uczestnicy korzystali z laboratorium wyposażonego w ponad 70 komputerów, sieci WiFi, a także salonu multimedialnego Windows Media Center. Patrząc na ogromne zaintereso-wanie środowiska konferencją, którego efektem jest ponad 2500 zarejestrowanych uczestni-ków, można stwierdzić, że wydarzenie to ma już ugruntowaną pozycję w kalendarzu imprez tech-nologicznych odbywających się w Polsce.http://wss.pl/

Wyniki f inansowe Microsoftu wyższe od spodziewanychMicrosoft opublikował swoje wyniki finansowe za pierwszy kwartał roku fiskalnego 2007 (trzeci kwartał roku kalendarzowego 2006). Korpora-cja odnotowała 11-procentowy wzrost zarów-no obrotów jak i zysków w stosunku do analo-gicznego okresu w roku poprzednim. Przycho-dy wyniosły 10,8 miliarda dolarów w stosunku do prognozowanych 10,7 mld dolarów. Dochód osiągnął poziom 3,48 mld dolarów. Na oprogra-mowaniu klienckim, na które składa się głównie system Windows, Microsoft zarobił 2,6 miliarda dolarów. Oprogramowanie serwerowe przynio-sło 827 milionów dolarów. Znaczący udział miał tutaj SQL Server 2005. Dział usług online przy-niósł 539 mln dolarów dochodu przy 136 milio-nach dolarów straty. MS Office i oprogramowa-nie biznesowe wygenerowały przychody rzędu 3,4 miliarda dolarów. Sprzedaż w dziale Enter-tainment and Devices wzrosła o 70%, głównie dzięki konsoli Xbox.http://wss.pl/

IE7

Po długich pracach Microsoft udostępnił do pobrania finalną wersję swojej flagowej przeglą-

darki webowej: Internet Explorer 7. Naj-nowsza wersja tej jak dotąd najpopular-niejszej na świecie przeglądarki inter-netowej przynosi wiele nowości. Naj-ważniejszą z nich jest bardzo długo wy-czekiwana i niezwykle przydatna możli-wość przeglądania wielu witryn z pozio-mu jednego okna aplikacji. Właściwość ta zwana potocznie obsługą zakładek od bardzo dawna dostępna była w pro-duktach konkurencji. Kolejne uspraw-nienia to zmieniony i uproszczony in-terfejs zapewniający więcej powierzch-ni na wyświetlanie witryn (szczególnie w trybie pełnoekranowym, dostępnym po wciśnięciu klawisza F11), zintegro-wany czytnik wiadomości nadawanych przy pomocy kanałów RSS, zintegro-wane okienko wyszukiwarki, ulepszo-ne drukowanie dzięki automatyczne-mu dopasowywaniu wielkości tekstu, funkcje anty-phishingowe zabezpiecza-jące przed kradzieżą osobistych da-nych i kradzieżą tożsamości, udosko-nalona obsługa stylów CSS 2.1. No-wa wersja przeglądarki obsługuje po-nadto przezroczystość plików graficz-

nych w formacie PNG. Najnowszego In-ternet Expolrera 7 można pobrać z pol-skiej witryny firmy Microsoft. Na stro-nie tej można znaleźć również pełne in-formacje o nowej przeglądarce, w tym instrukcję instalacji. Na razie nie wia-domo dokładnie kiedy zostanie wyda-na wersja polskojęzyczna. Microsoft na blogu IE7 ujawnił nieco statystyk doty-czących pobrań nowej przeglądarki In-ternet Explorer 7. Tylko w ciągu czte-rech pierwszych dni nową przeglądar-kę pobrało ponad trzy miliony użytkow-ników! Wynik jest z pewnością imponu-jący, a będzie prawdopodobnie jeszcze większy gdy Internet Explorer 7 zacznie być dystrybuowany wraz z bieżącymi poprawkami systemowymi w ramach automatycznych aktualizacji.

http://www.microsoft.com/poland/http://blogs.msdn.com/ie/default.aspx

Google Code Search

Firma Google uruchomiła no-wą usługę Google Code Search umożliwiającą przeszukiwanie

kodu źródłowego dostępnego w Inter-necie. Serwis ten pozwala między in-nymi na znalezienie fragmentów ko-du, w których można precyzyjnie okre-ślić rodzaj licencji i język programowa-nia. Dodatkowo umożliwia stosowanie wyrażeń regularnych (wspierana jest rozszerzona składnia wyrażeń regular-nych POSIX), ciągów znaków czy nazw paczek. Użytkownicy nowej usługi mo-gą korzystać zarówno z uproszczone-go jak i zaawansowanego interfejsu wy-szukiwania. Ponieważ rezultaty poszu-kiwań dostępne są w formatach GData oraz XML feed, można spodziewać się, że niedługo powstaną wtyczki do IDE pozwalające korzystać z dobrodziejstw Google Code Search z wewnątrz tych aplikacji. Google Code Search jest kolejnym ukłonem ze strony Google w kierunku społeczności programistów, a jednocześnie świadczy o próbie budo-

wy kompleksowego zestawu serwisów dedykowanych dla tego właśnie środo-wiska. Na dzień dzisiejszy trudno prze-widzieć powodzenie tego przedsięwzię-cia. Problem w tym, że rozwiązanie Go-ogle będzie musiało wytrzymać konku-rencję istniejących już na rynku podob-nych, lub pokrewnych rozwiązań – cho-ciażby Krugle czy Planet Source Code.

http://www.google.com/codesearchhttp://www.google.com/codesearch/advanced_code_searchhttp://www.google.com/help/faq_code-search.html

Page 9: Software Developer's Journal 01/2007 PL

www.sdjournal.org

Konferencja Adobe MAX 200623-26 października w Las Vegas odbyła się pierw-sza konferencja od czasu połączenia Adobe z Macromedią. W spotkaniu wzięli udział specja-liści i pasjonaci z całego świata. Głównym tema-tem była technologia Apollo, będąca rozszerze-niem technologii Flex, oraz nakreślenie przyszłości i kierunku rozwoju Adobe. Apollo jest projektem, który pozwoli uruchamiać Rich Internet Applica-tions (RIA) na każdym komputerze bez pośrednika jakim obecnie jest przeglądarka internetowa. Pre-zenterzy poruszali także kwestię technologii Flash Lite na urządzenia mobilne oraz inne nadchodzą-ce produkty. Podczas imprezy zostały także rozda-ne nagrody MAX 2006. W ciągu trzech dni odbyło się aż 100 warsztatów i zajęć praktycznych. http://www.adobe.com/http://www.adobe.com/events/max/

Monachium pomyślniemigruje na LinuksaStolica Bawarii jest w zaawansowanej fazie migra-cji 80% komputerów administracji publicznej na Linuksa. Proces ten rozpoczął się 3 lata temu, zaś termin jego zakończenia planowany jest na 2008 rok. Burmistrz miasta, Christine Strobel, powiedziała, że jest zadowolona z dotychczaso-wych wyników. Podkreśliła dużą łatwość z jaką odbywa się migracja. Do końca roku 2008 zdecy-dowana większość komputerów będzie pracować pod kontrolą klienta LiMux. Jeśli wszystko przebie-gnie pomyślnie, w ciągu dwóch lat migrację przej-dzie większość z 14 tysięcy komputerów. Migracja pokazuje łatwość przejścia na Linuksa pod kątem zastosowań biurowych. Okazuje się, że chociaż użytkownicy musieli zmienić niektóre swoje przy-zwyczajenia, to obyło się to bez większych proble-mów. Nie trzeba było też wielu szkoleń, czego się początkowo obawiano. Szkolenia obejmują 38% z 35 milionów euro przeznaczonych na migrację. Wykorzystywana jest dystrybucja Debian GNU/Linux 3.1, środowisko graficzne KDE 3.5 oraz pakiet biurowy OpenOffice 2.0. Wilhelm Hoegner, szef miejskiego działu IT uważa, że jak dotąd udana migracja na Linuksa nie stanie się prędko wzorem dla innych miast. Choć Monachium ściśle współpracuje na tym polu z Wiedniem i Paryżem, to rządzący w innych miastach politycy wciąż zbyt mało wiedzą o otwartym oprogramowaniu. http://www.heise.de/

Rewolucyjna współpraca Microsoft i Novell

Firmy Microsoft Corporation i Novell Inc. poinformowały o zawarciu sze-regu umów dotyczących działalności

i współpracy technicznej. Umowy te przewi-dują opracowanie serii nowych rozwiązań usprawniających współdziałanie produk-tów firm Novell i Microsoft, wprowadzenie ich na rynek oraz oferowanie odpowiedniej pomocy technicznej. Przedsiębiorstwa pod-pisały również porozumienie, które gwaran-tuje klientom prawo do korzystania z obję-tych patentami elementów oprogramowa-nia każdej z tych firm. Umowy będą obowią-zywać przynajmniej do 2012 r. Nowy model współpracy Microsoftu z Novellem zapew-ni klientom niespotykane wcześniej możli-wości wyboru i elastyczność dzięki lepszej zgodności operacyjnej systemów Windows. Dzięki porozumieniu z Microsoftem Novell uzyska znaczną przewagę nad innymi pro-ducentami systemu Linux i oprogramowa-nia open source, w odniesieniu do zgod-ności operacyjnej środowisk o mieszanym dostępie do kodu źródłowego. Microsoft będzie oficjalnie zalecać system SUSE Li-nux Enterprise klientom wdrażającym roz-wiązania oparte na systemach Windows i Linux, oraz dystrybuować kupony na usłu-gi utrzymania i pomocy technicznej do sys-temu SUSE Linux Enterprise Server. Klienci będą więc mogli odnosić korzyści zarówno z używania zgodnej operacyjnie wersji sys-temu Linux bez naruszania prawa patento-wego, jak i z efektów wspólnej pracy obu przedsiębiorstw. Microsoft i Novell wspól-

nie opracują ofertę w dziedzinie wirtualizacji systemów Windows i Linux. Usługi Web se-rvices i architektura zorientowana na usługi ciągle są podstawowym sposobem zapew-niania korzyści klientom przez firmy z bran-ży oprogramowania. W tym kontekście Mi-crosoft i Novell podejmą prace nad ułatwie-niem klientom zarządzania mieszanymi śro-dowiskami systemów Windows i SUSE Li-nux Enterprise oraz uproszczeniem łącze-nia usług katalogowych Microsoft Active Di-rectory z oprogramowaniem Novell eDirec-tory. Obydwie firmy chcą się również skon-centrować na poprawieniu zgodności mię-dzy aplikacjami biurowymi współpracując nad najlepszymi sposobami współużytko-wania dokumentów przez użytkowników pa-kietów OpenOffice i Microsoft Office. Ujaw-niono również plany opracowania mechani-zmów translacji mających poprawić zgod-ność operacyjną między formatami Open XML i OpenDocument. Proces integracyjny obejmie również platformy deweloperskie Mono i .NET. Microsoft i Novell urucho-mią placówkę badawczą, w której specja-liści obu firm będą projektować i testować oprogramowanie. Specjaliści są zdania, że nawiązanie współpracy Microsoftu z Novel-lem to punkt zwrotny w procesie populary-zacji systemu Linux, a jednocześnie krok milowy w procesie eliminowania konfliktów między producentem Okienek a społeczno-ścią open source.

http://7thguard.net

R E K L A M A

Page 10: Software Developer's Journal 01/2007 PL

10

www.sdjournal.orgAktualności

www.sdjournal.org Software Developer’s Journal 01/2007

Tort dla FirefoksaTwórcy Internet Explorera przysłali programistom Firefoksa tort z okazji wydania przez nich wersji 2.0 otwartej przeglądarki. Programiści Firefoksa za prezent podziękowali i zdementowali pogłoski mówiące o tym, jakoby tort był zatruty. http://fredericiana.com/2006/10/24/from-red-mond-with-love/

Zniknie największy bazar z piratamiWarszawski Stadion X-lecia zostanie zlikwidowa-ny, a w jego miejscu powstanie nowoczesny kom-pleks sportowy. Oznacza to likwidację funkcjonu-jącego na terenie Stadionu targowiska o dumnej nazwie "Jarmark Europa". Będzie to tym samym koniec handlu pirackimi płytami prowadzonego w tym miejscu na olbrzymią skalę. Na funkcjonu-jącym od 1989 roku, na terenie Stadionu X-lecia, targowisku handluje około 5 tys. podmiotów gospodarczych. Większość sprzedawanych towa-rów to odzież i obuwie, nie jest jednak tajemnicą, że można tam również bez większego problemu kupić pirackie płyty z oprogramowaniem, grami, filmami czy muzyką. Jak dotąd próby ukrócenia tego procederu przypominały walkę z wiatraka-mi. Choć Policja przeprowadziła na terenie Stadio-nu szereg nalotów, a ilość zarekwirowanych pirac-kich nagrań liczy się już w dziesiątkach milionów sztuk, to handel nielegalnymi płytami trwa w naj-lepsze. Likwidacja targowiska choć z pewnością nie rozwiąże definitywnie problemu nielegalnego handlu nośnikami w stolicy, będzie jednak niewąt-pliwie poważnym ciosem dla piratów działających tam na wielką skalę. http://www.msport.gov.pl/

Google: wirtualny potentatUżytkownicy Internetu zdają sobie sprawę, że Google to potężna firma. Mało kto jednak w pełni pojmuje prawdziwą skalę tej potęgi. Szacuje się, iż obecna wartość Google to ok. 147 mld USD. Tym samym ta 8-letnia firma przewyższa giganta o niemal stuletniej tradycji: firmę IBM (139 mld). Inni giganci Internetu dalece odstają od Google: eBay (45 mld), Yahoo (32 mld), Amazon (14 mld). Na wyobraźnię działa jeszcze bardziej porówna-nie Google z gigantami motoryzacyjnymi, których wartość na nowojorskiej giełdzie znacznie odbie-ga od wirtualnego potentata: DaimlerChrysler (54 mld USD), General Motors (20 mld), Ford (15 mld). Oczywiście Google nie wytrzymuje jeszcze konkurencji z największym potentatem IT; wartość Microsoft na giełdzie sięga obecnie 279 mld USD.http://www.pap.com.pl/

Współpraca Novella i British TelecommunicationsNovell zawarł z gigantem świata telekomunikacji, firmą British Telecommunications porozumienie, które dotyczy zarządzania profilami i cyfrową toż-samością milionów klientów uruchamianej przez BT sieci nowej generacji o nazwie 21CN. W ramach porozumienia dwa strategiczne produkty Novella, wieloplatformowe usługi katalogowe Novell eDirec-tory oraz zaawansowane rozwiązanie do zarządza-nia tożsamością Novell Identity Manager, zapew-nią obsługę oraz ochronę bazy profili i tożsamości w sieci 21CN. Technologie Novella umożliwią zaofe-rowanie klientom BT spersonalizowany sposób zin-tegrowanego zarządzania transmisją głosu, danych i usług szerokopasmowych, świadczonych na rzecz komunikacji mobilnej, transmisji wideo na żąda-nie i usług teleinformatycznych takich jak bezprze-wodowy dostęp do sieci Wi-Fi czy obsługa wirtu-alnych sieci prywatnych VPN. Według wypowiedzi wysoko postawionych pracowników Novella, pro-gram 21CN jest pierwszym etapem wprowadzania nowatorskich rozwiązań firmy BT na całym świecie. Pozwoli on udostępnić usługi telekomunikacyjne nowej generacji klientom w Wielkiej Brytanii oraz w wielu innych krajach. http://www.novell.pl/

NetBeans 5.5

Ostatnimi czasy na rynku IDE dla platformy Java liczą się tak na-prawdę tylko dwaj gracze. Mo-

wa tu oczywiście o otwartych projek-tach Eclipse i NetBeans. Obydwa przed-sięwzięcia mają zarówno swoich zwo-lenników jak i przeciwników, i można powiedzieć, że wzajemnie się napędza-ją. Dla programistów Javy jest to nie-wątpliwie komfortowa sytuacja – nie ma nic lepszego niż zdrowa konkurencja. Po silnym natarciu ze strony Eclipse Ca-listo przyszła kolej na uderzenie ze stro-ny NetBeans. I tak, po długim okresie oczekiwania projekt NetBeans docze-kał się wypuszczenia kolejnej stabilnej wersji oznaczonej numerem 5.5. Odsło-na ta oferuje szereg nowych możliwo-ści, przy czym główny nacisk położono na wsparcie technologii Java EE 5, Web services oraz Ajax. Twórcy NetBeans nie ukrywają, że ich głównym celem by-ło odciążenie w pracy programistów J2EE. Poniżej przedstawimy kilka udo-godnień oferowanych przez to rozwiąza-nie. Jeśli chodzi o podstawowe wspar-cie dla J2EE 5, to warto wspomnieć in-tegrację NetBeans z Sunowskim Serwe-rem Aplikacji Glassfish, kompletowanie kodu oraz integrację z dokumentacją API oferowanych przez J2EE 5, wspar-cie dla technologii Servlet 2.5, JavaSe-rver Pages 2.1, JavaServer Faces 1.2 oraz wbudowane przykłady J2EE. W ra-mach wsparcia dla mechanizmów skła-dowania NetBeans potrafi generować klasy Javy z istniejących schematów baz danych i odwrotnie – na bazie klas zbudowanych z poziomu IDE można ge-nerować warstwę DB (NetBeans wyko-rzystuje w tym przypadku technologię DB-from-Java oferowaną przez Glass-fish). Co ciekawe, silnik NetBeans od-powiedzialny za składowanie potra-fi działać bez serwera aplikacji, dzięki czemu można dołączać go do zwyczaj-

nych aplikacji webowych czy nawet apli-kacji J2SE. Dodatkowo NetBeans silnie wspiera technologię EJB 3.0, integruje się z API języka Java do obsługi serwi-sów webowych, a także udostępnia re-wolucyjny zestaw narzędzi do budowa-nia aplikacji GUI w oparciu o bibliotekę Swing. Dodatkowa, ukryta moc pakietu leży w jego rozszerzeniach. Dla przykła-du rozszerzenie Mobility Pack uważane jest za jedno z najlepszych środowisk do tworzenia aplikacji J2ME. Nowością jest rozszerzenie Enterprise Pack – udo-stępniana tam funkcjonalność wywo-dzi się z komercyjnego rozwiązania for-my Sun: Java Studio Enterprise. Kluczo-wymi możliwościami oferowanymi przez to rozszerzenie jest zaawansowana ob-sługa XML (włącznie z refaktoringiem) i UML. NetBeans 5.5 udostępnia jeszcze całe krocie innych udogodnień – szczegó-łowe informacje na ten temat można zna-leźć na domowej witrynie projektu. Jedno jest pewne – programiści innych języków mogą zazdrościć deweloperom Javy jed-nego – świetnych, darmowych rozwiązań typu IDE – czego NetBeans 5.5 jest ide-alnym przykładem.

http://www.netbeans.org/http://www.artima.com/forums/flat.jsp?forum=276&thread=182775

Page 11: Software Developer's Journal 01/2007 PL
Page 12: Software Developer's Journal 01/2007 PL

12

Zawartość

CD-ROM

www.sdjournal.org Software Developer’s Journal 01/2007

Turbo Delphi for .NET oraz Turbo C#

W poprzednim numerze Software Developer’s Jour-nal (12/2006) przedstawiliśmy Turbo Delphi i Turbo C++, dwa pierwsze z czterech nowych środowisk

programistycznych firmy Borland. Obecnie zajmiemy się śro-dowiskami przeznaczonymi dla platformy .NET - Turbo Delphi for .NET oraz Turbo C#.

Każde ze środowisk Turbo dostępne jest w dwóch wer-sjach Explorer i Professional. Narzędzia w wersji Explorer są bezpłatne, niezależnie od sposobu jego wykorzystania (edu-kacyjnego, komercyjnego, domowego). Są one w pełni funk-cjonalne, lecz nie można w nich zainstalować dodatkowych komponentów.

Wersje Turbo nie do końca są nową linią produktów. W rzeczywistości jest to uproszczona wersja bardziej zaawan-sowanego pakietu Borland Developer Studio 2006. Jedną z różnic jest liczba wbudowanych kompilatorów. BDS 2006 za-wiera cztery języki programowania, Delphi, Delphi .NET, C++, C#, a wersje Turbo zawierają tylko jeden z nich.

Turbo Delphi for .NET oraz Turbo C# służą do tworzenia aplikacji typu desktop oraz aplikacji sieciowych dla platfor-my .NET Framework w wersji 1.1. Pierwsze z nich pozwala na wykorzystanie języka Delphi do tworzenia rozwiązań dla Win-Forms, VCL.NET i ASP.NET, drugie służy do tworzenia apli-kacji dla technologii WinForms i ASP.NET z wykorzystaniem języka C#. Oba narzędzia pozwalają na tworzenie usług sie-ciowych .NET, serwerów i klientów .NET Remoting oraz kom-ponentów dla WinForms oraz ASP.NET (a w Turbo Delphi for .NET także komponentów dla VCL.NET).

Środowiska Turbo skracają proces programowania dzię-ki zastosowaniu wielu ułatwień dla programistów, w tym: dy-namicznych szablonów, refaktoryzacji, uzupełnień kodu, ana-liz kodu i uzupełnień bloków. Dostarczany zbiór komponentów pozwala na tworzenie różnorodnych aplikacji oraz, co warto podkreślić, aplikacji bazodanowych. Ponadto środowiska Tur-bo w wersjach Professional można rozbudować o komponenty własne, komponenty pochodzące od firm trzecich oraz dodatki do środowiska IDE. Turbo Delphi for .NET oraz Turbo C# łączą wydajne środowisko RAD, łatwość dostępu do danych i wydaj-ne wzorce z ulubionym językiem programowania, zapewniając wydajność oraz elastyczność w tworzeniu aplikacji klienckich dla serwerów oraz aplikacji sieciowych. Zawarty w pakietach Borland Data Provider (BDP) pozwala łączyć się z serwerami baz danych InterBase, mySQL, Microsoft SQL Server i Access. BDP zapewnia zarządzany dostęp do danych poprzez wpro-wadzenie i abstrakcję interfejsów ADO.NET co oznacza, że dla wielu baz danych wystarczy napisać jeden kod.

Turbo Delphi for .NET oraz Turbo C# umożliwiają popra-wienie kodu przy wykorzystaniu kilkunastu automatycznych funkcji refaktoryzacji, takich jak zadeklarowanie zmiennej, wy-łączenie metody i wiele innych funkcji pomocnych w zarzą-dzaniu hierarchiami klas. Rozszerzalne i adaptowalne „dyna-miczne szablony” (Live Templates) ułatwiają tworzenie wspól-nych części kodu, funkcja uzupełniania bloku (Block Comple-tion) dba o prawidłowe uporządkowanie kodu, a zintegrowa-ne środowisko IDE przyspiesza programowanie, uzupełniając identyfikatory Użytkownika oraz znajdując dla nich odpowied-nie metody, właściwości i funkcje. Narzędzia umożliwiają pro-gramistom tworzącym aplikacje wykorzystanie podejścia opar-

Rysunek 1. Turbo Delphi for .NET oraz Turbo C# w wydajnym środowisku RAD

tego o model UML (tzw. model driven development) dzięki śro-dowisku ECO III. Możliwe jest tworzenie usług sieciowych, apli-kacji ASP.NET oraz aplikacji webForms opartych na platformie ECO. Wbudowana funkcja dwukierunkowego projektowania pozwala wprowadzać zmiany do modelu UML i obserwować efekty w kodzie źródłowym i na odwrót. Obiekty tworzone pod-czas działania aplikacji opartej o platformę ECO można zapi-sać w pliku XML dzięki wbudowanej funkcji mapowania mode-lu obiektowego na strukturę relacyjną. W przyszłości aplikacja taka może być dalej rozwijana w BDS 2006 (w wersji Enterpri-se lub wyższej), gdzie istnieje możliwość składowania obiektów w serwerach SQL. Zarówno Turbo Delphi for .NET jaki i Tur-bo C# pozwalają na tworzenie kompletnych modeli klas UML, a następnie konwertowanie ich na kod źródłowy. Wprowadze-nie zmian do kodu źródłowego prowadzi do zaktualizowania modelu. Przy okazji automatycznie powstaje dokumentacja aplikacji w postaci diagramów UML.

Wykorzystanie technologii ASP.NET pozwala tworzyć w pełni funkcjonalne dynamiczne witryny internetowe zawiera-jące dane z serwerów SQL oraz powiązane z danymi elemen-ty ASP.NET sterujące dostępem do tych informacji. Ponadto dostępne jest alternatywne rozwiązanie nazwane IntraWeb for .NET, w którym można tworzyć interaktywne serwisy WWW.

Właściwości Turbo Delphi for .NET(wersje Explorer i Professional)Język ikompilator

• Możliwość tworzenia aplikacji w wydajnym, nowoczesnym ję-zyku obiektowym Delphi - pochodnej języka Object Pascal;

• Wysoko wydajny zarządzany kompilator kodu Delphi dla Microsoft .NET Framework 1.1.

Szkielety i pakiety SDK

• VCL.NET do szybkiego rozwoju aplikacji Borland Develo-per Studio dla Microsoft .NET Framework 1.1 – z pełnym szybkim projektowaniem wizualnym;

• .NET Windows Forms 1.1 z pełną funkcjonalnością szyb-kiego projektowania wizualnego;

Page 13: Software Developer's Journal 01/2007 PL

13

Zawartość

CD-ROM

www.sdjournal.orgSoftware Developer’s Journal 01/2007

• Możliwość tworzenia i instalacji nowych komponentów open source i komercyjnych (tylko wersja Turbo Delphi for .NET Professional);

• Microsoft .NET Framework SDK 1.1.

Zintegrowane środowisko rozwoju

• W pełni funkcjonalny Projektant formularzy bibliotek VCL.NET z wizualnymi wskaźnikami położenia obiektów, pełną obsługą techniki przeciągania i upuszczania i Inspektorem obiektów do adaptacji komponentów i interfejsów użytkownika;

• Wydajny Edytor kodów przyspiesza programowanie dzięki wykorzystaniu dynamicznych szablonów oraz funkcji pod-świetlania elementów składni, uzupełniania klas, pomocy i analizy błędów, uzupełniania kodu, adaptowalnego przy-pisywania klawiszy i refaktoryzacji;

• Debugowanie kodu z dostępem do najniższego poziomu w ramach zintegrowanego środowiska rozwoju;

• Wbudowane funkcje testowania w środowiskach DUnit i Nunit.

Rozwój i dostępność baz danych:

• Eksplorator baz danych z interfejsem dbExpress i obsługą techniki przeciągania i upuszczania;

• InterBase 7.5.1 Developer Edition – maksymalnie 20 użyt-kowników i 80 logicznych połączeń lokalnych;

• Sterownik dostępu do lokalnej bazy danych Borland Data Provider (BDP) dla baz Borland InterBase 7.5 i MySQL.

Rozwój aplikacji internetowych/sieciowych

• Pełna obsługa ASP.NET 1.1 z projektantem formularzy, edytorem etykiet i modelem kodu zakulisowego;

• Szybkie tworzenie witryn internetowych techniką WYSI-WYG w narzędziu IntraWeb v8.0 (tylko wersja Turbo Del-phi for .NET Professional);

• Komponenty Internet Direct (Indy) zapewniające do-stęp do wszystkich głównych protokołów internetowych, a w tym TCP/IP, HTTP, POP3, SMTP, UDP, FTP, Gopher, Finger, MAP4, NNTP, Telnet oraz Whois dla serwerów i klientów (tylko wersja Turbo Delphi for .NET Professional).

Modelowanie w środowisku Borland Together

• W pełni dwukierunkowe diagramy klas LiveSource;• Modelowanie w języku UML;• Tworzenie dokumentacji.

Aplikacje oparte o model UML:

• Wbudowane funkcje dwukierunkowego modelowania, mapo-wania obiektowego i relacyjnego oraz automatycznego utrwa-lania obiektów. Możliwość zapisania obiektów i danych w ba-zie danych XML lub w korporacyjnych bazach danych.

Właściwości Turbo C# (wersje Explorer i Professional)Język i kompilator: Microsoft Visual C#, wersja 1.1 – zarzą-dzany kompilator kodu dla .NET

Szkielety i pakiety SDK

• .NET Windows Forms 1.1 z pełną funkcjonalnością szyb-kiego projektowania wizualnego

• Możliwość tworzenia i instalacji nowych komponentów open source i komercyjnych (tylko wersja Turbo C# Pro-fessional)

• Foundation Class Library (FCL) 1.1 – ponad 4500 klas ob-fitujących w funkcjonalność: XML, dostęp do danych, po-bieranie plików, regularne wyrażenia, tworzenie obrazów, monitorowanie parametrów i logowanie, transakcje, kolej-kowanie komunikatów, poczta SMTP, itd.

Zintegrowane środowisko programistyczne

• Wydajny Edytor kodów przyspiesza programowanie dzięki wykorzystaniu dynamicznych szablonów oraz funkcji podświetlania elementów składni, uzupełniania klas, pomocy i analizy błędów, uzupełniania kodu, ada-ptowalnego przypisywania klawiszy i refaktoryzacji;

• Debugowanie kodu z dostępem do najniższego poziomu w ramach zintegrowanego środowiska rozwoju;

• Projektant oparty na języku UML i platformie modelowania wizualnego Together;

• Wbudowane funkcje testowania w środowisku Nunit.

Rozwój i dostępność baz danych;

• Eksplorator baz danych ze źródłem Borland Data Provider i obsługą techniki przeciągania i upuszczania;

• Pełna obsługa ADO.NET 1.1 z .NET Framework;• InterBase 7.5.1 Developer Edition – maksymalnie 20 użyt-

kowników i 80 logicznych połączeń lokalnych;• Sterownik dostępu do lokalnej bazy danych Borland Da-

ta Provider (BDP) dla baz Borland InterBase 7.5 i My-SQL.

Rozwój aplikacji internetowych/sieciowych;

• Pełna obsługa ASP.NET 1.1 z projektantem formularzy, edytorem etykiet i modelem kodu zakulisowego;

• Szybkie tworzenie witryn internetowych techniką WYSI-WYG w narzędziu IntraWeb v8.0 (tylko wersja Turbo C# Professional).

Modelowanie w środowisku Borland Together

• W pełni dwukierunkowe diagramy klas LiveSource;• Modelowanie w języku UML;• Tworzenie dokumentacji.

Aplikacje oparte o model UML

• Wbudowane funkcje dwukierunkowego modelowania, mapowania obiektowego i relacyjnego oraz automatycz-nego utrwalania obiektów pomocne w tworzeniu klas i baz danych. Możliwość zapisania obiektów i danych w bazie danych XML lub w korporacyjnych bazach danych.

Page 14: Software Developer's Journal 01/2007 PL

14

Zawartość

CD-ROM

www.sdjournal.org Software Developer’s Journal 01/2007

TrustPort Internet Gateway 4.5

W dzisiejszym świecie coraz więcej zależy od obie-gu informacji w sieci. Wszystkie znaczące fir-my mają dostęp do internetu i posiadają sieć w

swojej firmie – jest to ich główne źródło wymiany informa-cji przechowywania danych itp. Jakiekolwiek niepożądane oprogramowanie typu spyware, spam, wirusy, robaki inter-netowe itd. może spowodować dotkliwe straty finansowe i bezcenne straty w postaci utraty danych ważnych dla danej korporacji. Oczywiście można założyć „Mnie ten problem nie dotyczy, nie będę wydawał pieniędzy niepotrzebnie”. Nic bardziej błędnego – rozprzestrzenianie się niepożąda-nego oprogramowania w internecie jest na porządku dzien-nym i prędzej czy później dotknie każdego. Przykładem tu może być odbieranie codziennie spamu ze skrzynki poczto-wej. Tutaj naprzeciw wychodzi Czeska firma AEC która ofe-ruje swój najnowszy produkt TrustPort Internet Gateway i TrustPort Servers – który miałem przyjemność testować.

Jest to kompletny pakiet do ochrony komputera przed wszel-kim niepożądanym oprogramowaniem internetowym, spamem, spyware i wirusami. Całość pakietu składa się z dwóch części: TrustPort Internet Gateway – odpowiedzialnej za ochronę poczty i internetu oraz TrustPort Server – dodatkowe narzędzia, w skład których wchodzi antywirus i firewall (klucz do pobrania ze strony http://www.sdjournal.org/pl/01_2007.php).

Po instalacji pakietu – która jest bardzo prosta i czytel-na, musimy poświęcić chwilę na odpowiednie skonfiguro-wanie oprogramowania. Pierwszą rzeczą, na którą zwróci-łem uwagę, był skaner TrustPort Antivirus (otrzymał w paź-dzierniku 2006 ocenę Virus Bulletin 100%), który poza pod-stawowymi możliwościami skanowania dysków twardych i napędów, posiada również możliwość skanowania rejestru. Wielkim plusem jest możliwość obszernej konfiguracji ska-nera i jego wszelkich opcji. Z czystej ciekawości i przeska-nowałem swój dysk i byłem bardzo pozytywnie zaskoczo-ny kiedy zobaczyłem rezultaty – zostały usunięte wszelkie szkodliwe pliki, których inne skanery nawet nie pokazywa-ły jako zagrożenie. Następnie przyszedł czas na TrustPort

Internet Gateway. I tutaj również zostałem miło zaskoczony obszernymi możliwościami tego narzędzia. Pierwsza rzecz jaka rzuca się w oczy to bardzo czytelny interface w którym widać trzy zakładki : E-mail, Web, Common.

Zakładka E-mail odpowiada za ochronę poczty. Pierw-szą rzeczą jaką trzeba zrobić jest skonfigurowanie ustawień poczty. Następnie można przejść do dostępnych opcji – możliwości mamy bardzo wiele, między innymi: konfigurację antywirusa dla poczty, konfigurację ustawień anty-spamo-wych takich jak czarna, szara i biała lista adresów e-mail, filtr Bayesa, który analizuje zawartość wiadomości i stwier-dza czy dana wiadomość jest spamem czy nie. Inne to: Ima-ge Checker – wykrywa spam, który ma postać obrazka, Re-gular phrases filter – wyszukuje teksty typowe dla spamu, Public RBL and DSBL lists – jest to publiczna czarna lista z informacjami o spamerach. Oczywiście są też inne opcje, ale nie sposób je tu wszystkie opisać.

Zakładka Web odpowiada za ochronę komunikacji inter-netowej. Tutaj również najpierw trzeba skonfigurować usta-wienia i następnie przejść do dostępnych opcji takich jak: dodawanie zaufanych adresów URL oraz blokowaniedostę-pu do niepożądanych adresów. Mamy również możliwość ustawienia antywirusa dla internetu oraz inne narzędzia do kontroli. Ostatnia zakładka to Common, w której mamy możliwość ustawienia antywirusa i wszystkich innych usług. Następnym dostępnym narzędziem jest TrustPort Servers, który może pomóc w rozwiązaniu problemu wirusów i spy-ware znajdujących się w różnych dokumentach i plikach roz-syłanych za pomocą sieci. W skład TrustPort Server wcho-dzą: Server Antivirus i Server Firewall.

Pakiet firmy AEC udostępnia nam bardzo szeroką możli-wość konfigurowania skutecznego sposobu ochrony naszego komputera i sieci przed wszelkim szkodliwym oprogramowa-niem. W mojej ocenie pakiet sprawdził się bardzo dobrze. Jak będzie u innych? Zapraszam do sprawdzenia.

Jacek Łapiński

Rysunek 1. Okno konfiguracyjne narzędzia TrustPort Internet Gateway

Rysunek 2. Skaner antywirusowy podczas pracy

TTS Company Sp. z o.o.ul. Słowicza 5302-170 Warszawatel. (022) 868-40-42http://www.OprogramowanieKomputerowe.pl

Page 15: Software Developer's Journal 01/2007 PL

Lekcja 1. Opisuje instalację Microsoft SQL Servera 2000. Oprócz tego pokazane są podstawowe narzędzia do administrowania bazą danych takie jak: Enterprise Manager czy SQL Query Analyzer.Lekcja 2. Opisuje zarządzanie bazą danych i jej właściwościa-mi. Nauczymy się tworzyć grupy plików, dodawać i usuwać pliki z danymi i logami, a także ustawiać grupę domyślną. Na koniec poznamy tajniki administracji hasłami i kontami użytkowników.

Lekcja 3. Opisuje zarządzanie rolami i uprawnieniami z nimi związa-nymi. Nauczymy się też tworzyć skrypty przywracające dane i upraw-nienia w bazie danych, a także urządzenia archiwizujące. Sprawdzi-my też spójność bazy danych czy stworzymy kopię różnicową.Lekcja 4. Opisuje tworzenie nowych tabel i zarządzanie prawa-mi dostępu do nich. Nauczymy się także wykorzystywać na róż-ne sposoby polecenie select.

II część multimedialnego kursu na Microsoft Certified System Administration – CD 2

Page 16: Software Developer's Journal 01/2007 PL

16

Biblioteka

miesiąca

www.sdjournal.org Software Developer’s Journal 1/2007

Quartz - zarządzanie zadaniami w J2SE / J2EEZ biblioteką Quartz po raz pierwszy na poważ-

nie spotkałem się w 2004 roku podczas pro-jektowania modułu programu lojalnościowego

na platformie J2EE. Na zakończenie każdego miesiąca podliczane były punkty i na tej podstawie system wy-syłał żądania gratyfikacji do innego modułu. W uprosz-czeniu problem sprowadzał się do tego, aby aplikacja wykonała zadania w określonym czasie lub w określo-nych odstępach czasu bez interakcji z użytkownikiem.

Oczywiście, jak zazwyczaj, problem można było rozwiązać na kilka sposobów. Po pierwsze mogliśmy to zaimplementować sami, na przykład korzystając z klas java.util.Timer lub java.util.TimerTask dodanych w Ja-va SDK 1.3. Jednak, klasy te są zaledwie zalążkiem te-go co oczekiwałoby się od pełnej biblioteki do planowa-nia zadań, a w dodatku wymagałoby to sporo czasu, którego jak zwykle brakuje w napiętym harmonogramie projektu. Na koniec implementacja takiej biblioteki nie jest wcale trywialnym zadaniem i wymaga sporej wie-dzy o programowaniu wątków w Java.

Dobrze, w takim razie najzwyczajniej można było zakupić gotowy komercyjny produkt i problem z głowy. Po co wyważać otwarte drzwi? Niestety budżet tego nie przewidywał i w tym przypadku słusznie, ponieważ doskonałą alternatywą okazała się być darmowa biblio-teka Quartz, którą postaram się poniżej przybliżyć.

O biblioteceProjekt Quartz został założony przez James House-'a w 1988. W 2001 roku trafił na SourceForge jako pro-jekt typu Open Source i od tamtej pory stopniowo za-czął skupiać wokół siebie sporą grupę doświadczonych programistów. Po pewnym czasie został przeniesiony na witrynę http://www.opensymphony.com/quartz/ pro-jektu OpenSymphony, skąd można ściągnąć jego naj-nowsze wydanie (artykuł jest oparty na wersji numer 1.5.2). Tak wygląda w skrócie tło historyczne z burzli-wych dziejów rozwoju biblioteki (bardziej dociekliwym czytelnikom polecam Changelog projektu).

Quartz pozwala programistom korzystać z za-let programowania zdarzeniowego i świetnie wypeł-nia obszar jaki przez długi czas pozostawał zanie-dbany w specyfikacjach J2SE i J2EE. Dopiero ostat-nio w specyfikacji EJB 2.1 pojawiły się pierwsze ja-skółki w postaci Timer Services. W szczególności

Quartz pozwala aplikacji na zaplanowanie zdarzeń (ang. events), które powinny pojawić się w określo-nym punkcie (ang. trigger point) czasu. Wywołanie zdarzenia oznacza w tym przypadku uruchomienie mniejszego podprogramu (ang. job) w tle, bez inte-rakcji z użytkownikiem, niezależnie od innych zadań aktualnie przetwarzanych przez główną aplikację.

Stosowanie mechanizmu planowania zdarzeń jest nieodzowne dla całej gamy przedsięwzięć in-formatycznych, poczynając od dużych komercyj-nych rozwiązań korporacyjnych (ang. enterprise), a kończąc na małych samodzielnych (ang. stand-alone) aplikacjach lub narzędziach do monitorowa-nia i utrzymania systemów. Wśród typowych zasto-sowań biblioteki Quartz można wymienić:

• Tworzenie różnego rodzaju raportów. Często wy-generowanie skomplikowanego sprawozdania wy-maga przeszukania wielu źródeł danych i naraża użytkownika na długotrwałe oczekiwanie na wynik. W takim przypadku lepszym podejściem może oka-zać się uruchomienie w nocy zadania polegające-go na wypełnieniu tymczasowego widoku raportu. Dzięki temu część aplikacji odpowiedzialna za ra-portowanie działa bardziej dynamicznie, co pozwa-la uniknąć skarg sfrustrowanego użytkownika;

• Ciągłe testowanie i monitorowanie systemów w celu utrzymania jakości świadczonych usług;

• Wysyłanie przypomnień lub ostrzeżeń na przykład poprzez email lub SMS. Typowym przykładem jest tutaj codzienne sprawdzanie czy ważność ha-seł użytkowników wkrótce nie wygaśnie i powiado-mienie ich o tym kilka dni przed unieważnieniem.

Do podstawowych zalet biblioteki należy możliwość:

• uruchamiania Quartz zarówno w ramach samo-dzielnej aplikacji J2SE, jak i serwera aplikacji J2EE;

• uruchamiania Quartz jako samodzielnego progra-mu wywoływanego poprzez RMI;

Piotr Anioła

Autor tekstu pracuje obecnie w firmie BLStream na stanowisku Techniczny Kierownik Projektu. Od ponad 10 lat zajmuje się zarządzaniem projektami, projektowa-niem i implementacją systemów komputerowych.Kontakt z autorem: [email protected].

Zawartość katalogu /quartz-1.5.2/• docs/api – Javadoc API dla Quartz;• docs/dbTables – skrypty do założenia tabel Quartz

w bazie danych;• docs/wikidocs – główna dokumentacja Quartz (za-

cznij od index.html);• examples – przykłady użycia biblioteki;• lib – biblioteki wykorzystywane przez Quartz;• src – kod źródłowy.

Materiały do artykułuzamieszczone zostały

na płycie CD 1

Page 17: Software Developer's Journal 01/2007 PL

Quartz

17www.sdjournal.orgSoftware Developer’s Journal 1/2007

Listing 1. Zadanie HelloWorldJob

• uruchamiania Quartz w architekturze klastrowej;• wywoływania zadań w określonym punkcie czasu (z do-

kładnością do milisekund) lub z określoną częstotliwością (wykorzystując podobną semantykę jak popularne narzę-dzie UNIX Cron);

• przechowywania stanu zadań w relacyjnej bazie danych pomiędzy kolejnymi uruchomieniami programu;

• rozszerzania funkcjonalności dzięki zastosowaniu me-chanizmu wtyczek (plug-in) oraz interfejsów typu liste-ners monitorujących lub kontrolujących działanie biblio-teki;

• uruchamiania na wielu różnych platformach dzięki imple-mentacji w języku Java.

Oczywiście Quartz nie jest kryształem bez skazy. Jego zale-ty i wady postaram się przybliżyć w kolejnych punktach niniej-szego artykułu. Na początek spróbujmy uruchomić krótki pro-gram typu Hello World aby zapoznać się z podstawowymi me-chanizmami biblioteki.

Przygotowanie środowiskaDo uruchomienia naszego pierwszego przykładu potrzebna bę-dzie oczywiście wirtualna maszyna Java w wersji 1.3 lub wyż-szej. Zakładam, że czytelnik zna podstawowe technologie J2SE / J2EE i ograniczę do minimum wyjaśnienia odnośnie tej materii. Link do ściągnięcia pakietu Quartz znajduje się na stronie domo-wej biblioteki. W tym miejscu warto nadmienić, że wspomniany adres można znaleźć w ramce "W sieci". Pobrany plik możemy rozpakować, korzystając przykładowo z programu Java jar:

jar -xvf quartz-1.5.2.zip

Po rozpakowaniu archiwum w bieżącym katalogu powstanie katalog /quartz-1.5.2, którego pełną ścieżkę dostępu oznaczy-my nazwą QUARTZ_HOME. Podczas kompilacji naszych przy-kładów będziemy potrzebowali przede wszystkim binarną wer-sję biblioteki Quartz (quartz-1.5.2.jar) oraz zewnętrzne biblioteki umieszczone w podkatalogach katalogu QUARTZ_HOME/lib.

Hello WorldW pierwszym przykładzie zaimplementujemy proste zada-nie, polegające na wpisywaniu tekstu „Hello World!” do logów. Zgodnie z naszymi ustawieniami, Quartz będzie uruchamiał to zadanie co minutę. Podczas implementacji przykładu będzie-my korzystać z następujących kluczowych klas i interfejsów biblioteki umieszczonych w pakiecie org.quartz:

• interfejs Job − reprezentuje zadanie, które chcemy urucho-mić;

• klasa JobDetail − reprezentuje szczegółowe informacje o właściwościach konkretnej instancji zadania (Job);

• klasa JobDataMap − przechowuje informacje o stanie in-stancji zadania;

Wymagane/Opcjonalne biblioteki zewnętrzne używane przez Quartz• activation.jar – opcjonalna, głównie używana przez JavaMail;• commons-beanutils.jar – wymagana;• commons-collections-3.1.jar – wymagana;• commons-dbcp-1.2.1.jar – wymagana, jeśli zadania przecho-

wujemy w bazie danych;• commons-digester.jar – wymagana, jeśli używamy niektórych

wtyczek Quartz;• commons-logging.jar – wymagana;• commons-pool-1.2.jar – opcjonalna;• jdbc2_0-stdext.jar – wymagana, jeśli zadania przechowujemy

w bazie danych;• jta.jar – wymagana, jeśli zadania przechowujemy w bazie da-

nych;• log4j.jar – opcjonalna, ale praktycznie domyślnie wykorzysty-

wana do zapisu logów.

Zwróćmy uwagę, że Quartz został zbudowany i przetestowanyw oparciu o określone wersje bibliotek zewnętrznych. Serwery apli-kacji niejednokrotnie również są dostarczane z tymi samymi biblio-tekami, ale niekoniecznie w tej samej wersji. Dlatego należy zacho-wać ostrożność podczas instalowania aplikacji Quartz na serwerach aplikacji i unikać duplikowania bibliotek.

package listing1;

import java.util.Date;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.quartz.Job;

import org.quartz.JobDataMap;

import org.quartz.JobDetail;

import org.quartz.JobExecutionContext;

import org.quartz.JobExecutionException;

// Przykład Hello World.

public class HelloWorldJob implements Job {

private static final Log logger = LogFactory.getLog(

HelloWorldJob.class);

public void execute(JobExecutionContext context)

throws JobExecutionException {

// Szczegóły o zadaniu pobierz z klasy JobDetail

JobDetail jobDetail = context.getJobDetail();

// Zapisz do logów, o której uruchomiono zadanie

logger.info(jobDetail.getName() +

" uruchomiony o " + new Date());

// Parametry zadania są przechowywane w JobDataMap

JobDataMap jobDataMap = context.getMergedJobDataMap();

String invitation = jobDataMap.getString("POWITANIE");

// Sprawdź wymagane parametry

if (invitation == null) {

throw new JobExecutionException(

"Parametr POWITANIE nie ustawiony" );

}

// Wykonaj właściwą część zadania, czyli zapisz powitanie

// do logów

logger.info(invitation);

}

}

Page 18: Software Developer's Journal 01/2007 PL

18

Biblioteka

miesiąca

www.sdjournal.org Software Developer’s Journal 1/2007

Listing 2. Uruchomienie przykładu Hello World

• klasa abstrakcyjna Trigger − reprezentuje mechanizm, który pozwala na planowanie zadań. Określa kiedy i z jaką częstotliwością ma być uruchamiane zadanie;

• interfejs Scheduler − reprezentuje główny interfejs progra-mu do planowania zadań Quartz. Program ten zarządza re-jestrem instancji JobDetail i Trigger, a po rozpoczęciu dzia-łania jest odpowiedzialny za wywoływanie zadań (Job) zaini-cjowanych w momencie określonym przez związane z nimi obiekty typu Trigger.

Przykład zaczniemy od utworzenia klasy zadania HelloWorl-dJob. Każde zadanie musi implementować interfejs org.qu-artz.Job, co w praktyce sprowadza się do wypełnienia jednej metody o nazwie execute():

public void execute(JobExecutionContext context)

throws JobExecutionException;

Kiedy Quartz Scheduler ustali, że nadszedł już czas na urucho-mienie zadania, tworzy odpowiednią instancję typu Job i wywo-łuje metodę execute(). Scheduler wywołując zadanie nie spodzie-wa się żadnych informacji zwrotnych poza wyjątkiem JobExecu-tionException w przypadku wystąpienia błędu. Na Listingu 1 po-kazany jest kod źródłowy naszego przykładowego zadania. Pod-czas wywołania metody execute() Quartz przesyła kontekst Jo-bExecutionContext, który zawiera wiele cennych informacji o śro-dowisku uruchomieniowym biblioteki, programie Scheduler, in-stancji zadania oraz klasy rozpoczynającej zadanie (Trigger). W szczególności JobExecutionContext udostępnia referencję do klasy JobDetail.

Z klasy JobDetail można odczytać wiele cennych informacji o zadaniu jak na przykład nazwę zadania lub nazwę grupy, do której zadanie należy. JobExecutionContext zawiera również od-wołanie do JobDataMap. Klasa JobDataMap przechowuje parame-try zdefiniowane przez użytkownika, skonfigurowane dla danego zadania. W naszym przykładzie z obiektu JobDataMap pobieramy

parametr przechowujący tekst powitania. Na zakończenie meto-dy execute() pozostaje już tylko wypisanie tekstu powitania do logów. Mamy już zadanie, więc zobaczmy jak można je urucho-mić. Do tego celu wykorzystamy mechanizm Quartz Scheduler. Listing 2 pokazuje podstawowe kroki potrzebne do utworzenia i uruchomienia obiektu typu Scheduler. Zadania można planować w sposób programowy lub deklaratywny. Listing 2 przedstawia pierwszy ze sposobów. Obiekt Scheduler, po pobraniu z StdSche-dulerFactory, jest przesyłany jako argument do metody schedule-Job(), która odpowiada za powiązanie tego obiektu z zadaniem HelloWorldJob. W następnym kroku tworzony jest obiekt JobDe-tail dla zadania typu HelloWorldJob. W obiekcie tym rejestruje-my obiekt JobDataMap służący do przesłania w parametrze "PO-WITANIE" tekstu powitania. Do szczęścia potrzebny nam jest już tylko obiekt Trigger, który poinformuje Scheduler o tym aby uru-chamiał zadanie co minutę, od bieżącego czasu, bez określenia czasu zakończenia. Do utworzenia obiektu Trigger wykorzysta-na została klasa użytkowa TriggerUtils, która udostępnia wiele przydatnych metod upraszczających tworzenie i konfigurowanie obiektów Trigger. Na zakończenie pozostało tylko zarejestrowa-nie obiektów typu Job i Trigger oraz uruchomienie instancji Sche-duler. Zanim uruchomimy nasz przykład potrzebujemy jeszcze dwóch plików konfiguracyjnych. Jeden z parametrami bibliote-ki Quartz (Listing 3), drugi z parametrami biblioteki log4j do za-pisu logów (Listing 4). Oba pliki powinny znajdować się w miej-scu dostępnym podczas uruchomienia dla mechanizmu class lo-ader'a Java (na przykład w katalogu WEB-INF/classes dla apli-kacji WEB J2EE). Parametry biblioteki Quartz powinny być za-pisane w pliku o nazwie quartz.properties. W pliku tym moż-na skonfigurować wiele różnych aspektów Quartz. Domyślne wartości wymaganych parametrów są ustawione w pliku qu-artz.properties umieszczonym w pakiecie JAR biblioteki Qu-artz. W przykładzie ustawione są następujące parametry:

• org.quartz.scheduler.instanceName − nazwa instancji Scheduler. W naszym przykładzie jest „QuartzSchedu-

package listing1;

import java.util.Date;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.quartz.*;

import org.quartz.impl.StdSchedulerFactory;

// Przykład Hello World.

public class Listing2 {

private static final Log logger = LogFactory.getLog(

Listing2.class);

public static void main(String[] args) {

Listing2 listing2 = new Listing2();

try {

// Utwórz i uruchom Scheduler

Scheduler scheduler =

StdSchedulerFactory.getDefaultScheduler();

listing2.scheduleJob(scheduler);

scheduler.start();

} catch (SchedulerException ex) {

logger.error(ex);

}

}

// Utwórz i zaplanuj HelloWorldJob

private void scheduleJob(Scheduler scheduler)

throws SchedulerException {

// Utwórz JobDetail dla zadania

JobDetail jobDetail = new JobDetail("HelloWorldJob",

Scheduler.DEFAULT_GROUP, HelloWorldJob.class);

// Ustaw tekst powitania

obDetail.getJobDataMap().put("POWITANIE",

"Hello World!");

// Utwórz trigger, który jest uruchamiany co minutę

Trigger trigger = TriggerUtils.makeMinutelyTrigger();

trigger.setName("helloWorldTrigger");

// Uruchom trigger od teraz

trigger.setStartTime(new Date());

// Połącz trigger z zadaniem w Scheduler

scheduler.scheduleJob(jobDetail, trigger);

}

}

Page 19: Software Developer's Journal 01/2007 PL

Quartz

ler”. W konfiguracji klastrowej instancje powinny mięć unikalną nazwę;

• org.quartz.scheduler.instanceId − identyfikator instancji Scheduler. W konfiguracji klastrowej ta wartość powinna być również unikalna;

• org.quartz.threadPool.threadCount − określa ile wątków jest utworzonych i dostępnych do obsługi zadań;

• org.quartz.threadPool.class − określa klasę obsługującą pulę wątków o stałym rozmiarze, implementującą interfejs org.quartz.spi.ThreadPool. Dostarczona w bibliotece Quartz klasa org.quartz.simpl.SimpleThreadPool powinna spełnić potrzeby większości użytkowników. Jest możliwe, że w przy-szłości dostarczona zostanie nowa implementacja puli wąt-ków oparta na wprowadzonych niedawno koncepcjach w Ja-va 1.5 w klasie java.util.concurrent.ThreadPoolExecutor;

• org.quartz.jobStore.class − określa jak obiekty typu Job i Trigger są przechowywane podczas cyklu działania instan-cji Scheduler. Wartość org.quartz.simpl.RAMJobStore ozna-cza, że obiekty te będą przechowywane w pamięci RAM i in-formacja o ich stanie jest tracona po zatrzymaniu działania instancji Scheduler.

W drugim z plików konfiguracyjnych log4j.properties ustawio-ne jest, że podczas działania programu logi będą zapisywa-

ne na konsolę. W logach pojawią się wiadomości z poziomu ERROR, jedynie dla naszego przykładu w logach mogą pojawić się wiadomości z poziomu INFO lub wyższego.

Po uruchomieniu przykładu na konsoli powinniśmy ujrzeć zapis podobny do przedstawionego na Listingu 5.

Deklaratywne definiowanie zadańOprócz programowego podejścia, Quartz pozwala również na deklaratywne zaplanowanie zadań w zewnętrznym pliku XML. Jest to zalecane podejście, ponieważ zmiana ustawień w pli-ku XML nie wymaga ponownej kompilacji kodu źródłowego. Qu-artz, podobnie jak inne popularne biblioteki, udostępnia mecha-nizm wtyczek, które pozwalają na rozszerzanie jego możliwości. Do deklaratywnej konfiguracji zadań można użyć klasy org.qu-artz.plugins.xml.JobInitializationPlugin. Domyślnie wyszuku-je ona plik o nazwie quartz_jobs.xml w ścieżce classpath Java, a następnie ładuje informacje o zadaniach i czasie ich urucho-mienia z pliku XML. Wtyczki w Quartz rejestrujemy w pliku qu-artz.properties używając następnującej konwencji:

org.quartz.plugin.<nazwa wtyczki>.class=

<pełna nazwa klasy wtyczki>

org.quartz.plugin.<nazwa wtyczki>.

<nazwa parametru wtyczki>=<wartość>

Listing 3. quartz.properties dla przykładu Hello World

#Konfiguracja parametrów głównego programu Scheduler

org.quartz.scheduler.instanceName = QuartzScheduler

org.quartz.scheduler.instanceId = AUTO

#Konfiguracja ThreadPool

org.quartz.threadPool.threadCount = 5

org.quartz.threadPool.class =

org.quartz.simpl.SimpleThreadPool

#Konfiguracja JobStore

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

Listing 4. log4j.properties dla przykładu Hello World

log4j.rootLogger=error, stdout # Utwórz appender stdout

# Konfiguracja stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%5p

[%t] (%F:%L) - %m%n

# Wypisz wiadomości poziomu INFO lub wyższego

# dla przykładu Hello World

log4j.logger.listing1=INFO

R E K L A M A

Page 20: Software Developer's Journal 01/2007 PL

20

Biblioteka

miesiąca

www.sdjournal.org Software Developer’s Journal 1/2007

Listing 6 przedstawia przykład dla JobInitializationPlugin. Podane parametry mają następujące znaczenie:

• overWriteExistingJobs − określa, czy zadania zdefiniowane w XML mają nadpisać już istniejące o tej samej nazwie,

• failOnFileNotFound − określa, czy inicjalizacja wtyczki po-winna zakończyć się wyjątkiem w przypadku nie znalezie-nia pliku XML,

• validating − określa, czy struktura pliku XML powinna być zweryfikowana.

Pozostało nam jeszcze zapoznanie się ze strukturą samego pli-ku quartz_jobs.xml. Listing 7 przedstawia definicję zadań dla przykładu Hello World. Element <job> reprezentuje zadanie, któ-re chcemy zarejestrować w mechanizmie Scheduler Quartz. Za-wartość tagów <job-detail> i <trigger> odpowiada parametrom ustawionym programowo w przytoczonym powyżej przykładzie Listing 2, w metodzie scheduleJob(). Oczywiście jest możliwe zdefiniowanie wielu zadań w jednym pliku XML.

TriggerW Quartz wyróżniamy trzy rodzaje Trigger'ów:

• org.quartz.SimpleTrigger;

• org.quartz.CronTrigger;

• org.quartz.NthIncludedDayTrigger.

Pierwszy z nich został zaprojektowany z myślą o zadaniach, któ-re powinny być rozpoczęte w określonym momencie i powtarzać się n razy w pewnych odstępach czasu. Poniższy fragment kodu przedstawia Trigger, który rozpocznie pracę od razu, a następnie będzie uruchamiany co minutę, aż do zakończenia programu:

Trigger trigger = new SimpleTrigger

("myTrigger", Scheduler.DEFAULT_GROUP, new Date(),

null, SimpleTrigger.

REPEAT_INDEFINITELY, 60000L);

CronTrigger pozwala na znacznie bardziej skomplikowane pla-nowanie zadań. Format wyrażenia Quartz Cron jest bardzo podobny do jego odpowiednika w Unix. Składa się z siedmiu elementów:

<sekundy> <minuty> <godziny>

<dzień miesiąca> <miesiąc>

<dzień tygodnia> <rok opcjonalnie>

Szczegółowy opis formatu wyrażenia znajduje się w JavaDoc API klasy org.quartz.CronExpression.

Przykładowo, skonfigurowanie Triggera, który będzie wy-woływał zadanie co 10 minut, pomiędzy godzianami 9:00 i 16:00 od poniedziałku do piątku, wygląda następująco :

CronTrigger cTrigger = new CronTrigger

("myTrigger", Scheduler.DEFAULT_GROUP,

"0 0/10 9-16 ? * MON-FRI");

Oczywiście tę samą konfigurację można zadeklarować w pliku quartz_jobs.xml w tagu <trigger>. Pokazuje to Listing 8.

Ostatni z listy − NthIncludedDayTrigger − został niedaw-no dodany do biblioteki. Pozwala na wywołanie zadania n-te-go dnia w zadanych interwałach czasu. Na przykład wywoła-nie zadania każdego 10-tego dnia miesiąca wymaga zdefinio-wania Triggera w następujący sposób:

NthIncludedDayTrigger nTrigger =

new NthIncludedDayTrigger

("MyTrigger", Scheduler.DEFAULT_GROUP);

nTrigger.setN(10);

nTrigger.setIntervalType

(NthIncludedDayTrigger.

INTERVAL_TYPE_MONTHLY);

Dodatkowym udogodnieniem w Quartz są klasy implemen-tujące interfejs org.quartz.Calendar. Pozwalają one na zablo-kowanie wywołania zadań w pewnych zadanych przedziałach czasu, na przykład w dni wolne od pracy. Biblioteka dostarcza kilka gotowych implementacji w pakiecie org.quartz.impl.ca-lendar, na przykład HolidayCalendar. Listing 9 przedstawia fragment kodu z wykorzystaniem tej klasy.

Użycie na platformie J2EECzęstym problemem, z jakim spotykają się nowi użytkownicy bi-blioteki, jest sposób umieszczania i uruchamiania Quartz na plat-formie J2EE. Zasadniczo można wyróżnić dwie strategie. Pierw-sza polega na wywołaniu Quartz jako standardowego klien-ta J2SE poza kontenerem J2EE. Druga polega na umieszcze-niu Quartz w aplikacji Web (w pliku WAR) i uruchomieniu w ra-

LicencjaBiblioteka Quartz jest zupełnie darmowa, dostępna na licencji Apache Li-cense 2.0. Jedyną rzeczą, o której w praktyce należy pamiętać jest dołą-czenie jej kopii do naszego produktu. Pełny tekst licencji można przeczy-tać pod adresem: http://www.apache.org/licenses/LICENSE-2.0.

Listing 5. Przykładowy zapis logów na konsoli dla zadania Hello World

INFO [QuartzScheduler_Worker-0] –

HelloWorldJob uruchomiony o Mon Sep 25 15:12:15 EDT 2006

INFO [QuartzScheduler_Worker-0] - HelloWorld!

INFO [QuartzScheduler_Worker-0] –

HelloWorldJob uruchomiony o Mon Sep 25 15:13:15 EDT 2006

INFO [QuartzScheduler_Worker-0] - HelloWorld!

INFO [QuartzScheduler_Worker-1] –

HelloWorldJob uruchomiony o Mon Sep 25 15:14:15 EDT 2006

INFO [QuartzScheduler_Worker-1] - HelloWorld!

Listing 6. Parametry dla JobInitializationPlugin w pliku quartz.properties

org.quartz.plugin.jobInitializer.class =

org.quartz.plugins.xml.JobInitializationPlugin

org.quartz.plugin.jobInitializer.overWriteExistingJobs =

true

org.quartz.plugin.jobInitializer.failOnFileNotFound = true

org.quartz.plugin.jobInitializer.validating=false

Page 21: Software Developer's Journal 01/2007 PL

21

Quartz

www.sdjournal.orgSoftware Developer’s Journal 1/2007

mach aplikacji J2EE na serwerze. Pierwsze podejście stosuje-my najczęściej wtedy, gdy mamy już zdefiniowane komponen-ty EJB i nie możemy wprowadzać zmian na serwerze. Pole-ga ono na prostym wywołaniu serwisów EJB, poprzez ich in-terfejsy Home i Remote, lub na utworzeniu i wstawieniu wiadomo-ści JMS, która następnie jest przetwarzana przez odpowiedni komponent MDB (Message Driven Bean). W przypadku wywoła-nia komponentu EJB zalecane jest użycie klasy zadania org.qu-artz.jobs.ee.ejb.EJBInvokerJob. Wymaga ona przekazania odpo-wiednich parametrów w obiekcie JobDataMap, opisanych szcze-gółowo w dokumentacji JavaDoc API biblioteki, np. nazwa JNDI i nazwa metody komponentu EJB.

Drugie podejście ma przewagę nad pierwszym z kilku po-wodów. Przede wszystkim występuje tu mniejsza liczba po-tencjalnych punktów awarii, ponieważ zarządzamy tylko jed-

ną aplikacją, a nie dwoma. Poza tym zainstalowanie Quartz w aplikacji J2EE daje dostęp do zasobów oferowanych przez serwer aplikacji, jak sesje z serwisem pocztowym, zdefiniowa-ne źródła danych lub adaptery do innych zasobów.

Uruchomienie Quartz jako klienta J2EE jest trochę bardziej skomplikowane, niż jako klienta J2SE. Wynika to częściowo z bardziej złożonego procesu konfigurowania aplikacji, ale rów-nież z faktu nałożenia pewnych ograniczeń w specyfikacji J2EE na komponenty uruchamiane w ramach serwera aplikacji. W szczególności to kontener odpowiada za zarządzanie zasoba-mi serwera, w tym za tworzenie nowych wątków. Natomiast Qu-artz sam zarządza pulą wątków Java. Dlatego ważne jest zacho-wanie pewnych reguł, które zapewnią poprawne i stabilne dzia-łanie aplikacji. Załóżmy, że już mamy aplikację EAR z zaim-plementowanymi komponentami EJB. Najprostszym sposo-bem jest zbudowanie oddzielnego pliku Web WAR, który bę-dzie zawierał wszystkie potrzebne pliki do uruchomienia za-dań Quartz, a następnie umieszczenie go w aplikacji EAR. W standardowej strukturze katalogów aplikacji Web należy zadbać, aby znalazły się następujące pliki:

• web.xml (w /WEB-INF);• quartz.properties (w /WEB-INF/classes);• quartz_jobs.xml (w /WEB-INF/classes);• pliki binarne Quartz (w /WEB-INF/lib);• wymagane biblioteki zewnętrzne (w /WEB-INF/lib).

Listing 10 przedstawia deskryptor web.xml aplikacji Web. Zawiera on konfigurację Listenera org.quartz.ee.servlet.Qu-artzInitializerListener implementującego standardo-wy interfejs javax.servlet.ServletContextListener. Jego zadaniem jest inicjalizacja/zatrzymanie Quartz podczas startu/zamykania kontekstu Servletów w kontenerze J2EE. W web.xml można również podać wartości dla opcjonalnych parametrów Listenera:

• config-file − ścieżka i nazwa pliku z parametrami Quartz. Domyślna wartość: quartz.properties;

Produkty pokrewne• Flux Scheduler http://www.fluxcorp.com/;• Enterprise Batching Queuing http://www.argent.com/p/qe/qe.html;• Vexus consulting Avatar Job Scheduling Suite http://www.vexus.ca;• Oracle Scheduler http://www.oracle.com/technology/products/database/

scheduler/index.html;• Przykładowy opis programu Cron pod Linux http://www.linuxhelp.net/guides/cron/;• Tutorial o Timer Services w EJB 3.0 http://java.sun.com/javaee/5/docs/tutorial/doc/Session4.html;• JavaDoc klasy java.util.Timer http://java.sun.com/j2se/1.5.0/docs/api/java/util/Timer.html;• JavaDoc klasy java.util.concurrent.ThreadPoolExecutor http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/

ThreadPoolExecutor.html;• OSWorkflow http://www.opensymphony.com/osworkflow/.

Listing 7. quartz_jobs.xml dla przykładu Hello World

<quartz>

<job>

<job-detail>

<name>HelloWorldJob</name>

<group>DEFAULT</group>

<description>

Zadanie Hello World.

</description>

<job-class>

listing1.HelloWorldJob

</job-class>

<volatility>false</volatility>

<durability>false</durability>

<recover>false</recover>

<job-data-map allows-transient-data="true">

<entry>

<key>POWITANIE</key>

<value>Hello World!</value>

</entry>

</job-data-map>

</job-detail>

<trigger>

<simple>

<name>helloWorldTrigger</name>

<group>DEFAULT</group>

<job-name>HelloWorldJob</job-name>

<job-group>DEFAULT</job-group>

<start-time>2006-10-10 7:10:00 PM</start-time>

<!-- uruchom Trigger co minutę -->

<repeat-count>-1</repeat-count>

<repeat-interval>60000</repeat-interval>

</simple>

</trigger>

</job>

</quartz>

Page 22: Software Developer's Journal 01/2007 PL

22

Biblioteka

miesiąca

www.sdjournal.org Software Developer’s Journal 1/2007

• start-scheduler-on-load − określa czy metoda schedu-

ler.start() ma być wywołana podczas startu kontenera. Domyślna wartość: „true”

• shutdown-on-unload − określa, czy metoda scheduler.shut-down() ma być wywołana podczas zatrzymania kontene-ra. Domyślna wartość: „true”.

Reszta plików konfiguracyjnych (quartz.properties i quartz_jobs.xml) nie wyróżnia się niczym specjalnym. Istnieje również al-ternatywne podejście do zaprezentowanego rozwiązania, oparte na klasie org.quartz.ee.servlet.QuartzInitializerServlet i stan-dardowym mechanizmie ładowania Servletów przez kontener J2EE. Jednak zastosowanie Listenera jest uważane za imple-mentację bardziej przenośną i właściwą w tym przypadku.

JobStoreQuartz wykorzystuje JobStore do przechowywania informacji o zadaniach Job, obiektach Trigger, Calendar oraz Scheduler. W przykładzie Hello World użyta została implementacja org.qu-artz.simpl.RAMJobStore oparta na pamięci RAM. To wyjaśnia dla-czego po ponownym uruchomieniu instancji Scheduler jego stan i informacja o zadaniach były ładowane całkowicie od nowa.

Quartz udostępnia dwie implementacje JobStore pozwala-jące na zachowanie stanu zadań:

• org.quartz.impl.jdbcjobstore.JobStoreTX – zaprojektowana z myślą o uruchomieniu w środowisku 'stand-alone', gdy nie ma potrzeby integracji z serwisem transakcji w konte-nerze J2EE;

• org.quartz.impl.jdbcjobstore.JobStoreCMT – zaprojektowa-na dla zastosowań, gdy obsługa transakcji mechanizmu JobStore powinna być zarządzana przez kontener J2EE.

Obie implementacje są oparte na protokole JDBC i pozwalają na przechowywanie zadań w bazie danych. Skrypty SQL po-trzebne do założenia struktury tabel Quartz znajdują się w ka-talogu QUARTZ _ HOME/docs/dbTables.

Opis parametrów jakie należy ustawić dla poszczegól-nych implementacji JobStore znajduje się na stronie: http://wiki.opensymphony.com/display/QRTZ1/Configuration.

Praktyczne poradyPoniżej znajduje się kilka praktycznych porad dla użytkowni-ków Quartz:

• Do pobrania obiektu JobDataMap w metodzie execute() za-dania używaj metody getMergedJobDataMap() z argumen-tu typu JobExecutionContext. Metoda ta zwraca obiekt po-wstały z połączenia obiektów JobDataMap znajdujących się zarówno w obiekcie JobDetail , jak i obiekcie Trigger;

• Scheduler tworzy nową instancję typu Job podczas każde-go kolejnego wywołania zadania. Oznacza to, że wszel-kie wartości przechowywane w instancji obiektu zadania są tracone. Można to zmienić poprzez zamianę interfej-su org.quartz.Job na org.quartz.StatefulJob w implemen-tacji zadania. Powoduje to dwie główne zmiany. Po pierw-sze obiekt JobDataMap zostaje zachowany w JobStore po każdym wywołaniu zadania. Po drugie dwie instancje te-go samego zadania StatefulJob nie mogą być uruchomio-ne równocześnie;

Listing 8. Przykład konfiguracji Triggera w pliku quartz_jobs.xml

<trigger>

<cron>

<name>myTrigger</name>

<group>DEFAULT</group>

<job-name>myJob</job-name>

<job-group>DEFAULT</job-group>

<cron-expression>0 0/10 9-16 ? * MON-FRI

</cron-expression>

</cron>

</trigger>

Listing 9. Przykładowe użycie klasy HolidayCalendar

HolidayCalendar quartzCal = new HolidayCalendar();

// zablokuj 1 styczeń

Calendar gCal = GregorianCalendar.getInstance();

gCal.set(Calendar.MONTH, Calendar.JANUARY);

gCal.set(Calendar.DATE, 1);

quartzCal.addExcludedDate(gCal.getTime());

// Dodaj do scheduler, zastąp istniejący,

// uaktualnij Trigger'y

scheduler.addCalendar("holidaysCal", quartzCal, true, true);

Trigger trigger = TriggerUtils.makeImmediateTrigger(

"myTrigger", -1, 60000L);

trigger.setCalendarName("holidaysCal");

Listing 10. Plik web.xml

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

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems,

Inc. //DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

<!-- Użyjemy domyślnej nazwy quartz.properties

<context-param>

<param-name>config-file</param-name>

<param-value>/path/my_quartz.properties</param-value>

</context-param>

-->

<context-param>

<param-name>shutdown-on-unload</param-name>

<param-value>true</param-value>

</context-param>

<context-param>

<param-name>start-scheduler-on-load</param-name>

<param-value>true</param-value>

</context-param>

<listener>

<listener-class>

org.quartz.ee.servlet.QuartzInitializerListener

</listener-class>

</listener>

</web-app>

Page 23: Software Developer's Journal 01/2007 PL

Quartz

• Liczba wątków w puli Quartz ma spory wpływ na wydaj-ność aplikacji. Dlatego należy dobrać właściwą wartość zależnie od potrzeb. Zazwyczaj domyślna wartość 5 wy-starcza dla wiekszości zastosowań. Można ją zmniejszyć nawet do 1, jeśli aplikacja uruchamia zaledwie kilka za-dań parę razy w ciągu dnia. Wartości pomiędzy 50 a 100 stosuje się w przypadku planowania kilku tysięcy zadań, z których wiele uruchamianych jest co kilka minut. Przy ta-kich obciążeniach należy przeprowadzić odpowiednie te-sty wydajnościowe;

• Duże znaczenie dla wydajności aplikacji ma wybór Job-Store. RAMJobStore jest oczywiście o wiele szybszy od JDB-CJobStore;

• Quartz udostępnia mechanizm Listener. Pozwala on na obsługę różnych zdarzeń związanych z realizacją zadań (JobListener), obsługą obiektów typu Trigger (TriggerLi-stener) czy działaniem samego obiektu Scheduler (Schedu-lerListeners). Jednak użycie dużej liczby obiektów Liste-ner może znacznie spowolnić działanie aplikacji. Należy również unikać zbyt długiej obsługi monitorowanych zda-rzeń;

• Quartz nie udostępnia bezpośrednio obsługi przepły-wu zdarzeń, czyli możliwości zaplanowania wywołania odpowiednich zadań w wyniku zakończenia innych. Po-średnio można to wykonać poprzez użycie obiektów Li-stener, które po zakończeniu danego zadania rejestrują wykonanie kolejnego. Innym rozwiązaniem jest przesy-łanie w JobDataMap nazwy obiektu typu Job, które ma być uruchomione po zakończeniu działania aktualnego za-dania. W bardziej zaawansowanych aplikacjach polecam integrację Quartz z inną biblioteką dostępną w projekcie OpenSymphony: OSWorkflow;

• Niewielu użytkowników wie, że w repozytorium CVS bi-blioteki jest dostępna również aplikacja Web do zarządza-nia konfiguracją Quartz z poziomu przeglądarki. Znajduje się ona w katalogu /web i nie jest dostarczana w wersji bi-narnej.

PodsumowanieW ostatnim czasie w specyfikacjach J2SE i J2EE poja-wiły się nowe mechanizmy, jak Timer Services w EJB 2.1/3.0 lub klasy w pakiecie java.util.concurrent. Jed-nak rozwiązania te nie są wystarczające i każdy, kto mu-si zaplanować zadania w języku Java, z pewnością powi-nien zajrzeć do biblioteki Quartz. Zachęcam do zapozna-nia się z innymi jej elementami. Jako kolejny krok proponu-ję przejść do przykładów zawartych w katalogu /QUARTZ_HOME/examples/. Natomiast tym, którzy wnikliwiej zain-teresowali się rozwojem biblioteki, polecam stronę http://wiki.opensymphony.com/display/QRTZ/Quartz oraz udział w projektowaniu kolejnej wersji Quartz 2.0. n

W Sieci• Strona domowa http://www.opensymphony.com/quartz/;• Download http://www.opensymphony.com/quartz/download.action;• Forum użytkowników Quartz http://forums.opensymphony.com/forum.jspa?forumID=6;• Lista znaczących użytkowników Quartz http://wiki.opensymphony.com/display/QRTZ1/Quartz+Users.

������

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

���������

����

����

��������

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

����

����

����

����

����

����

����������

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

S P R O S T O W A N I E

Rysunek 1. Diagram klas bazy danych Sklep Rysunek 1. Diagram klas bazy danych Sklep

W numerze 11/2006 Software Developer’s Journal w artykule Obiektowe projektowanie relacyjnej bazy danych autorstwa Damiana Dudka został błędnie przerysowany Rysunek 1. Diagram klas bazy danych Sklep (po lewej stronie). Po prawej stro-nie zamieszczamy poprawny rysunek. Serdecznie przepraszamy autora za błąd. Dziękujemy za wyrozumiałość. Cały artykuł w poprawionej wersji można znaleźć na naszej stronie www.sdjournal.org

Redakcja SDJ

Page 24: Software Developer's Journal 01/2007 PL

24

Tam

byliśmy

www.sdjournal.org Software Developer’s Journal 01/2007

Są Państwo złotym sponsorem konfe-rencji Java Dev Days 2006. Co skłoniło Państwa do podjęcia takiej decyzji?Powody tak naprawdę są dwa główne. Je-den bardziej bieżący, lokalny, chcielibyśmy w jakiś sposób zaistnieć na krakowskim rynku jako pracodawca, który jest koja-rzony nie tylko poprzez targi / konferencje skierowane do swoich Klientów (a więc w ramach których prezentowana jest komer-cyjna oferta firmy, rozdawane są broszury opisujące produkty firmy), ale także jako firma, która potrafi sponsorować coś mniej komercyjnego, nie mającego bezpośred-niego przełożenia na działania handlowe (do Klientów), ale przeznaczone bardziej

dla środowiska deweloperów / programistów, dla ludzi, któ-rzy swoją pracę traktują jako coś więcej niż tylko sposób na zasilenie domowego budżetu. Chcemy się kojarzyć z firmą, która w tym co robi też chce czegoś więcej, niż tylko zarabiać pieniądze (co jest oczywistym celem każdej firmy). My nato-miast chcemy robić to dodatkowo z użyciem ciekawych tech-nologii, dając ludziom szansę realizacji pasji w ramach tego, co robią, przy okazji promując pewne technologie. DRQ za taką firmę się uważa i chcemy to pokazywać środowisku de-weloperów (a więc środowisku naszych potencjalnych przy-szłych pracowników). Drugi powód sponsorowania JDD, ten bardziej strategiczny, to promowanie technologii Java. Pro-

mując taką konferencję (a pamiętajmy, że o sponsorów dla tego typu „mało komercyjnych” konferencji bywa ciężko i nie są one popularne), napędzamy popularność tego języ-ka. A ta popularność nie jest jeszcze aż taka oczywista. My-śleliśmy do niedawna, że wszyscy programują w Javie, tym-czasem ogromnie zdziwiło mnie, gdy niedawno w czasie roz-mów ze studentami kierunków informatycznych wyszło, że duży procent spośród nich nie doceniał tej technologii i nie inwestowali w swoją wiedzę w tym zakresie. Dlatego mamy nadzieję, że może dzięki takim konferencjom, młodzi dewe-loperzy dużo chętniej skłonią się ku Javie. Oczywiście to nie jest jedyny i właściwy język programowania, każdy język ma swoje zastosowanie. Jednak Java – poprzez swoją popular-ność na świecie (a co za tym idzie – mnogość bibliotek, na-rzędzi wspierających etc.) – jest dziś „najrozsądniejszym wyborem” przy tworzeniu aplikacji z jakimi mają do czynie-nia firmy takie jak DRQ. Dlatego zależy nam na promowaniu tej technologii. To napędza krakowskie zaplecze profesjonal-nych deweloperów Javy, z którego za chwilę będziemy mogli korzystać, dla dobra naszych Klientów.Co z kolejnymi edycjami, czy będziecie Państwo kontynu-ować tradycję sponsorowania tej imprezy?Nie mogę tego dziś ostatecznie potwierdzić, ale na dziś dzień już rozpoczęliśmy pewne rozmowy z fundacją Proidea i wyrażamy wolę równie silnego zaangażowania w roku 2007. Wszystko dlatego, że JDD 2006 okazało się dużym sukcesem i cieszy się sporą popularnością (400 gości!), widzimy więc że nasze działanie ma sens.

Łukasz Majek – DRQ Kraków

Rysunek 1. Ekipa Software Mind z Brucem Eckhelem (drugi od lewej)

Java Dev Days 200621 października 2006 w Krakowie w Centrum

Sztuki i Techniki Japońskiej Manggha odbyła się konferencja Java Dev Days zorganizowana

przez Fundację Proidea. Poświęcona była technologii Java oraz praktykom projektowania oraz programo-wania aplikacji na tę platformę. Gościem honorowym był Bruce Eckhel, który promował swoją książkę Thin-king in Java. Rozpoczął on konferencje wykładem The World is Dynamic. Prelegentami byli również:

l Przemysław Pokrywkal Janusz Marchewal Jan Mrzygłódl Waldemar Kotl Jan Pieczykolanl Grzegorz Rdzanyl Jarosław Pałkal Łukasz Grabskil Marcin Kuciębal Marcin Płonkal Paweł Rzepa

Warsztaty przeprowadzili Łukasz Krawczyk, Michał Majcher, Łukasz Szandecki oraz Mariusz Kaczor.

PROIDEA została założona w 2004 roku. Powsta-ła w odpowiedzi na rosnące zapotrzebowanie na organizacje przekazujące w sposób kompetentny wiedzę z zakresu teleinformatyki. Wypełnia swoje cele statutowe wspierając edukację oraz promując inicjatywy służące popularyzowaniu informatyki w szkołach. Fundacja skupia wokół siebie grono spe-cjalistów o rozległej wiedzy informatycznej.

Sponsorzy główni: DRQ oraz Software Mind

Page 25: Software Developer's Journal 01/2007 PL
Page 26: Software Developer's Journal 01/2007 PL

26

Aplikacje

biznesowe

www.sdjournal.org Software Developer’s Journal 1/2007

e-POLTAXW dniu 16 sierpnia 2006 roku Ministerstwo

Finansów (MF) ogłosiło, że grupa oko-ło 7.5 tysiąca największych podatników

o rocznych przychodach przekraczających 5 mln euro, obsługiwanych przez tzw. wyspecjalizowa-ne urzędy skarbowe (US), może składać deklara-cje podatkowe drogą elektroniczną. Wykonaniem i jednocześnie wdrożeniem systemu e-POLTAX, obsługującego deklaracje elektroniczne zajęła się Państwowa Wytwórnia Papierów Wartościowych (PWPW).

W niniejszym artykule, poza przedstawieniem sposobu działania systemu e-POLTAX, skupimy się głównie na opisie formatów deklaracji elektro-nicznej. Wszystkie prezentowane przykłady po-wstały wyłącznie w oparciu o opublikowane przez MF schematy dokumentów. Poprawność składnio-wą plików XML weryfikowano przy użyciu aplika-cji off-line udostępnianej przez MF, natomiast do testów poprawności strukturalnej użyto walidatora dostępnego na stronie http://tools.decisionsoft.com/schemaValidate/.

Budowa i zasady funkcjonowania systemu e-POLTAXSystem e-POLTAX umożliwia składanie deklaracji podatkowych na trzy sposoby:

• bezpośrednio poprzez mechanizmy udostępnio-ne na stronie WWW umieszczonej pod adresem https://e-poltax.mf.gov.pl; do złożenia deklara-cji wystarczy standardowa przeglądarka interne-towa obsługująca protokół szyfrowania SSL v.3 (128 bitowy);

• przy pomocy aplikacji Off-Line, udostępnione na stronach MF; niestety aktualna wersja 1.5 do-stępna jest tylko dla systemów z rodziny Micro-soft Windows;

• poprzez moduły wbudowane w aplikacje (np. sys-temy finansowo-księgowe) dostarczone przez fir-my trzecie i korzystające ze schematów doku-mentów udostępnionych przez MF.

Każdy z powyższych sposobów wymaga posiada-nia przez podatnika bezpiecznego podpisu elek-tronicznego weryfikowanego za pomocą ważne-go kwalifikowanego certyfikatu. System e-POLTAX

akceptuje wszystkie certyfikaty dostępne na pol-skim rynku.

Zanim jednak prześlemy pierwszą deklarację drogą elektroniczną trzeba złożyć w US zawia-domienie o zamiarze składania deklaracji ZAW-E1 (oczywiście w papierowej wersji – patrz Ry-sunek 1), odrębnie dla każdej osoby upoważnio-nej do składania deklaracji. Następnie osoba upo-ważniona przesyła drogą elektroniczną zgłosze-nie w formacie ZAW-E2, w którym potwierdza wolę składania deklaracji drogą elektroniczną. Po weryfikacji powyższych zawiadomień US wydaje zaświadczenie ZAS-E potwierdzające zgodność danych zawartych w zawiadomieniu ZAW-E1 z danymi w zgłoszeniu ZAW-E2 złożonym przez osobę upoważnioną, a podatnik otrzymuje moż-liwość składania deklaracji drogą elektroniczną.

Janusz Ganczarski

Autor jest matematykiem i informatykiemKontakt z autorem: [email protected] domowa: www.januszg.hg.pl

Podstawowe akty prawne związane z deklaracjami elektronicznymi• Rozporządzenie Ministra Finansów z dnia 11 sierp-

nia 2006 r. w sprawie określenia rodzajów dekla-racji, które mogą być składane za pomocą środ-ków komunikacji elektronicznej (Dz.U. Nr 146, poz. 1060);

• Rozporządzenie Ministra Finansów z dnia 11 sierp-nia 2006 r. w sprawie trybu składania i wzoru zawia-domienia o zamiarze składania deklaracji w formie elektronicznej (Dz.U. Nr 146, poz. 1061);

• Rozporządzenie Ministra Finansów z dnia 11 sierp-nia 2006 r. zmieniające rozporządzenie w sprawie zaświadczeń wydawanych przez organy podatkowe (Dz.U. Nr 146, poz. 1062);

• Rozporządzenie Ministra Finansów z dnia 11 września 2006 r. w sprawie trybu składania oraz struktury logicznej zgłoszenia upoważnienia po-datnika lub osoby upoważnionej przez podatnika do składania deklaracji w formie elektronicznej i podpisywania deklaracji podpisem elektronicznym (Dz.U. Nr 168, poz. 1196);

• Rozporządzenie Ministra Finansów z dnia 11 wrze-śnia 2006 r. w sprawie struktury logicznej deklara-cji, sposobu ich przesyłania oraz rodzajów podpi-su elektronicznego, którymi powinny być opatrzone (Dz.U. Nr 168, poz. 1197);

• Rozporządzenie Ministra Finansów z dnia 2 paź-dziernika 2006 r. zmieniające rozporządzenie w sprawie struktury logicznej deklaracji, sposobu ich przesyłania oraz rodzajów podpisu elektroniczne-go, którymi powinny być opatrzone (Dz.U. Nr 179, poz. 1323).

Materiały do artykułuzamieszczone zostały

na płycie CD 1

Page 27: Software Developer's Journal 01/2007 PL

e-POLTAX

27www.sdjournal.orgSoftware Developer’s Journal 1/2007

Warto zauważyć, że osobą upoważnioną nie musi być na-wet pracownik firmy – może to być np. doradca podatkowy prowadzący obsługę księgową firmy.

Niezależnie od wybranego sposobu złożenia deklara-cji lub innego dokumentu, system e-POLTAX z założenia w ciągu kilkudziesięciu minut generuje i przesyła potwierdze-nie przyjęcia deklaracji na adres poczty elektronicznej oso-

by upoważnionej. Potwierdzenie ma postać pliku XML, któ-ry zawiera następujące informacje:

• nazwa podmiotu przyjmującego dokument elektroniczny (MF);

• identyfikator złożonego dokumentu nadany przez Central-ną Bazę Danych (CBD);

Rysunek 1. Zawiadomienie ZAW-E1

Rysunek 2. Schemat budowy działania systemu e-POLTAX (źródło MF)

��������

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

������

����������

���������

����������

���������

��� �������

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

��������

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

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

������

�����������

������

���

Page 28: Software Developer's Journal 01/2007 PL

28

Aplikacje

biznesowe

www.sdjournal.org Software Developer’s Journal 1/2007

Listing 1. Przykładowy plik z zawiadomieniem ZAW-E2

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

<!-- Zgłoszenie osoby upoważnionej do składania

i podpisywania deklaracji w formie elektronicznej

-->

<ZgloszenieRej xmlns:xsi=

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

xsi:noNamespaceSchemaLocation=

"http://e-poltax.mf.gov.pl/Repozytorium/Deklaracje/

ZAW-E2(1)_v1-0.xsd">

<!-- Nagłówek deklaracji

-->

<Naglowek>

<KodFormularza kodSystemowy="ZAW-E2">ZAW-E2

</KodFormularza>

<WariantFormularza>1</WariantFormularza>

</Naglowek>

<!-- Dane podatnika lub płatnika, którego deklaracje

składane w formie elektronicznej podpisuje osoba

upoważniona

-->

<Podmiot1>

<OsobaNiefizyczna>

<NIP>1234567890</NIP>

<PelnaNazwa>Firma S.A.</PelnaNazwa>

<REGON>123456789</REGON>

</OsobaNiefizyczna>

<AdresZamieszkaniaSiedziby rodzajAdresu="RAD">

<AdresPol>

<KodKraju>PL</KodKraju>

<Wojewodztwo>mazowieckie</Wojewodztwo>

<Powiat>warszawski</Powiat>

<Gmina>Centrum</Gmina>

<Ulica>Aleje Jerozolimskie</Ulica>

<NrDomu>1234</NrDomu>

<NrLokalu>1</NrLokalu>

<Miejscowosc>Warszawa</Miejscowosc>

<KodPocztowy>00-001</KodPocztowy>

<Poczta>Warszawa</Poczta>

</AdresPol>

</AdresZamieszkaniaSiedziby>

<Kontakt>

<Telefon>0221234567</Telefon>

<Faks>0221234567</Faks>

<Email>[email protected]</Email>

</Kontakt>

</Podmiot1>

<!-- Dane osoby fizycznej upoważnionej do podpisywania

deklaracji

-->

<Podmiot2>

<OsobaFizyczna>

<NIP>1112223344</NIP>

<ImiePierwsze>Jan</ImiePierwsze>

<Nazwisko>Kowalski</Nazwisko>

<DataUrodzenia>1980-01-01</DataUrodzenia>

<PESEL>80010199999</PESEL>

</OsobaFizyczna>

<AdresZamieszkania rodzajAdresu="RAD">

<AdresPol>

<KodKraju>PL</KodKraju>

<Wojewodztwo>mazowieckie</Wojewodztwo>

<Powiat>warszawski</Powiat>

<Gmina>Centrum</Gmina>

<Ulica>Aleje Jerozolimskie</Ulica>

<NrDomu>4321</NrDomu>

<NrLokalu>1</NrLokalu>

<Miejscowosc>Warszawa</Miejscowosc>

<KodPocztowy>00-001</KodPocztowy>

<Poczta>Warszawa</Poczta>

</AdresPol>

</AdresZamieszkania>

<Kontakt>

<Telefon>0221234567</Telefon>

<Faks>0221234567</Faks>

<Email>[email protected]</Email>

</Kontakt>

</Podmiot2>

<!-- Zakres terminu uprawnień do podpisu dekl aracji

-->

<ZakresTerminuUprawnien>

<WaznyOd>2006-10-01</WaznyOd>

<WaznyDo>2006-12-31</WaznyDo>

</ZakresTerminuUprawnien>

</ZgloszenieRej>

• wartość funkcji skrótu złożonego dokumentu, która jest identyczna z wartością użytą do podpisu składanego do-kumentu;

• wartość funkcji skrótu dokumentu w postaci otrzyma-nej przez system (łącznie z podpisem elektronicz-nym);

• typ dokumentu, którego dotyczy potwierdzenie (deklara-cja, wniosek lub zgłoszenie);

• data wpłynięcia dokumentu do systemu informatycznego administracji podatkowej (data ze stempla czasu);

• treść stempla czasu w postaci zakodowanej algorytmem Base64;

• numer NIP podmiotu głównego deklaracji, wniosku lub zgłoszenia;

• informacja o przyjęciu lub odrzuceniu dokumentu oraz ko-dy ewentualnych błędów.

Page 29: Software Developer's Journal 01/2007 PL

e-POLTAX

29www.sdjournal.orgSoftware Developer’s Journal 1/2007

Oczywiście system e-POLTAX nie weryfikuje poprawno-ści merytorycznej deklaracji – tę może wykonać wyłącznie pracownik US. Cały schemat działania systemu e-POLTAX przedstawiono na Rysunku 2.

Deklaracje elektroniczneJako format danych na potrzeby deklaracji elektronicznych wybrano XML, przy czym struktury poszczególnych doku-mentów, typy danych oraz słowniki opisane zostały przy użyciu XML Schema. Ta stosunkowo nowa technologia (specyfikacja pochodzi z 2001 roku) jest uważana za na-stępcę DTD i posiada od tego ostatniego znacznie większe możliwości.

Wszystkie dokumenty XSD (ang. XML Schema Defini-tion) z definicjami dostępne są w repozytorium schema-tów dokumentów umieszczonym na stronie WWW syste-mu e-POLTAX (https://e-poltax.mf.gov.pl/ ). Schematy do-kumentów elektronicznych są prawnie usankcjonowane rozporządzeniami MF (patrz ramka).

Pierwsze akty prawne opisujące pliki XSD zostały podpisane w dniu 11 września 2006r (od tego dnia rze-czywiście można mówić o technicznej i prawnej możliwo-ści składania deklaracji elektronicznych), a ostatnie do-stępne w momencie powstawania niniejszego tekstu po-chodzą z 2 października 2006 roku.

Także w drodze rozporządzenia MF określił termin wprowadzania kolejnych wzorów deklaracji elektronicz-nych (patrz ramka).

Rozporządzenia określają ponadto sposób opatrywa-nia deklaracji i innych dokumentów bezpiecznym podpi-sem elektronicznym weryfikowanym za pomocą ważnego kwalifikowanego certyfikatu, algorytm bezpiecznego pod-pisu elektronicznego, algorytm szyfrowania oraz funkcję skrótu.

MF dopuściło opatrywanie dokumentów podpisem elektronicznym przy użyciu jednego z dwóch formatów: XAdES-BES (ETSI TS 101 903) oraz PKCS#7, przy czym ten pierwszy wydaje się być znacznie lepiej przystosowany do potrzeb dokumentów w formacie XML.

Z deklaracji aktualnie obsługiwanych przez system e-POLTAX najpopularniejsze i zarazem najważniejsze są:

• PIT-4 – deklaracja na zaliczkę miesięczną na podatek do-chodowy od łącznej kwoty dokonanych wypłat;

• PIT-8A – deklaracja o zryczałtowanym podatku dochodo-wym;

• VAT-7 – deklaracja podatkowa dla podatku od towarów i usług.

Przykładowo wg danych dostępnych na stronie Podlaskie-go Urzędu Skarbowego w Białymstoku w 2005 roku do te-go urzędu złożono 4388 deklaracji PIT-4 i 910 deklaracji PIT-8A.

Repozytorium schematów dokumentówRepozytorium schematów dokumentów (patrz Rysunek 3) zostało podzielone na pięć części obejmujących: słowniki, definicje, potwierdzenie, szablony i deklaracje. Słowniki zawierają kody urzędów skarbowych (plik KodyUrzedow-Skarbowych_v1-0.xsd) i dwuliterowe kody krajów zgodne ze standardem ISO 3166 (plik KodyKrajow_v1-0.xsd).

Aktualnie dostępne są tylko kody urzędów skarbowych wyspecjalizowanych w obsłudze tzw. dużych podatników. W potwierdzeniach znajduje się jedynie schemat urzędo-wego potwierdzenia odbioru dokumentu elektronicznego (plik Potwierdzenie_v1-0.xsd), a definicje deklaracji i za-łączników do deklaracji umieszczono oczywiście w dekla-racjach.

Aktualnie repozytorium nie zawiera żadnych szablonów dokumentów.

Rysunek 3. Repozytorium schematów dokumentów

Rysunek 4. Program e-Poltax Off-Line z wczytanym zawiadomieniem ZAW-E2

Page 30: Software Developer's Journal 01/2007 PL

30

Aplikacje

biznesowe

www.sdjournal.org Software Developer’s Journal 1/2007

W budowie dokumentów XML zawierających deklara-cje, bardzo ważne są dokumenty zawarte w definicjach repozytorium. Zawierają one opis podstawowych typów danych (plik ElementarneTypyDanych_v1-0.xsd) i struk-tur (plik StrukturyDanych_v1-0.xsd) używanych w dekla-racjach. Typy i struktury danych przedstawiamy bliżej w ramce.

Na dokumenty, których schematy znajdują się w repo-zytorium składają się nie tylko elektroniczne odpowiedniki papierowych formularzy z deklaracjami. Znajdują się tam także wybrane rodzaje załączników i wniosków, które nie posiadają urzędowo określonego wzoru, a które mogą być elementem składowym deklaracji obsługiwanych przez system e-POLTAX. Typowym przykładem jest formularz ORD-ZU, który zawiera uzasadnienie przyczyn składania korekty deklaracji.

Pierwszym dokumentem elektronicznym, który przed-stawimy nie będzie jednak żadna z deklaracji, ale omówione wcześniej zawiadomienie ZAW-E2.

ZAW-E2 – Zgłoszenie osoby upoważnionej do składania i podpisywania deklaracji w formie elektronicznejStrukturę zawiadomienia ZAW-E2 zawiera plik ZAW-E2(1)_v1-0.xsd. Dokument zawiera cztery główne elemen-ty. Pierwszy to Nagłówek opisujący kod i wariant formu-larza. Nagłówki stanowią standardowy element każdego dokumentu elektronicznego w systemie e-POLTAX. Da-lej formularz ZAW-E2 zawiera element Podmiot1 opisują-cy dane podatnika, którego deklaracje będą składane dro-gą elektroniczną oraz element Podmiot2 zawierający da-ne osoby upoważnionej, która w imieniu podatnika będzie składała deklaracje. W danych obu podmiotów elementy składowe Kontakt są opcjonalne. Wartość atrybutu rodza-jAdresu w elementach AdresZamieszkaniaSiedziby i Adre-sZamieszkania oznacza, że są to adresy rejestracyjne obu podmiotów. Na końcu formularz ZAW-E2 zawiera okres w jakim osoba upoważniona może składać deklaracje dro-gą elektroniczną.

Przykładowy dokument z zawiadomieniem ZAW-E2 zawiera listing 1. Ten sam dokument wczytany do pro-

Rysunek 5. Program e-Poltax Off-Line z gotowym do podpisania zawiadomieniem ZAW-E2

Struktury danych opisane w pliku StrukturyDanych_v1-0.xsd:• TAdres – dane adresowe, może to być adres polski (ele-

ment AdresPol) lub adres zagraniczny (element AdresZagr); na adres polski składają się elementy: KodKraju, Wojewódz-two, Powiat, Gmina, Ulica, NrDomu, NrLokalu, Miejscowosc, KodPocztowy i Poczta; na adres zagraniczny składają się elementy: KodKraju, KodPocztowy, Miejscowosc, Ulica, NrDomu, NrLokalu, Pietro, NazwaRegionu i SkrzynkaPocz-towa;

• TIdentyfikatorOsobyFizycznej – podstawowe dane identyfi-kujące osobę fizyczną; są to następujące elementy: NIP, Imie-Pierwsze, Nazwisko, DataUrodzenia i PESEL;

• TIdentyfikatorOsobyFizycznejPelny – pełne dane iden-tyfikujące osobę fizyczną; są to elementy: NIP, ImiePierw-sze, Nazwisko, DataUrodzenia, ImieOjca, ImieMatki i PE-SEL;

• TIdentyfikatorOsobyNiefizycznej – podstawowe dane identyfi-kujące podmioty nie będą osobami fizycznymi; składają się na elementy: NIP, PelnaNazwa i REGON;

• TPodmiotDowolnyBezAdresu – podstawowe dane dowolne-go podmiotu; może to być osoba fizyczna (element Osoba-Fizyczna typu TIdentyfikatorOsobyFizycznej) lub pozostałe podmioty (element OsobaNiefizyczna tylu TidentyfikatorO-sobyNiefizycznej);

• TIdentyfikatorOsobyNiefizycznejPelny – pełne dane iden-tyfikujące podmioty nie będące osobami fizycznymi; są to następujące elementy: NIP, PelnaNazwa, SkroconaNazwa i REGON;

• TOsobaFizyczna – podstawowe dane osoby fizycznej; są to następujące elementy: OsobaFizyczna (typ TIdentyfikatorO-sobyFizycznej) oraz AdresZamieszkania (typ TAdres + atrybut rodzajAdresu);

• TOsobaNiefizyczna – podstawowe dane podmiotu nie będą-cego osobą fizyczną; są to elementy: OsobaNiefizyczna (typ TIdentyfikatorOsobyNiefizycznej) oraz AdresSiedziby (typ TA-dres + atrybut rodzajAdresu);

• TPodmiotDowolny – podstawowe dane dowolnego podmio-tu; typ jest rozszerzeniem typu TPodmiotDowolnyBezAdresu i posiada dodatkowy element AdresZamieszkaniaSiedziby (typ TAdres + atrybut rodzajAdresu);

• TOsobaFizycznaPelna – pełny zestaw danych o osobie fizycz-nej; elementy: OsobaFizyczna (typ TidentyfikatorOsobyFi-zycznejPelny) i Adres (typ Tadres);

• TOsobaNiefizycznaPelna – pełny zestaw danych o podmio-cie nie będącym osobą fizyczną; elementy: OsobaNiefizycz-na (typ TidentyfikatorOsobyNiefizycznejPelny) i Adres (typ Tadres);

• TPodmiotDowolnyPelny – pełny zestaw danych o dowol-nym podmiocie; element OsobaFizyczna (typ TIdentyfika-torOsobyFizycznejPelny) lub OsobaNiefizyczna (typ TIden-tyfikatorOsobyNiefizycznejPelny) oraz element Adres (typ TAdres).

gramu e-Poltax Off-Line oraz gotowy do podpisania z wyliczoną funkcją skrótu przedstawiono na rysunkach nr 4 i 5.

PIT-4 – deklaracja na zaliczkę miesięczną na podatek dochodowy od łącznej kwoty dokonanych wypłatStrukturę deklaracji PIT-4 opisuje plik PIT-4(17)_v1-0.xsd. Dokument zawiera cztery elementy: Nagłówek, Podmiot1,

Page 31: Software Developer's Journal 01/2007 PL

31

e-POLTAX

www.sdjournal.orgSoftware Developer’s Journal 1/2007

Listing 2. Przykładowy plik z deklaracją PIT-4

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

<Deklaracja xmlns:xsi=

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

xsi:noNamespaceSchemaLocation=

"http://e-poltax.mf.gov.pl/Repozytorium/

Deklaracje/PIT/PIT-4(17)_v1-0.xsd">

<Naglowek>

<KodFormularza kodSystemowy="PIT-4 (17)" kodPodatku="PIT"

rodzajZobowiazania="P">PIT-4</KodFormularza>

<WariantFormularza>17</WariantFormularza>

<CelZlozenia>1</CelZlozenia>

<Rok>2006</Rok>

<Miesiac>10</Miesiac>

<KodUrzedu>1472</KodUrzedu>

</Naglowek>

<Podmiot1 rola="Płatnik">

<OsobaNiefizyczna>

<NIP>1234567890</NIP>

<PelnaNazwa>Firma S.A.</PelnaNazwa>

<REGON>123456789</REGON>

</OsobaNiefizyczna>

<AdresZamieszkaniaSiedziby rodzajAdresu="RAD">

<AdresPol>

<KodKraju>PL</KodKraju>

<Wojewodztwo>mazowieckie</Wojewodztwo>

<Powiat>warszawski</Powiat>

<Gmina>Centrum</Gmina>

<Ulica>Aleje Jerozolimskie</Ulica>

<NrDomu>1234</NrDomu>

<NrLokalu>1</NrLokalu>

<Miejscowosc>Warszawa</Miejscowosc>

<KodPocztowy>00-001</KodPocztowy>

<Poczta>Warszawa</Poczta>

</AdresPol>

</AdresZamieszkaniaSiedziby>

</Podmiot1>

<!-- Dane wymiarowe deklaracji -->

<PozycjeSzczegolowe>

<!-- Liczba podatników -->

<P_19>10</P_19>

<!-- Suma wypłat -->

<P_20>20000</P_20>

<!-- Należne zaliczki -->

<P_21>4000</P_21>

<!-- Liczba podatników -->

<P_22>0</P_22>

<!-- Suma wypłat -->

<P_23>0</P_23>

<!-- Należne zaliczki -->

<P_24>0</P_24>

<!-- Liczba podatników -->

<P_25>0</P_25>

<!-- Suma wypłat -->

<P_26>0</P_26>

<!-- Należne zaliczki -->

<P_27>0</P_27>

<!-- Liczba podatników -->

<P_28>0</P_28>

<!-- Suma wypłat -->

<P_29>0</P_29>

<!-- Należne zaliczki -->

<P_30>0</P_30>

<!-- Liczba podatników -->

<P_31>0</P_31>

<!-- Suma wypłat -->

<P_32>0</P_32>

<!-- Należne zaliczki -->

<P_33>0</P_33>

<!-- Liczba podatników -->

<P_34>0</P_34>

<!-- Suma wypłat -->

<P_35>0</P_35>

<!-- Należne zaliczki -->

<P_36>0</P_36>

<!-- Liczba podatników -->

<P_37>0</P_37>

<!-- Suma wypłat -->

<P_38>0</P_38>

<!-- Należne zaliczki -->

<P_39>0</P_39>

<!-- Liczba podatników - Inne przychody -->

<P_40>0</P_40>

<!-- Suma wypłat - Inne przychody -->

<P_41>0</P_41>

<!-- Należne zaliczki - Inne przychody -->

<P_42>0</P_42>

<!-- Należne zaliczki - RAZEM -->

<P_43>4000</P_43>

<!-- Kwota zaliczek -->

<P_44>0</P_44>

<!-- Kwota przypadająca do pobrania -->

<P_45>0</P_45>

<P_46>0</P_46>

<P_47>0</P_47>

<P_48>0</P_48>

<P_49>0</P_49>

<P_50>0</P_50>

<P_51>4000</P_51>

<P_52>0</P_52>

<P_53>4000</P_53>

<P_54> </P_54>

</PozycjeSzczegolowe>

<Pouczenie>W przypadku niewpłacenia w obowiązującym

terminie kwoty z poz.53 lub wpłacenia jej

w niepełnej wysokości, niniejsza deklaracja stanowi

podstawę do wystawienia tytułu wykonawczego,

zgodnie z przepisami ustawy z dnia 17 czerwca 1966

r. o postępowaniu egzekucyjnym w administracji

(Dz.U. z 2005 r. Nr 229, poz.1954, z późn.zm)

</Pouczenie>

<Oswiadczenie>Oświadczam, że są mi znane przepisy

Kodeksu karnego skarbowego o odpowiedzialności za

uchybienie obowiązkom płatnika.</Oswiadczenie>

</Deklaracja>

Page 32: Software Developer's Journal 01/2007 PL

32

Aplikacje

biznesowe

www.sdjournal.org Software Developer’s Journal 1/2007

Listing 3. Przykładowy plik z korektą deklaracją VAT-7 oraz uzasadnieniem przyczyn korekty

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

<Deklaracja xmlns:xsi=

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

xsi:noNamespaceSchemaLocation=

"https://epoltax.mf.gov.pl/Repozytorium/Deklaracje/

VAT/VAT-7(9)_v1-0.xsd">

<Naglowek>

<KodFormularza kodSystemowy="VAT-7 (9)" kodPodatku="VAT"

rodzajZobowiazania="Z">VAT-7</KodFormularza>

<WariantFormularza>9</WariantFormularza>

<CelZlozenia poz="P_7">2</CelZlozenia>

<Rok>2006</Rok>

<Miesiac>10</Miesiac>

<KodUrzedu>1472</KodUrzedu>

</Naglowek>

<Podmiot1 rola="Podatnik">

<OsobaNiefizyczna>

<NIP>1234567890</NIP>

<PelnaNazwa>Firma S.A.</PelnaNazwa>

<REGON>123456789</REGON>

</OsobaNiefizyczna>

<AdresZamieszkaniaSiedziby rodzajAdresu="RAD">

<AdresPol>

<KodKraju>PL</KodKraju>

<Wojewodztwo>mazowieckie</Wojewodztwo>

<Powiat>warszawski</Powiat>

<Gmina>Centrum</Gmina>

<Ulica>Aleje Jerozolimskie</Ulica>

<NrDomu>1234</NrDomu>

<NrLokalu>1</NrLokalu>

<Miejscowosc>Warszawa</Miejscowosc>

<KodPocztowy>00-001</KodPocztowy>

<Poczta>Warszawa</Poczta>

</AdresPol>

</AdresZamieszkaniaSiedziby>

</Podmiot1>

<PozycjeSzczegolowe>

<P_20>0</P_20>

<P_21>0</P_21>

<P_22>0</P_22>

<P_23>0</P_23>

<P_24>0</P_24>

<P_25>0</P_25>

<P_26>0</P_26>

<P_27>0</P_27>

<P_28>1000000</P_28>

<!-- Podatek należny -->

<P_29>220000</P_29>

<!-- Wewnątrzwspólnotowa dostawa towarów -->

<P_30>500000</P_30>

<!-- Eksport towarów -->

<P_31>0</P_31>

<!-- Podstawa opodatkowania -->

<P_32>0</P_32>

<!-- Podatek należny -->

<P_33>0</P_33>

<!-- Podstawa opodatkowania - Import usług -->

<P_34>0</P_34>

<!-- Podatek należny - Import usług -->

<P_35>0</P_35>

<!-- Podstawa opodatkowania -->

<P_36>0</P_36>

<P_37>0</P_37>

<P_38>0</P_38>

<P_39>0</P_39>

<P_40>1500000</P_40>

<P_41>220000</P_41>

<P_42>0</P_42>

<P_43>0</P_43>

<P_44>0</P_44>

<P_45>0</P_45>

<P_46>1500000</P_46>

<P_47>330000</P_47>

<P_48>0</P_48>

<P_49>0</P_49>

<P_50>330000</P_50>

<P_51>0</P_51>

<P_52>0</P_52>

<P_53>0</P_53>

<P_54>0</P_54>

<P_55>110000</P_55>

<P_56>110000</P_56>

<P_57>110000</P_57>

<P_58>0</P_58>

<P_59>0</P_59>

<P_64>2</P_64>

<P_65>2</P_65>

</PozycjeSzczegolowe>

<Pouczenie>W wypadku niewpłacenia w obowiązującym

terminie kwoty z poz.53 lub wpłacenia jej

w niepełnej wysokości niniejsza deklaracja

stanowi podstawę do wystawienia tytułu

wykonawczego, zgodnie z przepisami ustawy z dnia

17 czerwca 1966 r. o postępowaniu egzekucyjnym

w administracji (Dz.U. z 2005 r. Nr 229, poz.1954,

z późn.zm).</Pouczenie>

<Oswiadczenie>Oświadczam, że są mi znane przepisy

Kodeksu karnego skarbowego o odpowiedzialności

za podanie danych niezgodnych z rzeczywistością.

</Oswiadczenie>

<Zalaczniki>

<Zalacznik_ORD-ZU>

<Naglowek>

<KodFormularza kodSystemowy=

"ORD-ZU (1)">ORD-ZU</KodFormularza>

<WariantFormularza>1</WariantFormularza>

</Naglowek>

<PozycjeSzczegolowe>

<Tresc poz="P_10">Uzasadnienie korekty deklaracji

za 10/2006</Tresc>

</PozycjeSzczegolowe>

</Zalacznik_ORD-ZU>

</Zalaczniki>

</Deklaracja>

Page 33: Software Developer's Journal 01/2007 PL

33

e-POLTAX

www.sdjournal.orgSoftware Developer’s Journal 1/2007

Listing 4. Przykładowy plik z deklaracją VAT-7K wraz z wnioskiem i przyspieszenie zwrotu podatku

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

<Deklaracja xmlns:xsi=

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

xsi:noNamespaceSchemaLocation="http://e-poltax.mf.gov.pl/

Repozytorium/Deklaracje/VAT/VAT-7K(3)_v1-0.xsd">

<Naglowek>

<KodFormularza kodSystemowy="VAT-7K (3)" kodPodatku="VAT"

rodzajZobowiazania="Z">VAT-7K</KodFormularza>

<WariantFormularza>3</WariantFormularza>

<CelZlozenia poz="P_7">1</CelZlozenia>

<Rok>2006</Rok>

<Kwartal>3</Kwartal>

<KodUrzedu>1472</KodUrzedu>

</Naglowek>

<Podmiot1 rola="Podatnik">

<OsobaFizyczna>

<NIP>1112223344</NIP>

<ImiePierwsze>Jan</ImiePierwsze>

<Nazwisko>Kowalski</Nazwisko>

<DataUrodzenia>1980-01-01</DataUrodzenia>

<PESEL>80010199999</PESEL>

</OsobaFizyczna>

<AdresZamieszkaniaSiedziby rodzajAdresu="RAD">

<AdresPol>

<KodKraju>PL</KodKraju>

<Wojewodztwo>mazowieckie</Wojewodztwo>

<Powiat>warszawski</Powiat>

<Gmina>Centrum</Gmina>

<Ulica>Aleje Jerozolimskie</Ulica>

<NrDomu>4321</NrDomu>

<NrLokalu>1</NrLokalu>

<Miejscowosc>Warszawa</Miejscowosc>

<KodPocztowy>00-001</KodPocztowy>

<Poczta>Warszawa</Poczta>

</AdresPol>

</AdresZamieszkaniaSiedziby>

</Podmiot1>

<PozycjeSzczegolowe>

<P_20>0</P_20>

<P_21>0</P_21>

<P_22>0</P_22>

<P_23>0</P_23>

<P_24>0</P_24>

<P_25>0</P_25>

<P_26>0</P_26>

<P_27>0</P_27>

<P_28>1000000</P_28>

<P_29>220000</P_29>

<P_30>500000</P_30>

<P_31>0</P_31>

<P_32>0</P_32>

<P_33>0</P_33>

<P_34>0</P_34>

<P_35>0</P_35>

<P_36>0</P_36>

<P_37>0</P_37>

<P_38>0</P_38>

<P_39>0</P_39>

<P_40>1500000</P_40>

<P_41>220000</P_41>

<P_42>0</P_42>

<P_43>0</P_43>

<P_44>0</P_44>

<P_45>0</P_45>

<P_46>1500000</P_46>

<P_47>330000</P_47>

<P_48>0</P_48>

<P_49>0</P_49>

<P_50>330000</P_50>

<P_51>0</P_51>

<P_52>0</P_52>

<P_53>0</P_53>

<P_54>0</P_54>

<P_55>110000</P_55>

<P_56>110000</P_56>

<P_57>110000</P_57>

<P_58>0</P_58>

<!-- Kwota do przeniesienia na następny okres -->

<P_59>0</P_59>

<!-- Podatnik wykonywał w okresie rozliczeniowym -->

<P_64>2</P_64>

<P_65>1</P_65>

</PozycjeSzczegolowe>

<Pouczenie>W wypadku niewpłacenia w obowiązującym

terminie kwoty z poz.53 lub wpłacenia jej

w niepełnej wysokości niniejsza deklaracja

stanowi podstawę do wystawienia tytułu

wykonawczego, zgodnie z przepisami ustawy z dnia

17 czerwca 1966 r. o postępowaniu egzekucyjnym

w administracji (Dz.U. z 2005 r. Nr 229, poz.1954,

z późn.zm).</Pouczenie>

<Oswiadczenie>Oświadczam, że są mi znane przepisy Kodeksu

karnego skarbowego o odpowiedzialności za

podanie danych niezgodnych z rzeczywistością.

</Oswiadczenie>

<Zalaczniki>

<Wniosek_VAT-ZT>

<Naglowek>

<KodFormularza kodSystemowy="VAT-ZT (3)">VAT-ZT

</KodFormularza>

<WariantFormularza>3</WariantFormularza>

</Naglowek>

<PozycjeSzczegolowe>

<P_20>110000</P_20>

<!-- Kwota do zwrotu w terminie 60 dni -->

<P_25>0</P_25>

<!-- Kwota do zwrotu w terminie 25 dni -->

<P_27>110000</P_27>

<Tresc poz="P_10">Uzasadnienie przyspieszonego zwrotu

podatku VAT z deklaracji VAT-7 za 3 kw. 2006</Tresc>

</PozycjeSzczegolowe>

</Wniosek_VAT-ZT>

</Zalaczniki>

</Deklaracja>

Page 34: Software Developer's Journal 01/2007 PL

34

Aplikacje

biznesowe

www.sdjournal.org Software Developer’s Journal 1/2007

PozycjeSzczegolowe, Pouczenie oraz Oświadczenie. Dwa pierwsze elementy opisują deklarację i podmiot ją składa-jący, element PozycjeSzczegolowe zawiera wszystkie wła-ściwe dane deklaracji, a dwa ostatnie elementy to po-uczenie o sankcjach grożących za brak terminowej wpłaty i nierzetelność danych wykazanych w deklaracji.

Przykładowy dokument XML zawierający deklarację PIT-4 przedstawiono na listingu nr 2. Warto zwrócić uwagę na in-formacje zawarte w nagłówku dotyczące wersji deklaracji PIT-4 (jest to już jak widzimy 17 wersja tego formularza) oraz atry-but rola zawarty w elemencie Podmiot1 (deklaracja dotyczy obowiązków płatnika).

PIT-8A – deklaracja na zaliczkę miesięczną na podatek dochodowy od łącznej kwoty dokonanych wypłatDrugą deklaracją, której obsługę w systemie e-POLTAX wpro-wadzono razem z PIT-4, jest formularz PIT-8A opisany w pliku PIT-8A(13)_v1-0.xsd. Deklaracja w formie elektronicznej nie różni się w swojej budowie od PIT-4, poza oczywistymi różni-cami w elementach Nagłówek i PozycjeSzczegolowe.

VAT-7 – miesięczna deklaracjadla podatku od towarów i usługSchemat formularza VAT-7 (plik VAT-7(9)_v1-0.xsd) został udostępniony na początku października 2006 roku razem z deklaracjami VAT-7K, VAT-8 i VAT-9. Nową wspólną cechą tych deklaracji jest element Załączniki, który zawiera załącz-niki składane opcjonalnie razem z deklaracją. Stąd razem z powyższymi formularzami określone zostały schematy trzech załączników:

• VAT-ZT (wniosek o przyspieszenie terminu zwrotu podatku);• VAT-ZZ (wniosek o zwrot podatku VAT);• ORD-ZU (uzasadnienie przyczyn korekty deklaracji).

Załączniki te w przeciwieństwie do deklaracji nie posiadają urzę-dowo określonego papierowego formatu, ale ich charakter powo-duje, że muszą zawierać kilka standardowych elementów repre-zentowanych odpowiednio w wersji elektronicznej. Przykładowy plik XML z korektą deklaracji VAT-7 wraz uzasadnieniem korek-ty przedstawiono na listingu nr 3. Poza zawartym w treści doku-mentu załącznikiem ORD-ZU warto zwrócić uwagę na wartość atrybutu rola w elemencie Podmiot1, która w odróżnieniu od de-klaracji PIT-4 i PIT-8A przyjmuje wartość „Podatnik ” oraz zmianę wartości elementu CelZlozenia na 2 (korekta deklaracji).

VAT-7K – kwartalna deklaracjadla podatku od towarów i usługDeklaracja VAT-7K (schemat zawarty w pliku VAT-7(9)_v1-0.xsd) jest składanym kwartalnie odpowiednikiem formularza VAT-7. Stąd jedyną różnicą w elektronicznych wersjach obu tych dekla-racji jest element Nagłówek, który zamiast numeru miesiąca (ele-ment Miesiąc) zawiera numer kwartału (element Kwartał).

Na listingu nr 4 przedstawiono przykładową deklara-cję VAT-7K, tym razem jednak składaną przez osobę fizycz-ną, czyli przez podmiot, który aktualnie nie ma takiej praw-nej możliwości. Deklaracja zawiera w sobie wniosek VAT-ZT o przyspieszenie zwrotu podatku, stąd poza dodaniem elemen-tów charakterystycznych dla tego załącznika, odpowiednio została zmodyfikowana wartość elementu P_65.

VAT-8 i VAT-9 – deklaracje dla podatku od towarów i usługDwie pozostałe deklaracje, wprowadzone razem z opisany-mi wcześniej formularzami VAT-7 i VAT-7K, należą do grupy deklaracji stosunkowo rzadko składanych przez podatników. Ich budowa nie odbiega od przedstawionych już dokumen-tów, przy czym jedynym dopuszczalnym rodzajem załącz-nika, który może być składany razem z VAT-8 i VAT-9, jest uzasadnienie przyczyn korekty deklaracji (ORD-ZU).

Projekt e-DeklaracjeJak informuje MF na swojej stronie WWW jednym z celów systemu e-POLTAX jest aktualizacja i weryfikacja wymagań funkcjonalnych, prawnych i organizacyjnych, które posłużą do wyboru docelowych rozwiązań w ramach prowadzone-go projektu e-Deklaracje współfinansowanego z Europej-

Podstawowe typy i struktury danych używane w deklaracjachElementarne typy danych opisane w pliku: ElementarneTypyDa-nych_v1-0.xsd:

• TZnakowy – typ znakowy ograniczony do jednej linii do 240 zna-ków;

• TTekstowy – typ znakowy ograniczony do 2000 znaków;• TProcentowy – wartość procentowa z dokładnością do 2

miejsc po przecinku;• TCalkowity – liczba całkowita;• TNaturalny – liczba naturalna;• TKwota2 – wartość kwotowa wykazana w złotych i groszach;• TKwotaC – wartość kwotowa wykazana w złotych;• TKwota2Nieujemna – wartość kwotowa nieujemna wykazana

w złotych i groszach;• TKwotaCNieujemna – wartość kwotowa nieujemna wykazana

w złotych;• TData – data w formacie RRRR-MM-DD;• TDataCzas – data i godzina;• TRok – rok;• TMiesiac – numeracja miesiąca;• TKwartal – numeracja kwartału;• TAdresEmail – adres e-mail;• TNrNIP – numer NIP;• TNrPESEL – numer PESEL;• TNrREGON – numer REGON;• TImie – pierwsze imię;• TNazwisko – nazwisko;• TMiejscowosc – nazwa miejscowości;• TJednAdmin – nazwa jednostki administracyjnej: wojewódz-

twa, powiatu lub gminy;• TUlica – nazwa ulicy;• TNrBudynku – numer budynku;• TNrLokalu – numer lokalu;• TKodPocztowy – kod pocztowy;• TCelZlozenia – ceł złożenia deklaracji: złożenie deklaracji po

raz pierwszy (1) lub korekta (2);• TNrDokumentu – numer dokumentu;• TWybor1 – pojedyncze pole wyboru;• TWybor1_2 – podwójne pole wyboru (1 lub 2);• TWybor1_3 – potrójne pole wyboru (1, 2 lub 3);• TSposobOpodatkowania – wybór sposobu opodatkowania (1,

2, 3 lub 4).

Page 35: Software Developer's Journal 01/2007 PL

e-POLTAX

35www.sdjournal.orgSoftware Developer’s Journal 1/2007

skiego Funduszu Rozwoju Regionalnego w ramach działa-nia 1.5 Sektorowego Programu Operacyjnego Wzrost Kon-kurencyjności Przedsiębiorstw. Projekt e-Deklaracje ma sta-nowić docelowy system bezpośredniej komunikacji elektro-nicznej pomiędzy przedsiębiorcami, a administracją podat-kową, umożliwiający wymianę drogą elektroniczną wszyst-kich dokumentów przewidzianych prawem. Obecne plany zakładają uruchomienie systemu e-Deklaracje na począt-ku 2008 roku.

Schemat systemu e-Deklaracje przedstawiono na Ry-sunku 6. Podatnik korzystający z portalu e-Deklaracje, sta-nowiącego jeden z elementów portalu e-PUAP (elektronicz-na Platforma Usług Administracji Publicznej), wybiera je-den z formularzy elektronicznych zdefiniowanych w Repo-zytorium Wzorów Dokumentów (RWD). Po jego wypełnie-niu i podpisaniu przy użyciu Infrastruktury Klucza Publicz-nego (PKI) dokument otrzymuje aplikacja e-Podatki, któ-rej zadaniem jest jego formalna weryfikacja, porównanie z danymi podatnika zawartymi w Krajowej Ewidencji Podat-ników (KEP), a docelowo w Centralnym Rejestrze Podmio-tów (CRP) oraz zapisanie w Centralnym Rejestrze Doku-mentów (CRD). Jednocześnie podatnik otrzymuje informa-cję zwrotną zawierającą m.in. unikalny numer referencyjny dokumentu.

Właściwy dla podatnika US otrzymuje dokument za pośrednictwem Platformy Integracji (PI) i w zależności od rodzaju sprawy dokument, po rejestracji w aplikacji Elek-troniczny Obieg Dokumentów (EOD), trafia albo do lokal-nego systemu POLTAX w US albo do realizacji zgodnie z przyjętą w US instrukcją kancelaryjną. CRD udostępnia podatnikowi informacje na temat stanu załatwiania spra-wy w US. Ponadto podatnik za pośrednictwem Centralnej Bazy Danych Operacyjnych (CBDO) będzie miał dostęp m.in. do informacji o stanie swojego salda.

W systemie e-Deklaracje bazy CBDO, CRD i CRP bę-dą stanowiły podstawowe źródło informacji zarówno dla po-datników jak i organów podatkowych. Ułatwi to i znacz-nie przyspieszy wymianę informacji pomiędzy urzędami i izbami skarbowymi oraz urzędami kontroli skarbowej. Z bazami tymi będą współpracować inne działające obecnie systemy centralne np. VIES (ang. VAT Information Exchange System).

PodsumowanieSystem e-POLTAX nie jest rozwiązaniem docelowym dla polskich podatników i administracji skarbowej, ale z ca-

łą pewnością przedstawione w artykule mechanizmy opi-su dokumentów elektronicznych, korzystające ze standar-du XML, zostaną utrzymane. Jest to zresztą w ocenie au-tora trafny wybór, korzystający z otwartych standardów projektowanych m.in. do takich zastosowań. Udostępnie-nie schematów elektronicznych dokumentów czyni admi-nistrację podatkową bardziej otwartą (nie powielono błę-dów ZUS) i umożliwia odpowiednie przygotowanie apli-kacji FK. Warto także zauważyć, że opracowane struktu-ry danych umożliwiają opracowanie schematu każdego ro-dzaju formularza podatkowego, nie tylko tych składanych przez przedsiębiorców.

Zastosowanie bezpiecznego podpisu elektronicznego na obecnym etapie dostępności systemu tylko dla grupy naj-większych przedsiębiorców nie jest oczywiście żadnym pro-blemem, ale już małego przedsiębiorcy lub osobę nie pro-wadzącą działalności gospodarczej, konieczność zakupu odpowiedniego urządzenia i opłacania abonamentu raczej nie zachęci do elektronicznego rozliczania się z fiskusem. Niewykluczone jednak, że w tematyce podpisu elektronicz-nego będą zmiany, ale to już jest temat na odrębny arty-kuł. W każdym razie MF w ramach projektu e-Deklaracje nie przewiduje udostępniania własnych certyfikatów.

System e-POLTAX niestety nie jest pozbawiony wad. Za-uważyli to m.in. doradcy podatkowi, którzy spotkali się na przedstawicielami MF na początku października 2006 roku. Oto postulaty wysuwane przez doradców, z którymi zgadza sie także autor:

• udostępnienie systemu w wersji testowej;• możliwości podpisania i wysłania wielu deklaracji w pacz-

kach, przy czym system przesyłałby potwierdzenie dla każdej deklaracji;

• znakowania czasem w momencie wysłania deklaracji, a nie w momencie otrzymania deklaracji przez system.

W czasie, gdy ukaże się niniejszy tekst dostępne już będą ko-lejne schematy deklaracji podatkowych. Pozostaje mieć na-dzieję, że cały system e-Deklaracje zostanie uruchomiony w terminie, a w dalszej perspektywie wszyscy podatnicy będą mieli możliwość odwiedzenia swojego US bez konieczności wy-chodzenia z własnego domu. n

Terminy wprowadzenia deklaracji elektronicznych• 16 sierpnia 2006: PIT-4, PIT-8A;• 1 października 2006: VAT-7, VAT-7K, VAT-8, VAT-9;• 1 grudnia 2006: CIT-2, CIT-2/O, CIT-8, CIT-8/O, CIT-6, CIT-D,

VAT-23, VAT-24;• 1 lutego 2007: VAT-10, VAT-11, VAT-12, VAT-Z, VAT-R, VAT-

R/UE, VAT-UE, VAT-UE/A, VAT-UE/B, VAT-UEK, WZS-1K, WZS-1M, WZS-1R, WZP-1K, WZP-1R, WZP-1M, ORD-U, ORD-TK, ORD-W1, POG-3A, IFT-1/IFT-1R, IFT-2/IFT-2R, IFT-3/IFT-3R, IFT/A.

Rysunek 6. Schemat systemu e-Deklaracje (źródło MF)

����

������

���

����

������

���

����

������

���

������

������

���

����

������

���

���

���

��

���

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

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

���

����

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

�����������

������

���������

����

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

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

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

��������

Page 36: Software Developer's Journal 01/2007 PL

36

Aplikacje

biznesowe

www.sdjournal.org Software Developer’s Journal 1/2007

Business ProcessExecution LanguageNieustannie zmieniające się warunki rynkowe

i wymagania klientów, wymuszają na przed-siębiorstwach ciągłe udoskonalanie i zmia-

nę procesów biznesowych. Powoduje to dodawanie coraz to nowszych aplikacji i rozbudowę istniejących systemów. W firmach o niskiej komputeryzacji budo-wa nowych systemów wspierających jej działalność, jak CRM (Customer Relationship Management), czy ERP (Enterprise Resource Planning), przynosi duży zwrot z inwestycji. Jednak przy dużej liczbie wdro-żonych aplikacji, zwrot z coraz to nowszych projek-tów maleje. Szefowie działów IT muszą borykać się z napiętymi planami, ograniczonymi budżetami, ro-snącą złożonością systemów informatycznych, ryzy-kiem ich rozbudowy i coraz trudniejszą replikacją da-nych pomiędzy niekompatybilnymi systemami.

Odpowiedzią na te problemy jest architektura zo-rientowana na serwisy (ang. Service Oriented Archi-tecture), w skrócie SOA. Dzięki niej możliwe jest bu-dowanie nowych wielofunkcyjnych aplikacji poprzez agregację funkcjonalności już istniejących systemów. Odbywa się to w sposób 2-fazowy. Najpierw udostęp-niane są serwisy, które eksponują usługi już istnieją-cych systemów. Następnie wiele serwisów jest łączo-nych i komponowanych w jeden proces biznesowy.

SOA i BPELSOA było rozwiązaniem znanym już w ubiegłym dzie-sięcioleciu. Jednakże rynek cierpiał na brak ustanda-ryzowanego sposobu integracji systemów. Obecnie coraz większą popularnością cieszy się Business Pro-cess Execution Language for Web Services (BPEL lub BPEL4WS). Jest to język, który służy do definiowania i wykonywania procesów biznesowych z wykorzysta-niem web serwisów, za pomocą których wyekspono-wane są serwisy podsystemów. Budowa procesu biz-nesowego polega na łączeniu i koordynowaniu wielu web serwisów w jednym przepływie.

BPEL łączy cechy dwóch starszych języków służących do opisu przepływów pracy (ang. work-flow). Pierwszym z nich jest WSFL (Web Service Flow Language), stworzony przez IBM i oparty na teorii grafów skierowanych. Drugim jest dziecko Mi-crosoftu, XLANG, który wykorzystywał ideę sche-matów blokowych.

Pierwsza wersja BPEL-a pojawiła się w sierpniu 2002 roku. Przyciągnęła ona uwagę wielu firm, któ-re przyłączyły się do współpracy. Zaowocowało to w marcu 2003 roku stworzeniem wersji 1.1, któ-ra miesiąc później została przekazana do organiza-cji standaryzacyjnej OASIS (Organization for the Ad-vancement of Structured Information Standards).

Podstawy językaDefinicja procesu biznesowego w języku BPEL pole-ga na określeniu porządku wywoływanych web ser-wisów. Czy mają być one wywoływane sekwencyj-

Piotr Skrobisz

Autor pracuje w firmie Oracle Corporation w dziale Mobi-le, Wireless and Voice Solutions, gdzie zajmuje się pro-jektowaniem systemów informatycznych. Jest również doktorantem w Instytucie Badań Systemowych PAN.Kontakt z autorem: [email protected]

Przykłady zastosowańOracle BPEL Process Manager’a• State Children’s Health Insurance Program (SCHIP).

Amerykańska firma Policy Studies, Inc. wykorzystała technologię BPEL do budowy systemu typu workflow, wspierającego przetwarzania wniosków rejestracji do amerykańskiego programu ubezpieczeń SCHIP;

• Dostawca elektryczności – integracja aplikacji w od-działach. Firma WIPRO użyła technologii BPEL do usprawnienia komunikacji pomiędzy oddziałami jed-nego z dużych dostawców elektryczności. Każdy z lo-kalnych oddziałów posiadał swoją własną aplikację do obsługi procesów biznesowych. Tak duża heteroge-niczność wymusiła zastosowanie architektury SOA;

• Corrections Corporation Of America (CCA) – inte-gracja aplikacji dla systemu więziennictwa. BPEL został wykorzystany przez firmę BIAS do zaimple-mentowania wymiany danych pomiędzy systemami dwóch amerykańskich firm z sektora więziennictwa – CCA i Hamilton County Jail Systems (CJIS);

• Health Canada – kontrola wydawania i niszcze-nia leków. W Kanadzie BPEL znalazł zastosowa-nie przy automatyzacji procesu kontroli wydawania i niszczenia leków. Budowa systemu wymagała in-tegracji z wieloma państwowymi wydziałami i agen-cjami oraz instytucjami międzynarodowymi;

• Lufthansa Flight Training (LFT) – system CRM. Spółka LFT, należąca do Lufthansa AG, wykorzy-stała BPEL do budowy łatwo modyfikowalnego sys-temu CRM zintegrowanego z SAP Financials i inny-mi wykorzystywanymi w firmie aplikacjami;

• Washington Group International (WGI) – system ERP. WGI dostarcza usług z najróżniejszych sek-torów przemysłu, jak budownictwo, górnictwo, transport, czy energetyka. Działalność takiej firmy wspierana jest przez ogromną liczbę najróżniejsze-go oprogramowania i serwerów. Przy tak heteroge-nicznym środowisku BPEL okazał się idealną tech-nologią do budowy systemu ERP.

Materiały do artykułuzamieszczone zostały

na płycie CD 1

Page 37: Software Developer's Journal 01/2007 PL

Business Process Execution Language

37www.sdjournal.orgSoftware Developer’s Journal 1/2007

• <pick> - umożliwia wybór jednej z wielu alternatywnych ścieżek na podstawie zdefiniowanych zdarzeń;

• <catch> i <catchAll> - pozwalają na przechwytywanie i ob-sługę wyjątków podobnie, jak w Javie w przypadku kon-strukcji try-catch.

Do bardzo ważnych elementów języka należą dodatkowo:

• <scope> - pozwala na wyodrębnianie logicznych bloków w całym procesie. Taki blok może posiadać lokalne zmien-ne niewidoczne poza nim, obsługę wyjątków dla czynno-ści w nim zawartych oraz obsługę rekompensacji w przy-padku wycofywania transakcji;

• <partnerLink> - wskaźnik na wykorzystywane web serwisy;• <variable> - definicja zmiennej.

Budowa przykładowegoprocesu biznesowegoNajlepszym sposobem nauki jest praktyka, dlatego w niniejszym artykule zbudujemy prosty proces BPEL-owy do obsługi zamó-wień książek. Aplikacja klienta (dalej dla uproszczenia nazywana klientem) przy wywołaniu procesu będzie przekazywać informa-cje takie jak: tytuł książki, autorzy, ilość egzemplarzy, numer kar-ty kredytowej, datę jej ważności, imię i nazwisko zamawiające-go oraz adres, dokąd książka ma być wysłana. Zadaniem nasze-go systemu, będzie weryfikacja podanej karty kredytowej, odpy-tanie równolegle dwóch księgarni o cenę danej książki, wybra-nie księgarni, gdzie cena książki jest najniższa, a następnie jej zakup. Na końcu proces przekaże żądanie dostarczenia pacz-ki do podsystemu, zajmującego się dostawą. Będzie go symulo-wał inny proces BPEL-owy. Do budowy naszego systemu wyko-rzystamy wcześniej przygotowane web serwisy, symulujące sys-temy zewnętrzne, z którymi się zintegrujemy (operator kart kre-dytowych oraz dwie księgarnie). Rysunek 1 przedstawia sche-mat procesu, którego budową się zajmiemy. Do konstrukcji na-szego procesu wykorzystamy Oracle JDeveloper 10g w wersji 10.1.3.1.0, a do jego uruchomienia Oracle BPEL Process Mana-ger 10.1.3.1.0. Oba programy można ściągnąć za darmo z nastę-pującej strony: http://www.oracle.com/technology/software/tech/

Rysunek 1. Schemat procesu do obsługi zamówień książek

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

������

����� ������

���������

�����������

���������

������

����������

���������

��������

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

��������

����� ������

����������

�����

���������

������

���������

�������

������

���������

���

�������

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

���

�������

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

�������

�����������

����

�������

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

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

�������

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

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

nie, czy też równolegle. Możliwe jest określenie operacji warun-kowych, pętli, czy też obsługa wyjątków. Język pozwala na de-finiowanie zmiennych, kopiowanie i przypisywanie ich wartości. Dzięki temu możliwe jest przekazywanie danych pomiędzy web serwisami i gromadzenie ich w trakcie realizacji procesu.

Składnia języka opiera się na XML-u, a z racji tego, że pro-ces operuje na web serwisach, wykorzystywane są lub mogą być między innymi takie standardy, jak SOAP, WSDL, UDDI, WS-Addressing, WS-ReliableMessaging, WS-Security, WS-Coordination, WS-Transaction. Należy zauważyć, że proces BPEL-owy sam w sobie jest web serwisem i może być wyko-rzystywany przez inne procesy, jako podproces. Proces biz-nesowy składa się z czynności. Do podstawowych należą na-stępujące elementy:

• <invoke> - wywołanie web serwisu;• <receive> - oczekiwanie na wywołanie procesu przez

klienta i odebranie od niego wiadomości;• <reply> - zwrócenie odpowiedzi w przypadku synchronicz-

nego wywołania procesu;• <assign> - operacje na wartościach zmiennych;• <wait> - uśpienie procesu, na określony czas;• <throw> - wyrzucenie wyjątku, analogicznie jak w Javie;• <terminate> - zakończenie procesu na przykład w wyniku

błędu lub awarii;• <compensete> - wywołanie czynności rekompensujących

(ang. compansation) w przypadku potrzeby wycofania transakcji.

Analogicznie, jak w tradycyjnych językach programowania, tak również w BPEL-u nie obyłoby się bez elementów od-powiedzialnych za kontrolę przepływu. Do dyspozycji mamy między innymi:

• <switch> - definiuje instrukcje warunkowe;• <while> - pętla;• <sequence> - oznacza, że zawarty w niej zbiór czynności

ma być wykonany sekwencyjnie;• <flow> - pozwala na wykonywanie czynności równolegle;

Page 38: Software Developer's Journal 01/2007 PL

38

Aplikacje

biznesowe

www.sdjournal.org Software Developer’s Journal 1/2007

Listing 1. Nowy asynchroniczny proces BPEL-owy

webservices/index.html. Instalacja nie powinna nastręczyć więk-szych trudności. W przypadku JDeveloper’a sprowadza się do jego rozpakowania. BPEL PM instaluje się przez uruchomienie programu setup.exe. Do naszych celów wystarczy wybranie opcji deweloperskiej. W dalszej części artykułu założymy, że został on zainstalowany na domyślnym porcie 9700. W pierwszej kolejno-ści przystąpimy do zainstalowania wyżej wspomnianych web serwisów, a następnie zbudujemy cały proces.

Przygotowanie web serwisówZgodnie z wcześniejszą deklaracją przy budowie naszego procesu biznesowego skorzystamy z trzech web serwisów. Do celów edukacyjnych wystarczy by były to jedynie proste klasy Javy symulujące systemy zewnętrzne. Będą one udo-stępniały następujące funkcjonalności:

• CreditCardCheckWS – posiada tylko jedną metodę do weryfikacji karty kredytowej. Jako parametry wejściowe przyjmuje numer karty, datę jej ważności oraz imię i na-

zwisko właściciela. W przypadku problemów z kartą wy-rzucany jest wyjątek:

void checkCreditCard(String cardNo, Date validTo,

String name)

throws CreditCardException

• BookStore1WS – usługa pierwszej księgarni. Posiada dwie metody. Pierwsza zwraca cenę książki. Jako parametry wejściowe przyjmowany jest tytuł i autorzy. Druga metoda służy do zakupu książki. Na wejściu przyjmuje tytuł, auto-rów, numer karty, datę jej ważności, imię i nazwisko zama-wiającego oraz ilość egzemplarzy:

double requestForQuote(String title, String authors)

int orderBook(String title, String authors,

String creditCard,

Date validTo,String name, int quantity)

• BookStore2WS – usługa drugiej księgarni. Posiada analo-giczne metody. Różnią się one jedynie nazwami dla zróż-nicowania naszego przypadku:

double RFQ(String title, String authors)

int buyBook(String title, String authors, String creditCard,

Date validTo, String name, int quantity)

Opis tworzenia web serwisów wykracza poza ten artykuł, dlatego wymagana jest podstawowa znajomość tej techno-logii. Czytelnik może również skorzystać z gotowych źródeł umieszczonych na płycie dołączonej do magazynu.

Jednym ze sposobów umieszczenia web serwisów w konte-nerze J2EE (wykorzystamy kontener OC4J dostarczany z Orac-le BPEL PM) jest wykorzystanie JDevelopera. W tym celu wybie-ramy z File->New->General->Applications->Application. Po po-daniu nazwy i katalogu w oknie dialogowym klikamy na przycisk Ok. W następnym oknie rezygnujemy ze stworzenia nowego pro-jektu. Do wybranego katalogu kopiujemy z płyty cały projekt za-wierający web serwisy – katalog ExternalWS. Dodajemy go ko-rzystając z menu File->Open i wybierając plik ExternalWS.jpr.

Rysunek 2. Nowy asynchroniczny proces BPEL-owy

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

<process name="OrderBook"

targetNamespace="http://xmlns.oracle.com/OrderBook"

xmlns="http://schemas.xmlsoap.org/ws/2003/03/

business-process/"

xmlns:client="http://xmlns.oracle.com/OrderBook"

xmlns:ora="http://schemas.oracle.com/xpath/extension"

xmlns:orcl="http://www.oracle.com/XSL/Transform/java/

oracle.tip.pc.services.functions.ExtFunc"

xmlns:xp20="http://www.oracle.com/XSL/Transform/java/

oracle.tip.pc.services.functions.Xpath20"

xmlns:ldap="http://schemas.oracle.com/xpath/

extension/ldap"

xmlns:bpelx="http://schemas.oracle.com/bpel/extension"

xmlns:bpws="http://schemas.xmlsoap.org/ws/

2003/03/business-process/">

<partnerLinks>

<partnerLink name="client"

partnerLinkType="client:OrderBook"

myRole="OrderBookProvider"

partnerRole="OrderBookRequester"/>

</partnerLinks>

<variables>

<variable name="inputVariable"

messageType="client:OrderBookRequestMessage"/>

<variable name="outputVariable"

messageType="client:OrderBookResponseMessage"/>

</variables>

<sequence name="main">

<receive name="receiveInput"

partnerLink="client"

portType="client:OrderBook"

operation="initiate"

variable="inputVariable"

createInstance="yes"/>

<invoke name="callbackClient"

partnerLink="client"

portType="client:OrderBookCallback"

operation="onResult"

inputVariable="outputVariable"/>

</sequence>

</process>

Page 39: Software Developer's Journal 01/2007 PL

Business Process Execution Language

39www.sdjournal.orgSoftware Developer’s Journal 1/2007

W kolejnym kroku tworzymy połączenie z kontenerem J2EE. Klikamy prawym klawiszem myszy w zakładce Connec-tions na folderze Application Server i wybieramy New Appli-cation Server Connection. Jako typ serwera aplikacji pozosta-wiamy opcję Autonomiczny OC4J 10g 10.1.3.

W celu umieszczenia web serwisów należy w zakład-ce Applications Navigator kliknąć prawym klawiszem myszy na pliku WebServices.deploy i wybrać Deploy To oraz nazwę wcześniej zdefiniowanego połączenia. Jeśli wszystko się po-wiodło, to web serwisy powinny być dostępne z poziomu prze-glądarki, a w szczególności ich opisy WSDL:

• http://localhost:9700/external/CreditCardCheckWSSoapHt-tpPort?wsdl;

• http://localhost:9700/external/BookStore1WSSoapHttpPort?wsdl;

• http://localhost:9700/external/BookStore2WSSoapHttpPor-t?wsdl.

Oczywiście możliwe jest umieszczenie ich na dowolnym ser-werze aplikacyjnym, jak również stworzenie własnych web serwisów, niekoniecznie zaimplementowanych w Javie, do czego serdecznie zachęcam.

Stworzenie nowego projektu BPELMając już gotowe web serwisy możemy przystąpić do ich inte-gracji budując asynchroniczny proces. Do tego celu użyjemy kre-atora, który wygeneruje cały szkielet projektu BPEL-owego: plik źródłowy procesu, interfejs WSDL, deskryptor oraz skrypt Ant-owy do kompilacji i umieszczania procesu na serwerze. Z menu

wybieramy File->New->General->Projects->BPEL Process Pro-ject. Podajemy nazwę procesu, np. OrderBook i jako typ proce-su pozostawiamy Asynchronous BPEL Process. Zatwierdzamy wszystko naciskając przycisk Finish. Generator stworzył nowy proces, który w zakładce Diagram powinien wyglądać tak, jak na Rysunku 2. Zwróćmy uwagę na pliki, jakie wygenerował kreator:

• OrderBook.bpel – źródło procesu;• OrderBook.wsdl – opis interfejsu procesu, parametry wej-

ściowe i wyjściowe. Dzięki temu możliwe jest wywoływa-nie procesu z poziomu innych procesów i aplikacji;

• OrderBook.xsd – plik XML Schema, który definiuje dane wejściowe i wyjściowe dla procesu. Jest on importowany w OrderBook.wsdl;

• build.xml i build.properties – pliki Ant-owe do kompilacji i umieszczania procesu na serwerze.

Jeśli wybierzemy plik OrderBook.bpel i przejdziemy do zakład-ki Source, będziemy mieli możliwość zobaczenia źródła procesu. Powinien być podobny do tego z Listingu 1. Na razie proces nic nie robi, poza odebraniem danych wejściowych od klienta (<rece-ive>), który go wywołuje, oraz wywołaniem klienta i przekazaniu mu odpowiedzi (<invoke>). Te dwa wywołania są korelowane auto-matycznie dzięki wykorzystaniu standardu WS-Addressing. Klient zdefiniowany jest w elemencie <partnerLink> w sekcji <partner-Links>. Tu też będą pojawiać się połączenia do wykorzystywa-nych web serwisów. W elemencie <variables> umieszczone są dwie zmienne, przechowujące odpowiednio dane wejściowe i wyj-ściowe. Przed przystąpieniem do komponowania procesu musi-my określić jakie dane będzie on otrzymywał i zwracał. Dla nasze-go prostego przykładu, jako parametry wejściowe wystarczą: tytuł, autorzy, ilość egzemplarzy, numer karty kredytowej, data jej waż-ności, imię i nazwisko, adres. Po zakończeniu proces będzie zwra-cał string z informacją, że książka została wysłana. Informacje te definiuje się w pliku XML Schema, w naszym przypadku w Order-Book.xsd. Należy go zmienić tak, jak pokazano to na Listingu 2.

Wywołanie web serwisuZgodnie z Rysunkiem 1 pierwszym krokiem w naszym procesie jest weryfikacja karty kredytowej. Sprowadza się on do wywoła-

Listing 2. Definicja parametrów wejściowych i wyjściowych procesu

<schema attributeFormDefault="unqualified"

elementFormDefault="qualified"

targetNamespace="http://xmlns.oracle.com/OrderBook"

xmlns="http://www.w3.org/2001/XMLSchema">

<element name="OrderBookProcessRequest">

<complexType>

<sequence>

<element name="title" type="string"/>

<element name="authors" type="string"/>

<element name="quantity" type="int"/>

<element name="creditCardNo" type="string"/>

<element name="validTo" type="dateTime"/>

<element name="name" type="string"/>

<element name="address" type="string"/>

</sequence>

</complexType>

</element>

<element name="OrderBookProcessResponse">

<complexType>

<sequence>

<element name="result" type="string"/>

</sequence>

</complexType>

</element>

</schema>

Rysunek 3. Wywołanie web serwisu z obsługą wyjątku

Page 40: Software Developer's Journal 01/2007 PL

40

Aplikacje

biznesowe

www.sdjournal.org Software Developer’s Journal 1/2007

nia web serwisu CreditCardCheckWS. Całe wywołanie umieści-my w nowym elemencie <scope>, co pozwoli na logiczne wyod-rębnienie tego kroku, jak również późniejszą obsługę wyjątków. W tym celu z zakładki Component Palette przeciągamy kompo-nent Scope i umieszczamy go pomiędzy już istniejącymi czynno-ściami receiveInput i callbackClient. Rozwijamy komponent Sco-pe naciskając znaczek plusa. Teraz możemy w nim umieszczać inne elementy. Przed definiowaniem wywołania web serwisu mu-simy stworzyć dla niego wskaźnik. Robi się to przez przeciągnię-cie komponentu PartnerLink na pole Services. W oknie dialogo-wym podajemy lokalizację opisu WSDL web serwisu (np. http://localhost:9700/external/CreditCardCheckWSSoapHttpPort?wsdl) i naciskamy ikonkę Parse WSDL File. Zatwierdzamy próbę stworzenia pliku WSDL z opisem typu Partner Link’a. Jako Part-ner Role wybieramy z listy jedyną opcję, CreditCardCheckWS_Role. Zamykamy okno naciskając przycisk Ok.

Teraz jesteśmy gotowi do zdefiniowania wywołania web ser-wisu. W tym celu przeciągamy komponent Invoke i umieszczamy go w elemencie Scope. Następnie przeciągamy ikonkę strzałki do uprzednio stworzonego ParnterLink’a. W oknie dialogowym zmieniamy nazwę i upewniamy się, że wybraną operacją web serwisu jest ta, która służy do weryfikacji karty. Następnie two-rzymy zmienną wejściową i wyjściową, klikając na ikonki Auto-matically Create Input Variable. Możemy zaznaczyć opcje Local Variable, aby zmienne były widoczne jedynie w zakresie elemen-tu Scope. Zatwierdzamy zmiany, naciskając przycisk Ok. Do tak zdefiniowanego wywołania musimy jeszcze przekazać wartości – numer karty kredytowej, datę jej ważności oraz imię i nazwi-sko. Przekopiujemy je ze zmiennej wejściowej procesu do zmien-nej wejściowej elementu Invoke. Dokonuje się tego poprzez uży-cie komponentu Assign. Umieszczamy go przed elementem In-voke. Klikamy na niego dwa razy. W oknie dialogowym wybiera-my opcję Create->Copy operation. W części From wybieramy ze zmiennej wejściowej procesu numer karty. Powinniśmy uzyskać wyrażenie XPath (wyświetlane na dole okna) podobne do tego:

/client:OrderBookProcessRequest/client:creditCardNo

Analogicznie w sekcji To konstruujemy wyrażenie dla zmien-nej wejściowej dla elementu Invoke:

/ns2:checkCreditCardElement/ns2:cardNo

Te same kroki powtarzamy dla daty ważności oraz imienia i nazwiska. W ten sposób zdefiniowaliśmy wywołanie web ser-wisu weryfikującego kartę kredytową, a tym samym skonstru-owaliśmy pierwszy krok naszego procesu biznesowego. Efekt powinien być zbliżony do przedstawionego na Listingu 3.

Obsługa wyjątkówWywoływany web serwis może wyrzucać wyjątki. Podob-nie do języków programowania takich jak Java, BPEL umoż-liwia ich obsługę. W naszym przypadku metoda checkCre-ditCard, może wyrzucić wyjątek CreditCardException przy braku pomyślnej weryfikacji karty. Gdy taka sytuacja na-stąpi zakończymy cały proces biznesowy. Obsługę wyjąt-ków można dodawać dla elementów Scope. W tym celu wy-bieramy w nim ikonkę Add Catch Branch. Powoduje to poja-wienie się elementu <faultHandlers>. Klikamy na jego repre-zentację graficzną i w oknie dialogowym naciskamy ikonkę Browse Faults. Wybieramy Partner Links->CreditCardChec-kWS->Imported WSDL->CreditCardCheckWSSoapHttpPort->CreditCardException.

Do zakończenia procesu służy komponent Terminate. Wy-starczy go przeciągnąć na obszar elementu <faultHandlers>. Po tych operacjach nasz proces powinien przypominać ten przedstawiony na Rysunku 3.

Listing 3. Wywołanie web serwisu CreditCardCheckWS

<scope name="checkingCreditCard"><variables>

<variable name="checkCreditCard_Input"

messageType="ns1:CreditCardCheckWS_checkCreditCard"/>

<variable name="checkCreditCard_Output"

messageType=

"ns1:CreditCardCheckWS_checkCreditCardResponse"/>

</variables><sequence name="Sequence_1">

<assign name="Assign_CardNo"><copy>

<from variable="inputVariable" part="payload"

query="/client:OrderBookProcessRequest/

client:creditCardNo"/>

<to variable="checkCreditCard_Input" part="parameters"

query="/ns2:checkCreditCardElement/ns2:cardNo"/>

</copy><copy>

<from variable="inputVariable" part="payload"

query="/client:OrderBookProcessRequest/client:validTo"/>

<to variable="checkCreditCard_Input" part="parameters"

query="/ns2:checkCreditCardElement/ns2:validTo"/>

</copy><copy>

<from variable="inputVariable" part="payload"

query="/client:OrderBookProcessRequest/client:name"/>

<to variable="checkCreditCard_Input" part="parameters"

query="/ns2:checkCreditCardElement/ns2:name"/>

</copy></assign>

<invoke name="checkCreditCard"

partnerLink="CreditCardCheckWS"

portType="ns1:CreditCardCheckWS"

operation="checkCreditCard"

inputVariable="checkCreditCard_Input"

outputVariable="checkCreditCard_Output"/>

</sequence>

</scope>

Rysunek 4. Test procesu BPEL-owego w konsoli administracyjnej

Page 41: Software Developer's Journal 01/2007 PL

41

Business Process Execution Language

www.sdjournal.orgSoftware Developer’s Journal 1/2007

Listing 4. Zrównoleglenie procesu BPEL-owego

Kompilacja i uruchomienie procesuPomimo, że nasz proces nie jest jeszcze skończony, warto go skompilować i przetestować. Upewnimy się, że web ser-wis CreditCardCheckWS jest w rzeczywistości wywoływany. Zakładając, że Oracle BPEL PM jest uruchomiony, tworzymy w JDeveloperze połączenie do niego. Postępujemy podobnie, jak to miało miejsce w przypadku połączenia do kontenera J2EE, z tym, że nie wybieramy opcji Application Server, a Inte-gration Server. Należy pamiętać, że domyślnie serwer pracuje na porcie 9700. Po pomyślnym skonfigurowaniu połączenia, umieszczamy aplikację na serwerze, klikając prawym klawi-szem myszy na projekcie BPEL-owym i wybierając Deploy To->Nazwa naszego połączenia->Deploy to default domain. Apli-kacja zostanie skompilowana i umieszczona na serwerze.

Teraz możemy przejść do konsoli administracyjnej Orac-le BPEL Process Manager’a i przetestować naszą aplikację. W tym celu otwieramy przeglądarkę i przechodzimy do http://localhost:9700/BPELConsole. Logujemy się jako bpeladmin (domyślne hasło: welcome1). Jeśli wszystko się powiodło, to po-winniśmy zobaczyć w konsoli administracyjnej w zakładce Da-shboard nasz proces OrderBook. Po kliknięciu na nim przecho-dzimy do panelu Initiate, który pozwala na przetestowanie na-szego procesu. Jest to wygenerowany dynamicznie klient, któ-ry wywołuje naszą aplikację, jak zwykły web serwis (jak zosta-ło to wcześniej wspomniane, proces posiada również swój wła-

sny opis WSDL). Wypełniamy formularz z danymi wejściowymi i naciskamy przycisk Post XML Message (patrz Rysunek 4).

Proces zostaje uruchomiony. Klikając na ikonkę Visual Flow możemy zobaczyć, jakie kolejne kroki zostały wykona-ne. Możliwe jest też podejrzenie przesyłanych danych i we-ryfikację, czy cały proces przebieg tak, jak zakładaliśmy. Je-śli web serwis CreditCardCheckWS został wywołany bez błę-dów, graf czynności powinien być taki, jak na Rysunku 5.

Rysunek 5. Graf czynności dla naszego procesu BPEL-owego

<scope name="checkPrices">

<variables>

<variable name="checkBookStore1_Input"

messageType="ns1:BookStore1WS_requestForQuote"/>

<variable name="checkBookStore2_Input"

messageType="ns1:BookStore2WS_RFQ"/>

</variables>

<flow name="Flow_1">

<sequence name="Sequence_2">

<assign name="setBookDetails2">

<copy>

<from variable="inputVariable" part="payload"

query="/client:OrderBookProcessRequest/

client:title"/>

<to variable="checkBookStore2_Input"

part="parameters"

query="/ns2:RFQElement/ns2:title"/>

</copy>

<copy>

<from variable="inputVariable" part="payload"

query="/client:OrderBookProcessRequest/

client:authors"/>

<to variable="checkBookStore2_Input"

part="parameters"

query="/ns2:RFQElement/ns2:authors"/>

</copy>

</assign>

<invoke name="checkBookStore2"

partnerLink="BookStore2WS"

portType="ns1:BookStore2WS" operation="RFQ"

inputVariable="checkBookStore2_Input"

outputVariable="checkBookStore2_Output"/>

</sequence>

<sequence name="Sequence_2">

<assign name="setBookDetails1">

<copy>

<from variable="inputVariable" part="payload"

query="/client:OrderBookProcessRequest/

client:title"/>

<to variable="checkBookStore1_Input"

part="parameters"

query="/ns2:requestForQuoteElement/ns2:title"/>

</copy>

<copy>

<from variable="inputVariable" part="payload"

query="/client:OrderBookProcessRequest/

client:authors"/>

<to variable="checkBookStore1_Input"

part="parameters"

query="/ns2:requestForQuoteElement/ns2:authors"/>

</copy>

</assign>

<invoke name="checkBookStore1"

partnerLink="BookStore1WS"

portType="ns1:BookStore1WS"

operation="requestForQuote"

inputVariable="checkBookStore1_Input"

outputVariable="checkBookStore1_Output"/>

</sequence>

</flow>

</scope>

Page 42: Software Developer's Journal 01/2007 PL

42

Aplikacje

biznesowe

www.sdjournal.org Software Developer’s Journal 1/2007

Listing 5. Operacja warunkowa Switch

Zachęcam do testu dla przypadku, gdy web serwis Credit-CardCheckWS wyrzuca wyjątek (jeśli została użyta dostarczo-na implementacja, należy podać numer karty 123456789). Wów-czas powinien on być obsłużony, poprzez zatrzymanie procesu.

Wywołania równoległePrzystąpmy teraz do dalszej budowy naszego procesu. Zgod-nie z Rysunkiem 1 mamy odpytać dwie księgarnie o cenę książ-ki. Oba te wywołania nie są ze sobą powiązane, dlatego najle-piej wykonać obie czynności równolegle. Do rozdzielania proce-su na dwie ścieżki służy komponent Flow. Możemy go umieścić w nowym elemencie Scope dla logicznego wyodrębnienia te-go kroku. W ten sposób proces został rozdzielony na dwie rów-noległe ścieżki. BPEL gwarantuje nam, że wszystkie operacje z obu ścieżek zostaną wykonane, zanim proces przystąpi do ko-lejnych czynności. W pierwszej ścieżce musimy wywołać web serwis księgarni 1, BookStore1WS, a konkretnie metodę odpytu-jącą o cenę książki. W drugiej ścieżce wywołujemy web serwis BookStore2WS. Obie operacje konstruujemy w podobny spo-sób, jak miało to miejsce w przypadku CrediCardCheckWS. Two-rzymy PartnerLink’i, konfigurujemy komponenty Invoke, za pomo-cą Assign kopiujemy wartości do parametrów wejściowych (tytuł, autorzy oraz imię i nazwisko). Jeśli całe zrównoleglenie umieści-liśmy w odrębnym elemencie Scope, to zmienne wyjściowe kom-ponentów Invoke pozostawmy, jako zmienne globalne. Posłużą one przy operacji warunkowej, do porównania cen książki.

Po zakończeniu wymienionych kroków powinniśmy uzy-skać wynik przedstawiony na Listingu 4 i Rysunku 6.

WarunkiBPEL umożliwia również operacje warunkowe, co pozwala na wybór odpowiedniej ścieżki w zależności od wyników uzyska-nych w poprzedzających operacjach. W naszym przypadku chcemy porównać ceny książki w obu księgarniach i dokonać zakupu tam, gdzie jest ona tańsza. Do tego celu posłuży nam komponent Switch. Przypomina operację switch znaną z tra-dycyjnych języków programowania. Może posiadać wiele ele-mentów <case>, do których przypisane są warunki oraz jeden blok <otherwise>, który jest wykonywany, jeśli żaden z warun-ków nie zostanie spełniony. Z racji tego, że musimy porównać dwie ceny, wystarczy nam jeden element <case> i <otherwise>. Warunki dodajemy po kliknięciu ikonki View Condition Expres-sion. Możemy wpisać sami odpowiednie wyrażenie XPath lub skorzystać z pomocy kreatora, klikając na ikonkę XPath Expression Builder. W naszym przypadku musimy porównać

Rysunek 6. Zrównoleglenie procesu BPEL-owego

<switch name="LowerPrice">

<case condition="bpws:getVariableData(

'checkBookStore1_Output','parameters','/ns2:

requestForQuoteResponseElement/ns2:result')

<=bpws:getVariableData('checkBookStore2_Output','

parameters','/ns2:RFQResponseElement/ns2:result')">

<sequence name="Sequence_3">

<assign name="setOrderDetails1">

<!--Tutaj kopiujemy ze zmiennej wejściowej procesu

do zmiennej buyBook1Input składowe: title, authors,

quantity, creditCardNo, validTo, name. -->

</assign>

<invoke name="buyBook1" partnerLink="BookStore1WS"

portType="ns1:BookStore1WS"

operation="orderBook"

inputVariable="buyBook1Input"

outputVariable="buyBook1_Output"/>

Rysunek 7. Wywołanie asynchroniczne

</sequence>

</case>

<otherwise>

<sequence name="Sequence_4">

<assign name="setOrderDetails2">

<!--Tutaj kopiujemy ze zmiennej wejściowej procesu

do zmiennej buyBook2_Input składowe: title, authors,

quantity, creditCardNo, validTo, name. -->

</assign>

<invoke name="buyBook2" partnerLink="BookStore2WS"

portType="ns1:BookStore2WS" operation="buyBook"

inputVariable="buyBook2_Input"

outputVariable="buyBook2_Output"/>

</sequence>

</otherwise>

</switch>

Page 43: Software Developer's Journal 01/2007 PL

43

Business Process Execution Language

www.sdjournal.orgSoftware Developer’s Journal 1/2007

wartości zmiennych zwróconych przez web serwisy księgarni. Odpowiada temu poniższe wyrażenie:

bpws:getVariableData('checkBookStore1_Output',

'parameters',

'/ns2:requestForQuoteResponseElement/ns2:result')

<= bpws:getVariableData

('checkBookStore2_Output','parameters','/ns2:

RFQResponseElement/ns2:result')

W następnym kroku odpowiednio w blokach <case> i <otherwi-se> umieszczamy wywołania web serwisów księgarni, a kon-kretnie ich metod do zakupu książki. Gotowy fragment proce-su przedstawia Listing 5.

PodprocesyOstatnim krokiem w naszym procesie jest przekazanie żąda-nia przesłania paczki do podsystemu, który zajmuje się ich ob-sługą. Odbędzie się to w sposób asynchroniczny. Nasz pro-ces wywoła odpowiedni web serwis, a następnie zatrzyma się w oczekiwaniu na odpowiedź. Nic nie stoi na przeszkodzie by był to inny proces BPEL-owy, ponieważ na zewnątrz widoczne są one jako zwykłe web serwisy. Zbudujemy prosty proces Ful-FillOrder, który będzie symulował przetwarzanie wysłania pacz-ki. Z tego powodu użyjemy komponentu Wait, który będzie usy-piał instancję procesu na 3 sekundy. Jako parametry wejścio-we będzie przyjmował id zamówienia, adres oraz imię i nazwi-sko. Do głównego procesu, który jest klientem dla podprocesu, będzie zwracany string „Book sent”. Użycie tutaj procesu asyn-chronicznego ma swoje uzasadnienie. W rzeczywistym syste-

mie obsługa żądania wysłania paczki może wymagać manu-alnej pracy człowieka i może zająć kilka godzin lub dni. Z tego powodu użycie wywołania synchronicznego, byłoby bardzo nie-efektywne i odbijałoby się na wydajności całej aplikacji. W przy-padku wywołania asynchronicznego cały proces jest usypiany i budzony, dopiero gdy zostanie przysłana wiadomość zwrotna. Podejście takie znacznie oszczędza zasoby serwera, gdy in-stancji takiego procesu są setki, czy tysiące.

Listing 6 przedstawia przykładowy proces FulFillOrder.Po umieszczeniu procesu na serwerze, możemy przystą-

pić do stworzenia dla niego PartnerLink’a w procesie głów-nym. Adres opisu WSDL możemy znaleźć w konsoli admini-stracyjnej, po kliknięciu na nazwie FulFillOrder, w zakładce WSDL. Ponieważ proces będzie uruchamiany asynchronicz-nie, to z listy Partner Role wybieramy opcję FulFillOrderProvi-der, a z My Role FulFillOrderRequester.

Proces wywołujemy za pomocą komponentu Invoke, podob-nie, jak robiliśmy to dla wcześniejszych web serwisów. Do ode-brania wiadomości zwrotnej korzystamy z elementu Receive.

Po przekompilowaniu procesu i umieszczeniu go na ser-werze, możemy przetestować skończony proces BPEL-owy. Warto zwrócić uwagę, że po wywołaniu procesu FullFillOrder, główny proces jest usypiany w oczekiwaniu na odpowiedź. Przedstawia to Rysunek 7.

PodsumowanieNiniejszy artykuł zapoznał czytelnika jedynie z podstawowymi i najczęściej używanymi elementami języka BPEL. Stanowi to jednak dobry początek do budowy własnych bardziej skompli-kowanych procesów biznesowych.

Warto zaznaczyć, że Oracle BPEL Process Manager nie skazuje deweloperów jedynie na web serwisy. W celu umożliwie-nia bardziej elastycznej integracji, wykorzystywany jest standard Web Service Invocation Framework (WSIF). Pozwala on na pod-pinanie do procesu BPEL-owego zwykłych klas Javy, komponen-tów EJB, kolejek JMS, adapterów Java Connector Architecture (JCA), baz danych, itp. Poza elastycznością przy integracji moż-liwe jest znaczne zwiększenie wydajność, z racji wyeliminowania narzutu, jaki niosą ze sobą web serwisy i SOAP.

Innym z ciekawych udogodnień, jakie oferuje Oracle BPEL PM, jest wsparcie dla procesów wymagających udziału manual-nej pracy ludzi, jak na przykład zatwierdzanie wniosków. Dzięki komponentowi Human Task, możliwe jest budowanie tzw. work-flow’ów, co znacznie zwiększa możliwości opisywanej technologii.

BPEL jest coraz bardziej cenionym i popularnym standar-dem na rynku. Stanowi kolejny krok naprzód w świecie aplika-cji biznesowych. Dowodem na to jest szybko rosnąca liczba jego zastosowań w systemach CRM, ERP, przetwarzania i re-alizacji zamówień, czy integracji danych. n

Listing 6. Kod procesu do obsługi żądań wysłania paczki

<partnerLinks>

<partnerLink name="client"

partnerLinkType="client:FulfillOrder"

myRole="FulfillOrderProvider"

partnerRole="FulfillOrderRequester"/>

</partnerLinks><variables>

<variable name="inputVariable"

messageType="client:FulfillOrderRequestMessage"/>

<variable name="outputVariable"

messageType="client:FulfillOrderResponseMessage"/>

</variables><sequence name="main">

<receive name="receiveInput" partnerLink="client"

portType="client:FulfillOrder" operation="initiate"

variable="inputVariable" createInstance="yes"/>

<assign name="setResult"><copy>

<from expression="string('Book sent')"/>

<to variable="outputVariable" part="payload"

query="/client:FulfillOrderProcessResponse/

client:result"/>

</copy></assign>

<wait name="Wait_1" for="'PT3S'"/>

<invoke name="callbackClient" partnerLink="client"

portType="client:FulfillOrderCallback"

operation="onResult"

inputVariable="outputVariable"/>

</sequence>

W Sieci• artykuły, tutoriale, dokumentacje, porady na temat technologii

BPEL oraz serwera Oracle BPEL PM http://www.oracle.com/technology/products/ias/bpel/index.html• strona domowa organizacji standaryzacyjnej OASIS www.oasis-open.org• informacje na temat standardu WSIF http://ws.apache.org/wsif/

Page 44: Software Developer's Journal 01/2007 PL

44

Programowanie

Java

www.sdjournal.org Software Developer’s Journal 1/2007

Aplikacje Java w telewizji interaktywnejNie zapomnę, gdy pewnego razu mój szef

na jednej z burz mózgu rzucił „Przecież Java będzie za niedługo wszędzie, będzie-

my ją mieć nawet w naszej lodówce!”. To stwierdze-nie wywołało na mej twarzy bardzo dyplomatyczny uśmiech. Wyobrażałem sobie upgrade firmware-u w lodówce za pomocą parówki drobiowej i zimową wersję Pacman-a na zawołanie. Jednak szef jak to szef, zawszę ma rację. Java swoją krucjatę prze-prowadziła przez serwery, komputery stacjonarne, telefony komórkowe i PDA. Nie wszyscy wiedzą, że zagościła też na dobre w świecie telewizji interak-tywnej.

Czym w zasadzie jest telewizja interaktyw-na? Można powiedzieć… w Polsce przyszłością, a w krajach wyżej rozwiniętych codziennością. To telewizja, która zapewnia użytkownikowi pewien poziom interakcji, to coś więcej niż bierne ogląda-nie. Wyobraź sobie, że Twój telewizor potrafi śle-dzić Twoje aukcje internetowe, że umożliwia Ci udział w czasie rzeczywistym w ulubionym telewi-zyjnym quizie i głosowanie w programie „Decyzja należy do Ciebie”; oglądając wieczorne wiadomo-ści możesz na ekranie swojego telewizora odebrać pocztę, a nawet zapłacić rachunek za prąd. Nic nie stoi na przeszkodzie by zamówić sobie film z inte-raktywnej wypożyczalni. Nie dość, że nie będziesz musiał po niego wychodzić z domu to obejrzysz go w zasadzie natychmiast. To wszystko za pomocą pilota w ręku.

Java na pokładzieNa początku lat 90-tych powstało konsorcjum DVB (Digital Video Broadcasting) zrzeszające nadawców telewizyjnych. Za jeden z celów obrało sobie standaryzacje i normalizacje w obrębie tele-wizji cyfrowej, czego efektem dziś jest obecność języka Java w aplikacjach interaktywnych. Pod-stawowym API do tworzenia ich jest JavaTV firmy Sun [TABELA1]. Definiuje ono podstawowy mo-del aplikacji oraz wprowadza szereg niezbędnych funkcjonalności do innych pakietów. Inne, stoso-wane na co dzień API, z którymi warto się zapo-znać to HAVI i DAVIC, jednak tutaj nie będą one opisywane.

Generalnie aplikacje interaktywne dzielimy na DVB-HTML i DVB-J. Te pierwsze nie są zbyt popularne ze względu na uciążliwą implementację. Stanowią ze-stawy stron HTML opartych na standardzie HTML 1.1, CSS 2.0, DOM 2.0 oraz ECMAScript i są stosowane ja-ko podkomponenty. Wszyscy znamy z pewnością mi-dlety, applety, servlety więc nadszedł czas poznać Xlet – tym mianem określamy wspomniane aplikacje DVB-J. Xlet jest zasadniczo podobny do appletu (programu-jący w Javie zaraz wyłapią te podobieństwa). Ma okre-ślony cykl życia i docelowo działa na najwyższym po-ziomie middlewaru w tzw. set-top boxie (w skrócie STB - nazywanym też terminalem MHP) czyli urządzeniu podobnym do dekodera cyfrowego. Każdy Xlet mo-że przyjąć jeden z czterech stanów: załadowany (Lo-aded), wstrzymany (Paused), uruchomiony (Active) oraz zniszczony (Destroyed). Kolejne etapy cyklu życia Xlet-a są następujące:

• Menedżer aplikacji ładuje klasę główną Xlet-u, tworzy jedną instancję przez odwołanie do kon-struktora;

• Gdy użytkownik lub inny Xlet zażąda urucho-mienia Xlet-u, menedżer aplikacji wykonu-je metodę initXlet(). Xlet może równie do-brze zainicjować się sam, np. by pobrać nowe ustawienia czy też przeładować zasoby gra-ficzne. Po takiej akcji Xlet znajduje się w stanie „wstrzymany”;

Tomasz Kuprowski

Autor od lat pracuje na etacie programisty. Podobno nieźle zna się także na sieciach i systemach IT. W wol-nym czasie uczy się oraz chodzi po górach i robi im zdjęcia. Nie gardzi również sportami zimowymi.Kontakt z autorem: [email protected]

Materiały do artykułuzamieszczone zostały

na płycie CD 1

Rysunek 1. Eclipse – kreator nowej klasy

Page 45: Software Developer's Journal 01/2007 PL

Aplikacje Java w telwizji interaktywnej

45www.sdjournal.orgSoftware Developer’s Journal 1/2007

Listing 1. Game.java

package org.sdj.kuprowski.snake;

import org.dvb.ui.DVBAlphaComposite;

import org.dvb.ui.DVBGraphics;

import org.havi.ui.*;

import org.havi.ui.event.HKeyEvent;

import org.havi.ui.event.HKeyListener;

import javax.tv.xlet.*;

...

/** Glowna klasa Xletu @author Tomasz Kuprowski / Software

Developers Guide 2006 */

public class Game extends Component implements HKeyListener,

Xlet {

/** kontext aplikacji */

private XletContext context;

/** uchwyt sceny */

private HScene scene;

...

/** obrazy uzywane w aplikacji */

public Image image_body, image_apple, image_background;

/** obiekt monitorujacy ladowanie obrazkow */

public MediaTracker tracker;

/** Initializacja Xlet-u, zapamietanie kontekstu,

utworzenie sceny, zaladowanie grafiki */

public void initXlet(XletContext ctx) throws

XletStateChangeException {

setName("SDJsnake");

this.context = ctx;

HSceneFactory factory = HSceneFactory.getInstance();

HSceneTemplate hst = new HSceneTemplate();

hst.setPreference(HSceneTemplate.SCENE_SCREEN_DIMENSION,

new org.havi.ui.HScreenDimension(1, 1),

HSceneTemplate.REQUIRED);

hst.setPreference(HSceneTemplate.SCENE_SCREEN_LOCATION,

new org.havi.ui.HScreenPoint(0, 0),

HSceneTemplate.REQUIRED);

scene = factory.getBestScene(hst);

scene.setBounds(0, 0, 720, 576);

scene.setLayout(null);

scene.setBackgroundMode(HScene.NO_BACKGROUND_FILL);

scene.add(this);

scene.addKeyListener((KeyListener) this);

setSize(scene.getSize());

image_body = getToolkit().getImage("body.jpg");

image_apple = getToolkit().getImage("apple.jpg");

image_background = getToolkit().getImage("back.jpg");

tracker = new MediaTracker(this);

tracker.addImage(image_body, 0);

tracker.addImage(image_apple, 1);

tracker.addImage(image_background, 2);

try {

tracker.waitForID(0);

tracker.waitForID(1);

tracker.waitForID(2);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

/** Funkcja obslugi : start Xlet-u */

public void startXlet() throws XletStateChangeException {

validate();

monit_obj = new Monitor(this);

monit_obj.start();

scene.setVisible(true);

scene.requestFocus();

}

/** Funkcja obslugi : pauza Xlet-u */

public void pauseXlet() {

scene.setVisible(false);

game_state = Cons.GAME_PAUSED;

}

/** Funkcja obslugi : zatrzymanie Xlet-u, zatrzymanie

watku Monitor, usuniecie Listenerow */

public void destroyXlet(boolean unconditional)

throws javax.tv.xlet.XletStateChangeException {

monit_obj.interrupt();

if (unconditional) {

if (scene != null) {

removeKeyListener(this);

scene.setVisible(false);

scene.remove(this);

HsceneFactory.getInstance().dispose(scene)

scene = null;

}

context.notifyDestroyed();

} else {

throw new XletStateChangeException(

"Please don't let me die!");

}

}

/** Funkcja obslugi klawiszy pilota @param key */

public void keyPressed(KeyEvent key) {

if (VK_ready) {

switch (key.getKeyCode()) {

case HKeyEvent.VK_UP: if (course != Cons.DOWN) course =

Cons.UP; break;

case HKeyEvent.VK_LEFT: if (course != Cons.RIGHT)

course = Cons.LEFT; break;

...

}

VK_ready = false;

}

}

Page 46: Software Developer's Journal 01/2007 PL

46

Programowanie

Java

www.sdjournal.org Software Developer’s Journal 1/2007

• Wywołanie metody startXlet() powoduje zmianę stanu Xlet-u na „uruchomiony”. Xlet wówczas wyświetla się na ekranie i zaczyna interakcję z użytkownikiem;

• W każdej chwili Xlet może zostać wstrzymany po wywo-łaniu metody pauseXlet() i wznowiony poprzez metodę startXlet(). Może się to dziać wielokrotnie podczas pra-cy Xlet-u bowiem STB i maszyna wirtualna nie zakładają multitaskingu z prawdziwego zdarzenia, a naraz tylko je-

den Xlet może być aktywny i widoczny – z tego powodu aplikacje w tle muszą być wstrzymane;

• Po wywołaniu metody destroyXlet() Xlet przechodzi w stan ‘zniszczony’ zwalniając wszystkie swoje zasoby.

Aplikacje interaktywne mogą oferować jeden z trzech pozio-mów interakcji:

• Rozgłoszeniowy, gdzie tylko odbieramy dane od operatora (ślepa interakcja);

• Jednokierunkowy, gdy możemy coś wysłać poprzez za-pewniony kanał zwrotny w postaci np. łącza ADSL (głoso-wanie w quizach);

• Dwukierunkowy, gdy aplikacja komunikuje się w obie stro-ny (email, web services, gry online).

OgraniczeniaZanim przystąpimy do pisania naszej pierwszej aplikacji, warto dowiedzieć się, jakie czekają nas ograniczenia w maszynie wir-tualnej STB. Dla przykładu… pisząc applet napotkamy ograni-czenia wynikające z zabezpieczeń, takie jak np. brak dostępu do dysku użytkownika i możliwość komunikacji wyłącznie z ip ho-sta, z którego applet został pobrany. W midletach natomiast, nie skorzystamy z operacji na liczbach zmiennoprzecinkowych.

Maszyna wirtualna w STB po pierwsze ma okrojone API. Szereg pakietów jest niedostępnych ze względu na oszczęd-ność pamięci i fakt, że są po prostu zbędne. Odchudzono nawet tak kluczowe pakiety jak java.lang, java.util, java.io i java.net, a to dlatego, że STB nie zawsze mają kanał zwrotny (w postaci łącza internetowego) czy też system plików. Nie możemy także korzy-stać z funkcji macierzystych. Występuje również specyficzny in-terfejs użytkownika zgodny z wymogami środowiska TV (np. ste-rowanie aplikacji pilotem) oraz szereg zasad związanych z do-stępem do zasobów, komunikację między Xletami i cyklem życia aplikacji. Nie wspominając o ograniczonej liczbie obsługiwanych formatów plików audio i video.

Dla początkujących bardzo ważne jest zrozumienie ogra-niczeń i różnic w warstwie prezentacji. Otóż wiele klas i obiek-tów z, nazwijmy to, „pure Java” ma swoje zastępniki i tak oto dla przykładu, komponenty z pakietu java.awt (takie jak kla-

Rysunek 2. Eclipse – konfiguracja środowiska startowego

Rysunek 3. Eclipse – konfiguracja środowiska startowego

Rysunek 4. Eclipse – argumenty VM i aplikacji

Page 47: Software Developer's Journal 01/2007 PL

Aplikacje Java w telwizji interaktywnej

47www.sdjournal.orgSoftware Developer’s Journal 1/2007

wisze, listy rozwijane, checkboxy, itp.) są dla nas niedostępne. W zamian używa się ich odpowiedników z API HAVI, które udostępnia okna dialogowe, pola tekstowe, własne klawisze, czy etykiety tekstowe oraz nawet tak podstawowe komponen-ty jak HContainer i HComponent. STB posiadają również specy-ficzny menedżer okien, różniący się znacznie od stosowane-go w aplikacjach na PC. Zamiast obiektów Frame używa się Hscene, który m.in. kontroluje pozycje focusa na ekranie i to jak dana aplikacja „leży” i czy jest aktualnie widoczna.

Pierwszy XletTelewizja interaktywna jest dosyć hermetyczną dziedziną, gdzie uzyskanie darmowego wsparcia technicznego, znalezienie w sie-ci kodu źródłowego przykładowych aplikacji od A do Z lub po-

branie dobrych, darmowych narzędzi do authoringu nie jest zbyt oczywiste. Dla przykładu, zakup komercyjnego środowiska pro-gramowego takiego jak np. MIT-xperts iDesigner to koszt rzę-du 5.000 Euro za 1 licencję (dla jednostek edukacyjnych). Na-tomiast, jeżeli chcielibyśmy testować nasze aplikacje bezpośred-nio na STB, to Starter Kit, który generuje sygnał cyfrowy audio/video wraz z pakietem informacyjnym kosztuje tyle, co… średniej klasy, nowy samochód. Sporo, prawda? Jednak nam, początku-jącym zapaleńcom, w zupełności wystarczy darmowy emulator OpenMHP lub XletView oraz dowolne środowisko do programowa-nia w Javie dla Linuxa lub Windows. Należy jednak mocno pod-kreślić, że te darmowe narzędzia nie pozwolą nam poznać bar-dziej zaawansowanych możliwości MHP ze względu na to, że implementują one jedynie część tego standardu. W OpenMHP, któ-rego będziemy używać w dalszej części artykułu, nie ma moż-liwości odtwarzania klipów MPEG4, nie zaimplementowano ko-munikacji między Xlet-ami, pobierania danych z kanału informa-cyjnego, nie wszystkie komponenty HAVI są zaimplementowane i przetestowane, a podpięcie zewnętrznego debugera wydaje się być niemożliwe.

Nadszedł czas na praktyczny przykład. Napiszemy znaną wszystkim, prostą grę Snake (niech nikogo nie przerazi jej ubo-ga implementacja – program powstał po prostu pewnego wie-czoru). Klawisze strzałek naszego pilota TV posłużą do ste-rowania ruchem węża, klawisze Volume Up i Volume Down będą zmieniać prędkość gry, a klawiszami czerwony i zielony będzie-my odpowiednio wstrzymywać i wznawiać grę. W tym projekcie skorzystamy ze środowiska Eclipse i emulatora OpenMHP. Musi-

Rysunek 5. OpenMHP – ścieżki do bibliotek

Rysunek 6. OpenMHP – konfiguracja Xletu w emulatorze

Słownik pojęć• STB – Set-top Box, elektroniczne urządzenie podłączane do

telewizora. Umożliwia odtwarzanie video, dźwięku, przeglą-danie stron internetowych czy granie w gry komputerowe itp. STB wykorzystuje w tym celu łącze ethernetowe, antenę sa-telitarną, łącze telewizji kablowej, linię telefoniczną (włącza-jąc w to DSL) albo nawet zwykłą antenę UHF/VHF;

• EPG - Electronic Program Guide, elektroniczny przewodnik po kanałach, grupuje wybrane kanały według ich tematyki, pozwala szybko znaleźć interesujący nas program, prezentuje szczegóło-we informacje o kanale, wspiera system zamówień programów Near Video On Demand i system kontroli rodzicielskiej;

• DVB - Digital Video Broadcast, standard cyfrowej telewizji. Charakteryzuje się jakością obrazu i dźwięku porównywalną do zapisu DVD (500i), pozwala na interaktywny odbiór, tj. włą-czenie napisów w różnych językach oraz przełączenia języka ścieżki audio. W standardzie DVB obraz i dźwięk kodowane są przy pomocy enkodera MPEG, tak jak w DVD;

• MHP – Multimedia Home Platform, Otwarty standard opro-gramowania w telewizji cyfrowej zdefiniowany przez konsor-cjum DVB. Umożliwia uruchomienie aplikacji pisanych przez niezależnych dostawców na różnych urządzeniach do odbio-ru telewizji cyfrowej. MHP umożliwia użytkownikowi korzysta-nie z aplikacji nadawanych razem z programem telewizyjnym w trakcie oglądania telewizji;

• Middleware – inaczej oprogramowanie / warstwa pośredniczą-ca pomiędzy hardware-em a aplikacją.

Rysunek 7. Snake w emulatorze

Page 48: Software Developer's Journal 01/2007 PL

48

Programowanie

Java

www.sdjournal.org Software Developer’s Journal 1/2007

my jeszcze pobrać i zainstalować pakiety JavaTV oraz JMF (Ja-va Media Framework). Zaczynamy… tworzymy nowy projekt i podpinamy pod niego pakiety javatv.jar oraz jmf.jar. Na-stępnie cały folder org z folderu głównego OpenMHP paku-jemy do pliku jar i tak przygotowane archiwum również podpi-namy do projektu (unikniemy w ten sposób bałaganu w widoku Package Explorer). Powinniśmy także skopiować katalog sta-tic (również z OpenMHP) do folderu głównego naszego projek-tu. Przygotowujemy klasę główną naszego pierwszego Xlet-u. [Rysunek 1] Rozszerzy ona klasę java.awt.Component i zaim-plementuje interfejsy org.havi.ui.event.HkeyListener oraz ja-vax.tv.xlet.Xlet. Automatycznie środowisko zaimplementuje nam następujące metody:

public void initXlet(XletContext arg0) throws

XletStateChangeException {}

public void startXlet() throws XletStateChange

Exception {}

public void pauseXlet() {}

public void destroyXlet(boolean arg0) throws

XletStateChangeException {}

public void keyTyped(KeyEvent arg0) {}

public void keyPressed(KeyEvent arg0) {}

public void keyReleased(KeyEvent arg0) {}.

Obsługę pilota zaszyjemy w funkcje keyPressed. Metoda get-KeyCode() klasy KeyEvent zwraca kod wciśniętego na pilocie kla-wisza. Odpowiednich kodów należy szukać w klasie org.ha-vi.ui.event.HKeyEvent. Dla przykładu kod czerwonego klawisza występuje jako wartość statyczna VK _ COLORED _ KEY _ 0 kla-

sy HKeyEvent, a z kolei klawisz zwiększania głośności to VK _ VO-

LUME _ UP. Badaniem kolizji węża, przeliczaniem współrzędnych, naliczaniem punktów itp. czyli ogółem logiką ruchu zajmie się osobny wątek. Tego komentować nie musimy, natomiast bliżej przyjrzymy się utworzeniu sceny i przerysowaniu ekranu, a tak-że funkcjonowaniu Xlet-u.

Na pierwszy ogień pójdzie metoda initXlet. Zapamiętamy w niej kontekst aplikacji XletContext (posłużymy się nim później zamykając aplikację), pobierzemy fabrykę, która posłuży nam do utworzenia sceny (jedna aplikacja może mieć tylko jedną scenę). Funkcja getBestScene(…) klasy HSceneFactory zwraca więc obiekt Hscene, dla którego określimy rozmiary sceny, jej układ, tryb prze-

rysowania tła i dodamy słuchacza HKeyListener. Załadujemy również grafikę w postaci plików JPEG. Wykorzystamy przy tym obiekt MediaTracker, aby dopilnować by obrazki zostały załado-wane do końca, nim aplikacja spróbuje je już wyświetlać.

Kolejna metoda obsługi startXlet uruchomi nam osobny wą-tek na bazie klasy Monitor, ustawia widoczność sceny i nadaje jej focus. Z kolei w metodzie destroyXlet przerwiemy wątek uru-chomiony w poprzedniej metodzie, usuniemy słuchacza HkeyLi-stener, zamkniemy scenę i za pomocą zapamiętanego wcze-śniej kontekstu powiadomimy menedżera aplikacji, że Xlet koń-czy swoje działanie. Metoda paint, którą odziedziczyliśmy po ja-va.awt.Component, przerysowuje scenę. W metodzie initXlet ustawiliśmy rozmiary sceny zgodnie ze standardem PAL na 720x576 pixeli. Z kolei obszar roboczy gry to 640x480 pixeli, ze względu na wygodne podzielenie ekranu na 32x24 pola. Do wy-świetlania prostych komunikatów na ekranie użyliśmy czcionkę Tiresias, która jest czcionką podstawową w standardzie MHP. I to w zasadzie wszystko, co należało wspomnieć o metodzie pa-int. Wypada jeszcze wspomnieć o samej logice gry. Otóż, osob-ny wątek na podstawie aktualnego kierunku poruszania się węża ustala jego pozycję, weryfikując czy jego głowa nie znajduje się na tej samej pozycji co jabłko lub jego ogon. Wszystkie elemen-ty ogona są przechowywane w LinkedList. Losowanie nowej po-zycji jabłka odbywa się bez blokowania, tzn. po pierwszym loso-wym wyznaczeniu nowej pozycji, jeśli jest ona zajęta przez ogon to jest przesuwana pod kątem 45 stopni po planszy aż do skutku.

TestOtwieramy menedżer aplikacji OpenMHP. Podczas pierwszego uruchomienia musimy dokonać wstępnej konfiguracji, poda-

Tabela 1. Specyfikacja JavaTV

Pakiet Opisjavax.tv.xlet Definiuje Xlet, cykl życia, klasy pomocniczejavax.tv.locator Mechanizmy dostępu do usług rozgłoszeniowych i zasobów multimedialnych za pomocą URL-ijavax.tv.net Mechanizmy transmisji datagramów IPjavax.tv.graphics Rozszerzenie pakietu java.awt o specyficzne dla platformy TV funkcje, np. przeźroczystośćjavax.tv.util Klasy narzędziowe, zarządzanie zegarami i wątkami zegarowymijavax.tv.media Rozszerzenie Java Media Framework o specyficzne dla platformy TV funkcjejavax.tv.media.protocol Rozszerzenie JMF o protokoły transportu strumieni danychjavax.tv.service Definicja usług TV (kanały informacyjne) i mechanizmów wymiany informacjijavax.tv.service.guide Obsługa systemu EPGjavax.tv.service.navigation Nawigacja pomiędzy usługami, ich typy, zarządzanie usługami w tym np. Listy ulubionych usługjavax.tv.service.transport Mechanizmy transportu strumieni danych, informacji rozgłoszeniowychjavax.tv.service.selection Warstwa prezentacji usług (np. picture-in-picture), wyboru nowych usług

����������

����������

����������

����������

����������

�����������

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

�����������

Rysunek 8. Cykl życia Xletu

Page 49: Software Developer's Journal 01/2007 PL

Aplikacje Java w telwizji interaktywnej

jąc ścieżki do bibliotek JavaTV oraz JMF. [Rysunek 5] Konfi-gurację możemy również zmienić ręcznie edytując pliki con-stants.properties i openmhp.properties z folderu static. Na-stępnie dodajemy nowy projekt / aplikację.

Wybieramy opcję Add z menu prawego klawisza myszki i na nowo otworzonej formatce podajemy nazwę projektu, ścieżkę bazową do projektu Eclipse’a, pełną nazwę klasy naszego Xlet-u; wprowadzamy również identyfikatory apli-kacji i organizacji. [Rysunek 6] Po zapisaniu ustawień mo-żemy uruchomić nasz Xlet, wybierając opcję Start ze zna-nego nam już menu.

Otworzy się okno podglądu TVScreen for MHP, następnie okno pilota RemoteControl oraz najważniejsze okienko Output, na którym widać wszystkie komunikaty emulatora. Jeśli nasza aplikacja spowoduje jakiś wyjątek to jego treść pojawi się rów-nież w tym oknie. Co ważne, zamiast za każdym razem mo-zolnie klikać w Start, możemy uruchomić nasz Xlet bezpo-średnio z poziomu środowiska Eclipse.

Musimy tylko odpowiednio przygotować środowisko startowe. OpenMHP pozwala uruchomić dowolny Xlet z linii poleceń korzystając z klasy org.openmhp.system.RunXlet. Podajemy wówczas jako parametry folder roboczy, na-zwę klasy Xlet-u oraz identyfikatory aplikacji i organizacji

nie zapominając oczywiście o classpath. Przykładowe po-lecenie to:

java -classpath .;.;\javatv_fcs\javatv.jar; \JMF\lib\jmf.jar;

org.openmhp. system.RunXlet . HelloWorld 32 1.

Z poziomu Eclipse’a w menu Run wybieramy opcję Run… i w zakładce Main w polu Main class wpisujemy org.openmhp.system.RunXlet. Następnie przechodzimy do zakładki Arguments i w polu Program arguments podaje-my rozdzieloną spacjami nazwę katalogu roboczego, iden-tyfikatory aplikacji i organizacji i na końcu ponownie nazwę katalogu roboczego. Teraz w polu VM arguments podaje-my parametr maszyny wirtualnej –classpath oraz ścieżkę do plików javatv.jar oraz jmf.jar. [Rysunek 3, 4] Teraz pozo-staje już tylko wpisać w polu Working directory nazwę folde-ru bazowego OpenMHP i umieszczać w nim przy każdej kom-pilacji pliki class naszego Xlet-u, co łatwo wykonać stosu-jąc Ant-a lub linki symboliczne w Linuxie. [Rysunek 2] Jeśli w oknie Output zobaczymy komunikat Class java.awt.X is not allowed in MHP Thread oznacza to, że classloader nie zała-dował wskazanej klasy z pakietu AWT uznając, że nie wy-stępuje ona w MHP. Niuans ten można ominąć dopisując nazwę wskazanej klasy w pliku allowedClasses.txt w katalo-gu static. Jeżeli po uruchomieniu naszego Xlet-u nie poja-wi się nic w oknie podglądu, a w oknie Output nie raportowa-no żadnego błędu, wówczas musimy poeksperymentować ze ścieżką classpath, bo jak sami przyznają autorzy OpenMHP – „Classpaths are a bit tricky…”.

ZakończenieTen artykuł z założenia miał mieć charakter CIG (Comple-te Idiot’s Guide). Nie sposób opisać w krótkim artykule na-wet podstaw programowania aplikacji MHP. Ogrom zagad-nień dotyczących telewizji interaktywnej - dziedziny, w którą jest zaangażowanych ponad 270 nadawców telewizyjnych z 35 krajów – sprawia, że możnaby z powodzeniem wyda-wać miesięcznik, a może i nawet tygodnik zatytułowany „Multimedia Home Platform Developer’s Guide”. W Polsce jest już kilka firm, które tworzą software dla odbiorców z Azji i Europy Zachodniej, a wraz z rozwojem telewizji interaktyw-nej w Polsce na pewno część z nas znajdzie sobie finanso-wo atrakcyjną pracę. n

W Sieci• http://java.sun.com/products/javatv/index.jsp Strona domowa JavaTV;• http://www.interactivetvweb.org/ Serwis InteractiveTvWeb czyli bogate źródło wiedzy na temat

programowania aplikacji interaktywnych;• http://www.mhp-knowledgebase.org/ Baza wiedzy o MHP;• http://www.openmhp.org/ Strona projektu OpenMHP;• http://java.sun.com/products/java-media/jmf/ Strona domowa Java Media Framework;• http://www.dvb.org/ Witryna Digital Video Broadcasting;• http://www.davic.org/ Witryna API DAVIC;• http://www.havi.org/ Witryna API HAVI;

R E K L A M A

Page 50: Software Developer's Journal 01/2007 PL

50

Warsztat

GWT – WEB 2.0

www.sdjournal.org Software Developer’s Journal 1/2007

GWT – WEB 2.0 na maksaMiałem sen... w którym aplikacje webowe

zaczęły przypominać normalne programy. Zawierały bogaty i funkcjonalny interfejs,

a użytkownik nie był zmuszany do czekania po każ-dym kliknięciu na przeładowanie strony. Programi-ści przestali rwać sobie włosy z głowy, nie musząc się więcej martwić o utrzymanie zgodnego zacho-wania i wyglądu swych programów pomiędzy róż-nymi przeglądarkami internetowymi. Co więcej – ich praca przestała w końcu być nieustannym mie-szaniem HTMLa, JavaScriptu i Javy. Wreszcie mo-gli odetchnąć z ulgą, programując zwarte aplikacje – w jednym języku, w jeden sposób, w jednym stan-dardzie dla klienta i serwera. Bez tagów, scriptletów i javascriptowych trików. Aplikacje internetowe za-częły działać szybciej, wymieniając w trakcie pracy z serwerem tylko niezbędne dane (i to asynchronicz-nie), zamiast setek kilobajtów HTMLa. Miałem sen, w którym założenia WEB 2.0 i możliwości oferowa-ne przez technologię AJAX stały się proste w użyciu, z wykorzystaniem zwartego, solidnego narzędzia.

Wiosną tego roku Google spełniło marzenia, prze-kazało programistom dar – zestaw narzędzi i biblio-tek programistycznych do tworzenia stron zgodnych z WEB 2.0. Z ich użyciem pisanie aplikacji działających na takich zasadach jak Google Mail czy Google Maps, stało się zdecydowanie prostsze. Google po raz kolejny udowodniło, że jego produkty cechuje przede wszyst-kim nowatorstwo i wysoka jakość. Również w podej-ściu do biznesu – podobnie jak inne kluczowe produk-ty firmy, GWT jest dystrybuowane za darmo, bez ogra-niczeń w używaniu. A przecież nie można określić Go-ogle mianem organizacji charytatywnej...

Google Web Toolkit– Jak to działa?Domyślam się, że część Czytelników po wstępie do artykułu może sobie pomyśleć, że GWT to po prostu YEWF (Yet Another Web Framework) i zanegować je-go ideę, nie chcąc zmieniać swych przyzwyczajeń, nie widząc w tym znaczących korzyści. Przy zalewie rozmaitych rozwiązań, takie podejście ma swoje uza-sadnienie. Zachęcam jednak do zapoznania się z tre-

ścią artykułu, by zobaczyć, że GWT jest poniekąd in-ne – wierzę, że wyznacza nowy standard programo-wania aplikacji webowych, a JSP i ciągła komunikacja HttpRequest-HttpResponse przechodzą do lamusa.

Główną cechą GWT jest możliwość pisania części klienckiej aplikacji internetowej w języku Java, w spo-sób przypominający w dużym stopniu programowa-nie aplikacji SWING. Tak napisany program zostaje przetłumaczony przez GWT do JavaScriptu i pozwala na uruchomienie po stronie przeglądarki internetowej. Komunikacja aplikacji klienta z serwerem odbywa sie asynchronicznie z użyciem technologii AJAX. GWT dostarcza szeroki zbiór komponentów graficznych (ang. widgets) z bardzo wygodną obsługą zdarzeń. Rozbudowanie bibliotek GWT o własne komponenty nie jest trudne i wprowadza dużą dowolność rozwią-zań. Ponadto aplikacje GWT można łatwo i szybko te-stować w trakcie programowania, z użyciem środowi-ska uruchomieniowego Google Web Browser. Co bar-dzo ważne – GWT nie wymaga dedykowanych środo-wisk programistycznych, programiści nie muszą zmie-niać więc swoich przyzwyczajeń.

Zastanówmy się głębiej nad główną ideą GWT – transformacji Javy do JavaScriptu. Zważywszy na ogromną odmienność tych języków, można powie-dzieć że Google dokonało niemal cudu (choć wca-le nie było pierwsze – patrz np. projekt XML11). Jakie są najważniejsze zalety takiego rozwiązania? Przede wszystkim łatwość programowania i debugowania aplikacji. Pewnie większość programistów używa śro-dowisk z podpowiadaniem składni i uzupełnianiem ko-du Javy, co zdecydowanie przyspiesza proces pro-gramowania. Mocna kontrola typów języka Java czy-ni aplikacje mniej podatnymi na błędy. Rozbudowane debuggery (jak np. w środowisku Eclipse) pozwalają precyzyjnie śledzić zachowanie aplikacji. I co chyba najważniejsze – aplikacja staje się bardzo jednorodna, poprzez implementacyjne zbliżenie do siebie warstw serwera i klienta.

W razie konieczności, nie stanowi żadne-go problemu łączenie aplikacji GWT z JSP, PHP czy innymi technologiami. Tym nie mniej, może-my stworzyć w pełni działającą aplikację interne-tową, której część kliencka będzie reprezentowa-na przez „czyste” pliki HTML. Programista nie mu-si (wreszcie!) mieszać kodu HTMLa ze skrypta-mi innych języków. Cała statyczna część aplikacji może zostać napisana w HTMLu i odizolowana od reszty, natomiast części dynamiczne (interakcja z użytkownikiem) zostaną stworzone w Javie. Pro-gramista może więc skupić się wyłącznie na logi-ce aplikacji, oddając pracę nad wyglądem webma-

David de Rosier

Autor od wielu lat pasjonuje się językami programowania. Centrum jego zainteresowań zawodowych stanowi techno-logia Java, głównie w kontekście wytwarzania aplikacji we-bowych oraz obsługi baz danych. W wolnych chwilach autor zajmuje się implementacją zaawansowanych algorytmów szachowych w różnych dziwnych językach programowania.Kontakt z autorem: [email protected]

Materiały do artykułuzamieszczone zostały

na płycie CD 1

Page 51: Software Developer's Journal 01/2007 PL

GWT – WEB 2.0 na maksa

51www.sdjournal.orgSoftware Developer’s Journal 1/2007

sterom i grafikom. GWT składa się z czterech podstawo-wych komponentów:

• kompilatora kodu Java do JavaScriptu (GWT Java-to-Ja-vaScript Compiler),

• środowiska testowego, umożliwiającego uruchamianie i de-bugowanie aplikacji (GWT Hosted Web Browser),

• zbioru klas JavaScript emulujących standardowe klasy ję-zyka Java (JRE Emulation Library),

• biblioteki elementów interfejsu użytkownika (GWT Web UI).

Dochodzi do tego jeszcze zestaw narzędzi dodatkowych, np. automatyzujących tworzenie projektów GWT, czy budowę aplikacji wpierającej wiele języków.

Gdzie leży kruczek? Właściwie go nie ma – tworzenie apli-kacji webowych staje się zdecydowanie szybsze i mniej podat-ne na błędy, a powstałe aplikacje są pozbawione problemu nie-kompatybilności i bardziej skalowalne. Szukając minusów moż-na wspomnieć o dodatkowych stu kilobajtach (plik JavaScript, będący jądrem GWT), które przeglądarka musi załadować przy starcie aplikacji (tylko jednokrotnie, później plik przechowywany jest przez cache przeglądarki). W rzeczywistości jednak trud-no tu mówić o ograniczeniu lub nadmiernym obciążaniu inter-netu, bowiem przy używaniu AJAXa, aplikacja w trakcie działa-nia wymienia z serwerem znacznie mniej danych w porównaniu z rozwiązaniem klasycznym (każdorazowe przeładowywanie stron). Puryści JavaScriptu z pewnością zwrócą uwagę na to, że generowany JavaScript jest niezbyt czytelny dla człowieka. To prawda ale czy musi być? GWT zakłada, że programowanie i debugowanie odbywa się na poziome Javy, nie JavaScriptu. Kompilator C++ może budować niezbyt optymalny kod assem-blera ale póki wszystko działa sprawnie i bezbłędnie – komu fi-nalnie to przeszkadza?

Hello GWT World!Jeśli mówimy o jakiejś nowości w świecie programowania nie może się obyć bez aplikacji typu Hello world, która po-zwoli rzucić okiem na składnię i strukturę kodu. Zacznijmy od utworzenia nowego projektu – nazwijmy go po prostu GWTTest. W katalogu głównym GWT znajdziemy dwa na-rzędzia automatyzujące ten proces. Pierwsze z nich tworzy nowy projekt:

projectCreator -ant GWTTest

eclipse GWTTest -out c:\projects\gwttest

Po wykonaniu tej instrukcji zostanie utworzony katalog (c:\projects\gwttest) z podkatalogami src i test, oraz, co bardzo przydatne, skrypt ANTa pozwalający skompilować projekt. Użyt-kownicy środowiska Eclipse mogą skorzystać z dodatkowego parametru -eclipse, który wygeneruje plik .project. Tak powsta-ły projekt można łatwo zaimportować do Eclipsa wybierając z menu File opcję import, a potem Existing projects in workspa-ce. GWT dostarcza narzędzie pozwalające wygenerować testo-wą aplikację – naszą aplikację Hello World:

applicationCreator -out c:\projects\

gwttest org.sdjournal.gwt.client.Main

Polecenie to utworzy klasę Java w zadanym pakiecie oraz kil-ka dodatkowych plików. Zacznijmy od nazwy pakietu – appli-cationCreator wymusza, by nasza klasa została umieszczona w pakiecie client. Jest to konwencja GWT pozwalająca w łatwy sposób odróżnić część kliencką od serwerowej. Omówione zo-stanie to szerzej w dalszej części artykułu. Przyjrzyjmy się do-kładnie wygenerowanej klasie (patrz Listing 1). Nazwijmy ją kla-są startową, bowiem implementuje ona interfejs EntryPoint – co jest obowiązkowe dla przynajmniej jednej klasy w obrębie modu-łu webowego. Kiedy moduł zostaje po raz pierwszy ładowany, wszystkie klasy startowe zostają automatycznie zainicjalizowane poprzez wykonanie metody onModuleLoad(). Możemy tę operację określić mianem zdarzenia typu start aplikacji (ściślej – modułu). Dalsza część kodu musi wydawać się bardzo znajoma Czytelni-kom znającym bibliotekę SWING. Utworzony zostaje tam przy-cisk oraz nieedycyjne pole tekstowe (etykietka). Następnie za-implementowana zostaje obsługa zdarzenia – kliknięcie przyci-sku. W tym przypadku w postaci anonimowej klasy wewnętrz-nej. Czytelnicy mniej biegli w Javie mogą początkowo mieć kło-poty z takimi konstrukcjami, jednak jest to zapis bardzo praktycz-ny i szybko można się przyzwyczaić do takiej notacji. W tym wy-padku kod zdarzenia sprawdza, czy etykieta jest pustym ciągiem znaków, jeśli nie, ustawia ją na wartość Hello World, w przeciw-nym wypadku – kasuje ją. Dwie ostatnie linie kodu są bardzo ważne – łączą one kod z plikiem HTML. Nasza aplikacja w Javie nie generuje bowiem całego wyjścia HTML, a jedynie dwa ele-menty – przycisk i etykietę. Cała reszta znajduje się w statycz-nym pliku HTML – możemy go znaleźć w pakiecie org.sdjour-nal.gwt.public. Zachęcam do zapoznania się z jego budową – nie znajdziemy tam żadnych osadzonych skryptów innych języ-ków. Jedyną niestandardową konstrukcją wewnątrz jest znacznik meta, który definiuje nazwę modułu GWT użytego na tej stronie:

<meta name='gwt:module' content= 'pl.com.sdj.gwt.Main'>

W jaki sposób łączymy więc kod Javy i HTML? Można w uproszczeniu powiedzieć, że kierunek jest tutaj odwrotny niż w przypadku np. JSP – to kod Javy informuje aplikację, w jakim miejscu HTMLa zostanie osadzony. Oczywiście fizycznie bę-dzie to JavaScript, wygenerowany z naszej klasy. Powróćmy do ostatnich linii kodu Java. Konstrukcja typu:

RootPanel.get("slot1").add(button);

odwołuje się do elementu strony HTML, którego atrybut id jest ustawiony na wartość slot1. Może to być na przykład komórka tabeli, element DIV, itp. Prawda, że proste?

Szybki startPracę z GWT najłatwiej rozpocząć od analizy istniejących przykła-dów. Po rozpakowaniu archiwum z GWT znajdziemy wewnątrz ka-talog samples z kilkoma aplikacjami. Polecam uruchomić przykład KitchenSink, ukazujący pełne spektrum możliwości GWT. Aby zo-baczyć aplikację w oknie środowiska uruchomieniowego GWT, wy-starczy wykonać plik KitchenSink-shell. Jeśli chcemy obejrzeć apli-kację w oknie preferowanej przeglądarki internetowej, musimy naj-pierw uruchomić plik KitchenSink-compile, celem skompilowania aplikacji, a następnie otworzyć przykładową stronę – plik Kitchen-Sink.html z katalogu www/com.google.gwt.sample.kitchensink.KitchenSink.

Page 52: Software Developer's Journal 01/2007 PL

52

Warsztat

GWT – WEB 2.0

www.sdjournal.org Software Developer’s Journal 1/2007

Każda aplikacja (podobnie jak aplikacja SWING) musi zawie-rać (przynajmniej jeden) RootPanel, na którym będziemy osa-dzali inne elementy graficzne. RootPanel jest więc łącznikiem między naszą aplikacją powstałą w Javie, a plikiem HTML. Jeśli nie określimy parametru w metodzie get tej klasy, domyślnie Ro-otPanel odniesie się do elementu BODY pliku HTML.

Czas uruchomić nasz przykład. Kiedy stworzyliśmy projekt z użyciem narzędzi GWT, w głównym katalogu projektu pojawi-ły się dwa wykonywalne pliki – Main-compile i Main-shell. Pierw-szy z nich pozwala na przetransformowanie klas Java do plików JavaScript. Wynik zostanie zapisany w (automatycznie utwo-rzonym) katalogu web. W katalogu tym znajdzie się też plik Ma-in.html, który możemy otworzyć z użyciem przeglądarki interne-towej i zacząć podziwiać efekty swojej pracy. Jeszcze łatwiej można zobaczyć wygenerowaną stronę, uruchamiając plik Ma-in-shell. Wystartuje on testowe środowisko GWT, które zawiera konsolę oraz przeglądarkę. Jest również niezastąpione przy te-stowaniu komunikacji klient-serwer, zawiera bowiem wbudowa-ną, uproszczoną wersję serwera Tomcat (działającą domyślnie na porcie 8888).

Praca z projektami GWTW poprzednim punkcie omówiłem pokrótce pewne aspekty związane z budową projektu GWT, spróbujmy jednak teraz tę wiedzę usystematyzować.

Struktura katalogówPojedynczy projekt GWT może łączyć ze sobą kod aplikacji klienta i serwera. Mimo wszystko logicznym błędem byłoby zbytnie mieszanie takiego kodu. Google zaleca podział aplika-cji na przynajmniej trzy pakiety różniące się nazwą ostatniego członu w ścieżce pakietów: Pakiet client – zawierający cały kod przeznaczony do transformacji do JavaScriptu. Będą się tu znajdowały klasy odpowiedzialne za wygląd i logikę aplika-cji po stronie klienta, własne komponenty, a także interfejsy serwisów odpowiedzialnych za komunikację z serwerem. Na-leży pamiętać, że niektóre mechanizmy języka Java nie mo-gą być używane wewnątrz tego pakietu, bowiem nie zawsze możliwa jest transformacja do JavaScript (więcej szczegółów w punkcie dedykowanym kompatybilności).

Pakiet server – to przede wszystkim miejsce dla servletów obsługujących komunikację z klientem. Może się tu znajdo-wać też cała niekliencka logika aplikacji, jak na przykład klasy odpowiedzialne za komunikację z bazą danych.

Pakiet public – tutaj będziemy umieszczać wszystkie pliki nie będące plikami Java, jak dodatkowe skrypty JavaScript, pli-ki HTML, CSS oraz pliki graficzne. Nie wszystkim może przy-paść do gustu koncepcja mieszania tych plików ze źródłami Ja-va – zapewne część Czytelników przyzwyczajona jest do od-dzielania warstwy webowej i Javowej od siebie. W GWT podział ten jednak nie jest aż tak oczywisty i to raczej kwestia przyzwy-czajenia się do nowej koncepcji. W trakcie kompilacji projektu GWT, pliki z pakietu client zostaną przetransformowane na Ja-vaScript i skopiowane do katalogu web, natomiast pliki z katalo-gu public zostaną tam po prostu skopiowane.

Koncepcja modułów GWTAplikacja GWT może zostać podzielona na zbiory logicznych komponentów i funkcjonalności, tzn. modułów. Każdy moduł po-winien odpowiadać pewnej niezależnej części aplikacji, dzięki te-

mu łatwo jest uczynić go przenośnym i budować biblioteki kom-ponentów na potrzeby różnych aplikacji. Moduły mogą dziedzi-czyć po sobie, łatwo uzupełniając możliwości już istniejących.

Każdy moduł zdefiniowany jest w pliku nazwa _ modu-

łu.gwt.xml i powinien zostać umieszczony w głównym pakie-cie, tzn. na tym samym poziomie, na którym znajdują się pa-kiety client, server i public.

Podstawowym modułem pochodzącym ze zbioru standar-dowych klas GWT jest com.google.gwt.user.User i to po nim będą dziedziczyć wszystkie nasze aplikacje. Ponadto moduł powinien zawierać tzw. entry point, czyli nazwę klasy inicjali-zującej interfejs użytkownika. Przykładowo plik modułu (o na-zwie Main.gwt.xml) z opisanej wcześniej aplikacji Hello World, wygląda następująco:

<module>

<inherits name='com.google.gwt.user.User'/>

<entry-point class='org.sdjournal.gwt.client.Main'/>

</module>

Poniżej opisano znaczenie poszczególnych elementów (ta-gów), które mogą znaleźć się w pliku definicji modułu:

• inherits-name – nazwa modułu po którym dziedziczy bieżący moduł; możliwe jest dziedziczenie po wielu mo-dułach;

• entry-point – klasa inicjalizująca interfejs użytkownika w obrębie modułu; jej metoda onModuleLoad zostanie wy-konana w trakcie ładowania modułu;

• source – tag pozwalający zdefiniować pakiety z plikami Ja-va, które zostaną w trakcie kompilacji przetransformowane do JavaScriptu (nie jesteśmy więc ograniczeni wyłącznie do pakietu client);

• public – definiuje katalogi których zawartość (zwykle pliki graficzne i HTML) zostanie skopiowana do katalogu web w trakcie kompilacji projektu;

• servlet – definiuje klasę i ścieżkę servletów do komunikacji klient-serwer; wartość ta używana jest tylko na potrzeby śro-dowiska uruchomieniowego GWT – w środowisku produkcyj-nym wszystkie servlety będą musiały być zdefiniowane w de-skryptorze aplikacji internetowej (pliku web.xml);

• script – pozwala na umieszczenie zewnętrznego skryptu JavaScript w module;

• stylesheet – umieszcza zewnętrzny plik CSS na potrzeby modułu;

• extend-property – pozwala na zdefiniowanie dodatkowych parametrów konfiguracyjnych; zwykle używane do określe-nia obsługiwanych przez aplikację wersji językowych.

Hosted-modeW poprzednich punktach wspominałem już o środowisku uru-chomieniowym GWT, przyjrzyjmy się jednak zważniej jakie ko-rzyści płyną z jego używania. Standardowo, by przetestować webaplikację musimy ją opublikować na serwerze aplikacji i wte-dy uruchomić. Często czyni to debugowanie aplikacji dość uciąż-liwym. W przypadku GWT również nie jest to proste – po stro-nie klienta operujemy bowiem na wygenerowanych plikach Ja-vaScript. w przypadku błędu nie zawsze łatwo będzie odnaleźć który fragment kodu Java odpowiada za nieprawidłowe działa-nie JavaScriptu. Tryb hosted-mode pozwala ominąć te problemy.

Page 53: Software Developer's Journal 01/2007 PL

GWT – WEB 2.0 na maksa

53www.sdjournal.orgSoftware Developer’s Journal 1/2007

To środowisko z wbudowaną przeglądarką internetową oraz ser-werem aplikacji, który w trakcie pracy korzysta z klas Javy, a nie z generowanego JavaScriptu. Dzięki temu możemy debugować naszą aplikację tak jak klasyczną aplikację Java. Również sa-mo uruchamianie aplikacji do testów staje się znacznie szybsze i prostsze niż w przypadku pracy z serwerem aplikacji.

Gdy tworzymy nową aplikację z użyciem narzędzia ap-plicationCreator, zostaje automatycznie wygenerowany plik (o nazwie nazwa_aplikacja-shell), który uruchamia nasz mo-duł w środowisku GWT. W przypadku środowiska Eclipse, ist-nieje możliwość takiego skonfigurowania go, by aplikacja uru-chamiała się w trybie Hosted-mode automatycznie po wybra-niu przycisku Run z poziomu Eclipse.

Z Javy do JavaScriptu– rozprawka o kompatybilnościProgramując moduł webowy aplikacji musimy mieć świadomość, że kod źródłowy zostanie finalnie przetłumaczony przez kompi-lator GWT na JavaScript. Zastanówmy się głębiej nad ideą ta-kiej transformacji. W części klienckiej aplikacji używać będziemy nie tylko elementów graficznych dostarczonych przez GWT ale także standardowych klas Javy, jak choćby kolekcji. Czy rzeczy-wiście możemy to robić i czy programiści Google podjęli próbę przeportowania Javy do JavaScriptu? W znacznej części – tak! Są jednak pewne różnice, o których należy pamiętać. Rozwa-żymy poniżej cechy i elementy języka Java, które nie występują w JavaScripcie, jednak zostały zasymulowane przez GWT. Po-wiemy też o mechanizmach, które mogą sprawiać trudności lub w ogóle nie powinny występować w części aplikacji klienta.

Zacznijmy od typów danych – wszystkie podstawowe typy (np. int oraz klasa Integer) mogą być z powodzeniem używane (czyt. konwertowane do JavaScriptu). Dotyczy to również ca-łych klas, których składowymi są proste typy danych lub klasy dziedziczące po nich. Jedynym wyjątkiem jest typ long, który nie ma swojego bezpośredniego odpowiednika w JavaScrip-cie. Będzie on reprezentowany poprzez typ zmiennoprzecin-kowy (double-precision).

Java i JavaScript to języki o bardzo odmiennej naturze, fizycznie nie jest więc możliwe, by zezwolić na używanie wszystkich cech języka Java w implementacji części klienc-kiej. Przykładowo JavaScript nie ma wbudowanej koncepcji wielowątkowości i raczej nie byłaby ona łatwa do zasymulo-wania. Takie konstrukcje języka Java jak Object.wait() czy Object.notify() nie powinny być wiec stosowane w modu-le webowym aplikacji. Kompilator GWT nie zgłosi co praw-da błędu, jednak zignoruje taki kod.

Również Reflection jest mechanizmem, którego nie da się przenieść bezpośrednio na JavaScript. Kompilator GWT gene-ruje raczej statyczny skrypt, więc dynamiczne ładowanie klas nie jest możliwe do zrealizowania. GWT wprowadza co prawda pew-ne klasy pomocnicze pozwalające częściowo zrekompensować ten brak, jednak w tym wypadku będziemy musieli używać dedy-kowanych rozwiązań, zamiast standardowych. Przykładowo po-branie nazwy klasy obiektu jest możliwe z użyciem statycznej metody GWT.getTypeName(Object).

Rozbudowany mechanizm serializacji obiektów Javy nie jest możliwy do zaimplementowania po stronie JavaScriptu, dlatego też GWT, na potrzeby komunikacji aplikacji klienckiej z serwe-rem, dostarcza własny mechanizm serializacji. Inną, raczej nie-możliwą do zaimplementowania po stronie JavaScriptu techni-

ką jest destrukcja (finalizacja) obiektów. Klasy aplikacji klienta nie powinny więc używać słowa kluczowego finalize.

Ostatnim elementem wartym omówienia są wyrażenia regu-larne. Oba języki umożliwiają ich używanie, jednak składnia wy-rażeń regularnych nieznacznie różni się pomiędzy Javą a Java-Scriptem, a kompilator GWT nie jest w stanie dokonać transfor-macji. Należy więc zachować tu pewną ostrożność i najlepiej ko-rzystać z wyrażeń interpretowanych identycznie przez oba języki.

Interfejs użytkownika à la GWTZ punktu widzenia programisty, Google Web Toolkt to przede wszystkim biblioteka klas interfejsu użytkownika, tylko że dedykowana na potrzeby internetu. Jak już było to wspomniane, programowanie przypomina używanie biblio-tek AWT albo SWING. Przyjrzyjmy się jakie możliwości da-je nam GWT w świecie aplikacji webowych, ograniczonym przecież w porównaniu do rozwiązań okienkowych.

Praca z panelamiPanele służą do wygodnego rozmieszczania elementów interfej-su użytkownika (np. przycisków czy pól edycyjnych) w zdefiniowa-nym przez programistę układzie. Głównym panelem aplikacji po-winien zawsze być RootPanel, który definiuje w jakim miejscu stro-ny HTML powinien zostać osadzony (poprzez zadany parametr ID elementu HTML). Do panelu RootPanel możemy dodać bez-pośrednio elementy GUI, ale lepiej jest umiejscowić tutaj najpierw któryś z paneli, definiujących kolejność rozłożenia elementów w swoim obrębie. Do wyboru mamy niemały zbiór możliwości:

• HorizontalPanel – rozmieszcza elementy w poziomie, od lewej do prawej strony;

• VerticalPanel – rozmieszcza elementy w pionie;• FlowPanel – działa podobnie jak HorizontalPanel, jed-

nak jeśli sumaryczna szerokość wszystkich elemen-tów w rzędzie przekracza rozmiar okna przeglądarki, zaczyna wyświetlanie kolejnych elementów w nowym wierszu;

• DockPanel – wyróżnia centralny, duży obszar na główny ele-ment panelu oraz miejsce na dodatkowe elementy po bo-kach oraz ponad i poniżej obszaru centralnego. Dla przy-kładu zobaczmy kod dodający przycisk u dołu panelu: new DockPanel().add(new Button(), DockPanel.SOUTH);

• HTMLPanel – praktyczny panel, którego zwartość jest po prostu kodem HTML; możliwe jest jednak wstawianie do wnętrza tego panelu elementów interfejsu GWT. Zobacz-my to na przykładzie:

HTMLPanel p = new HTMLPanel

("<div width='250'>Komentarz:<span id='txt'></span></div>");

p.add(new Label("Test"),"txt");

• ScrollPanel – panel do wykorzystania raczej wewnątrz in-nych paneli; ma zdefiniowaną stałą wielkość – jeśli jego zawartość przekroczy rozmiar panelu, zostaną wyświetlo-ne paski przewijania;

• TabPanel – umożliwia łatwe tworzenie zakładek; przykła-dowo poniżej utworzymy panel z dwiema zakładkami, gdzie jedna wyświetla przycisk, a druga tekst:

TabPanel p = new TabPanel();

p.add( new Button("Tab1"), "TAB 1");

p.add( new Label("Tab2"), "TAB 2");

• FormPanel – tworzy formularz HTML.

Page 54: Software Developer's Journal 01/2007 PL

54

Warsztat

GWT – WEB 2.0

www.sdjournal.org Software Developer’s Journal 1/2007

Elementy interfejsu użytkownikaGoogle Web Toolkit dostarcza zestaw podstawowych kontrolek, będących bezpośrednimi odpowiednikami elementów formularzy HTML oraz kilka rozbudowanych komponentów, na bazie których można budować złożone interfejsy użytkownika. Do podstawo-wych elementów należeć będą: pole tekstowe (klasa TextBox), li-sta (ListBox), przycisk (Button), pole wyboru (CheckBox) i duże po-le tekstowe (TextArea). Ponadto znajdziemy klasę reprezentującą link (Hyperlink), element graficzny (Image) oraz dowolny fragment kodu HTML (HTML). Używanie podstawowych elementów inter-fejsu użytkownika jest raczej intuicyjne. Skupmy się więc bardziej na złożonych kontrolkach, których bezpośrednia implementacja w HTMLu i JavaScripcie byłaby zapewne niemałym wyzwaniem. Jedną z takich kontrolek jest niewątpliwie DialogBox. Wyświe-tlanie okienek dialogowych spędza sen z powiek niejedne-mu programiście aplikacji webowych – nikt nie lubi wyskaku-jących okienek, przeglądarki starają się je blokować, a w rze-czywistości i tak nie możemy zasymulować pełnej funkcjonal-ności okna dialogowego, bowiem takie okienko nie może być modalne. Okno dialogowe z GWT to jedynie warstwa w obrę-bie okna głównego, ale zachowująca się jak niezależne, mo-dalne okienko. Możemy je nawet przesuwać w obrębie okna przeglądarki! Zobaczmy przykład takiego okna, zawierające-go listwę tytułową, komunikat i przycisk Close:

DialogBox db = new DialogBox();

db.setText("Dialog Box");

DockPanel panel=new DockPanel();

panel.add( new Button("Close"), DockPanel.SOUTH);

HTML msg = new HTML("To jest DialogBox");

panel.add(msg,DockPanel.CENTER);

db.setWidget(panel);

db.show();

Przykład okna dialogowego z aplikacji KitchenSink został zapre-zentowany na Rysunku 1. Innym bardzo ciekawym i dość nie-

standardowym w webaplikacjach komponentem graficznym jest drzewo – reprezentowane tu przez obiekt klasy Tree. Pojedynczy element drzewa, reprezentowany jest przez obiekt TreeItem. Zo-baczmy przykład tworzący dwupoziomowe, rozwijalne drzewo:

TreeItem t1 = new TreeItem("Poziom 1");

TreeItem t2 = new TreeItem("Poziom 2");

t1.addItem( t2 );

Tree tree = new Tree();

tree.addItem( t1 );

Pisząc o rozbudowanych komponentach GWT nie sposób nie wspomnieć o możliwości tworzenia wielopoziomowego me-nu aplikacji internetowej, przypominającego standardowe menu okienkowych programów. Podobnie jak w poprzednich przykła-dach – programista nie ma zbyt wiele pracy, by utworzyć dzia-łającą kontrolkę – wystarczy zainicjować obiekt typu MenuBari umieścić go w jakimś panelu. Elementy menu dodajemy za po-mocą metody addItem.

Obsługa zdarzeńAby umożliwić operowanie na elementach interfejsu użytkow-nika należy zaimplementować mechanizm obsługi zdarzeń. Są to proste interfejsy, których implementację często zawie-rać będziemy bezpośrednio w wywołaniu metody:

Button b = new Button( "Alert" );

b.addClickListener(new ClickListener() {

public void onClick(Widget sender) {

Window.alert( "Alarm!" );

}

});

Pisanie osobnych klas obsługi zdarzenia może mieć uzasad-nienie w przypadku, kiedy więcej niż jedna kontrolka wykonu-je dokładnie tę samą operację. Przykładowo element menu i przycisk mogą mieć identyczną obsługę zdarzenia. W nie-których przypadkach można też napisać jedną metodę obsłu-gi zdarzenia dla wielu kontrolek i rozpoznawać wewnątrz, któ-ra z nich metodę wywołała:

public class EventTest implements ClickListener {

Button a = new Button("A");

Button b = new Button("B");

public EventTest() {

a.addClickListener ( this );

b.addClickListener ( this );

}

public void onClick(Widget sender) {

if( sender == a ) { /* obsluga zdarzenia */ }

}

}

Każdemu zdarzeniu może towarzyszyć więcej niż jeden li-stener je obsługujący. W takich sytuacjach funkcje obsługi zdarzeń zostaną uruchomione w kolejności ich dodania do kontrolki. Można również usunąć dodany uprzednio obiekt za pomocą metody removeNazwaListenera, np.

myButton.removeClickListener( listener );

Listing 1. Aplikacja Hello world wygenerowana przez narzędzie applicationCreator

package org.sdjournal.gwttest.client;

import com.google.gwt.core.client.EntryPoint;

import com.google.gwt.user.client.ui.*;

public class Main implements EntryPoint {

public void onModuleLoad() {

final Button button = new Button("Click me");

final Label label = new Label();

button.addClickListener(new ClickListener() {

public void onClick(Widget sender) {

if (label.getText().equals(""))

label.setText("Hello World!");

else

label.setText("");

}

});

RootPanel.get("slot1").add(button);

RootPanel.get("slot2").add(label);

}

}

Page 55: Software Developer's Journal 01/2007 PL

55

GWT – WEB 2.0 na maksa

www.sdjournal.orgSoftware Developer’s Journal 1/2007

Niektóre interfejsy obsługi zdarzeń deklarują kilka metod. Je-śli nie chcemy każdorazowo implementować wszystkich me-tod, możemy skorzystać z wygodnego mechanizmu adapte-rów. Adapter to prosta klasa implementująca dany interfejs, zawierająca puste metody (nie wykonujące żadnych akcji). Przykładowo interfejs KeyboardListener zawiera kilka metod. Chcąc zaimplementować tylko jedną z nich (onKeyPress), mo-żemy łatwo skorzystać z adaptera:

KeyboardListener list = new KeyboardListenerAdapter() {

public void onKeyPress(Widget sender, char keyCode,

int modifiers) {

// implementacja metody

}

}

Komunikacja z serweremDotychczas skupialiśmy się na części klienckiej aplikacji, czas opisać sposób użycia GWT po stronie serwera oraz komunika-cję pomiędzy obiema stronami. Mechanizm komunikacji określa-ny jest mianem RPC (Remote Procedure Calling).

Stwórzmy przykładową aplikację, by zobaczyć w jaki sposób dynamicznie podmienić zwartość listy rozwijanej danymi pocho-dzącymi z serwera. Niech interfejs użytkownika zawiera dwie li-sty rozwijane – pierwsza z nazwami kontynentów, druga – z na-zwami państw. Kiedy użytkownik wybierze wartość z pierwszej listy (kontynent), aplikacja pobierze z serwera powiązaną kolek-cję nazw państw i wyświetli ją na drugiej liście.

Proces komunikacji z serwerem początkowo może wydawać się nieco zawiły, musimy bowiem w tym celu stworzyć dwa in-terfejsy i jedną klasę. Pierwszy z interfejsów reprezentuje żąda-nie do serwera, a drugi – odpowiedź. Konieczność posiadania dwóch różnych interfejsów bierze się z asynchronicznej natury komunikacji z serwerem. Wspomniane interfejsy znajdują się po stronie klienta, natomiast klasa, będąca defacto servletem, zo-stanie umieszczone po części serwera. Zacznijmy od interfej-su żądania – musi on dziedziczyć po interfejsie RemoteService i w naszej przykładowej aplikacji będzie wyglądał następująco:

public inteface CountryService extends RemoteService {

public Collection getCountries(String continent);

}

Metoda getCountries to nasze faktyczne żądanie. Klasa ob-sługująca je po stronie serwera musi implementować ten in-terfejs oraz dziedziczyć po klasie RemoteServiceServlet:

public class CountryServiceImpl

extends RemoteServiceServlet implements CountryService {

public Collection getCountries(String continent) {

return /* kolekcja państw */;

}

}

Pozostało jeszcze utworzyć interfejs reprezentujący odpo-wiedź ze strony serwera. Musi on mieć taką samą nazwę jak interfejs żądania ale z końcówką Async. Interfejs również musi zawierać metodę o tej samej nazwie co interfejs żąda-nia, ale z jednym dodatkowym parametrem na końcu – Async-Callback wskazuje on na klasę aplikacji klienta, która obsłuży odpowiedź.

W tym układzie nie ma więc uzasadnienia, by metoda in-terfejsu zwracała jakąś wartość (jak w interfejsie żądania) – typ zwracanego przez metodę parametru musi więc być usta-wiony na void:

public inteface CountryServiceAsynch {

public void getCountries(String continent,

AsyncCallback callback); }

Na koniec pozostało połączyć wszystko w całość. Zobaczmy jak wysłać żądanie i obsłużyć je ze strony klienta. W pierw-sze kolejności należy utworzyć obiekt reprezentujący inter-fejs – obiekt ten w nomenklaturze GWT określany jest mia-nem client proxy:

CountryServiceAsynch hservice =

(CountryServiceAsynch)GWT.create(CountryService.class);

Uważny Czytelnik może odnieść wrażenie, że w kodzie powy-żej jest błąd – metodzie create przekazujemy bowiem interfejs żądania, jednak otrzymujemy instancję interfejsu odpowiedzi. To jednak jak najbardziej poprawny zapis.

W kolejnym kroku musimy określić adres URL, pod którym znajduje się servlet, z którym zamierzamy się komunikować. Należy pamiętać, iż adres może wskazywać wyłącznie na tę samą domenę i port z których uruchomiliśmy stronę.

ServiceDefTarget endpoint = (ServiceDefTarget)hservice;

endpoint.setServiceEntryPoint("/country.srv");

Przed nami najważniejsze zadanie – musimy utworzyć klasę, która otrzyma odpowiedź od serwera i zinterpretuje ją. Klasa ta musi implementować interfejs AsyncCallback. Dobrym roz-wiązaniem jest jej bezpośrednia implementacja, np tak:

AsyncCallback callback = new AsyncCallback() {

public void onFailure(Throwable caught) {

Window.alert( "Error: " + caught.getMessage() );

}

public void onSuccess(Object result) {

// obsługa odpowiedzi

} };

Rysunek 1. Zbudowane na warstwie HTML modalne okno dialogowe, które można swobodnie przesuwać w obrębie okna przeglądarki. Implementacja takiego rozwiązania to zaledwie kilka linii kodu

Page 56: Software Developer's Journal 01/2007 PL

56

Warsztat

GWT – WEB 2.0

www.sdjournal.org Software Developer’s Journal 1/2007

Klasa implementuje dwie metody – onFailure, która jest urucha-miana w przypadku błędu i standardowo będzie wyświetlać ko-munikat o niepowodzeniu operacji, oraz metodę onSuccess, która obsłuży odpowiedź serwera. Parametr tej drugiej metoda (obiekt typu Object), to rzeczywista odpowiedź od serwera, a jej typ jest zgodny z typem zwracanym przez metodę interfejsu żądania (w naszym przypadku będzie to Collection). Wewnątrz me-tody należy więc dokonać odpowiedniego rzutowania typów. W naszej przykładowej aplikacji metoda onSuccess powinna zaktu-alizować dane w liście rozwijanej z państwami, np. w taki sposób:

Collection c = (Collection)result;

countries.clear();

for( Iterator i=c.iterator(); i.hasNext(); )

countries.addItem( (String)i.next() );

Utworzyliśmy powyżej wszystkie niezbędne obiekty, pozostało już tylko wykonać żądanie. W naszym przykładzie interfejs żą-dania oczekuje parametru typu String, wskazującego na nazwę kontynentu – pobierzemy go z listy rozwijanej o nazwie htype:

String selectedType = htype.getValue

( htype.getSelectedIndex() );

hservice.getCountry( selectedType, callback );

Finalnie wywołaliśmy metodę asynchronicznego interfejsu. Aplikacja nie będzie więc czekać na odpowiedź serwera, tylko będziemy mogli kontynuować pracę. Aby uruchomić i przete-stować nasz kod na serwerze aplikacji, musimy jeszcze zmo-dyfikować plik web.xml, deklarując w nim utworzony servlet:

<servlet><servlet-name>countryService</servlet-name>

<servlet-class>org.sdjournal.gwt.server.

CountryServiceImpl</servlet-class></servlet>

<servlet-mapping><servlet-name>countryService</servlet-name>

<url-pattern>/country.srv</url-pattern>

</servlet-mapping>

Pozostaje jeszcze omówić jedną kwestię, którą dla uproszcze-nia pominąłem. Obiekty, na których operujemy podczas komu-nikacji klient-serwer, muszą być serializowalne. Wszystkie ty-py proste i ich tablice spełniają ten warunek. Klasy utworzone przez programistę powinny w tym celu implementować interfejs com.google.gwt.user.client.rpc.IsSerializable (jak wspomnie-liśmy w rozdziale o kompatybilności – nie możemy tu używać java.io.Serializable). Problemem pozostają kolekcje, które do-myślnie operują na niezserlializowanych obiektach typu Object. Aby umożliwić przesyłanie kolekcji między serwerem i klientem (jak w naszej przykładowej aplikacji), musimy poinformować apli-kację kliencką, jakiego typu są elementy kolekcji. Siłą rzeczy ko-lekcja będzie musiała być monolityczna i zawierać obiekty seria-lizowalne. Przekazanie informacji o typie elementów kolekcji od-bywa się z użyciem odpowiedniego przypisu w komentarzu inter-fejsu żądania. W naszym przypadku finalna wersja interfejsu po-winna więc wyglądać następująco:

public inteface CountryService extends RemoteService {

/** @gwt.typeArgs <java.lang.String> */

public Collection getCountries(String continent);

}

Gdybyśmy przekazywali kolekcję jako parametr wejściowy metody interfejsu, w komentarzu musielibyśmy jeszcze podać nazwę parametru, np. tak:

@gwt.typeArgs mojParametr <java.lang.Integer>

Implementacja własnych komponentówJedną z największych zalet GWT jest łatwość pisania własnych komponentów. To właśnie ten mechanizm pozwala na upodob-nienie naszej strony internetowej do normalnej, okienkowej apli-kacji. Wyobraźmy sobie formularz, który w zależności od wpro-wadzanych danych ukrywa lub wyświetla niektóre pola, zmienia ich typ, albo doładowuje dynamicznie zawartości list. Wszystko to możliwe jest do zaprogramowania z poziomu JavaScriptu, jed-nak nie jest to operacja łatwa, a na dodatek troszczyć się będzie-my musieli o kompatybilność kodu między przeglądarkami. Napi-sanie podobnego rozwiązania z użyciem GWT nie powinno być zbyt czasochłonne. Nietrywialne poruszanie się po obiektach drzewa DOM, zachowanie zgodności kodu itp, zostało bowiem w GWT obudowane przez wygodne w użyciu obiekty Javy. Ponad-to możliwość tworzenia własnych komponentów tworzy bardziej czytelny, a przede wszystkim przenośny, kod.

Zwykle nowe komponenty pisane przez programistów bę-dą kombinacjami lub rozszerzeniami komponentów podstawo-wych. Klasycznym przykładem prostego komponentu może być panel z kilkoma powiązanymi logicznie elementami, trak-towany jako całość. Niestandardowe rozwiązania będą jed-nak wymagały większego nakładu pracy oraz częściowej im-plementacji bezpośrednio w JavaScripcie. Jednak i tutaj GWT przychodzi z pomocą udostępniając nam mechanizm JSNI (JavaScript Native Interface).

Stwórzmy dla przykładu prosty komponent. Wyobraźmy so-bie sytuację, w której użytkownik ma możliwość wyboru w formu-larzu wartości z listy rozwijanej (combo box), jednak w przypadku braku poszukiwanej wartości powinien mieć możliwość wpisania własnej. W tym celu na końcu listy umieścimy wartość specjal-ną, np. o nazwie „>> zdefiniuj <<”. Kiedy użytkownik wybierze ta-ką wartość, wyświetlone zostanie normalne pole edycyjne. Jeśli całość zamkniemy w jednym komponencie, będziemy mogli zde-finiować dla niego metodę getValue(), która, w zależności od sy-tuacji, zwróci wartość z listy rozwijanej lub pola edycyjnego. Taki komponent możemy stworzyć na bazie standardowych obiektów GWT. Będziemy tu potrzebowali listę (komponent ListBox), po-le tekstowe (TextBox) oraz panel, na którym umieścimy oba ele-menty (w tym przypadku użyjemy HorizontalPanel). Prostym roz-wiązaniem byłoby stworzenie klasy rozszerzającej klasę repre-zentująca panel i dodanie do niej elementów formularza. Takie rozwiązanie ma jednak istotną wadę – nasz komponent będzie udostępniał wszystkie metody panelu, jak np. możliwość usunię-cia elementu, a na to nie chcielibyśmy pozwolić. Rozwiązaniem jest stworzenie własnej klasy, która zawiera wewnątrz kompo-nenty GWT i deleguje na zewnątrz tylko te metody, które chcemy udostępnić. Pojawia się jednak tutaj jeden specyficzny dla GWT problem – nasz komponent do poprawnego działania po stronie klienta musi wywołać w konstruktorze metodę initWidget(). Aby mięć taką możliwość, będziemy musieli odziedziczyć naszą kla-sę po klasie com.google.gwt.user.client.ui.Composite, która de-dykowana jest tworzeniu komponentów użytkownika.

Na Listingu 2 zamieszczony został kod opisanego kom-ponentu. Przyjmuje on w konstruktorze dwa parametry –

Page 57: Software Developer's Journal 01/2007 PL
Page 58: Software Developer's Journal 01/2007 PL

58

Warsztat

GWT – WEB 2.0

www.sdjournal.org Software Developer’s Journal 1/2007

etykietę i wartość elementu specjalnego, odpowiedzialne-go za wyświetlenie pola tekstowego. Klasa deleguje meto-dę addItem z klasy ListBox, byśmy mogli dodawać nowe ele-menty do listy. Wartym uwagi fragmentem kodu jest meto-da onChange, wykonywana w przypadku zmiany wartości na liście rozwijanej. To właśnie tutaj znajduje się kod odpowie-dzialny za wyświetlenie lub ukrycie pola tekstowego. Nale-ży zwrócić uwagę, że metoda onChange pochodzi z interfejsu ChangeListener, który nasz komponent implementuje. Aby zdarzenie zmiany wartości na liście mogło być obsłużone, musimy zarejestrować nasz komponent, jako listener listy rozwijanej (patrz konstruktor): combo.addChangeListener( this );Pozostaje przetestować utworzony komponent, np tak:

EditableComboBox ecb = new EditableComboBox

(">>zdefiniuj<<","-1");

ecb.addItem("Wartosc 1", "1");

ecb.addItem("Wartosc 2", "2");

JavaScript Native InterfaceTransformacja kodu Javy do JavaScriptu może być w nie-których przypadkach niewystarczająca – czasem przydat-nym może okazać się bezpośrednia implementacja fragmen-tów kodu w JavaScripcie. Nic nie stoi na przeszkodzie, by do-łączyć do aplikacji zewnętrzne pliki JavaScript, jednak w ta-kiej sytuacji zostaniemy pozbawieni możliwości odwoływania się do struktur zawartych w takim pliku z poziomu aplikacji Ja-va. GWT rozwiązuje tę kwestię poprzez JSNI (JavaScript Na-tive Interface), oparty koncepcyjnie na standardowym mecha-nizmie Javy – JNI (Java Native Interface). Mechanizm ten po-zwala na łączenie kodu Java z funkcjami napisanymi bezpo-średnio w JavaScripcie. Zobaczmy przykład:

public static native void jsalert(String msg) /*-{

$wnd.alert(msg);

}-*/;

Różnica między klasycznym JNI a JSNI polega na tym, że w przypadku tego ostatniego możemy zawrzeć implementa-cję metody bezpośrednio w klasie Java. Musi ona jednak zo-stać otoczona komentarzem. Google wprowadziło następują-cą notację dla oznaczenia osadzonego JavaScriptu: deklarac-ja metody(parametry) /*-{ treść metody JavaScript }-*/; przy czym deklaracja metody musi zawierać słowo kluczowe native. Me-chanizm JSNI pozwala na pełną interakcję kodu JavaScriptu z kodem Javy i vice versa. Oczywiście faktycznie będzie miało to miejsce po stronie wygenerowanego JavaScriptu. Uruchamia-nie metod Javy po stronie JavaScriptu wymaga użycia dość nie-wygodnej składni. Na przykładzie poniżej przedstawiono sposób wywołania metody void test(String str) z klasy org.sdjournal.gwt.Example:

[email protected]:

:test(Ljava/lang/String;)("test");

Zamiast this możemy w powyższej konstrukcji używać nazwy zmiennej wskazującej na obiekt klasy Example. Natomiast me-todę statyczną będziemy uruchamiać bez wskazania na żaden obiekt, rozpoczynając zapis od znaku @. Dostęp do pól klas Javy jest nieco prostszy: var [email protected]::field.

Środowisko programistyczne IntelliJ Idea daje pełne wsparcie dla programistów JSNI, udostępniając funkcję podkreślania składni, a nawet uzupełniania kodu wewnątrz osadzonego JavaScriptu.

i18nW obecnych czasach raczej trudno wyobrazić sobie poprawnie zbudowaną aplikację internetową nie wspierającą wielu wersji językowych. Na szczęście GWT dostarcza wygodne narzędzia ułatwiające zarządzanie wersjami językowymi i tworzenie tłuma-czeń. Początkowo cały proces może wydawać się nieco pokręt-ny, jednak GWT pozwala go w znacznej części zautomatyzować z użyciem własnych narzędzi. Z punktu widzenia kodu Java, tłu-maczenia będą reprezentowane przez dedykowane ku temu in-terfejsy. W przykładzie poniżej przedstawiono taki interfejs tłu-maczący nazwy dwóch podstawowych przycisków – Ok i Anuluj:

public interface Translations extends Constants {

String ok();

String cancel(); }

Listing 2. Implementacja własnego komponentu – lista rozwijana, która w przypadku wybrania (zdefiniowanej w konstruktorze) wartości specjalnej, wyświetla pole edycyjne, w którym użytkownik może wprowadzić własną wartość (spoza listy)public class EditableComboBox extends Composite implements

ChangeListener {

protected ListBox combo;

protected TextBox newElement;

protected String newElementValue;

public EditableComboBox(String newElementLabel, String

newElementValue) {

this.newElementValue = newElementValue;

combo = new ListBox();

combo.setVisibleItemCount( 1 );

combo.addItem(newElementLabel, newElementValue);

combo.addChangeListener( this );

newElement = new TextBox();

newElement.setVisible( true );

HorizontalPanel panel = new HorizontalPanel();

panel.add( combo );

panel.add( newElement );

initWidget( panel );

}

public void onChange(Widget sender) {

if( sender == combo && combo.getSelectedIndex() >= 0 ) {

newElement.setVisible( combo.getValue(combo.getSelectedI

ndex()).equals(newElementValue) );

}

}

public String getValue() {

String val = combo.getValue(combo.getSelectedIndex());

return val.equals( newElementValue ) ?

newElement.getText() : val;

}

public void addItem(String item, String value) {

combo.addItem( item, value );

}

}

Page 59: Software Developer's Journal 01/2007 PL

GWT – WEB 2.0 na maksa

59www.sdjournal.orgSoftware Developer’s Journal 1/2007

Aby móc używać takiego interfejsu w naszej klasie, musimy go zainstancjonować za pomocą metody GWT.create(). Tak powsta-ły obiekt będzie reprezentował aktualnie wybrany język. Oczywi-ście można mieć wiele różnych interfejsów dla jednego języka, np. jeden będzie reprezentował elementy interfejsu, drugi komu-nikaty. Zobaczmy przykład utworzenia przycisku Anuluj:

Translations trans=(Translations)GWT.

create(Translations .class);

Button cancel=new Button(trans .cancel());

Pozostaje jeszcze rozwiązać zagadkę, gdzie znajdują się faktyczne tłumaczenia? Oczywiście w pliku .properties. Prawdopodobnie większość Czytelników ma obecnie wra-żenie, że jest zbyt dużo do oprogramowania, aby uzyskać fi-nalny efekt – pliki .properties oraz konieczność implemen-tacji interfejsu. Na szczęście ten ostatni może zostać wy-generowany automatycznie na bazie pliku z tłumaczenia-mi. Prześledźmy cały proces. W pierwszej kolejności wyge-nerujmy plik .properties z naszymi tłumaczeniami za pomo-cą narzędzia GWT:

i18nCreator -out c:\projects\gwttest org.

sdjournal.gwt.client.Translator

Pierwszy parametr komendy wskazuje na lokalizację na-szego projektu a drugi określa nazwę interfejsu z tłumacze-niami (wraz z pakietem). Narzędzie wygeneruje dwa pliki – Translator.properties (w zadanym pakiecie) oraz Translator-i18n.cmd – w katalogu głównym projektu. Możemy teraz wy-edytować plik z tłumaczeniami, dodając tam nasze przyci-ski, np:

ok = Ok

cancel = Anuluj

Następnie uruchommy narzędzie Translator-i18n – wygene-ruje ono automatycznie interfejs z niezbędnymi metodami. I to wszystko! W niektórych środowiskach programistycz-nych (np. Eclipse lub IntelliJ IDEA) łatwo można dodać plik generatora do procesu kompilacji projektu, by zautomatyzo-wać cały proces. To samo można zrobić z użyciem skryp-tu ANTa. Jeśli chcemy by nasza aplikacja obsługiwała wie-le języków, musimy zdefiniować osobny plik .properties dla każdego z nich (ale tylko jeden interfejs!). Przykładowo plik Translations _ fr.properties będzie zawierał tłumaczenia na język francuski a Translations _ en _ US.properties – tłuma-czenia na amerykańską odmianę angielskiego. Lista obsłu-

giwanych przez naszą aplikację języków powinna zostać za-deklarowana w pliku definicji modułu:

<extend-property name="locale" values="fr"/>

<extend-property name="locale" values="en_US"/>

Ponadto nasz moduł musi dziedziczyć po dostarczanym przez Google module I18N: <inherits name="com.google.gwt.i18n.I18N"/>.

Na koniec powinniśmy jeszcze zdefiniować wybrany język na stro-nie HTML. Możemy to zrobić w dwojaki sposób – używając dedy-kowanego meta taga w nagłówku HTMLa: <meta name="gwt:proper-ty" content="locale=en_NZ"> albo poprzez parametr w adresie URL strony, np: http://sdjournal.org/przyklad.htm?locale=en_NZ. To dru-gie rozwiązanie pozwala na łatwe przełączanie się między wer-sjami językowymi. Opisany powyżej sposób tłumaczenia tekstów może okazać się niewystarczający w przypadku bardziej złożo-nych fraz, jak na przykład komunikaty o błędach. Nierzadko bę-dziemy bowiem musieli zamieszczać tam informacje dynamiczne, jak np. kod błędu, nazwę użytkownika itd. W tym celu mamy do dyspozycji mechanizm sparametryzowanych tłumaczeń, obsługi-wany przez interfejs Message. Przypomina on mocno opisany wy-żej mechanizm statycznego tłumaczenia (interfejs Constants), z tą różnicą, iż metody interfejsu mogą posiadać parametry. Z pozio-mu plików .properties będziemy odwoływać się do parametrów poprzez znaczniki {nr_parametru}, przy czym numeracja para-metrów rozpoczyna się od zera, np: Błąd nr {0}, użytkownik {1} nie jest zdefiniowany w systemie. Chcąc utworzyć plik ze sparametry-zowanymi tłumaczeniami należy uruchomić opisane wcześniej na-rzędzie i18nCreator z dodatkową opcją -createMessages.

PodsumowanieTak jak przeminęła era assemblera, wyparta przez języki wyż-szego poziomu, tak samo nadejdzie kres czystego HTMLa. Apli-kacje internetowe w epoce Web 2.0, mogą przypominać klasycz-ne programy i tego właśnie będą oczekiwać użytkownicy. Z tech-nicznego punktu widzenia, kod takich aplikacji będzie składał się w większości z JavaScriptu – nie z HTMLa. GWT, będąc defac-to generatorem JavaScriptu, idzie dokładnie z tym postępem, a może bardziej – tworzy go. Użytkownicy Lynxa i Internet Explo-rera 4.0 będą musieli dać za wygraną... Na koniec warto za-dać sobie pytanie czy należy unikać JavaScriptu? Oczywiście, że nie! JavaScript to piękny i pełen możliwości język, a niechęć do niego bierze się raczej z pobieżnej znajomości, niż rzeczy-wistych wad języka. Niewątpliwym minusem jest niekompatybil-ność podstawowego JavaScriptu miedzy przeglądarkami. W in-ternecie nie brak jednak rozwiązań obudowujących niskopozio-mowe operacje na drzewie DOM i dających przenośny interfejs. Niektóre z bibliotek javascriptowych, jak np. DOJO lub Prototype, pozwalają na uzyskanie takich samych efektów, jakie daje nam GWT, a kod ich kod będzie zdecydowanie czytelniejszy i krótszy, niż ten generowany. GWT, jak każde inne rozwiązanie, nie jest idealne dla wszystkich. Po prostu - każdemu według potrzeb. Z pewnością webmasterzy, czujący się swobodnie w świecie Ja-vaScriptu, lecz niekoniecznie w Javie – wybiorą rozwiązanie opar-te na bezpośrednim kodowaniu skryptów. Programiści Java zaś postąpią na odwrót, a zwolennicy Ruby on Rails pójdą jeszcze in-ną ścieżką. Ta programistyczna wieża Babel tylko pozornie sieje zamęt i chaos. W rzeczywistości umiejscawia nas w najbardziej demokratycznym ze światów, w którym zawsze możemy wybrać, a jeśli nie mamy z czego – możemy zbudować coś od podstaw... n

W Sieci• główna strona projektu GWT – http://code.google.com/webtoolkit/• forum programistów GWT http://groups.google.com/group/Google-Web-Toolkit• strona domowa wtyczki Googlipse, usprawniającej pracę

z GWT w środowisku Ecipse – http://www.googlipse.com/• strona konkurencyjnego narzędzia – XML11, które również

umożliwia transformację kodu Javy do JavaScriptu http://www.xml11.org/

Page 60: Software Developer's Journal 01/2007 PL

60

Bazy

danych

www.sdjournal.org Software Developer’s Journal 1/2007

Rozszerzenia środowiska bazodanowego KexiKexi jest środowiskiem dla tzw. desktopowych

baz danych (ang. desktop/workgroup databa-ses), to jest narzędziem przedkładającym ła-

twość tworzenia i rozwijania aplikacji bazodanowych, nad bogactwo zaawansowanych opcji. Ciężar prze-twarzania danych jest przeniesiony na serwer SQL, którym obecnie może być MySQL, PostgreSQL lub SQLite. Korzystanie z tego ostatniego – wbudowa-nego w Kexi – umożliwia zredukowanie konieczności konfiguracji serwera baz danych praktycznie do ze-ra. Naturalną konkurencją dla Kexi jest Microsoft Ac-cess oraz FileMaker.

Program Kexi, rozwijany na zasadach Open So-urce, jest obecnie dostępny w postaci kodu źródło-wego oraz binariów dla większości popularnych dys-trybucji Linuksa, dla BSD oraz Solarisa. Jest też do-stępny w wersji dla MS Windows. W produkcji pro-gramu uczestniczą profesjonalni programiści, użyt-kownicy oraz firmy a całość jest zarządzana pod skrzydłami organizacji KDE.

Z uwagi na mnogość popularnych silników baz danych oraz języków skryptowych, aplikacja Ke-xi jest w dużej mierze zbudowana z wtyczek (ang. plugins), dzięki czemu użytkownicy nie są zmuszani do spełniania zbyt wielu zależności w czasie insta-lacji programu. W szczególności, do uzyskania peł-nej funkcjonalności nie jest wymagane instalowanie bibliotek klienckich MySQL lub PostreSQL, czy też konfigurowanie serwerów tychże silników – w więk-szości przypadków wystarcza efektywna baza pli-kowa SQLite.

Rozszerzenia aplikacjiDzięki modularyzacji z użyciem wtyczek zyskuje się jeszcze dwie rzeczy. Aplikacja nie ładuje do pamię-ci nieużywanych komponentów, przez co jej start jest o wiele szybszy niż programu o architekturze mono-litycznej. Drugą korzyścią jest łatwość rozszerzania aplikacji – wykorzystując ściśle zdefiniowane API, programista może dodać niestandardową funkcjonal-ność bez ingerencji w samo jądro programu. O tym ostatnim aspekcie mówi niniejszy artykuł.

Głównymi czynnościami wykonywanymi w aplika-cjach bazodanowych jest wprowadzanie danych oraz ich przetwarzanie i wyprowadzanie do systemów ze-

wnętrznych. W niniejszym artykule będą przedsta-wione dwa rozszerzenia:

• narzędzie służące do eksportowania tabel da-nych do nieobsługiwanego przez Kexi formatu Fixed-Width Text;

• dodanie nowego elementu interfejsu użytkownika na przykładzie widżetu suwaka (ang. slider), pozwalają-cego na nowy sposób wprowadzania danych.

Potrzebne narzędzia i składnikiDo zbudowania planowanych rozszerzeń będzie po-trzebne środowisko umożliwiające kompilowanie apli-kacji Kexi. Dla uproszczenia, założenie jest takie, że korzysta się z gcc 3.x lub 4.x na Linuksie. Zwykle nie byłoby konieczne posiadanie kodu źródłowego całe-go program, a jedynie plików nagłówkowych dla API rozszerzeń. W tym przypadku konieczne jest jednak korzystanie z (w momencie pisanie tego artykułu) jeszcze nie wydanej publicznie Kexi w wersji 1.1. Jest to część KOffice 1.6, planowanego na październik 2006 – czytelnik może nie być w stanie zdobyć nie-zbędnych pakietów deweloperskich Kexi dla swojej dystrybucji. Należy wykonać następujące czynności:

• Upewnić się co do posiadania zainstalowanych pa-kietów z bibliotekami Qt oraz KDE, jak też pakietów z nagłówkami dla tych bibliotek; zwykle nazywają-cych się, odpowiednio: qt3-devel oraz kdelibs3-de-vel. Nie jest konieczne korzystanie ze środowiska KDE – potrzebne funkcje będą uruchamiane w tle niezależnie od uruchomionego pulpitu;

• Pobrać kod źródłowy Kexi. Znajduje się on na stro-nie poświęconej artykułowi (link podany na koń-cu artykułu). Aktualną wersję można też pobrać z repozytorium Subversion KDE – sposób pobrania oraz instrukcje kompilacji znajdują się na http://kexi-project.org/w/?UsingSubversion (zalecana wer-sja zawsze aktualnego kodu) lub pobrać paczkę z kodem źródłowym (dla naszych potrzeb wymaga-

Jarosław Staniek

Jarosław Staniek jest z wykształcenia informatykiem, pracuje w firmie OpenOffice Polska w Warszawie. Jest założycielem projektu KDElibs for Windows oraz zarzą-dza projektem Kexi w ramach organizacji KDE.Kontakt z autorem: [email protected]

Rysunek 1. Dane tabeli pomiary

Page 61: Software Developer's Journal 01/2007 PL

Rozszerzenia środowiska bazodanowego Kexi

61www.sdjournal.orgSoftware Developer’s Journal 1/2007

Listing 1. Główny program eksportu do formatu Fixed-Width Text (main.cpp)

#include <stdio.h>

#include <qfile.h>

#include <kdebug.h>

#include <kcmdlineargs.h>

#include <kapplication.h>

#include <kinstance.h>

#include <kaboutdata.h>

#include <kexidb/connection.h>

#include <kexidb/tableschema.h>

#include <kexidb/queryschema.h>

#include <kexidb/cursor.h>

#include <kexidb/simplecommandlineapp.h>

static KCmdLineOptions options[] = {

{ "+db_name", I18N_NOOP("Database name"), 0},

{ "+table_or_query", I18N_NOOP("Table or query name

(as data source)"), 0}, { "+output_file",

I18N_NOOP("Output filename in Fixed-Width Text format\n"

"(use \"-\" for standard output)"), 0},

KCmdLineLastOption

};

int main(int argc, char** argv) {

KexiDB::SimpleCommandLineApp app(

argc, argv, options, "ExportToFixedWidth",

"0.1", "", KAboutData::License_LGPL,

"(C) 2006, Jaroslaw Staniek\n", "",

"http://www.koffice.org/kexi");

KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

if (args->count()<3) {

KCmdLineArgs::usage();

return 1;

}

const QString dbName( args->arg(0) ),

dataSourceName( args->arg(1) ),

outputFName( args->arg(2) );

if (!app.connectionData()->fileName().isEmpty()

&& dbName==outputFName) {

kdWarning() << "Output filename cannot be the same

as database filename" << endl;

return 1;

}

if (!app.openDatabase( dbName )) {

app.debugError();

return 1;

}

KexiDB::Connection *conn = app.connection();

KexiDB::TableSchema *table = conn->tableSchema(

dataSourceName );

KexiDB::QuerySchema *query = table ? table->query()

: conn->querySchema( dataSourceName );

if (!query) {

kdWarning() << "Data source '" << dataSourceName <<

"' not found" << endl;

return 1;

}

QFile outputFile(outputFName);

bool ok;

if (outputFName=="-")

ok = outputFile.open(IO_WriteOnly, stderr);

else

ok = outputFile.open(IO_WriteOnly);

if (!ok) {

kdWarning() << "Could not open '" << outputFName <<

"' output file: "

<< outputFile.errorString() << endl;

return 1;

}

QTextStream outputStream(&outputFile);

if (!exportToFixedWidthText(query, outputStream)) {

kdWarning() << "Error exporting '" << dataSourceName

<< "' to '" << outputFName << "'" << endl;

app.closeDatabase();

return 1;

}

outputFile.close();

if (!app.closeDatabase()) {

app.debugError();

return 1;

}

return 0;

}

na jest wersja co najmniej 1.6 rc1) – http://download.kde.org/download.php?url=unstable/koffice-1.6-rc1/ ;

• Skompilować Kexi. Wystarczy przeprowadzić kompilację w katalogach koffice/lib/ oraz koffice/kexi/, omijając inne programy pakietu KOffice. Dokonuje się tego poleceniami:

cd koffice; ./configure –prefix=`kde-config –prefix`

cd lib; make; make install; cd ../

kexi; make; make install

(w przypadku pobierania źródeł w postaci archiwum) oraz: cd koffice/; make -f Makefile.cvs; ./

configure –prefix=`kde-config –prefix`

cd lib; make; make install; cd ../

kexi; make; make install

• Potrzebne będą autoconf oraz automake, ten ostat-ni można zastąpić szybszym unsermake. Po kompila-cji nie należy usuwać katalogu ze skompilowanym ko-

dem źródłowym, gdyż uniemożliwiłoby to ewentualne testy.

• Sprawdzić poprawność zbudowania i zainstalowania Kexi, na przykład przez uruchomienie programu i otwarcie przykłado-wej bazy danych Simple_Database.kexi znajdującej się w ka-talogu koffice/kexi/examples/ – należy ją wygenerować uru-chamiając znajdujący się tam skrypt build_kexi_files.sh;

• Szczegółowa wiedza na temat kompilacji wykracza po-za zakres niniejszego artykułu. W razie problemów moż-na skorzystać z pomocy oferowanej na stronie http://kexi-project.org/w/?Support. W dalszej lekturze artykułu przy-da się znajomość biblioteki Qt, jednak przykłady będą dość zrozumiałe dla każdego znającego język C++.

Pliki z omawianym kodem źródłowym znajdują się na stronie dedykowanej niniejszemu artykułowi. Na końcu artykułu znaj-

Page 62: Software Developer's Journal 01/2007 PL

62

Bazy

danych

www.sdjournal.org Software Developer’s Journal 1/2007

Listing 2. Funkcja eksportująca dane (pozostała część main.cpp)

bool exportToFixedWidthText(KexiDB::QuerySchema

*query, QTextStream& outputStream) {

KexiDB::Connection *conn = query->connection();

KexiDB::Driver *drv = conn->driver();

// policz szerokosci kolumn (zaleznie od typu danych)

KexiDB::QueryColumnInfo::Vector vector =

query->fieldsExpanded();

QValueVector<uint> columnSizes(vector.size());

for (uint i = 0; i<vector.count(); i++) {

KexiDB::QueryColumnInfo *info = vector[i];

switch (info->field->type()) {

case KexiDB::Field::Text:

case KexiDB::Field::LongText: {

QString len;

if ( true != conn->querySingleString(

QString("SELECT MAX(LENGTH(%1)) FROM %2")

.arg(drv->escapeIdentifier(info->aliasOrName()))

.arg(drv->escapeIdentifier(info->field->table()->name())),

len) ) {

conn->debugError();

return false;

}

columnSizes[i] = len.isEmpty() ? 5 : len.toInt();

break;

}

case KexiDB::Field::Byte: columnSizes[i]=4; break;

case KexiDB::Field::ShortInteger: columnSizes[i]=6;break;

case KexiDB::Field::Integer: columnSizes[i]=12; break;

case KexiDB::Field::BigInteger: columnSizes[i]=21; break;

case KexiDB::Field::Boolean: columnSizes[i]=2; break;

case KexiDB::Field::Date: columnSizes[i]=11; break;

case KexiDB::Field::DateTime: columnSizes[i]=20; break;

case KexiDB::Field::Time: columnSizes[i]=8; break;

case KexiDB::Field::Float: columnSizes[i]=16; break;

case KexiDB::Field::Double: columnSizes[i]=20; break;

case KexiDB::Field::BLOB: columnSizes[i]=5; break;

default: columnSizes[i]=2; break;

}

columnSizes[i] = QMAX( columnSizes[i],

info->captionOrAliasOrName().length() );

columnSizes[i]++;

}

// otworz kursor bazodanowy i wypisz dane do strumienia

// wyjsciowego

KexiDB::Cursor *cursor = conn->executeQuery( *query );

if (!cursor) {

conn->debugError();

return false;

}

cursor->moveFirst();

if (cursor->error()) {

cursor->debugError();

conn->deleteCursor(cursor);

return false;

}

bool printColumnNames = true;

while (!cursor->eof()) {

const uint fields = QMIN(cursor->fieldCount(),

vector.count());

for (uint i = 0; i<fields; i++) {

KexiDB::QueryColumnInfo *info = vector[i];

QString str( printColumnNames ?

info->captionOrAliasOrName()

: cursor->value(i).toString() );

if (info->field->isNumericType()) {

outputStream << str.rightJustify( columnSizes[i] );

outputStream << " ";

}

else

outputStream << str.leftJustify( columnSizes[i] );

}

outputStream << "\n";

// nazwy kolumn pokazane, teraz pokaz pierwszy wiersz

if (printColumnNames) {

printColumnNames = false;

continue;

}

if (!cursor->moveNext() && cursor->error()) {

cursor->debugError();

conn->deleteCursor(cursor);

return false;

}

}

query->connection()->deleteCursor( cursor );

return true;

}

duje się opis kompilacji obu rozszerzeń przy wykorzystaniu tych plików.

Narzędzie eksportudo formatu Fixed-Width TextMając przygotowane środowisko z potrzebnymi funkcjami API, najpierw napiszemy program służący do eksportowania tabel danych do formatu Fixed-Width Text. Pomoże to przy okazji poznać API dostępu do baz danych używane w Kexi – warstwę abstrakcji zaimplementowaną w bibliotece KexiDB. W czasie pisania programów korzystających z tej biblio-teki przydatna może być dokumentacja http://www.kexi-project.org/docs/svn-api/html/namespaceKexiDB.html.

Narzędzie eksportu będzie dla uproszczenia stanowić osob-ny program wywoływany z linii poleceń. Programy tego typu są przydatne w integracji różnych systemów przetwarzania informa-cji. Przy okazji uniknie się nieistotnych dla poruszanego tematu spraw związanych np. z integracją w interfejsie użytkownika.

Pierwszą rzeczą do napisania jest łączenie się z bazą da-nych według parametrów podanych przez użytkownika. Na Li-stingu 1 znajduje kod programu głównego. Nie korzystamy z okien startowych Kexi, więc są przyda się klasa KCmdLineArgs z biblioteki kdecore i argumenty opisane strukturą KCmdLineOp-tions. Obiekt klasy KexiDB::SimpleCommandLineApp obsłuży in-stancję programu bez GUI, dodając obsługę argumentów –driver <nazwa _ sterownika _ baz _ danych> (lub -drv, domyśl-

Page 63: Software Developer's Journal 01/2007 PL

Rozszerzenia środowiska bazodanowego Kexi

63www.sdjournal.orgSoftware Developer’s Journal 1/2007

Listing 3. Klasa widżetu suwaka obsługującego dane z bazy

// kexidbslider.h

#include <plugins/forms/kexiformdataiteminterface.h>

#include <knuminput.h>

class KexiDBSlider : public KIntNumInput,

public KexiFormDataItemInterface { Q_OBJECT

// wlasciwosci potrzebne w trybie projektowania

// formularza

Q_PROPERTY(QString dataSource READ dataSource

WRITE setDataSource DESIGNABLE true)

Q_PROPERTY(QCString dataSourceMimeType

READ dataSourceMimeType WRITE

setDataSourceMimeType DESIGNABLE true) public:

KexiDBSlider(QWidget *parent, const char *name=0);

virtual ~KexiDBSlider();

// nazwa zrodla danych

inline QString dataSource() const {

return KexiFormDataItemInterface::dataSource(); }

// typ zrodla danych (obecnie kexi/table lub kexi/query)

// - potrzebne do rozroznienia tabeli od zapytania, gdy

// nie roznia sie nazwa

inline QCString dataSourceMimeType() const

{return KexiFormDataItemInterface::dataSourceMimeType();}

// biezaca wartosc widzetu

virtual QVariant value();

// uzywane, gdy zrodlo danych jest niepoprawne

virtual void setInvalidState(const QString& displayText);

// zwraca true jesli wartosc edytora jest NULL - musi byc

// ona trzymana w osobnej zmiennej, bo oryginalny widzet

// przechowuje tylko wartosci typu int

virtual bool valueIsNull() { return m_valueIsNull; }

// zwraca true jesli wartosc edytora jest pusta

virtual bool valueIsEmpty() { return valueIsNull(); }

// zwraca wartosc flagi 'tylko do odczytu'

virtual bool isReadOnly() const { return !isEnabled(); }

// wskazuje na wlasciwy widzet, ktory powinien otrzymac

// focus (tutaj jest nim ten sam widzet)

virtual QWidget* widget() { return this; }

// obsluga klawiszu strzalek - zawsze zezwalaj na

virtual bool cursorAtStart() { return true; }

virtual bool cursorAtEnd() { return true; }

// czyszczenie wewnetrznej wartosci widzetu, powrot

// do wartosci oryginalnej

virtual void clear();

virtual void setEnabled(bool enabled);

public slots:

// obsluga wlasciwosci 'zrodlo danych'

void setDataSource(const QString &ds)

{ KexiFormDataItemInterface::setDataSource(ds); }

// obsluga wlasciwosci 'typ zrodla danych'

inline void setDataSourceMimeType(const QCString &ds)

{ KexiFormDataItemInterface::setDataSourceMimeType(ds); }

// obsluga zablokowania mozliwosci edycji

virtual void setReadOnly( bool readOnly ) {

setEnabled(!readOnly); }

protected slots:

// reakcja na zmiane wartosci ze strony uzytkownika

void slotValueChanged();

protected:

// reakcja na otrzymane dane z bazy

virtual void setValueInternal(const QVariant& add,

bool removeOld);

private:

bool m_invalidState : 1;

bool m_valueIsNull : 1;

};

// kexidbslider.cpp

#include <qlineedit.h>

#include "kexidbslider.h"

#include <kexiutils/utils.h>

#include <kexidb/queryschema.h>

KexiDBSlider::KexiDBSlider(QWidget *parent, const char

*name)

: KIntNumInput(parent, name), KexiFormDataItemInterface()

, m_invalidState(false), m_valueIsNull(true)

{

setRange(0, 100, 1/*step*/, true/*slider*/);

setFocusPolicy(QWidget::StrongFocus);

// we want to react on text changes, not only on clicking

QLineEdit *editor = KexiUtils::findFirstChild<QLineEdit>(

m_spin, "QLineEdit");

if (editor)

connect( editor, SIGNAL(textChanged(const QString&)),

SLOT(slotValueChanged()) );

}

KexiDBSlider::~KexiDBSlider() {}

void KexiDBSlider::setInvalidState(

const QString& displayText ) {

setEnabled(false);

KexiFormDataItemInterface::setValue(minValue());

m_invalidState = true;

if (focusPolicy() & TabFocus)

setFocusPolicy(QWidget::ClickFocus); }

void KexiDBSlider::setEnabled(bool enabled) {

if(enabled && m_invalidState)

return;

KIntNumInput::setEnabled(enabled); }

void KexiDBSlider::setValueInternal(

const QVariant &add, bool removeOld) {

Q_UNUSED(add);

Q_UNUSED(removeOld);

KIntNumInput::setValue( m_origValue.toInt() );

m_valueIsNull = m_origValue.isNull(); }

Qvariant KexiDBSlider::value() {

return m_valueIsNull ? QVariant() : KIntNumInput::

value(); }

void KexiDBSlider::slotValueChanged() {

m_valueIsNull = false;

signalValueChanged(); }

void KexiDBSlider::clear() {

KIntNumInput::setValue( m_origValue.toInt() );

m_valueIsNull = true;

}

// metadefinicje Qt dla klasy KexiDBSlider

#include "kexidbslider.moc"

Page 64: Software Developer's Journal 01/2007 PL

64

Bazy

danych

www.sdjournal.org Software Developer’s Journal 1/2007

nym jest obsługa plików .kexi), –user <nazwa _ uzytkownika> (lub -u), –password (lub -p, opcjonalnie), –host <nazwa _ kom-

putera> (domyślnie jest localhost), –port <numer _ portu> (do-myślna wartość zależna od bazy) oraz –local-socket <nazwa _

pliku _ gniazda _ lokalnego> (opcjonalnie). Czyni to przygoto-wywany program prostszym do napisania.

Pozostaje dodać własne obowiązkowe argumenty. Po-trzebne są trzy – kolejno – nazwa bazy danych, nazwa tabe-li lub zapytania oraz nazwa pliku do zapisania wyniku ekspor-tu. Te argumenty odczytuje się przy pomocy metody KcmdLi-neArgs::arg(int). Klasa SimpleCommandLineApp zapewnia zbu-dowanie struktury danych przechowującej dane potrzebne do połączenia. Można uzyskać do niej dostęp poprzez KexiDB::ConnectionData KexiDB::SimpleCommandLineApp::connectionDa-

ta() – korzystamy z tej możliwość aby na wszelki wypadek upewnić się, że nazwa pliku bazy (o ile baza jest w pliku) nie jest identyczna z nazwą pliku wyjściowego.

Bazę otwiera się wywołaniem KexiDB::SimpleCommandLine-App::openDatabase(nazwa), po czym można już korzystać z po-łączenia wykorzystując obiekt KexiDB::Connection, dostępny po-przez KexiDB::SimpleCommandLineApp::connection(). Obiekt Ke-

xiDB::Connection zawiera m.in. informacje o tabelach i zapyta-niach, więc korzystamy z metody KexiDB::Connection::tableSche-ma(nazwaTabeli) a w przypadku gdy nie znaleziono tabeli o zada-nej nazwie, także z KexiDB::Connection::querySchema(nazwaTabe-li). Wart uwagi jest fakt, że ostatecznie i tak zawsze korzysta się z zapytania – obiekt tabeli oferuje bowiem metodę KexiDB::Table-Schema::query() zwracającą zapytanie tożsame z SELECT * FROM nazwaTabeli, dzięki czemu dalsze działania będą jednolite nieza-leżnie od źródła danych przeznaczonych do eksportu. Przed wła-ściwym eksportem należy przygotować plik wyjściowy otwierając go w trybie do zapisu przy pomocy obiektu klasy QFile. Sam eks-port wykonuje się poprzez obiekt klasy QTextStream, strumienia dbającego o właściwe zakodowanie ewentualnych znaków na-rodowych. Warto uwzględnić przydatny szczególny przypadek – nazwa „-” oznacza standardowe wyjście – jest do niego dostęp poprzez systemowy wskaźnik FILE *stdout. Funkcja exportToFi-xedWidthText() będzie odpowiedzialna za wykonanie właściwego eksportu. Jej kod wpiszemy przed funkcją main().

Właściwy eksport do formatu tekstowego należy przeprowa-dzić w dwóch etapach. Format Fixed-Width wymaga znajomości preferowanej szerokości każdej z kolumn, tak aby pomieściła da-ne z każdego rekordu. Danych może być wiele, więc aby uniknąć potrzeby ponownego otwierania źródła danych, najpierw należy

policzyć szerokości kolumn i zapamiętać je. Można tego doko-nać metodą KexiDB::QuerySchema::fieldsExpanded() obiektu zapy-tania, co zwróci wektor w którym elementami są struktury Query-ColumnInfo niosące informacje o kolumnie zapytania. Używając KexiDB::QueryColumnInfo::field->type() uzyskuje się informację o typie danych (uogólnionym, niezależnym od silnika bazy da-nych). W zależności od typu danych, przewidujemy maksymal-ną szerokość kolumny, np. 8-bitowa liczba zajmie do 4 znaków (z ewentualnym znakiem „-”), a typ data/czas 20 znaków. Szcze-gólnym przypadkiem są typy KexiDB::Field::Text i KexiDB::Field::LongText – dla nich przydatne jest wykonanie zapytania li-czącego długość maksymalnego tekstu – SELECT MAX(LENGTH(na-zwaKolumny)) FROM tabelaLubZapytanie.

Drugi etap eksportu to wypisanie w pętli dla każdego re-kordu odpowiednio sformatowanej linii tekstu. Dotychczas operowaliśmy na samym schemacie zapytania. Odczyt da-nych rekord po rekordzie wymaga zaalokowania obiektu kur-sora KexiDB::Cursor poprzez wywołanie metody KexiDB::Con-nection::executeQuery(const &KexiDB::QuerySchema). Najpierw wypisywane są nazwy każdej z kolumn, ponownie wykorzy-stując do tego wektor informacji o kolumnach KexiDB::Query-ColumnInfo::Vector. Metoda QueryColumnInfo::captionOrA-

liasOrName() pozwoli wypisać bardziej zrozumiałą dla użyt-kownika etykietę kolumny lub jej alias zamiast zwykłej nazwy. Dopełniania wierszy spacjami najłatwiej dokonać metodami QString::leftJustify(liczbaSpacji) oraz QString::rightJusti-fy(liczbaSpacji), liczby spacji to szerokości kolumn uzyska-ne w pierwszym kroku eksportu. Wartości liczbowe mogą być wyrównywane do prawej, a pozostałe do lewej. Aby to spraw-dzić typ, korzystamy z pomocnej metody KexiDB::Field::isNu-mericType() dla składowej KexiDB::QueryColumnInfo::field.

Po wykonanym eksporcie pozostaje usunąć kursor bazy danych (KexiDB::Connection::deleteCursor(kursor)), zamknąć bazę danych (KexiDB::SimpleCommandLineApp::closeDatabase()) oraz zamknąć plik wyjściowy (QFile::close()).

Testy eksportuProgram jest gotowy do użycia. Obsługiwane są bazy plikowe .kexi oraz bazy na serwerach SQL. Przykładowe wywołanie eks-portu tabeli adresy z bazy firmy.kexi na standardowe wyjście:

./fixed_width_export firmy.kexi -

Rysunek 2. Projekt formularza (na pasku narządzi widoczny nowy przycisk)

Rysunek 3. Widżety suwaka w formularzu wyświetlające dane z tabeli pomiary

Page 65: Software Developer's Journal 01/2007 PL

65

Rozszerzenia środowiska bazodanowego Kexi

www.sdjournal.orgSoftware Developer’s Journal 1/2007

Listing 4. Klasa fabryki widżetów udostępniająca widżet suwaka

// customfactory.h

#include <formeditor/widgetfactory.h>

#include <kgenericfactory.h>

class KexiCustomFactory : public

KFormDesigner::WidgetFactory {

Q_OBJECT public:

KexiCustomFactory(QObject *parent, const char *name,

const QStringList &args);

virtual ~KexiCustomFactory();

virtual QWidget *createWidget(const QCString &classname,

QWidget *parent,

const char *name, KFormDesigner::Container *container,

int options = DefaultOptions );

virtual void createCustomActions(KActionCollection*

col) {};

virtual bool createMenuActions(const QCString &classname,

QWidget *w, QPopupMenu *menu, KFormDesigner::

Container *container) { return false; }

virtual bool startEditing(const QCString &classname,

QWidget *w,

KFormDesigner::Container *container) { return false; }

virtual bool previewWidget(const QCString &, QWidget *,

KFormDesigner::Container *) { return false; }

virtual QValueList<QCString> autoSaveProperties(

const QCString &classname)

return QvalueList<QCString>(); }

protected:

virtual bool isPropertyVisibleInternal(const

QCString& classname, QWidget *w,

const QCString& property, bool isTopLevel); };

// customfactory.cpp

#include "customfactory.h"

#include <klocale.h>

#include <plugins/forms/kexidataawarewidgetinfo.h>

#include "kexidbslider.h"

KexiCustomFactory::KexiCustomFactory(

QObject *parent, const char *name, const QStringList &)

: KFormDesigner::WidgetFactory(parent, name) {

KexiDataAwareWidgetInfo *wi =

new KexiDataAwareWidgetInfo(

this, "stdwidgets", "QSlider" /*override*/);

wi->setName(i18n("Slider"));

wi->setClassName("KexiDBSlider");

wi->addAlternateClassName("QSlider", true/*override*/);

wi->setNamePrefix(

i18n("Widget name", "slider"));

wi->setDescription(i18n(

"A slider widget for editing integer values"));

wi->setPixmap("slider");

addClass(wi);

m_propDesc["label"] = i18n("Label Text");

m_propDesc["value"] = i18n("Value");

m_propDesc["minValue"] = i18n("Minimum Value");

m_propDesc["maxValue"] = i18n("Maximum Value");

m_propDesc["suffix"] = i18n("Suffix Text");

m_propDesc["prefix"] = i18n("Prefix Text");

m_propDesc["specialValueText"] = i18n(

"property name", "Special\nValue Text"); }

KexiCustomFactory::~KexiCustomFactory() {}

QWidget* KexiCustomFactory::createWidget(

const QCString &c, QWidget *p, const char *n,

KFormDesigner::Container *container, int options) {

QWidget *w = 0;

if (c == "KexiDBSlider")

w = new KexiDBSlider(p, n);

return w; }

bool KexiCustomFactory::isPropertyVisibleInternal(

const QCString& classname,

QWidget *w, const QCString& property, bool isTopLevel) {

bool ok = true;

if (property=="dataSource" || property==

"dataSourceMimeType")

return false; //force hide

if(classname == "KexiDBSlider") { //hide properties

if (property=="relativeValue" || property==

"referencePoint")

return false;

}

return ok && WidgetFactory::isPropertyVisibleInternal(

classname, w, property, isTopLevel); }

// deklaracja punktu dostepu do biblioteki dynamicznej

// (wtyczki)

KFORMDESIGNER_WIDGET_FACTORY(

KexiCustomFactory, kexicustomwidgets)

//metadefinicje Qt dla klasy KexiCustomFactory

#include "customfactory.moc"

Przykładowe wywołanie eksportu tabeli adresy do pliku ad-resy.txt z bazy firmy na serwerze MySQL znajdującym się pod adresem data.base.org, korzystając z konta użytkowni-ka scott:

./fixed_width_export -p –drv mysql -h data.base.org

-u scott firmy adresy -

Otrzymany wynik jest następującej postaci:

Id Kod Miejscowość Ulica

3 16-300 Augustów Rynek 3

3034 80-029 Gdańsk Nakielska 15

10916 94-241 Łódź Cieplarniana 60

23113 51-616 Wrocław Parkowa 2A

Nowy element GUI: widżet suwakaProgram Kexi zawiera zestaw widżetów do wyświetlania i wpro-wadzania danych bądź do sterowania (np. przycisk). W konkret-nych zastosowaniach zdarzają się specyficzne typy danych dla których lepiej mogą się sprawdzać niestandardowe metody ich wprowadzania czy wyświetlania. Jednym z takich typów jest licz-ba całkowita ograniczona przedziałem (np. 0..100). Kiedy wpro-wadzanie wartości ma być szybkie i niekoniecznie precyzyjne – za to przy użyciu myszy – warto pokusić się o użycie widżetu su-waka zamiast zwykłego pola do wprowadzania liczby.

Page 66: Software Developer's Journal 01/2007 PL

66

Bazy

danych

www.sdjournal.org Software Developer’s Journal 1/2007

Suwak zostanie zbudowany przy użyciu klasy KIntNumIn-put dostępnej w bibliotece kdeui. Jest ona bardziej rozbudo-wana niż QSlider z biblioteki Qt – zawiera dodatkowo pole do wpisywania wartości liczbowej, co jest przydatne gdy jednak nadarzy się potrzeba skorzystania z klawiatury. Wygląd wi-dżetu KIntNumInput jest przedstawiony na Rysunku 2.

Zgodnie z nieformalną zasadą używaną dla widżetów for-mularzy w Kexi, widżet suwaka będzie miał nazwę KexiDBSli-der. Powinien on dziedziczyć nie tylko z klasy KIntNumInput ale też z KexiFormDataItemInterface, czyli z interfejsu programi-stycznego przeznaczonego do deklarowania widżetów obsłu-gujących dane z bazy danych. Deklaracja oraz implementacja klasy KexiDBSlider znajdują się na Listingu 3.

Podstawową sprawą w „podłączeniu” widżetu do bazy da-nych jest zdefiniowanie właściwości dataSource oraz dataSour-ceMimeType. Jest to proste, gdyż należy w implementacji wywo-łać odpowiednią metodę nadklasy KexiFormDataItemInterface. Nie da się tego uniknąć ze względu na sposób działania mecha-nizmu właściwości w Qt, gdzie użyte we właściwościach (Q _ PRO-PERTY) metody muszą być jawnie zadeklarowane jako KexiDBSli-der::dataSource(), KexiDBSlider::setDataSource(), itd.

W konstruktorze klasy KexiDBSlider można zainicjować pewne ustawienia domyślne. Wywołanie KIntNumInput::se-tRange(0, 100, 1, true) ustawi domyślny zakres suwaka na 0..100, krok na 1 oraz włączy pokazywanie suwaka obok pola z liczbą. Konieczne jest wywołanie metody signalValueChan-ged() z nadklasy w momencie zmiany wartości. Można by zro-bić to przez połączenie sygnału valueChanged(int value) wła-ściwego suwaka QSlider* KIntNumInput::m _ slider. Problem jednak w tym, że formularz powinien otrzymać od suwaka informację o zmianie wartości od razu po rozpoczęciu edy-cji, czyli także po wpisaniu lub usunięciu pierwszego znaku w polu obok suwaka. Niestety pole to nie jest dostępne w pu-blicznym API klasy KIntSpinBox, z której korzysta KIntNumIn-put. Aby zapewnić obsłużenie także tego przypadku, można

zastosować prosty zabieg: wyszukać pole przy pomocy kon-strukcji QLineEdit *editor = KexiUtils::findFirstChild<QLine-Edit>(m _ spin, "QLineEdit"), wiedząc że w hierarchii widże-tów podrzędnych suwaka jest tylko jeden obiekt QLineEdit. Po znalezieniu pola, łączymy jego sygnał QLineEdit::textChange-d(const QString&) do slotu KexiDBSlider::slotValueChanged().

Implementacja metody QVariant KexiDBSlider::value() ma zapewnić zwracanie poprawnej wartości bieżącej suwaka. Ja-ko, że bazy danych obsługują także wartość NULL, a KIntNu-mInput::value() operuje na typie int, potrzebna jest dodatko-wa flaga bool m _ valueIsNull. Ustawienie jej na true będzie oznaczało, że value() ma zwrócić wartość NULL, czyli QVa-riant(). Implementacja metod bool valueIsNull() oraz bo-ol valueIsEmpty(), jest oczywista i opiera się na wspomnia-nej fladze. Flaga m _ valueIsNull jest uaktualniana w metodzie setValueInternal(), która odpowiada za zainicjowanie widże-ta oryginalną wartością m _ origValue pobraną z bazy danych (jest ona zdefiniowana w nad-nadklasie KexiDataItemInterfa-ce). Metoda clear() po prostu przywraca przy pomocy metody KIntNumInput::setValue() wartość do domyślnej m _ origValue. Dla uproszczenia nie zajmujemy się sposobem wyświetlania wartości NULL, co wykraczałoby poza zakres artykułu.

Widżet suwaka jest gotowy, jednak to nie wystarczy by można było go użyć w aplikacji Kexi, gdyż program musi wie-dzieć o jego istnieniu. Aby spełnić ten warunek należy zbu-dować odpowiednie rozszerzenie akceptowane przez Kexi. Działa ono na zasadzie wtyczki, co oznacza, że aby dodać rozszerzenie nie jest wymagana żadna modyfikacja oryginal-nego programu Kexi lub jego reinstalacja. Wtyczka taka sta-nowi tzw. fabrykę widżetów – bibliotekę dynamicznie ładowa-ną zdolną to tworzenia obiektów widżetów na żądanie macie-rzystego programu Kexi.

Fabryka widżetów (której deklaracja i implementacja znajdu-ją się na Listingu 4) na potrzeby pisanego rozszerzenia otrzyma nazwę KexiCustomFactory, a dziedziczyć będzie z klasy KFormDe-signer::WidgetFactory, dostępnej w bibliotece kformdesigner – składnika Kexi. Będzie to prosty przypadek fabryki oferującej tyl-ko jedną klasę widżetu – zaimplementowanego wcześniej suwa-ka. W konstruktorze fabryki KexiCustomFactory wymagane jest zadeklarowanie istnienia oferowanych widżetów. Jest tak, gdyż informacje te są wykorzystywane przez macierzysty program także zanim zostanie utworzony pierwszy obiekt widżeta. Przy pomocy klasy KexiDataAwareWidgetInfo należy zadeklarować ta-kie cechy jak nazwę klasy widżetu (metoda setClassName()), na-zwę dostępną do przetłumaczenia (metoda setName()), ikonę wi-

Listing 5. Plik do budowania wtyczki

// custom_widget/Makefile.am

include $(top_srcdir)/kexi/Makefile.global

kde_module_LTLIBRARIES = kformdesigner_kexicustomwidgets.la

kformdesigner_kexicustomwidgets_la_LDFLAGS = $(

all_libraries) $(KDE_PLUGIN) \

$(VER_INFO) -module -no-undefined

kformdesigner_kexicustomwidgets_la_SOURCES =

kexidbslider.cpp customfactory.cpp

kformdesigner_kexicustomwidgets_la_LIBADD = \

$(top_builddir)/kexi/formeditor/libkformdesigner.la \

$(top_builddir)/kexi/plugins/forms/libkexiformutils.la

servicesdir=$(kde_servicesdir)/kformdesigner

services_DATA=kformdesigner_kexicustomfactory.desktop

rcdir = $(kde_datadir)/kexi

rc_DATA = kformdesigner_kexicustomwidgets.rc

SUBDIRS = .

INCLUDES = -I$(top_srcdir)/kexi -I$(top_srcdir)/kexi/

core $(all_includes)

METASOURCES = AUTO

Listing 6. Plik deklarujący wtyczkę dla nowej fabryki widżetów w środowisku KDE

[Desktop Entry]

Encoding=UTF-8

Type=Service

ServiceTypes=KFormDesigner/WidgetFactory

Name=Custom Kexi Widgets

X-KDE-Library=kformdesigner_kexicustomwidgets

X-KFormDesigner-FactoryGroup=kexi

X-KFormDesigner-WidgetFactoryVersion=2

X-KFormDesigner-XMLGUIFileName=

kformdesigner_kexicustomwidgets.rc

Page 67: Software Developer's Journal 01/2007 PL

67

Rozszerzenia środowiska bazodanowego Kexi

www.sdjournal.orgSoftware Developer’s Journal 1/2007

dżetu na pasku narzędzi (metoda setPixmap()), prefiks nazwy używany do utworzenia domyślnej nazwy obiektu („suwak1”, „suwak2”, itp. – metoda setNamePrefix()), krótki opis przeznacze-nia widżetu (metoda setDescription()). Dodatkowo dodaje się też zwroty, które mają być później dostępne do tłumaczenia, np. właściwość „minValue” suwaka może być wyświetlana w Panelu właściwości Kexi jako „Wartość minimalna”, zamiast mniej jasnej i nie przetłumaczonej „minValue”.

Za właściwe tworzenie obiektów klasy KexiDBSlider od-powiada metoda KexiCustomFactory::createWidget(). Należy ją zaimplementować, sprawdzając żądaną nazwę klasy (pa-rametr c) i tworząc nowy widżet z żądanymi parametrami: p (widżet nadrzędny) oraz n (nazwa). Metoda isPropertyVisi-

bleInternal() ma zwracać false, jeśli dana właściwość ma być ukryta na liście właściwości. Jest to używane w przypadku właściwości dataSource, dataSourceMimeType, które są raczej wyświetlane na karcie danych panelu właściwości w projek-tancie formularzy. Warto też ukryć właściwości relativeValue i referencePoint niesprawdzające się w obecnym przypadku. Pozostałe metody, jak createCustomActions(), pozostaną pu-ste, gdyż w przypadku suwaka nie mają one zastosowania.

Gotową implementację fabryki deklarujemy jako bibliotekę dostępną dla ładowania dynamicznego (mechanizmem KDE), dopisując na końcu linię KFORMDESIGNER _ WIDGET _ FACTORY(Ke-

xiCustomFactory, kexicustomwidgets).Na listingu 5 znajduje plik Makefile.am, służący do zbu-

dowania biblioteki z fabryką. Biblioteka jest ładowana na zasadzie wtyczki (modułu) o nazwie kformdesigner_kexi-customwidgets. Ważna jest tu deklaracja katalogów doce-lowych gdzie będą trafiały zbudowane pliki – zmiana tych ścieżek uniemożliwiłaby odnalezienie wtyczki przez środo-wisko KDE.

Do działania wtyczki potrzebne są ponadto dwa dodat-kowe pliki konfiguracyjne. Jednym jest plik usługi środowi-ska KDE – kformdesigner_kexicustomfactory.desktop (Listing 6), poszukiwany podczas próby ładowania wtyczki przez Ke-xi. Drugim jest kformdesigner_kexicustomwidgets.rc, deklaru-jący akcje paska narzędzi w aplikacji Kexi. Jedyną akcją do-starczaną przez wtyczkę jest library _ widget _ KexiDBSlider (prefiks nazwy jest obowiązkowy), umożliwiająca wstawienie nowego widżetu do formularza. Oba pliki są dostępne razem z kodem źródłowym do tego rozszerzenia.

Testy widżetu suwakaDo przetestowania widżetu suwaka można użyć prostej ba-zy danych test.kexi. Jest ona dostępna na stronie niniejsze-go artykułu. Tabela o nazwie pomiary zawiera pola tempera-tura i wilgotność, oba typu liczba całkowita (Rysunek 1). Przy

rozpoczęciu projektowania formularza (także o nazwie pomia-ry) można się zorientować, że w Kexi stał się dostępny nowy przycisk paska narzędzi – „Suwak” (Rysunek 2). Formularz czerpie dane z tabeli pomiary i ma wstawione dwa widżety suwaka, przy czym pierwszy suwak ma źródło danych w po-lu temperatura, drugi – w polu wilgotność. Suwaki umożliwia-ją w tym przypadku szybką modyfikację obu wartości, jak też zwiększają czytelność danych (Rysunek 3).

Kompilacja rozszerzeńNależy wykonać następujące czynności:

• Rozpakować pliki fixed_width_text_src.tar.bz2 oraz cu-stom_widgets_src.tar.bz2 w katalogu koffice/kexi/tests/, co utworzy podkatalogi fixed_width oraz custom_widgets ;

• Do linii SUBDIRS w pliku koffice/kexi/tests/Makefile.am dopisz nazwę katalogów fixed_width oraz custom_widget;

• Powtórnie przeprowadzić konfigurację, aby powstały pli-ki Makefile w nowo dodanych katalogach (cd ../koffice; ./configure –prefix=̀ kde-config –prefix̀ ), kompilację i insta-lację obu rozszerzeń (cd kexi/tests/fixed_width; make; ma-ke install; cd ../custom_widgets; make; make install). Na wszelki wypadek można odświeżyć cache konfiguracji KDE, aby upewnić się, że wtyczka jest wykrywana przez system uruchamiając kbuildsycoca –noincremental.

WnioskiW omówionych rozwiązaniach przyjęto pewne konieczne uproszczenia. Format Fixed-Width Text będzie obsługiwany w przyszłych wersjach Kexi z poziomu GUI, na zasadzie po-dobnej jak ma to obecnie miejsce z formatem CSV. Obsłu-ga formatu Fixed-Width Text będzie uzupełniona też funk-cją importu, powstaną funkcje udostępnione dla innych apli-kacji, w tym programów biurowych. Widżet suwaka prawdo-podobnie znajdzie się w standardowej bibliotece widżetów wbudowanych w aplikację i zostanie rozszerzony obsługę liczb z cyframi po przecinku.

Interfejsy programistyczne pozwoliły na skupienie się na za-daniu – większość potrzebnych funkcji jest od razu wbudowana, np. klasa KexiDB::SimpleCommandLineApp pozwoliła na szybkie zbudowanie programu działającego z linii poleceń z niezbędnymi opcjami. Z kolei API widżetów pozwoliło łatwo dodać obsługę ba-zy danych do istniejącego widżetu powszechnego użycia (KInt-SpinBox). W obu rozszerzeniach nie użyto ani jednej linii kodu za-leżnej od konkretnego serwera SQL, dzięki czemu dodanie ob-sługi nowego typu źródła danych na ogół nie wymagałoby doko-nywania zmian w niniejszych programach. n

Listing 7. Plik deklarujący akcje paska narzędzi dla rozszerzenia suwaka w aplikacji Kexi

<!DOCTYPE kpartgui>

<kpartgui name="kexiformpartinst" version="1">

<ToolBar name="widgets" fullWidth="false">

<text>Widgets</text>

<Action name="library_widget_KexiDBSlider"/>

</ToolBar>

</kpartgui>

W Sieci• Strona niniejszego artykułu z potrzebnymi zasobami: http://www.kexi.pl/wiki/index.php/Artykuł:Pisanie_rozszerzeń_

dla_Kexi• Główna strona projektu Kexi: http://kexi-project.org• Polska strona projektu Kexi: http://www.kexi.pl• Strona internetowa firmy OpenOffice Polska: http://openoffice.com.pl

Page 68: Software Developer's Journal 01/2007 PL

68

Wywiad

SDJ

www.sdjournal.org Software Developer’s Journal 1/2007

Rozmowa z Davem ChappelemDave Chappell, Vice President and Chief

Technilogy Evenagelist Prograss Softwa-re. Wywiad przeprowadzono na konferen-

cji dotyczącej SOA.Sylwia Pogroszewska: Jest Pan autorem artykułów na temat Javy...Dave Chappel: Tak, napisałem wiele artykułów o Ja-vie, wiele z moich artykułów dotyczyło również aplika-cji migracyjnych, oprogramowania typu MOM (Mes-sage-Oriented Middleware) i korporacyjnej magistra-li usług (Enterprise Service Bus) jako środków do bu-dowania architektury zorientowanej na usługi (Service Oriented Architecture). Nie chodzi więc tylko o Javę, ale o łączenie różnorodnych platform i aplikacji w bar-dziej interoperacyjną SOA przy użyciu usług siecio-wych, protokołów, oraz technologii takich jak ESB.SDJ: I właśnie o korporacyjnej magistrali usług chcia-łeś nam dzisiaj opowiedzieć?DC: Cóż, to nie ja wpadłem na ten pomysł, to wynik pracy wielu naprawdę inteligentnych ludzi w Progress Software, którzy razem z naszymi klientami przez la-ta wspólnie określali wymagania oraz rozwiązania dla kompleksowej integracji systemów przy użyciu architek-tury zorientowanej na usługi, dla komunikacji za pomo-cą różnorodnych technologii, jednak skupiając się głów-nie na uzyskaniu niezawodności, dostępności i skalo-walności korporacyjnych systemów opartych na aplika-cjach usługowych komunikujących się między sobą we wspólnej magistrali usługowej. Mówiąc w skrócie, tech-nologia ESB jest wykorzystywana do łączenia, pośred-niczenia, oraz zarządzania interakcją pomiędzy różno-rodnymi aplikacjami świadczącymi usługi w sieci.

Cała historia zaczęła się, kiedy na początku 2000 roku firma Sonic Software weszła na rynek ze swo-im produktem, który oferował rozwiązania enterprise messaging i spełniał wymogi specyfikacji Java Mes-sage Service. Od początku zgłaszało się do nas bar-dzo wielu klientów, takich jak Commerce One i GE Glo-bal eXchange Services (GE GXS), którzy próbowa-li tworzyć rynki elektroniczne w oparciu o nasze opro-gramowanie oraz globalne korporacje, jak Philips Elec-tronics, gdzie próbowano zintegrować rozsiane po ca-łym świecie oddziały firmy w scentralizowanym syste-mie przesyłu płatności. Spodobały się im nasze rozwią-zania, ale powiedzieli, że JMS to za mało, bo nie chcą angażować programistów za każdym razem, kiedy bę-dzie trzeba połączyć jeden system z innym. Potrzebo-wali struktury usługowej na wyższym poziomie, za po-mocą której mogliby opisać wzajemne interakcje tych systemów bardziej poprzez konfigurację, niż kodowa-nie. Wiem, że wasi czytelnicy, którzy zawodowo zajmu-ją się kodowaniem, pomyślą teraz, że ESB polega bar-

dziej na konfiguracji, niż programowaniu, jednak wciąż istnieje wystarczająco duża ilość kodu, który trzeba na-pisać gdzie indziej, w formie rdzenia logiki biznesowej. W ten sposób deweloperzy wnoszą wartość do bizne-su - nie musi to koniecznie polegać na pisaniu kodu łą-czącego aplikacje. ESB uwalnia programistę od zmar-twień związanych z tworzeniem infrastruktury zabez-pieczeń, pisania niskopoziomowego kodu obsługują-cego protokoły sieciowe, czy zapewnienia niezawodno-ści każdej aplikacji, dzięki czemu może się on skupić na logice biznesowej i rzeczywistej implementacji samych usług, może budować bardziej wszechstronną SOA w dowolny sposób, który uzna za odpowiedni.SDJ: …w takim razie, czy mógłbyś opowiedzieć, jak budować architekturę oprogramowania opartą na SOA?DC: Naturalnie. Tak naprawdę SOA jest modelem projektowania, poprzez który deweloperzy i projek-tanci z branży IT tworzą usługi wykorzystując w tym celu istniejące komponenty aplikacji i źródła danych, łącząc je następnie ze sobą przy pomocy standardo-wych interfejsów. Dzięki temu można podnosić war-tość już rozpoczętych inwestycji i istniejących zaso-bów oprogramowania, możliwe jest współdzielenie zasobów systemowych pomiędzy zespołami dewelo-perów, pomiędzy działami.SDJ: …co jest najważniejsze przy budowaniu aplika-cji opartych na SOA?

Sylwia Pogroszewska

Zdjęcie 1. Dave Chappel

Page 69: Software Developer's Journal 01/2007 PL

Wywiad SDJ

69www.sdjournal.orgSoftware Developer’s Journal 1/2007

DC: Najważniejszą rzeczą jest to, że możesz budować syste-my umożliwiające automatyzację funkcji w dziedzinach bizne-su, w których nie było to dotąd możliwe. Tworząc SOA budujesz o wiele bardziej elastyczną architekturę, która potrafi reagować na zmienne wymagania pojawiające się w biznesie. Największa presja, z jaką obecnie mają do czynienia deweloperzy polega na tym, że nieustannie żąda się od nich tworzenia nowych funkcji i wprowadzania zmian w istniejących systemach tak, aby zaspo-kajać potrzeby ludzi związanych z biznesem. SOA dostarcza no-wą, o wiele bardziej elastyczną architekturę, która pozwala pro-gramistom o wiele lepiej reagować na potrzeby ludzi biznesu związane z implementowaniem nowych funkcji i wprowadzaniem zmian w istniejących systemach oprogramowania.SDJ: Jak udało się wasze dzisiejsze seminarium?DC: Jak się udało? Bardzo - przyszło wielu ludzi. Mieliśmy dwie pełne sale… Myślę, że wzięło w nim udział sześćdziesiąt, mo-że siedemdziesiąt osób. Odbiór był bardzo dobry, wykształceni ludzie z wielu różnych środowisk. Spotkaliśmy się z ludźmi, któ-rzy już tworzą swoje własne architektury zorientowane usługo-wo korzystając z własnych technik i kodu… i oni naprawdę po-znali, jak wiele korzyści może dać ESB, kiedy nie trzeba zajmo-wać się całą tą dodatkową pracą. Mieliśmy dużo ciekawych py-tań, które potwierdziły dobre zrozumienie problemu… Jakie to były pytania? Cóż, przede wszystkim ludzie chcieli się dowie-dzieć, na jakim etapie są ich koledzy w innych częściach świa-ta, bo wielu z nich miało wrażenie, że zostają trochę w tyle i próbują nadrabiać zaległości w wiedzy. Patrząc na wyniki son-daży, które regularnie prowadzę z podobnymi grupami w innych krajach mogę powiedzieć, że jeśli chodzi o rozumienie tego, czym jest SOA, znajdują się mniej więcej na tym samym pozio-mie, co reszta świata. Powiedziałbym, że około 20 procent już bierze udział w jakimś projekcie związanym z SOA, wielu jesz-cze nie zaczęło, ale wiedzą, że będą musieli; zdają sobie spra-wę z korzyści, jakie to ze sobą niesie, ale dopiero zaczynają poznawać, na czym polega. Tak wygląda typowy przekrój pu-bliczności, która pojawia się na tych forach… Ale gdybym miał przeprowadzić sondaż na grupie klientów Sonic Software, wy-niki bardzo by się różniły. To dlatego, że oni posiadają już infra-strukturę umożliwiającą integrację SOA w ramach ESB, korzy-stają z SOA w o wiele większym zakresie. Nie muszą poświę-cać tak dużo czasu na tworzenie niezawodnego modelu prze-syłania komunikatów, nie muszą się przejmować sposobem ko-ordynacji usług, czy tworzeniem zabezpieczeń, bo wszystko to jest już częścią ESB. Jedną z rzeczy, która może zaintereso-wać twoich czytelników jest wersja 7.0 Sonic ESB, która zawie-ra zrealizowany w środowisku Eclipse zestaw narzędzi do bu-dowy rozwiązań w architekturze SOA.SDJ: Dlaczego Eclipse?DC: Dlaczego Eclipse? Bo naszym zdaniem jest to narzędzie, po które deweloperzy sięgają najchętniej. SDJ: A co z NetBeans? Czy zamierzacie …DC: Nie, nie mamy w planach wsparcia dla NetBeans, wybra-liśmy Eclipse. Stworzyliśmy nasz zestaw narzędzi do budo-wania rozwiązań w architekturze SOA (SOA Workbench) wo-kół Eclipse, które obsługuje cały cykl tworzenia usług, konfi-gurowania usług, testowania usług, koordynacji wzajemne-go oddziaływania usług, oraz uruchamiania usług. Zasadni-czo oznacza to zarządzanie całym cyklem życia SOA, co jest nigdy nie kończącym się procesem. Jednym z unikalnych ele-mentów zestawu narzędzi Eclipse jest środowisko debuge-

ra stworzone specjalnie dla usług rozproszonych. Koncentru-je się ono na zachodzących procesach, dzięki czemu możesz ustawiać punkty przerwań dla poszczególnych usług, śledzić krok po kroku całe procesy i debugować wywołania usług, kiedy każda z nich otrzymuje i wysyła żądania do innych. Co więcej, można to robić zdalnie, dlatego nawet jeśli usługi dzia-łają na wielu maszynach, debuger automatycznie przejdzie tam, gdzie są one uruchomione. Możesz zajrzeć do wnętrza usługi, prześledzić przepływ danych, możesz ją debugować i przekonać się, gdzie leży problem… To wyjątkowa możliwość.SDJ: … tu w Polsce?DC: Na razie nie. Koncentrujemy się na zdobywaniu rynku. Sonic istnieje, jak już wspominałem, od sześciu lat. Zaczynali-śmy w Ameryce Północnej i kilku krajach Europy, a dopiero w zeszłym roku zaczęliśmy rozszerzać naszą obecność w całej Europie. Skupiamy się na rozwoju firmy i nabieramy rozpędu. Umacniamy relacje z naszą macierzystą korporacją, którą jest Progress, i która ma już przedstawicielstwa w Polsce oraz in-nych krajach; w większości krajów europejskich. Dzięki temu możemy wejść na polski rynek i pozyskiwać nowych klientów. Przed nami ekscytujące możliwości…SDJ: Więc poprzez tą konferencję prezentujecie te narzędzia, tak?DC: Tak, dzisiaj pokazywaliśmy narzędzia, rozmawialiśmy głównie o architekturze, ESB, również o kwestiach związanych z kulturą korporacyjną, które towarzyszą wdrażaniu SOA. Ele-mentem wdrażania SOA jest to, że deweloperzy muszą po-przez organizację szeroko komunikować się z innymi działami informując, co robią, i dlaczego to robią, muszą też budować współpracę międzyludzką na nowych poziomach. W przeszło-ści wielu deweloperów zajmowało się tworzeniem jednej bądź kilku aplikacji, skupiając się przede wszystkim na własnym dziale i własnych zadaniach, ale teraz, razem z pojawieniem się architektury zorientowanej na usługi, każdy, kto posiada kawa-łek logiki aplikacji lub danych musi myśleć, jak zamierza opako-wać ten kawałek logiki w interfejs usługi i udostępnić go innym zespołom deweloperskim, tak żeby mogły one skorzystać po-nownie z twojego kawałka logiki biznesowej. Dodatkowo, na-stępnym razem, kiedy trzeba będzie stworzyć nowe oprogra-mowanie musisz też wiedzieć, w jaki sposób wyszukiwać inne już istniejące usługi, które mogą spełniać wymagania tworzonej przez ciebie aplikacji. Wtedy następne zadanie będzie polegało na tym, żeby wykorzystać ponownie jak największą ilość tych usług łącząc je w jeden program; i tak właśnie będzie wyglądał nowy sposób tworzenia oprogramowania. To oznacza, że zmia-ny zachodzące w kulturze korporacyjnej wykraczają daleko po-za technologię, kiedy musisz nauczyć się współpracować z in-nymi zespołami, żeby wykonać jakieś zadanie.SDJ: Na polskim rynku można zauważyć trzy firmy, są to BEA, IBM i Sonic. Czym różni się oferta Sonic Software od te-go, co proponują IBM i BEA? Jest wiele innych firm, ale te trzy są najbardziej popularne, są tutaj zauważane.DC: No cóż… idea ESB polega na tym, że masz do dyspozycji elastyczną architekturę zapewniającą wsparcie dla rozproszonej architektury SOA, którą próbujesz zbudować. Jeśli patrzeć na to w ten sposób, Sonic ESB dostarcza szkieletu, na którym możesz zbudować wysoce skalowalną, lepszą rozproszoną architektu-rę, która pozwala ci instalować i korzystać z poszczególnych ele-mentów infrastruktury w dowolnej chwili i miejscu. Poza tym, So-nic ESB jest jedynym produktem, który oferuje architekturę stałej dostępności (Continuous Availability Architecture). Architektura

Page 70: Software Developer's Journal 01/2007 PL

70

Wywiad

SDJ

www.sdjournal.org Software Developer’s Journal 1/2007

stałej dostępności pozwala infrastrukturze SOA przetrwać awa-rie, umożliwia jej dalsze funkcjonowanie w razie awarii i zakłóceń w sieci. Działa to w ten sposób, że nie wymaga żadnego specja-listycznego sprzętu, współdzielonych zasobów dyskowych i te-go typu rzeczy. W przypadku innych rozwiązań zapewniających wysoki stopień dostępności musisz polegać na łączeniu sprzę-towym (hardware clustering), współdzielonych zasobach dysko-wych, cofnięciu do ostatniej zapisanej transakcji, i ręcznym roll-forward recovery. Sonic ESB jest o wiele dojrzalszym produktem. Nasz pierwszy produkt ESB wszedł na rynek w marcu 2002 ro-ku. Sprzedajemy go od ponad czterech lat i mamy ponad 350 klientów, z czego 250 już z niego korzysta i wiele się dzięki temu nauczyliśmy, ulepszyliśmy też nasze oprogramowanie. Z drugiej strony, IBM i BEA późno dołączyły do gry i dopiero zaczynają. Próbują unowocześniać swoje systemy tak, by zbudować coś na kształt ESB, ale w obu przypadkach przeszkodą jest przestarza-ła infrastruktura, dlatego stworzenie dobrego produktu będzie dla nich bardzo trudnym wyzwaniem.SDJ: Oferta Sonic jest tańsza?DC: Zdecydowanie tak. Sonic opiera się na filozofii, która mó-wi, że integracja powinna dotyczyć całego przedsiębiorstwa. Jest tańsza, jeśli chodzi o licencjonowanie, ale ważniejsze od tego są jeszcze koszt nabycia (cost of ownership) oraz prosto-ta zdalnej instalacji, zarządzania i utrzymania. Mamy na przy-kład klientów, którzy zaimplementowali opcje zdalnego urucha-miania niewymagające żadnych działań ze strony człowieka… udostępniające kompletną infrastrukturę SOA razem z instala-cją wszystkich elementów Sonic ESB, kontenerem usług, ser-werami komunikacyjnymi, definicjami usług, wszystkimi ele-mentami uruchomieniowymi wymaganymi przez usługi, jak arkusz stylów XSLT dla usług przekształcających dane, oraz wszystkimi zabezpieczeniami. Dzięki opcjom zdalnego uru-chamiania wszystko może zostać zrobione w przeciągu minut. W przypadku dowolnej innej infrastruktury opartej na serwe-rze aplikacji J2EE wymaga to obecności człowieka, który mu-si pracować na miejscu przez kilka tygodni, zanim wszystko za-cznie działać. To samo odnosi się do Websphere, mają podob-ną architekturę i nawet bardziej skomplikowane oprogramowa-nie, które musi obsługiwać armia konsultantów. Taka jest głów-na różnica między nami. Co więcej, w kwestii dostępności oni nie mają nawet w przybliżeniu tak dobrych rozwiązań, jakie So-nic oferuje dzięki swojej architekturze stałej dostępności.SDJ: A co z klientami? Jakie sektory was interesują? Sektor rządowy, ubezpieczeniowy, bankowy?DC: Tak, to są rzeczywiście typowe dziedziny zastosowań. Wie-lu z naszych klientów na całym świecie zajmuje się finansami, te-lekomunikacją, obrotem detalicznym, o którym już wspomnia-łem, zarządzaniem łańcuchem dostaw, a ostatnio obserwujemy duży popyt ze strony władz lokalnych i federalnych. Spotkaliśmy się z tym w Stanach, spotkaliśmy się z tym w Europie, w Holan-dii. Mamy kilka przypadków zastosowania w wymiarze sprawie-dliwości, gdzie łączone są bazy danych przechowujące informa-cje o przestępcach… więc jeśli masz do czynienia z wymiarem sprawiedliwości, albo jeśli masz konflikt z prawem, to daleko nie uciekniesz, bo Sonic poprzez ulepszenie procesu integracji baz danych zamierza sprawić, że informacje będą dostępne w czasie rzeczywistym. Inną dziedziną zastosowań są systemy reagowa-nia kryzysowego. W Stanach Zjednoczonych mamy to na przy-kładzie Dystryktu Kolumbii w Waszyngtonie, gdzie używa się na-szego oprogramowania do połączenia wszystkich dzielnic mia-

sta i okolicznych terenów w sieć obsługującą telefony alarmowe i identyfikującą schematy mogące sygnalizować większy problem. Jeśli więc ktoś łączy się z numerem 911, który służy do zgłosze-nia pożaru, eksplozji i podobnych wypadków, ten system auto-matycznie połączy się z innymi, które zgłaszają takie zdarzenie i automatycznie zidentyfikuje odpowiedni schemat, który może na przykład oznaczać atak terrorystyczny.SDJ: Jeszcze tylko dwa pytania. Pierwsze dotyczy głównej technologii wykorzystywanej w waszych produktach, a dru-gie… jako czytelnik, jak odbierasz „Software Developer’s”?DC: Rozumiem. Cóż, w czasie ostatnich kilku lat skupialiśmy się głównie na projektantach systemów, docieraliśmy do nich dzięki konferencjom, takim jak ta, którą poprowadziłem dzisiaj. Odwie-dzaliśmy wiele miast na całym świecie, w Europie, Stanach Zjed-noczonych i Azji, zapraszaliśmy deweloperów do dyskusji o tech-nologii, i okazało się to bardzo dobrym pomysłem. Jeśli chodzi o technologie, które ma do zaoferowania Sonic, to tak naprawdę są to dwa główne produkty, Sonic ESB, o którym już mówiłem i Actional, który jest platformą do zarządzania systemami wykona-nymi w architekturze zorientowanej na usługi (SOA management platform). Actional to infrastruktura umożliwiająca stosowanie za-sad bezpieczeństwa, kontrolę i zarządzanie całą siecią SOA bez względu na technologię, w której została zbudowana. Jeśli pod-stawą twojej sieci SOA jest logika sieciowa, lub serwer aplikacji, lub broker EAI, Sonic ESB, lub ESB innego dostawcy, platfor-ma zarządzania SOA będzie w stanie automatycznie monitoro-wać sieć usług, będzie w stanie wyświetlić użytkownikowi infor-macje o parametrach jakości połączeń i automatycznie zastosuje zasady poprzez całościowy proces biznesowy. Na przykład, jeśli ustalasz politykę, według której wszystkie usługi muszą posiadać możliwość szyfrowania, audytu i logowania, platforma zarządza-nia SOA będzie w stanie zastosować tę politykę dla wszystkich usług, które są częścią jakiegoś procesu biznesowego. To są dwa główne produkty w ofercie Sonic Software.

Jeśli chodzi o waszych czytelników, którzy są dewelope-rami, którzy mogą być zainteresowani tworzeniem architek-tur zorientowanych na usługi, najczęściej zadawane pyta-nia brzmią w ten sposób - jakie są technologie, które powinni znać korzystający z ESB i jak nauczyć się korzystać z ESB? Sonic ESB w całości opiera się na standardach, co oznacza, że każdy aspekt, z którym się zetkniesz w ramach ESB wy-korzystuje jakiś standard. Na przykład, jeśli tworzysz usługi przekształcania danych XML, głównym standardem, który ma tu zastosowanie jest XSLT, dlatego deweloperzy powinni za-poznać się z tą technologią. Jeśli tworzysz usługi content ba-sed routing do badania zawartości usług, żeby określić, gdzie przekierować dany proces biznesowy, wtedy w użyciu będzie XPath, JavaScript lub nawet Java. Tak więc deweloperzy po-winni się zapoznać z tymi technologami. Budując architekturę SOA przy użyciu ESB bardzo ważnym aspektem są też usłu-gi sieciowe, takie jak WSDL i SOAP, oraz nowsze, bardziej za-awansowane usługi sieciowe, jak WS-ReliableMessaging, WS-Security, WS-Policy, i WS-Addressing. Wersja 7.0 Sonic ESB, o której opowiadałem, jako pierwsza dostarcza imple-mentacji tych zaawansowanych protokołów usług sieciowych. Deweloperzy powinni poznać te technologie, bo są to umie-jętności, dzięki którym łatwiej będzie im znaleźć pracę. Przy-szłość należy do technologii pochodnych XML oraz do inter-fejsów i protokołów budowanych w oparciu o standardy.SP: Dziękuję za wywiad.

Page 71: Software Developer's Journal 01/2007 PL

R E K L A M A

Page 72: Software Developer's Journal 01/2007 PL

72

Kasa dla

programisty

www.sdjournal.org Software Developer’s Journal 1/2007

Rozmowa z Marcinem KuciębąMarcin Kucięba, Software Development Mana-

ger Centrum Rozwoju Oprogramowania Sa-bre w Krakowie

Magdalena Filip: Czy może mi Pan powiedzieć czym zajmuję sie Centrum Rozwoju Oprogramowania Sabre w Polsce?Marcin Kucięba: Centrum Rozwoju Oprogramowania Sabre zajmuje się tworzeniem rozwiązań dla sektora turystycznego i lotniczego. Centrum istnieje już sześć lat. Jednak dopiero dwa ostatnie lata to okres szczegól-nie dynamicznego rozwoju. Działalność w Polsce po-dzielona jest głównie na dwa obszary: Travel Network i Airlines Solutions. Grupa Travel Network zajmuje się tworzeniem i utrzymywaniem oprogramowania, któ-re związane jest między innymi z procesem rezerwa-cji biletów i połączeń lotniczych. Sabre jest właścicie-lem jednego z czterech GDS na świecie, czyli syste-mu do wyszukiwania i rezerwacji połączeń lotniczych, hoteli, wycieczek. Firma ma szczególnie mocną pozy-cję na rynku amerykańskim, gdzie większość transak-cji bookingowych dotyczących biletów lotniczych prze-chodzi właśnie przez system Sabre. Drugim obszarem działalności jest tworzenie rozwiązań i systemów infor-matycznych dla przemysłu lotniczego, czyli Airline So-lutons. Są to głównie aplikacje wspomagające obsługę lotnisk, cargo, boardingu, a także umożliwiające zarzą-dzanie rezerwacją miejsc w samolotach.SDJ: Czy Centrum Rozwoju Oprogramowania Sabre tworzy, czy tylko wdraża oprogramowanie?MK: W Krakowie zajmujemy się tworzeniem, modyfika-cją oraz utrzymaniem oprogramowania. W wielu przy-padkach systemy i serwisy stworzone jakiś czas temu w USA, są przez nas przenoszone na nowe technolo-gie czy platformy. Dobrym przykładem może być jeden z projektów prowadzonych przez mój zespół. Prace do-tyczyły migracji systemu służącego do definiowania cen połączeń lotniczych. Architektura całego tego sys-temu charakteryzowała się obecnością dużej ilości roż-nych technologii: Java, JSP, C++, CORBA, Platforma NSK, MQSeries. Nasze zadanie polegało na uprosz-czeniu architektury oraz przeniesieniu systemu w cało-ści na Javę, używając frameworków Spring, Hibernate oraz bazy Oracle, a w warstwie systemowej rozwiązań typu Open Systems. Tak więc podsumowując, w Krako-wie zajmujemy się: utrzymywaniem systemów, ich mo-dernizacją oraz implementacją wszelkiego rodzaju no-wych funkcji, produktów, usług.SDJ: Czy zespół pracujący u Państwa jest stricte Polski czy zagraniczny?MK: Większość zatrudnionych w Krakowie to Polacy, chociaż nie tylko. Pracują u nas również obywatele in-nych krajów Unii Europejskiej, którzy przyjechali do Pol-

ski w poszukiwaniu ciekawej pracy. Bardzo dużo osób przyjeżdża również ze Stanów. Są to robocze wizyty na tydzień czy dwa, ale są i takie osoby, które przyjechały do Krakowa na rok i dłużej. To, że decydują się na takie dłuższe pobyty to także zasługa uroku miasta. Te dłuż-sze kontakty są bardzo ważne. Szczególnie teraz, kiedy firma rozrasta się w takim tempie, potrzebujemy wspar-cia w sprawach organizacji, zarządzania oraz kształce-nia liderów w Polsce. Tak więc można powiedzieć, że mamy zespół międzynarodowy. Poza tym, bardzo czę-sto zespoły, w których pracujemy, złożone są nie tylko z deweloperów z Krakowa, ale również z deweloperów pracujących w Stanach czy Indiach w Bangalore, gdzie Sabre posiada ośrodek deweloperski.SDJ: Ilu pracowników zatrudnia Centrum Rozwoju Oprogramowania Sabre?MK: Jeszcze 2,5 roku temu zatrudnialiśmy zaledwie 30-40 osób. Obecnie jest to ponad 300 pracowników. Jak widać dynamika wzrostu zatrudnienia jest ogrom-na. Amerykanie cenią krakowski rynek pracy, chcą dalej w niego inwestować. Angażują się bardzo mocno w to, co się tutaj tworzy, zarówno w obszarze technologii, za-rządzania zespołami i projektami, lidershipem oraz moty-wacją pracowników. Bardzo wysoko cenią naszą wiedzę technologiczną i fachowość. Pomagają nam natomiast w dziedzinach, w których mamy mniejsze doświadczenie.SDJ: Jakie kryteria stawia firma przed kandydatem na pracownika?MK: Osoba, która chce pracować w Sabre, musi być przede wszystkim otwarta. Szukamy ludzi, którzy chcą pracować przy rozwoju software'u w dynamicznie roz-

Magdalena Filip

Zdjęcie 1. Marcin Kucięba

Page 73: Software Developer's Journal 01/2007 PL

Kasa dla programisty

wijającej się firmie, którzy chcą i nie boją się kwestionować sta-tus quo, są w staniu aktywnie uczestniczyć we wprowadzaniu nowych technologii, kreowaniu nowych pomysłów, wdrażaniu nowych rozwiązań. Sabre stawia na osoby umiejące pracować w zespole, nieobawiające się nowych wyzwań, chętne do nauki. To są pracownicy, których szukamy. SDJ: Jakich specjalistów poszukuje Sabre? MK: W tym momencie poszukujemy doświadczonych dewelo-perów, którzy mają już dłuższy staż pracy i odpowiednią wie-dzę. Takich osób jest dość mało na rynku, i można powiedzieć, że znalezienie i zatrudnienie takich ludzi stanowi wyzwanie dla firm informatycznych. Sabre zatrudnia również ambitnych, mło-dych pracowników, dla których nasza firma jest bardzo często pierwszym miejscem pracy. Jeśli chodzi o rodzaj doświadczenia zawodowego, to nasze oczekiwania są dość szerokie. W Sabre pracujemy z wieloma technologiami. Poczynając od tych, których my w kraju już raczej nie obsługujemy, a które głównie obecne są w Stanach, poprzez standardowe technologie: C, C++, Java, RDBMS, kończąc na technologicznych nowościach. Poszukuje-my wiec specjalistów w niemal wszystkich dziedzinach.SDJ: Jaką ścieżkę kariery oferuje Sabre swoim pracownikom?MK: Ścieżka kariery zależy od tego, w jaki sposób zespół rekruta-cyjny oceni kandydata. Pracownik następnie ma możliwość awan-su z pozycji np. „junior developer” na pozycję „developer” bądź „senior developer”. Dalsza kariera może rozwijać się w jednym z dwóch kierunków. Pierwsza opcja to ścieżka menadżerska, która zaczyna się od „Software Developer Supervisor”, a wyżej są sta-nowiska menadżerskie. Druga możliwość związana jest bardziej z technologią i są to stanowiska o profilu techniczno – architekto-nicznym. Niemniej również i takie osoby muszą wykazywać pew-ne cechy menażerskie. Na awans szansę mają osoby wyjątkowe, które będą potrafiły poprowadzić i motywować zespół. SDJ: Jakie kryterium decyduje o przyjęciu do pracy?MK: Bardzo ważne jest to, jak przebiega rozmowa z kandy-datem. Jeżeli przeprowadzam rozmowę kwalifikacyjną jestem skłonny do zatrudnienia osoby, która może ma mniejszą wiedzę, ale widać, że ma potencjał, chęć do pogłębiania wiedzy. Szcze-

gólnie cenimy chęć poznawania nowych technologii, nie ucieka-nia w jedną wąską dziedzinę, gdyż informatyka zmienia się bar-dzo dynamicznie. To, co dziś jest aktualne, jutro może być juz przestarzałe. Ludzie, którzy są w stanie przeskoczyć z jednej technologii na drugą, z jednego projektu na inny, to osoby, które mają największe szanse w Sabre.SDJ: Czy zamierzają Państwo powiększyć zespół pracowników?MK: Rekrutacja jest prowadzona właściwie na bieżąco. W momen-cie, gdy zbierzemy odpowiednią ilość kandydatów organizowane są tzw. „Assestment Days” czyli dni poświęcone rekrutacji. W fir-mie wyznacza się zespoły, które prowadzą proces rekrutacyjny. Kandydat zawsze przechodzi przez rozmowy z dwoma zespołami. Pozwala to na konsultacje w większej liczbie osób i na lepszą oce-nę potencjalnych pracowników. Decyzja o ewentualnym zatrudnie-niu podejmowana jest kolektywnie w gronie minimum 4 osób.SDJ: Jakie są warunki finansowe proponowane pracownikom?MK: Uważam, że firma zapewnia dobre warunki finansowe, a także dodatkowo system premiowania, opiekę medyczną i wie-le ciekawych opcji kulturalno – socjalnych. Fakt, że zdecydowana większość ofert jest przyjmowanych przez kandydatów świadczy o dostosowaniu naszej oferty do oczekiwań rynku. Uważam, że jest to bardzo dobry wynik, szczególnie biorąc pod uwagę dość wysoką konkurencję na rynku pracy IT w Krakowie. Duży odse-tek podpisywanych umów świadczy o tym, że to, co proponuje-my kandydatom, jest powyżej średniej na rynku.SDJ: Jakiej rady udzieliłby Pan osobom ubiegającym się o pracę w Sabre? Co musiałaby zrobić taka osoba?MK: Taki idealny kandydat, musiałby przekonać nas, że jest w nim inicjatywa do tego żeby się uczyć i zgłębiać wiedzę. Braki w wiedzy, jeżeli nawet są, mogą zostać zniwelowane, nadrobione. Jeżeli ktoś mnie o tym przekona, to ja jestem skłonny taką osobę zatrudnić. Sabre pracuje dla takiego sektora, że w Polsce trudno jest znaleźć specjalistów znających problematykę przemysłu lot-niczego i turystycznego - po prostu ich nie ma. Co nie znaczy, że w firmie nie ma doskonałych specjalistów, którzy juz się na tym znają. To właśnie są osoby, które były w stanie się tego szybko na-uczyć. Takie osoby zawsze będą miały pierwszeństwo. n

R E K L A M A

Page 74: Software Developer's Journal 01/2007 PL

74

Algorytmy

zadanie

www.sdjournal.org Software Developer’s Journal 01/2007

LicytacjaBył pochmurny listopadowy dzień. Zza okna

dochodziły odgłosy kropel deszczu uderza-jących w parapet a ja właśnie skończyłam

czytać ostatni rozdział mojej ulubionej książki. Praw-dę mówiąc, nie miałam pomysłu na ciekawe spędze-nie tego dnia, ale w pewnej chwili przypomniałam so-bie o czym w ostatnich dniach prowadzili intensyw-ne rozmowy moi koledzy z pracy. Dyskutowali za-wzięcie o jakichś internetowych zawodach w progra-mowaniu… zaraz, zaraz, jak one dokładnie się nazy-wały? Internetowe Mistrzostwa Polski w Programo-waniu? Tak, to była właśnie ta nazwa, tylko gdzie te-go szukać w sieci? Kilka prostych zapytań i po pro-blemie: http://opss.safo.biz i… wybrałam zadanie na chybił-trafił. Oho, mam już chyba zajęcie na dzisiaj, pomyślałam po przeczytaniu treści. Zadanie wydało mi się ciekawe, a sposób rozwiązania przyszedł mi do głowy stosunkowo szybko, choć przypuszczałam że z pewnością nie będzie tak łatwo i gdzieś będzie tkwił haczyk. „Licytacja”, bo na ten właśnie problem algorytmiczny trafiłam, miała następującą treść:

„Dwóch matematyków Pi i Sigma spotkało się wie-czorem na partyjce pokera. Ponieważ nie mieli pienię-dzy, postanowili grać „na zapałki”. Pi miał przy sobie tylko niebieskie zapałki, a Sigma tylko zielone. Przed przystąpieniem do licytacji Pi wyłożył a swoich niebie-skich zapałek, zaś Sigma dołożył b swoich zielonych. Pi zaczyna licytację. Licytują na zmianę. W każdym kroku licytacji zawodnik dorzuca tyle swoich zapałek, ile aktualnie jest zapałek przeciwnika w puli. Licytacja trwała dość długo i gracze nie mogli się doliczyć aktual-nej liczby zapałek w puli. Wiedzieli jednak, ile razy każ-dy z nich dorzucał zapałki podczas licytacji.”

ZADANIEPomóż matematykom określić, ile zapałek jest w pu-li po n krokach licytacji. Ponieważ to matematycy, zadowoli ich znajomość reszty z dzielenia tej liczby (liczby zapałek po n krokach) przez ustaloną przez nich „magiczną” liczbę m.

WEJŚCIEPierwsza linia wejścia zawiera liczbę zestawów da-nych C C1 1000≤ ≤( )W kolejnych wierszach wejścia znajdują się zestawy danych. Każdy z C zestawów danych składa

się z jednego wiersza zawierającego liczby całkowite a, b, n, m, oddzielone pojedynczą spacją

0 2 0 2 2 231 31 31≤ < ≤ < ≤ <( )a b n m, , ,

Liczby a, b określają kolejno liczbę niebieskich zapa-łek Pi oraz zielonych Sigmy znajdujących się w pu-li przed rozpoczęciem licytacji. Liczba n określa licz-bę kroków licytacji. Liczba m to ustalona przez gra-czy „magiczna” liczba.

WYJŚCIEDla każdego zestawu danych, wynikiem jest linia za-wierająca jedną liczbę - resztę z dzielenia przez m licz-by zapałek po n krokach licytacji, przy założeniu, że przed przystąpieniem do licytacji w puli znajduje się a niebieskich zapałek Pi oraz b zielonych zapałek Sigmy.

PRZYKŁADDla danych wejściowych:

3

1 1 4 1000

5 6 7 1000

4 101 23 999

poprawną odpowiedzią jest:

13

309

767

Pierwsza metoda była tak oczywista, że bez większe-go namysłu napisałam program rozwiązujący problem.

Monika Franczak

Autorka jest pracownikiem Działu Business Intelligence w firmie SAFO, odpowiedzialnym za projektowanie oraz wdrażanie systemów informatycznych opartych na hur-towni danych i narzędziach OLAP.Kontakt z autorką: [email protected]

Listing 1. Rozwiązywanie intuicyjne

var lz,ilz:longint; a,b:int64; n,m,i:longint;

begin

readln(lz);

for ilz:=1 to lz do

BEGIN

readln(a,b,n,m); a:=a mod m; b:=b mod m;

for i:=1 to n do

begin

if (i mod 2)=1 then a:=a+b

else b:=b+a; a:=a mod m; b:=b mod m;

end;

writeln((a+b) mod m);

END;

end.

Page 75: Software Developer's Journal 01/2007 PL

Licytacja

75www.sdjournal.orgSoftware Developer’s Journal 01/2007

Wystarczyło napisać zwykłą pętlę i pamiętać, że operacja mo-dulo (znajdowania reszty z dzielenia) jest rozdzielna względem dodawania i mnożenia – to po to, aby już na początku procesu wartości zmiennych nie wykroczyły poza zakres. Trochę mnie to zaniepokoiło, ponieważ do tej pory problemy na OPSS wyma-gały zdecydowanie większej wiedzy z dziedziny algorytmizacji, ale postanowiłam spróbować. Moje pierwsze podejście do „Li-cytacji” wyglądało następująco (Listing 1). Dla obliczenia liczby zapałek po n krokach licytacji, refren pętli musiał wykonać się n razy, inaczej mówiąc: mój program miał złożoność liniową, co dla dużych n powodowało, że zaczynał działać długo i nie zwra-cał wyników w ustalonym limicie czasowym. Trzeba więc jednak podejść do tego problemu z innej strony, pomyślałam. Przeczy-tałam raz jeszcze treść zadania. Zaczęłam zapisywać i liczyć „na piechotę” ile zapałek jest w grze w kolejnych krokach licyta-cji.Na podstawie powyższej tabeli oraz warunków zadania do-tyczących przebiegu licytacji, zauważyłam, że mają miejsce na-stępujące równości:

l dla n nieparzystych: S n Pi n Sig n Pi n Sig n S n S n n( ) = ( ) + ( ) = ( ) + −( ) = −( ) + −( ) >1 1 2 1,l dla n parzystych:

S n Pi n Sig n Pi n Sig n S n S n n( ) = ( ) + ( ) = −( ) + ( ) = −( ) + −( ) >1 2 1 1,

To już było coś, pomyślałam, ponieważ dzięki tym własno-ściom ogólny wzór na S(n) przyjął postać:S n S n S n n

S a b

S a b

( ) = −( ) + −( ) >

( ) = +

( ) = +

1 2 1

0

1 2

, Po chwili namy-słu stwierdziłam dalej, że każdy wyraz ciągu S(n) jest kom-binacją liniową liczb a i b, czyli można go zapisać w postaci: S n a l n b l na b( ) = ⋅ ( ) + ⋅ ( ) . Ponieważ kolejne wyrazy tego ciągu po-wstają przez zsumowanie dwóch poprzednich wyrazów, to:

l n l n l n

l

l

a a a

a

a

( ) = −( ) + −( )( ) =

( ) =

1 2

0 1

1 1

oraz analogicznie:

l n l n l n

l

l

b b b

b

b

( ) = −( ) + −( )( ) =

( ) =

1 2

0 1

1 1

To spostrzeżenie spowodowało, że na „Licytację” od tej chwili mogłam patrzeć zupełnie inaczej. Problem przybrał postać wyznaczenia wyrazu ciągu S(n) określonego wzo-rem: S n a F n b F n( ) = ⋅ +( ) + ⋅ +( )1 2 gdzie F(n) oznacza n-ty wy-raz ciągu Fibonacciego zdefiniowanego następująco:

F

F

F n F n F n n

0 0

1 1

1 2 1

( ) =

( ) =

( ) = −( ) + −( ) >,

Widać zatem, że zadanie można sprowadzić do problemu ob-liczenia zadanych wyrazów ciągu Fibonacciego. Jeden z pod-stawowych i najprostszych algorytmów obliczania wyrazów cią-gu Fibonacciego ma również złożoność liniową, a zatem niewiele wnosi pod kątem wydajności do wcześniejszych prób rozwiąza-nia problemu (Listing 2). Jednak spojrzenie na „Licytację” jak na problem ciągu Fibonacciego pozwoliło mi podejrzewać, że jed-nak znajomość szybkich i być może nawet skomplikowanych al-gorytmów znajdzie tutaj zastosowanie. Poszukiwania optymal-nego rozwiązania skierowałam w stronę sposobów wyznacza-nia liczb Fibonacciego. Odświeżyłam swoja wiedzę matematycz-ną z dziedziny algebry i teorii liczb. To, co sobie przypomniałam, zapisałam w następującej postaci: 1 1

1 0

1 11 0

2 1

1 0

1

1

=

=

≥+

F FF F

F FF F

nn

n n

n n

, 11Przeczuwałam, że to będzie klucz do sukcesu, ale będzie trzeba jeszcze nad nim popraco-

Tabela 1. Kroki w licytacji

Krok (n) 0 1 2 3 4Zapałek Pi (Pi(n)) a a+b a+b 2a+3b 2a+3bZapałek Sigmy (Sig(n)) b b a+2b a+2b 3a+5bRazem zapałek (S(n)) a+b a+2b 2a+3b 3a+5b 5a+8b

Listing 2. Wyznaczenie n-tej liczby Fibonacciego, złożoność liniowa

function Fib(n:longint):int64;

var F,F1,F2:int64; i:longint;

begin

if n=0 then Fib:=0

else

begin

F1:=0; F:=1;

for i:=2 to n do

begin

F2:=F1; F1:=F; F:=F2+F1;

end;

Fib:=F;

end;

end;

Listing 3. Binarne mnożenie macierzy kwadratowej stopnia 2

type _mac=array[1..2,1..2] of int64;

var MAC_A: _mac=((1,1),(1,0));

T: array[1..32] of _mac; M: int64;

function mnoz(m1,m2:_mac):_mac;

var wyn:_mac;

begin

wyn[1,1]:=(m1[1,1]*m2[1,1]+m1[1,2]*m2[2,1]) mod M;

wyn[1,2]:=(m1[1,1]*m2[1,2]+m1[1,2]*m2[2,2]) mod M;

wyn[2,1]:=(m1[2,1]*m2[1,1]+m1[2,2]*m2[2,1]) mod M;

wyn[2,2]:=(m1[2,1]*m2[1,2]+m1[2,2]*m2[2,2]) mod M;

mnoz:=wyn;

end;

procedure init;

var i:longint;

begin

T[1]:=MAC_A;

for i:=2 to 32 do

begin

T[i]:=mnoz(T[i-1],T[i-1]);

end;

end;

Page 76: Software Developer's Journal 01/2007 PL

76

Algorytmy

zadanie

www.sdjournal.org Software Developer’s Journal 01/2007

wać. Standardowy algorytm potęgowania macierzy ma bowiem złożoność liniową, więc znowu nie jest to żadna korzyść w po-równaniu do poprzednich metod rozwiązania „Licytacji”. Szuka-łam jednak dalej, tym razem sięgając pamięcią do wykładów z metod numerycznych poświęconych obliczeniom macierzo-wym. Jakie były efektywne sposoby potęgowania macierzy? Na-gle mnie olśniło. Przecież to oczywiste, że w tym przypadku na-leży wykorzystać algorytm binarny, który ma złożoność logaryt-miczną. Algorytm binarny potęgowania macierzy jako swoje główne założenia przyjmuje fakt, że każdą liczbę naturalną K,K ≥1można przedstawić jako sumę potęg liczby 2 (co do tego nie ma chyba większych wątpliwości, wszak każda liczba na-turalna może być zapisana w systemie binarnym), czyli istnie-je ciąg z(i) o wyrazach 0 lub 1, taki że:

K z i i

i

j

= ( )⋅=∑ 20

Pojawić się może pytanie, w jaki sposób znaleźć te potęgi licz-by 2, które „generują” zadaną liczbę K. Tutaj odpowiedź wy-daje się być, powiem nawet więcej: jest, prosta. Wystarczy znaleźć zapis binarny liczby K (nie będę tutaj zanudzać niko-go opowieściami jak to należy zrobić, bowiem akurat ten pro-blem nie należy do zadań mocno skomplikowanych – jest ra-czej trywialny….). Miejsca (pozycje), na których w zapisie występuje cyfra 1 wskazują szukane potęgi. Dla przykładu:209 11010001dec b( ) ( )= , stąd 209 2 2 2 27 6 4 0= + + + . Drugim zało-żeniem tego algorytmu są prawa działań na potęgach, czy-li wzory znane chyba wszystkim ze szkoły podstawowej lub średniej: a a aR S R S+ = ⋅ . Łącząc te dwa fakty i stosując je dla ob-liczeń macierzowych otrzymujemy:

A AK z i

i

ji( )⋅

=∏ 2

0

gdzie A jest w dowolną macierzą kwadratową. Dla zobrazowania powyższych zasad podam przykład:

A A A A A A209 128 64 16 1 2 2 2 27 6 4 0

= = ⋅ ⋅ ⋅+ + + . Siła binarnego algorytmu mnożenia macierzy nie polega jednak na wykorzystaniu zwy-kłych praw matematyki (przecież większość algorytmów mniej lub bardziej korzysta z zasad matematycznych) lecz na tym, że dla obliczenia 2i-tej potęgi korzysta się z uprzednio obli-czonej wartości potęgi 2i-1, czyli wykorzystana jest prosta za-leżność rekurencyjna:

A A

A A A ii i i

1

2 2 21 1

0

=

= ⋅ >− −

,

Ale ale… chyba zbyt daleko odbiegłam od pierwotnego tema-tu, powrócę zatem do problemu „Licytacji”. Przedstawiony po-wyżej algorytm binarny mnożenia macierzy wykorzystam do obliczenia liczby Fibonacciego. Aby dokonać dodatkowej opty-malizacji, wykorzystam fakt, że potęgować będę nie dowolną macierz, lecz konkretną znaną mi macierz kwadratową.

A =

1 11 0

W tym celu, na początku procesu obliczeniowego obliczę i zapiszę w tablicy T kolejne binarne (1, 2, 4, 8, 16, …) potęgi A tak, aby móc je potem wykorzystać w trakcie obliczeń. Pa-miętać tutaj należy, że warunkiem zadania jest podanie wyni-ku jako reszty z dzielenia przez magiczną liczbę M. Aby mieć pewność, że wszystkie pośrednie wyniki obliczeń nie wyjdą poza zakres typu danych całkowitych int64, operację modulo będę wykonywać na każdym tymczasowym wyniku występu-jącym podczas działania algorytmu (Listing 3).

Jak widać z powyższego kodu, wygenerowanie tablicy po-mocniczej T jest nieskomplikowaną czynnością, stanowiącą niewielki koszt, wykonaną jednorazowo dla pojedynczego ze-stawu danych. Dla uproszczenia zapisów i elegancji rozwiąza-nia zastosowałam funkcję pomocniczą mnóż, realizującą mno-żenie dwóch macierzy. W tym przypadku nie było konieczne wykorzystanie ogólnego algorytmu mnożenia macierzy, ponie-waż, z założenia, macierz jest kwadratowa stopnia 2.

W tym momencie poczułam, że naprawdę jestem blisko roz-wiązania problemu. Mając przygotowane właściwie wszystkie fragmenty rozwiązania, pozostało tylko zebrać je w całość aby otrzymać końcowy efekt. Niemalże bez kłopotów przygotowałam funkcję Fib obliczającą n-ty wyraz ciągu Fibonacciego (Listing 4). Szybkie sprawdzenie czy dobrze działa i dalej do roboty. Pozo-stał tylko finał, czyli napisanie głównego programu, który będzie wczytywał dane wejściowe i dla każdego zestawu danych prze-prowadzał niezbędne obliczenia. Cały czas pamiętać trzeba tyl-ko o tym, że wynik końcowy ma być modulo M (Listing 5).

Uff, udało mi się napisać niezły kawałek kodu… I po-myśleć tylko że po przeczytaniu treści zadania wydawa-ło mi się, że wystarczy napisać zwykłą pętlę. A tu, proszę, przydała się i algebra, i teoria liczb, i metody numeryczne. Chyba mi się spodobało. Ale co to? Za oknem już nie pada, czyżby rozpoczęła się złota polska jesień? W takim razie skorzystam z okazji i wyjdę z domu trochę się przewietrzyć. Ale już wiem, czym się zajmę gdy następnym razem będzie słota i deszcz. Zapisałam sobie adres tej strony w Zakład-kach, ot tak, na wszelki wypadek. n

Listing 4. Wyznaczanie n-tej liczby Fibonacciego, złożoność logarytmiczna

function Fib(n:longint):int64;

var W: _mac; b: longint; J: _mac=((1,0),(0,1));

begin

W:=J; b:=1;

while (n<>0) do

begin

if (n mod 2=1) then W:=mnoz(W,T[b]); inc(b); n:=n div 2;

end;

Fib:=W[1,2];

end;

Listing 5. Program główny dla rozwiązania

var lz,ilz:longint; a,b,n:int64;

begin

readln(lz); / wczytanie liczby zestawow

for ilz:=1 to lz do

begin

readln(a,b,n,M); init; a:=a mod M; b:=b mod M;

a:=(a*Fib(n+1)) mod M; b:=(b*Fib(n+2)) mod M;

writeln((a+b) mod M); // liczba zapalek po n krokach

end;

end.

Page 77: Software Developer's Journal 01/2007 PL
Page 78: Software Developer's Journal 01/2007 PL

78 www.sdjournal.org Software Developer’s Journal 01/2007

Tworzenie usługi w środowisku Progress Sonic Workbench

W poprzednim klubie technicznym, przedstawili-śmy przegląd narzędzi, z których składa się śro-dowisko Sonic Workbench. Zaprezentowaliśmy, jak stworzyć swój własny projekt ESB oraz w jaki spo-sób skorzystać z dostarczanych przez producenta przykładów. Posiadajmy więc wiedzę potrzebną, aby przejść do kolejnego bardzo ważnego zadania związanego z budowaniem infrastruktury ESB. W niniejszym numerze skoncentrujemy się na tworzeniu usług ESB.

USŁUGI ESBUsługa w ESB to modularny, wielokrotnie wykorzy-stywany element funkcjonalności. Realizowane przez usługę zadania, takie jak np. wbudowane ope-racje transformacji, mogą być związane z zapew-nianiem pracy infrastruktury ESB lub bezpośrednio z wykonaniem logiki aplikacji np. obliczeniem war-tości podatku. Usługi ESB są uruchamiane w konte-nerach, które zapewniają zarządzenie cyklem życia danej funkcjonalności (np. uruchamianiem i wyłą-czaniem usługi) oraz odpowiadają za połączenie usługi z magistralą komunikatów, co zaprezentowa-no na Rysunku 1.

Aby lepiej zrozumieć, w jaki sposób zachodzi inte-rakcja z wykorzystaniem usługi, prześledźmy poniż-szy scenariusz. Dane wejściowe danej usługi zostają do niej dostarczone w postaci wiadomości, tzw. XQMes-sage i w takiej też formie prezentowane są wyniki dzia-łania usługi. Każda z wiadomości jest przetwarzana sekwencyjnie wewnątrz logiki usługi realizowanej we-wnątrz metody service(). Rysunek 2 jest ilustracją procesu przetwarzania wiadomości wewnątrz każdej z usług (i odpowiadających im kontenerów). Zgodnie z przedstawionym rysunkiem kolejne etapy procesu przetwarzania wiadomości są następujące:

• Wiadomość w normatywnym formacie dociera do kontenera ESB;

• Nasłuchujący punkt końcowy konwertuje ją do formatu wewnętrznego Sonic ESB XQMessage;

• Wiadomość jest dostarczana do dispatchera;• Wiadomość zostaje umieszczona na wejściu od-

powiedniej usługi, a do jej treści dodawany jest nowy domyślny adresat – wyjście z usługi;

• Usługa otrzymuje wiadomość, wykonuje ope-racje na wiadomości (np. przekształca jej za-

wartość, dodając nowe informacje). Może tak-że zmienić kontekst wiadomości;

• Usługa umieszcza wiadomość na wyjściu, ewentualnie przesyła ją do specjalnego wyj-ścia sygnalizującego błąd w przetwarzaniu;

• Dispatcher sprawdza zawartość wiadomości na wyjściu i przesyła ją do następnego punktu;

• Punkt końcowy konwertuje wiadomość XQMes-sage do odpowiedniego formatu natywnego;

• I przesyła wiadomość do kolejnego punktu podłą-czonego do korporacyjnej magistrali usług.

A zatem w kontekście Sonic ESB usługi są zarzą-dzanymi elementami – klientami magistrali ko-munikatów, które mogą być wykorzystywane po-jedynczo lub łączone w procesy ESB (o których więcej w kolejnym odcinku). Właściwie cała logika aplikacji mieści się wewnątrz usług, a wiadomości i kontekst ich przetwarzania jest przekazywany do usługi. Na poziomie usługi można zrealizować ob-sługę błędów, a samymi usługami można zarzą-dzać (konfigurować je i monitorować) z poziomu menadżera domeny. Ich interfejsy są zdefiniowane przy pomocy technologii XML i WSDL. W Sonic ESB każda działająca usługa jest instancją pewnego typu usługi. W celu stworzenia usługi należały za-implementować interfejs XQService, używając pro-stego API, a następnie dodając odpowiednie klasy i parametry konfiguracyjne stworzyć klasy oczeku-jące na poszczególnych punktach końcowych.

Gdy tak stworzony fragment kodu otrzyma wia-domość, zostanie ona odpowiednio zwalidowana, a później przesłana do wspomnianej metody servi-ce(). Po wykonaniu operacji wiadomość jest wysy-łana za pomocą JMS. Wiadomości JMS dostarczane z kolejki komunikatów (SonicMQ) są odpowiednio prze-twarzane przez instancję MessageListener, która za-pewnia wewnętrzne przetwarzanie wymagane przez

platformę i specyficzne operacje realizowane przez daną usługę. Po przetworzeniu nowa lub tylko zmo-dyfikowana wiadomość jest wysyłana do kolejnego punktu w magistrali. Jednakże usługi ESB nie są klien-tami JMS w pełnym tego słowa znaczeniu. Ich cykl ży-cia jest sterowany zewnętrznie przy pomocy kon-tenerów, bezpośrednio nie biorą one udziału w two-rzeniu połączeń JMS, sesji, ani instancji MessageLi-stener. Konfigurację oraz tego typu operacje zapew-nia kontener. Wiadomości w korporacyjnej magistra-li usług posiadają identyfikator i kontekst, który jest przesyłany wraz z wiadomością. W JMS nie ma takich atrybutów jak nagłówek, QoS czy kontekst zawarto-ści, który jest automatycznie przekazywany. Imple-mentacja obsługi przychodzącej wiadomości (za po-mocą MessageListener) jest dużo bogatsza niż w przypadku JMS. Przykładowy kod prostej metody se-rvice() zaprezentowano na Listingu 1. Wszystkie usługi ESB muszą implementować także metody in-it() i destroy() interfejsu XQService. Jak już wspo-mniano, każda usługa działająca w ESB to instancja pewnego typu, a jej konfiguracja jest przechowywana w postaci pliku XML w Directory Service.

Progress Software Corporation jest dostawcą infrastruktury do rozwoju, wdrażania, integra-cji i zarządzania aplikacjami biznesowymi. Więcej informacji – http://www.progress.com

Progress Sonic ESBKLUB TECHNICZNY PROGRESS SOFTWARE

Rysunek 1. Schemat relacji pomiędzy usługą ESB, konte-nerem i magistralą komunikatów

�����������

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

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

������

Listing 1. Kod prostej metody service()

public void service (XQServiceContext ctx)

throws XQServiceException {

// Otrzymanie informacji o wiadomości i pobranie wiadomości z wejścia

XQEnvelope letter = ctx.getFirstIncoming();

XQMessage inMsg = letter.getMessage();

// Proste przetwarzanie i nadpisanie treści informacji o wiadomości

XQMessage outMsg = myAction.performMyCode(in);

letter.setMessage(outMsg);

// Wysłanie wiadomości do standardowego (domyślnego) wyjścia

ctx.addOutgoing(letter);

}

Page 79: Software Developer's Journal 01/2007 PL

79www.sdjournal.orgSoftware Developer’s Journal 01/2007

TWORZENIE WŁASNEGO TYPU USŁUGW celu stworzenia nowego typu usługi i powiązanego z nią szablonu konfiguracji należy wykonać kilka kro-ków. W środowisku Sonic Workbench należy stworzyć nowy projekt, co można wykonać, wybierając opcję Fi-le->New->Other, opcję Source Folder w węźle Java i po-dając nazwę nowego folderu. Następnie wybieramy Fi-le->New->Java Service Type, a w oknie dialogowym na-leży wskazać właśnie stworzony folder i podać unikalną nazwę usługi. Na kolejnym ekranie można zdefiniować parametry pracy usługi, na razie pozostawiamy je bez zmian, przechodząc do kolejnego ekranu pozwalające-go określić nazwę klasy, która będzie zawierała imple-mentację usługi. Klikając Finish, spowodujemy utworze-nie szkieletu usługi. Efekt powinien przypominać zrzut ekranu z Rysunku 3. Teraz możemy przystąpić do mo-dyfikacji działania usługi. W tym celu zrealizujemy ope-rację wypisania komunikatu „Hello world” wewnątrz usługi. W metodzie service() dodajmy linię kodu:

msg.SetStringHeader

("MyService","Hello world")

zaraz po pobraniu treści wiadomości i wejściu w sekcję try. Usługę możemy już dowolnie rozszerzać. Niestety scenariusze, takie jak opakowanie istniejącej klasy w celu wykorzystania jej logiki w usłudze, bezpośrednie komunikowanie się pomiędzy usługą a JMS, odczyty-wanie parametrów konfiguracyjnych i inne, wykracza-ją poza zakres tego krótkiego przeglądu.

INSTALOWANIEUSŁUGI W REPOZYTORIUMPo modyfikacji kodu, usługę instalujemy w kontekście Sonic Domain. W tym celu można wykorzystać testo-wy kontener dev.ESBTest i sprawdzić, jak działa na-

sza usługa. Instalacja jest bardzo prosta, wystarczy z menu kontekstowego pliku .esbstyp wybrać opcję Upload Service Type. W oknie należy zwrócić uwa-gę na nazwę usługi, wartości wszystkich parametrów inicjalizacyjnych dla instancji usługi oraz w szczegól-ności na punkty końcowe usługi zaprezentowane w polu Advanced. Można samodzielnie modyfikować wspomniane wartości w celu dostosowania usługi do własnych potrzeb, a następnie, wybierając przycisk OK, zatwierdzić operację. W wyniku uruchomienia usłu-gi środowisko poinformuje nas, że trzeba zrestartować kontener - co też należy uczynić. Po instalacji możemy modyfikować podane wcześniej wartości za pomo-cą menu kontekstowego pliku .esbstyp definiującego usługę i opcji Configure Service Instance.

DALSZE KROKIAby wykorzystać wynik przeprowadzenia powyż-szych operacji, można stworzyć instancje odpowia-dające właśnie zainstalowanemu typowi usługi. Do

tego celu służy narzędzie Sonic Management Conso-le, które opiszemy w jednym z kolejnych odcinków. Można także zastosować tzw. scenariusze, które słu-żą do testowania konfiguracji magistrali przy pomo-cy zestawu wiadomości. Wreszcie można rozpocząć pracę z narzędziami, takimi jak debuger i okno śle-dzenia, które omówimy dokładniej już w następnym klubie technicznym.

PODSUMOWANIEW tym odcinku przybliżyliśmy pojęcia związane z usługami ESB oraz zaprezentowaliśmy, jak stworzyć nową klasę usług przy użyciu Sonic Workbench. W kolejnym odcinku zaprezentujemy, jak stworzyć wła-sny proces ESB, który będzie składał się operacji wy-konywanych przez instancje przedstawionych w ni-niejszym klubie usług ESB. Przyjrzymy się bliżej defi-niowaniu i śledzeniu wykonania takiego procesu oraz możliwościom, jakie oferuje w tym zakresie produkt Progress Sonic ESB.

KLUB TECHNICZNY PROGRESS SOFTWARE

Rysunek 2. Diagram przetwarzania wiadomości przez usługę wewnątrz kontenera

�������

������

����������

�������

������

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

���

���

���

��������

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

��

� � � � � � � � �

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

Rysunek 3. Sonic Workbench po stworzeniu usługi

30-dniową wersję testową produktu Sonic Workbench można pobrać ze strony firmy So-nic Progress Softwarehttp://www.sonicsoftware.com/products/sonic_esb_family/index.ssp

Page 80: Software Developer's Journal 01/2007 PL

80 www.sdjournal.org Software Developer’s Journal 01/2007

Magic eDeveloper - zdarzeniowe podejście do programowania

Seria ostatnich artykułów stanowiła wstęp do progra-mowania w środowisku Magic eDeveloper. Materiał w nich zaprezentowany pozwala na tworzenie aplikacji w tym narzędziu. Opisane dotychczas zostały zasady pra-cy środowiska, jego komponenty, własności oraz pod-stawowe metody wizualizacji danych. W tym odcinku zostanie zaprezentowana metoda tworzenia aplikacji, w której wykorzystuje się mechanizm zdarzeń.

Jak zwykle wszystkie elementy środowiska, umożliwiające uruchomienie systemu są do po-brania ze strony internetowej: http://komtech.pl/software/

DEFINICJA ZDARZENIA W ŚRODOWISKU MAGIC EDEVELOPERZdarzeniem nazywamy każdą aktywność środowi-ska, która zostanie wykonana w rezultacie zaistnienia przypisanego dla niej tzw. wyzwalacza. W praktyce, większość czynności wykonywanych zarówno przez programistę jak i końcowego użytkownika jest pewne-go rodzaju zdarzeniami zaimplementowanymi w śro-dowisku lub zaprogramowanymi w aplikacji.

Środowisko Magic eDeveloper posiada domyśl-nie zdefiniowane podstawowe zdarzenia, czyli po-wiązanie tzw. akcji, których zaistnienie powodu-je wywołanie określonych zachowań środowiska. W dalszej części tego artykułu będzie dla nich sto-sowana nazwa – zdarzenia wewnętrzne (Internal Event), gdyż ich definicja i zachowanie jest opisa-ne wewnątrz środowiska Magic. Są to wszystkie możliwe predefiniowane zachowania systemu, jak choćby przeskok z pola, kliknięcie, zmiana rekordu, zamknięcie zadania i wiele innych.

By zachować jednorodność środowiska, część predefiniowanych zdarzeń wewnętrznych jest do-myślnie powiązana ze skrótami klawiaturowymi, tworząc tzw. zdarzenia klawiaturowe, które są w środowisku Magic eDeveloper nazywane systemo-wymi (System Event). Przykładem tej definicji jest wciśnięcie klawisza ESC, które spowoduje wywoła-nie zdarzenia wewnętrznego Close, które to spowo-duje zamknięcie aktywnego zadania.

Inny przykład to wciśnięcie klawisza Down. Zda-rzeń opartych na tym wyzwalaczu jest wiele. W edy-cji danych w układzie tabeli, wciśnięcie tego przyci-sku spowoduje wywołanie zdarzenia wewnętrznego Next Row, a to domyślnie wymusi przeniesienie kur-

Dystrybutor: Komtech Sp. z o.o.Rynek 10, 26-600 Radomtel. (048)3688300http://www.komtech.pl/software/

Klub Magic’aKLUB TECHNICZNY MAGIC

Rysunek 1. Formatka programu użytego do dalszych prac

Rysunek 2. Definicja zmiennej – przycisk

sora do kolejnego rekordu, dzięki czemu do bufora zo-stanie załadowany kolejny rekord i wykona się dla niego faza Record Prefix oraz Record Main.

Jednak w przypadku edycji danych za pomo-cą formularza nie wyposażonego w formant tabe-li, wciśnięcie tego przycisku spowoduje wywołanie akcji Next Field, a w rezultacie przeniesienie kur-

sora do kolejnego dostępnego na formularzu po-la. Definicja tych domyślnych zdarzeń klawiaturo-wych jest zapisana w specjalnej tabeli w menu Set-tings opcji Keyboard Mapping. Dzięki temu progra-mista ma możliwość dowolnego przedefiniowania zachowania systemu bazując na skrótach klawia-turowych.

Page 81: Software Developer's Journal 01/2007 PL

81www.sdjournal.orgSoftware Developer’s Journal 01/2007

Programista otrzymuje jeszcze jeden potężny mechanizm – programowanie zdarzeń – dzięki któ-remu może dowolnie zmieniać zachowanie systemu w następstwie zaistnienia zdefiniowanych wyzwala-

czy (również zdarzeń wewnętrznych, systemowych, czy nowych opisanych przez programistę) oraz two-rzyć nowe zdarzenia – poprzez przypisanie własnych wyzwalaczy i wiązanie ich z określonymi zachowania-

mi w aplikacji. Dzięki temu istnieje możliwość zmiany domyślnego zachowania systemu choćby w przypad-ku zaistnienia akcji „Close”, czy zdefiniowania zupeł-nie nowych definicji, które zostaną użyte w algoryt-mie aplikacji.

PRZYCISK– PROSTY PRZYKŁAD WYKORZYSTANIA ZDARZENIA WEWNĘTRZNEGOJak już zostało wspomniane, każda aktywność po-woduje wywołanie jakiegoś zdarzenia. Najpraw-dopodobniej najczęściej stosowanym wyzwala-czem jest skrót klawiaturowy ESC, który wywołu-je akcję wewnętrzną Close. Bardzo często w aplika-cjach stosuje się element graficzny – przycisk, któ-ry również służy do wywołania określonego działa-nia, np. zamknięcia zadania. By zaznajomić się z mechanizmem przypisania przyciskowi określonej akcji, zostanie w wybranym programie użyta kon-trolka Push Buton i przypisana mu akcja wewnętrz-na Close. Wciśnięcie tego przycisku spowoduje wy-wołanie akcji i zamknięcie aktywnego zadania, tak samo jak wciśnięcie klawisza ESC.

Bazą dla dalszych prac będzie program wy-świetlający dane Klient – Zamówienia, utworzony w poprzednim odcinku. Trzeba zmodyfikować wy-gląd tego programu, by umożliwić umieszczenie na formatce jeszcze kilku przycisków. W tym ce-lu formatkę podzadania wyświetlającą zamówie-nia dla wybranego klienta należy zmniejszyć, by po prawej stronie okna głównego znalazło się wię-cej miejsca na ewentualne przyciski (Rysunek. 1.).

Element ekranowy Przycisk (Push Button) może funkcjonować jako samodzielny obiekt zdefiniowany jedynie na formatce, ale zalecane jest by obiekt ten był powiązany ze zmienną opisaną w zadaniu w jego fazie Record Main. Taka konstrukcja ułatwia określenie spo-sobu poruszania się po formatce.

W tym celu należy przejść do edycji zada-nia nadrzędnego programu Klient – Zamówienia i utworzyć w jego fazie Record Main, na końcu defi-nicję zmiennej wirtualnej (Select Virtual).

Polecenie to powołuje do istnienia zmienną, która nie ma bezpośredniego powiązania z bazą danych, może służyć do przechowania wyników tymczasowych określonych przeliczeń lub, jak w tym przypadku, pozwolić na zdefiniowanie aktyw-nego elementu formularza jakim jest przycisk.

Po wstawieniu operacji Select Virtual dostęp-na jest opcja umożliwiająca określenie jakiego typu zmienna będzie dostępna (natychmiast po utwo-rzeniu zamiast nazwy pojawiają się dwa znaki za-pytania). Dwukrotne kliknięcie powoduje otwarcie okna umożliwiającego opisanie tej zmiennej. Na-leży najpierw podać nazwę zmiennej, w tym przy-padku zostanie użyta nazwa: BT_Zamknij, która dość jednoznacznie określa co to będzie za zmien-na. Kolejny krok to wybór modelu, jeśli taki byłby zdefiniowany (np. globalny model do określania

KLUB TECHNICZNY MAGIC

Rysunek 3. Definicja własności przycisku

Rysunek 4. Określenie etykiety dla przycisku

Page 82: Software Developer's Journal 01/2007 PL

82 www.sdjournal.org Software Developer’s Journal 01/2007

przycisków). Ponieważ w tym przypadku nie ist-nieje taki model, niezbędne jest opisanie tej zmien-nej indywidualnie. Do obsługi przycisków wybie-ra się atrybut znakowy (Alpha), zaś opcja Pictu-re określa maksymalną długość łańcucha znaków, który może zostać użyty jako etykieta przycisku. W tym przykładzie użyto 12 znaków. Do tego mo-mentu zmienna może pełnić funkcję umożliwiają-cą wyświetlenie czy przechowanie łańcucha zna-ków. Dopiero zmiana sposobu wyświetlania z do-myślnego trybu Edit na Push button (we własno-ściach w opcji Style / GUI Display) ustala sposób działanie tej zmiennej (Rysunek. 2.)

Każdy przycisk powinien mieć przypisaną ak-cję, czyli określenie co się stanie, jeśli zostanie wci-śnięty. W tym celu należy podświetlić wybór try-bu wyświetlania, a to spowoduje pojawienie się do-datkowego przycisku z trzeba kropkami, umożli-wiającego ustalenie dodatkowych parametrów tej zmiennej (krok 1). Po wciśnięciu pojawi się okno własności, w którym należy określić parametr Ra-ise Event czyli rodzaj zdarzenia, które nastąpi po jego wciśnięciu (Rysunek. 3.)

Wywołanie tej opcji (krok 2) spowoduje wy-świetlenie okna umożliwiającego wybór typu zda-rzenia powiązanego z przyciskiem. Na liście znaj-duje się znajduje się kilka typów (Event type), z których należy wybrać Internal (Krok 3), gdyż wci-śnięcie tego przycisku ma wywołać zdarzenie we-wnętrzne środowiska Magic. Przejście do kolejnej opcji (Event) powoduje wywołanie słownika – li-sty dostępnych zdarzeń (Krok 4), z których nale-ży wybrać Close – zamknięcie zadania. Po wybra-niu należy zatwierdzić klawiszem Enter wszystkie ekrany, aż do ekranu z fazami zadania.

Od tego momentu w zadaniu będzie funkcjonować zmienna wirtualna o nazwie BT_Zamknij, która jest przy-ciskiem, którego wciśnięcie spowoduje wywołanie akcji Close, czyli zamknięcie zadania. Być może wydaje się być to skomplikowane, lecz w praktyce taka definicja jest zazwyczaj określona w repozytorium modeli i po-tem używana w ramach potrzeb w zadaniach.

Przy definicji zmiennej tego typu konieczne jest określenie jeszcze jednego atrybutu – etykiety przy-cisku umieszczonego na formatce. Stosuje się do te-go zazwyczaj opcję Init przy definicji zmiennej. Wią-że się ją z wyrażeniem zawierającym ciąg znaków, będący wyświetlaną etykietą, np. „&Zamknij” (Ry-sunek. 4.). Umieszczenie w ciągu znaków znaku „&” oznacza wprowadzenie dodatkowego skrótu klawia-turowego aktywującego przycisk (np. ALT+Z),

Ostatni etap to umieszczenie zmiennej na for-matce w wyznaczonym miejscu. Przy prawidłowej definicji wstawienie na formatce zmiennej, spowo-duje umieszczenie przycisku z opisanymi wcze-śniej własnościami (Rysunek. 5.)

Pozostaje zapisanie wszystkich zmian, spraw-dzenie programu pod względem poprawności i uru-chomienie programu.

Rysunek 5. Wstawienie zmiennej – przycisku na formatkę.

Rysunek 6. Umieszczenie i własności przycisku „Szczegóły”

KLUB TECHNICZNY MAGIC

Page 83: Software Developer's Journal 01/2007 PL

83www.sdjournal.orgSoftware Developer’s Journal 01/2007

Po uruchomieniu, by zakończyć pracę, można wcisnąć klawisz ESC, kliknąć na przycisk „x” w pra-wym górnym rogu okna (zdarzenia predefiniowane), kliknąć przycisk „Zamknij”, albo wcisnąć skrót ALT+Z (zdarzenia zdefiniowane przez programistę).

Ten sposób definiowania zdarzeń stosuje się w aplikacjach bardzo szeroko, zazwyczaj do opi-sania podstawowych zdarzeń jak Zamknij, Wybierz (akcja Select), czyli wywołania zdarzeń wewnętrz-nych. Do opisania bardziej skomplikowanych al-gorytmów stosuje się mechanizm redefiniowania zdarzeń wewnętrznych lub definiowanie tzw. zda-rzeń użytkownika.

REDEFINICJA ZDARZENIA WEWNĘTRZNEGOOpisany powyżej mechanizm powiązania wybra-nej akcji z przyciskiem jest szeroko wykorzysty-wany podczas tworzenia aplikacji w środowisku Magic. Sposób ten będzie również wykorzystywa-ny w kolejnych metodach wykorzystania zdarzeń w aplikacjach.

Proste powiązanie akcji i przycisku jest w wielu przypadkach niewystarczające do zbudowania algo-rytmu. Dlatego często stosuje mechanizm, w którym przycisk wywołuje akcję (najczęściej jest to akcja we-wnętrzna ZOOM lub w przypadku starszych wersji śro-dowiska User Action), a w logice aplikacji opisany jest algorytm reakcji systemu, który zostanie wykonany w przypadku zaistnienia tej akcji.

Dlaczego używana jest tu akcja Zoom albo User Action? Spowodowały to względy historyczne, gdyż zdarzenie Zoom od początku powstania środowiska Magic było używane do wywołania logiki skojarzonej z kontrolką (Zoom – Rozwiń). W przypadku User Ac-tion, w starszych wersjach środowiska Magic było do-stępnych 20 takich akcji, które nie miały wprost przy-pisanego wewnętrznego działania i służyły do wyko-rzystania przez programistę (User Action 1, User Ac-tion 2, itd.). Metoda ta jest bardzo uniwersalna gdyż daje programiście szerokie możliwości w budowie lo-giki, zapewniając jednocześnie kompatybilność z roz-wiązaniami tworzonymi w poprzednich wersjach śro-dowiska Magic eDeveloper.

By zaprezentować ten mechanizm warto przy-gotować kilka programów, które mogą się wzajem-nie wywołać w wyniku zaistnienia zdefiniowanego zdarzenia. Dotychczas zostały stworzone dwie ta-bele umożliwiające przechowywanie informacji o nagłówkach zamówień i powiązanych z nimi kon-trahentami. Kolejnym krokiem będzie zdefiniowa-nie tabeli przechowującej informacje o produktach związanych z zamówieniami.

Zostanie wykorzystany program Klient – Zamó-wienia, w którym umieszczony zostanie jeszcze je-den przycisk, uruchomiający oddzielny program (za-danie), pozwalający na modyfikację listy produktów skojarzonych z wybranym zamówieniem. Niezbędne jest więc zdefiniowanie tabeli Zamowienia_Linie o następującej strukturze:

• ID_Zamówienia – identyfikator zamówienia do zachowania relacji z tabelą Zamowienia_Nagl;

• Nr_linii – pole numeryczne, przechowujące dane z zakresu 1 – 99;

• Nazwa_produktu – pole 30 znakowe;• Cena_jednostkowa – pole numeryczne o for-

macie „3.2”;• Ilosc_zamawiana – pole numeryczne o for-

macie „3”.

Należy też zdefiniować dla tej tabeli jeden indeks unikalny składający się z dwóch segmentów: ID_Zamówienia i Nr_Linii Mechanizm zakładania tabel i powiązanych z nimi modeli został szczegóło-wo opisany w odcinku 3 i 4 tego cyklu. By przyspie-szyć dalsze prace można wygenerować program o nazwie Zamówienia – Linie, który troszczy się o ob-sługę tej tabeli, co zostało opisane w odcinku 6.

Mając przygotowaną tabelę i wygenerowany program można przystąpić do realizacji zdarzenia opartego na przedefiniowaniu wewnętrznej akcji. Podobnie jak w przypadku opisanym w poprzed-nim punkcie, również i tu wyzwalaczem będzie wciśnięcie przycisku umieszczonego na formula-rzu wyświetlającym zamówienia.

W tym celu należy ponownie przejść do edycji pro-gramu Klient – Zamówienia, lecz tym razem modyfiko-wane będzie zadanie Zamówienia. To w nim należy za-łożyć zmienną wirtualną, będącą przyciskiem, który tym razem jest powiązany z akcją Zoom. Metoda two-rzenia jest dokładnie taka sama jak przy definicji przy-cisku z akcją Close – różni się tylko powiązaną akcją oraz etykietą na przycisku (w tym przypadku: „Szcze-góły”). Tak zdefiniowaną zmienną trzeba umieścić na formularzu w obrębie formatki podzadania Zamówie-nia (Rysunek. 6.) Od tego momentu kontrolka ta mo-że zostać użyta do opisania zdarzenia.

Po powrocie do tablicy wykonawczej zadania Zamówienia należy ustawić kursor na ostatniej pozycji w oknie z fazami (na fazie Record Suffix) i utworzyć nową linię, w której trzeba wybrać opera-cję Handler – służącą do definicji zdarzenia.

KLUB TECHNICZNY MAGIC

Rysunek 7. Definicja zdarzenia na obsługującego akcję Zoom na kontrolce BT_Szczegóły

Rysunek 8. Deklaracja zmiennej typu parametr.

Page 84: Software Developer's Journal 01/2007 PL

84 www.sdjournal.org Software Developer’s Journal 01/2007

Definicja ta w uproszczeniu wygląda nastę-pująco: jeśli w zadaniu system zarejestruje użycie wyzwalacza opisanego w kolumnie Event, dodatko-wo pod warunkiem zaparkowania kursora w okre-ślonym polu, na określonej kontrolce (opcjonalny parametr CTRL), należy wykonać operacje zapisa-ne w oknie Operation: Handler On …

W tym przypadku szczegółowa definicja sa-mego zdarzenia ma postać: Handler na akcję we-wnętrzną Zoom, na kontrolce BT_Szczegóły (Ry-sunek. 7.) ma spowodować uruchomienie poleceń opisanych w oknie Operation: Handler On Zoom. Te-raz można zająć się opisaniem zachowania syste-mu po zaistnieniu tego zdarzenia, czyli ma nastą-pić uruchomienie programu Zamówienia – Linie.

By to zrealizować wystarczy umieścić na liście ope-racji polecenie Call Program i wybrać z listy wymieniony powyżej program. Już na tym etapie mechanizm obsłu-gi zdarzenia zadziała poprawnie, choć ze względu na re-lacje pomiędzy tabelami dane będą wprowadzanie i wy-świetlane błędnie. Po uruchomieniu nie ma przekazania do nowego okna informacji o edytowanym zamówieniu, co w tym przypadku jest krytyczne.

Ponieważ mamy tu powiązanie dwóch oddziel-nych drzew programów musi nastąpić jawne przeka-zanie parametru pomiędzy nimi. W tym celu koniecz-ne jest zadeklarowanie parametrów w programie wy-woływanym. Po otwarciu do edycji programu (a do-kładnie zadania) Zamówienia Linie w fazie Record Main trzeba na początku utworzyć jeszcze jedną linie do de-klaracji parametru z operacją Select Parametr. Pomię-

dzy wymienionymi programami konieczne jest prze-kazanie jedynie identyfikatora zamówienia, dlatego wystarczająca jest jedna operacja Select Parameter. Podobnie jak w przypadku deklaracji zmiennej wirtu-alnej i tu należy określić typ zmiennej – przekazywa-nego parametru, przy czym można skorzystać z de-finicji modeli. Warto nazwać zmienną: Id_Zamówie-nia_PAR, co jednoznacznie ją określi (Rysunek. 8.). W przypadku większej liczby, każdy parametr musi być zadeklarowany oddzielną operacją Select Parametr.

Gdy w tej zmiennej znajdzie się wartość identyfika-tora przetwarzanego zamówienia, należy użyć ją do de-finicji zakresu (Range) na polu ID_Zamowienia (by wy-świetlić z tej tabeli rekordy powiązane z wybranym za-mówieniem), oraz w opcji Init, by zapewnić powiązanie przy tworzeniu nowych rekordów (Rysunek. 9) co stwo-rzy relację pomiędzy tabelami.

Ostatni krok to przekazanie właściwej warto-ści identyfikatora zamówienia w obsłudze zdarze-nia. W zdarzeniu zdefiniowanym w zadaniu Klient – Zamówienia.Zamówienia (często stosuje się ta-ką notację, gdyż jednoznacznie określa ścieżkę w drzewie: Program „Klient – Zamówienia”, podzada-nie „Zamówienia”) występuje polecenie Call Prog. Polecenie to ma opcję Arg (Parametry), która służy do powiązania lokalnych zmiennych lub wyrażeń z parametrami oczekiwanymi w programie wywo-ływanym. Należy tu wymienić zmienną ID_Zamo-wienia z tabeli Zamowienia_Nagl.(Rysunek. 10).

Po sprawdzeniu składni program nadaje się już do uruchomienia. Jak widać działa w nim zarówno obsługa

zdarzenia jak i powiązanie pomiędzy danymi. Oczywi-ście nad samą formą wizualizacji należy jeszcze popra-cować, lecz opisana funkcjonalność pracuje poprawnie.

W tej części zostało wykorzystane zdarzenie ba-zujące na przycisku związanym z akcją wewnętrzną Zoom. Równie dobrze mogłoby tu być użyta akcja User Action 1, wymieniona wcześniej. Analogicznie można by również zdefiniować zdarzenie bazujące na akcji Close (opisanej w poprzedniej części). Spowodowało-by to zablokowanie możliwości wyjścia z zadania, gdyż zamiast wewnętrznego znaczenia akcji Close (czyli zamknięcia aktywnego zadania) nastąpiłoby urucho-mienie podprogramu. Byłby to rezultat błędnego rede-finiowania wewnętrznego znaczenia akcji. Jednak roz-wiązanie to często się spotyka, włączając nawet prze-chwytywanie akcji Close, czy Exit, by zabezpieczyć się przez możliwością zamknięcia okna przerwania dzia-łania w trakcie algorytmu. Lecz wykorzystuje się tu do-datkową własność zdarzenia – Enable, która określa w jakim przypadku ma nastąpić obsługa opisanego zda-rzenia. Pozwala to na indywidualne sterowanie działa-niem poszczególnych zdarzeń.

ZDARZENIE UŻYTKOWNIKA – KOLEJNY KROK W ZDARZENIOWYM PODEJŚCIU DO PROGRAMOWANIAOpisane wcześniej techniczne sposoby definiowania zdarzeń można wykorzystać przy całkowicie zdarzenio-wym podejściu do tworzenia aplikacji w środowisku Ma-gic eDeveloper. Dotychczas wyzwalaczem dla zdarze-nia było wciśnięcie (kliknięcie) przycisku, choć w rze-czywistości było to zaistnienie zdarzenia powiązanego z tym przyciskiem. W takim rozwiązaniu w kodzie apli-kacji znajdzie się wiele zdarzeń powiązanych z akcją ZOOM (lub inną – wewnętrzną) w korelacji z wybranymi zmiennymi (kontrolkami przycisków na ekranie). Przy rozbudowanych programach i skomplikowanej logice ważne jest, by nazwy kontrolek przycisków choć w czę-ści oddawały sens zdarzenia, gdyż w innym przypadku kod aplikacji staje się mało czytelny.

Alternatywą jest wiązanie zdarzeń z akcjami, któ-re są powoływane do istnienia również przez progra-mistę i nie bazują na akcjach wewnętrznych ani syste-mowych. Tak zwane zdarzenia użytkownika (nie my-lić ze zdarzeniami wewnętrznymi User Action), są de-finiowane w specjalnym repozytorium User Events na poziomie zadania. Mogą określać dowolną aktywność przewidywaną przez programistę, która zostanie opro-gramowana później (Rysunek. 11.). Zdarzenie to mo-że być dalej powiązane z przyciskiem, czy wywołane w logice aplikacji za pomocą operacji Raise Events.

Bazując na programie Klient – Zamówienia, w zadaniu Zamówienia możliwe jest zdefiniowanie kilku typów zdarzeń:

• Wydruk dokumentu to zdarzenie, które zostanie użyte do uruchomienia programu drukującego dokument. Dodatkowo dla tego zdarzenia zdefi-niowany jest wyzwalacz – skrót klawiaturowy

Rysunek 9. Wykorzystanie zmiennej typu parametr w celu uzyskania relacji pomiędzy tabelami.

Rysunek 10. Wykorzystanie parametrów przy wywoływaniu podprogramów.

KLUB TECHNICZNY MAGIC

Page 85: Software Developer's Journal 01/2007 PL

85www.sdjournal.orgSoftware Developer’s Journal 01/2007

CTLR+P. Oznacza to, iż niezależnie od programo-wego wywołania tego zdarzenia, zostanie zaini-cjowane po uruchomieniu tego skrótu;

• Odświeżenie okna to zdarzenie, które docelowo zo-stanie użyte do ponownego odczytania danych wy-świetlanych na ekranie. Będzie mogło być użyte w logice aplikacji, lecz dodatkowo przyporządkowano mu wyzwalacz bazujący na czasie. Zdarzenie to zo-stanie wywołane automatycznie co 30 sekund;

• Nieprawidłowe ID Zamówienia to zdarzenie które zostanie zainicjowane gdy wartość pola ID_Zamowienia będzie miało wartość 0. Może być przydatne do obsługi sytuacji niepożąda-nej przy edycji danych;

• Edycja linii to typowe zdarzenie, które nie ma zdefiniowanego żadnego wyzwalacza i będzie wywołane tylko z logiki aplikacji (z zadania) za pomocą polecenia Raise Events, lub poprzez wciśnięcie powiązanego z nim przycisku.

We wszystkich przypadkach jest to tylko definicja akcji, która może zaistnieć w danym zadaniu. Sama obsługa zdarzenia, czyli powiązanie akcji z konkretnym działa-niem jest definiowane w logice aplikacji, analogicznie do przykładu ilustrującego redefiniowanie zdarzenia opisa-nego w poprzednim rozdziale. Tym razem parametrem operacji Handler będzie jednak zdarzenie typu User a w

szczególności np. Edycja linii (Rysunek. 12.). Takie opi-sanie zdarzeń pozwala na stworzenie przejrzyste-go kodu, gdyż każda aktywność jest tu jednoznacz-nie nazwana i obsłużona. Poza tym, zdarzenie np. Edycja Linii opisane na poziomie zadania może być wywołane w wielu miejscach aplikacji i za pomocą wielu wyzwalaczy. Może być powiązanie z przyci-skiem na ekranie, może to być rezultat zadziałania skrótu klawiszowego, możliwe jest wywołanie au-tomatycznie gdy zostaną spełnione określone kry-

teria w algorytmie itd. Ważne jest to, iż kod samego zdarzenia (czyli zbiór operacji w ramach niego wy-konywanych) istnieje tylko w jednym miejscu i nie musi być powielany w zadaniu.

Logika zdarzenia może zawierać dowolne kon-strukcje bazujące na zmiennych pochodzących z faz Record Main, zmiennych lokalnych zdefinio-wanych w ramach zdarzenia, operacji wywołania innych zdarzeń czy innych programów. Warto za-uważyć, że wszystkie polecenia są wykonywane w trybie nie interakcyjnym w kolejności zgodnej z ich definicją. Zdarzenie jest więc jakby fazą wtrąconą w podstawowy model działania zadania.

PODSUMOWANIENiedoceniane przez wielu programistów środowi-ska Magic zdarzenia, umożliwiają tworzenie przej-rzystych i wydajnych aplikacji, w których każda aktywność jest jednoznacznie określona i opro-gramowana. Artykuł ten przybliżył ideę stosowa-nia tego typu metody programowania, lecz nie wy-czerpał całego materiału. Dodatkowe informacje na ten temat można znaleźć w dokumentacji środo-wiska Magic eDeveloper. Bardziej zaawansowane przykłady zastosowanie tej metody projektowa-nia zostały przedstawione w udostępnionym kur-sie programowania w środowisku Magic eDevelo-per. Kurs ten jak też dodatkowe komponenty i in-formacje można odnaleźć na stronie internetowej http://komtech.pl/software/.

W następnym artykule zostanie opisany jesz-cze jeden element tworzenia zadań interaktyw-nych, mianowicie mechanizm kontrolowania war-tości zmiennych oraz sposób tworzenia tzw. pro-gramów wyboru czyli słowników. Kolejny arty-kuł zostanie natomiast poświęcony idei tworzenia programów wsadowych i ich przykładowych za-stosowań.

Mamy nadzieję, że informacje te pozwolą czy-telnikom na samodzielną pracę ze środowiskiem Magic oraz odkrywaniem nowych możliwości te-go narzędzia.

Rysunek 11. Przykłady definicji zdarzeń użytkownika

Rysunek 12. Definicja zdarzenia użytkownika – Edycja linii

DODATKOWE INFORMACJEW cyklu Klub Magic’a do tej pory ukazały się następujące artykuły:

• Magic eDeveloper – wysoko produktywna technologia ponad 4GL do tworzenia aplikacji C/S i Web;• Magic eDeveloper – instalacja pakietu;• Magic eDeveloper – Wstęp do programowania: repozytoria i modele;• Magic eDeveloper – Wstęp do programowania: Tabela – znaczenie, cechy i definicja;• Magic eDeveloper – Wstęp do programowania: Program – budowa i cechy funkcjonalne;• Magic eDeveloper – Wstęp do programowania: Program – tworzenie pierwszego programu• Magic eDeveloper – Wstęp do programowania: Program – dostęp do danych w trybie końcowego

użytkownika ;• Magic eDeveloper – Wstęp do programowania: Program – łączenie danych z wielu tabel – relacja 1:1;• Magic eDeveloper – Wstęp do programowania: Program – łączenie danych z wielu tabel – relacja 1:1,

opcje połączenia;• Magic eDeveloper – Wstęp do programowania: Program – łączenie danych z wielu tabel – relacja 1:n.

KLUB TECHNICZNY MAGIC

Page 86: Software Developer's Journal 01/2007 PL

86 www.sdjournal.org Software Developer’s Journal 01/2007

Rafał Kocisz

Moja przygoda z tzw. postmodernistycznymi językami programowania zaczęła się jakoś pod koniec studiów. Mniej więcej w tamtym okresie trafiłem na wspania-

łą książkę Andrew Hunta i Davida Thomasa pt. „The Pragma-tic Programmer: From Journeyman to Master”. Jako żądny wie-dzy student połknąłem to dzieło w okamgnieniu. Właśnie wtedy pierwszy raz uderzył mnie fakt, iż moja wiedza o językach pro-gramowania jest mocno ograniczona. W tamtym okresie tkwi-łem po czubek głowy w świecie C++. Wydawało mi się, że zna-jąc dobrze STL i potrafiąc cytować fragmenty standardu ISO/IEC 14882 złapałem Pana Boga za nogi i nic więcej już mi nie potrzeba do osiągnięcia programistycznej Nirvany. Książka An-drew i Davida ostudziła mnie nieco i dała wiele do myślenia. W szczególny sposób uderzyła mnie pewna rada umieszczo-na w rozdziale traktującym o budowaniu portfolio wiedzy. Ra-da ta brzmiała: naucz się co najmniej jednego nowego języka programowania w ciągu roku. Co więcej, autorzy Pragmatycz-nego Programisty udowodnili mi na stronicach swojej książki, że nauka taka może być bardzo pożyteczna. Czytając tę książ-kę, pierwszy raz zetknąłem się bliżej z Perlem – ulubionym (w momencie pisania książki) postmodernistycznym językiem pro-gramowania Andrew i Davida. Powziąłem sobie wtedy silne po-stanowienie, że zastosuję się do zalecenia i co rok nauczę się nowego języka. Ale, ale – korzystam z przymiotnika „postmo-dernistyczny” w odniesieniu do języków programowania – mo-że warto w końcu wyjaśnić o co chodzi? Terminu „postmoder-nistyczny język programowania” po raz pierwszy użył Larry Wall, twórca Perla. Gdyby zapytać filozofa bądź historyka sztu-ki na czym polega postmodernizm to zapewne w potoku uczo-nej wypowiedzi moglibyśmy wyłowić zapewne dominujące sło-wo kluczowe: dekonstrukcja. I tu właśnie leży sedno sprawy – otóż języki postmodernistyczne zostały zbudowane na bazie dekonstrukcji i rekombinacji cech innych języków programowa-nia. Tak właśnie powstały Perl, Python, Ruby, Tcl i wiele innych. Oczywiście niemalże każdy język programowania w taki czy in-ny sposób czerpie z dorobku swoich poprzedników – jednakże w niektórych przypadkach mamy do czynienia z dekonstrukcją na bardzo szeroką skalę. Mamy tu podobną sytuację jak z post-modernizmem w sztuce – potrzebna jest bardzo solidna baza, z której można by czerpać. Trudno przeprowadzać dekonstruk-cję jeśli... nie ma czego dekonstruować. A przykładowo Ruby – mój ulubiony dialekt postmodernistyczny, według zapewnień swojego twórcy – Yukihiro Matsumoto – powstał na bazie ta-

Postmodernistycznejęzyki programowania

kich języków jak Ada, C++, CLU, Lisp, Java, Perl, Python, PHP, oraz Smalltalk. Tyle jeśli chodzi o dygresję. Kontynuując głów-ny wątek: jakiś czas po przeczytaniu Pragmatycznego Pro-gramisty znalazłem wreszcie czas na naukę Perla. Dość szyb-ko przerobiłem klasyczną pozycję Learning Perl z wydawnic-twa OReilly i zacząłem stosować ten „egzotyczny język skryp-towy” w praktyce. Pierwszym szokiem było wyjście poza do-brze znany, bezpieczny teren statycznej kontroli typów. Mocno zaintrygowany tematem zacząłem drążyć dalej i dalej. Przeło-mem była książka Higher Order Perl: „Transforming Programs with Programs” autorstwa Marka Jasona Dominusa. Autor po-kazał tu prawdziwą moc drzemiącą w Perlu – szczerze zachę-cam każdego programistę do przeczytania tej pozycji, potrafi dobrze namieszać w głowie. Idąc dalej tropem Perla trafiłem na Ruby – język programowania rodem z Japonii. I zgadnijcie ko-go spotkałem przy tej okazji? Okazało się, że są tu moi starzy pragmatyczni znajomi – Andrew Hunt i David Thomas. Panowie Ci błyskawicznie dostrzegli potencjał tego języka i stali się je-go oddanymi propagatorami. Zachęcony ich entuzjazmem, po-stanowiłem wziąć się do nauki. Dla zabawy zacząłem pisać so-bie w Ruby... raytracera. Jakież było moje zdziwienie, kiedy po trzech wieczorach – nie znając wcześniej składni języka i ucząc się wszystkiego „w locie”, napisałem w pełni działający (oczywi-ście w pewnym bardzo podstawowym zakresie) program. Gdy-bym chciał zrobić coś podobnego w C++, to (zakładając, że nie znałbym tego języka i musiałbym uczyć się go w trakcie pra-cy) zajęłoby mi to o wiele, wiele więcej czasu. W Ruby wszyst-ko jest takie... domyślne. Koncepcje i mechanizmy wyrwane z innych języków są tutaj pięknie złączone w jedną, logiczną całość. Trudno to krótko i zwięźle opisać – trzeba to poczuć – najlepiej kodując w tym języku (osobom, które chciałyby szyb-ko zapoznać się z podstawami Ruby polecam darmową książ-kę Why’s (Poignant) Guide to Ruby; można ją znaleźć pod adre-sem http://poignantguide.net). Według mnie najpiękniejsze przy nauce postmodernistycznych języków programowania jest nie-samowite rozszerzanie się horyzontów myślowych. Znajdziemy tu mieszankę właściwości, o których w ogóle się nam nie śni-ło – zakładając, że znaliśmy jedynie C++, C# czy Javę. Patrząc z tej perspektywy uczenie się Ruby (bądź innego postmoderni-stycznego języka programowania) jest przedsięwzięciem ryzy-kownym – łatwo się uzależnić i trudno przestawić się ponow-nie na kodowanie w „zwyczajnych” dialektach. Jednakże, mo-im zdaniem nawet sama nauka daje bardzo dużo. Przykładowo, ja w sensie zawodowym cały czas pracuję z językiem C++, lecz od kiedy zacząłem poznawać i analizować alternatywne rozwią-zania, potrafię zdobyć się na pewien dystans i o wiele wyraźniej dostrzegać zarówno mocne jak i słabe strony C++. Konkludując, jeśli jesteś programistą któregoś z wiodących (w sensie prze-mysłowym) języków i poza nim nie interesuje Cię nic innego, to gorąco Cię namawiam: jeszcze dziś zacznij uczyć się jednego z postmodernistycznych języków programowania. Gwarantuję Ci, że sprawi to, iż staniesz się lepszym programistą! n

Autor pracuje na stanowisku Starszego Specjalisty ds. Oprogra-mowania w firmie BLStream (www.blstream.com) oraz odbywa studia doktoranckie na Wydziale Informatyki Politechniki Szcze-cińskiej (www.wi.ps.pl). Centrum zainteresowań zawodowych au-tora stanowią technologie mobilne, przetwarzanie równoległe oraz języki programowania w ujęciu ogólnym.Kontakt z autorem: [email protected]

Page 87: Software Developer's Journal 01/2007 PL

87

Księgozbiór

www.sdjournal.orgSoftware Developer’s Journal 01/2007

Więcej niż architektura oprogramowania

Autor: Luke HohmannWydawnictwo: HelionISBN: 83-246-0110-4Ocena: 4,5

Los, przyszłość i droga życia oprogramowania nie zawsze jest prosta. W wielu przypadkach iden-tyczne postępowanie w stosunku do tworzonych czy rozpowszechnianych narzędzi może przy-nieść odwrotne skutki. Dlatego w tej kwestii nie możemy opierać się na sztywnych wzorcach i opi-sach co mamy zrobić. To od wniosków pochodzących z analizy czynników, które wpływają na opro-gramowanie, zależy nasze działanie, a nie od grafiku postępowania. Biorąc do ręki tę książkę spo-dziewałem kolejnego, teoretycznego wykładu o tworzeniu diagramów jak i relacjach klient – opro-gramowanie. Jednak nie znajdziemy w tej książce, poza miejscami gdzie jest to konieczne, su-chych, tematycznych definicji i porad działania, które nie sprawdzają się w realnym świecie. Autor

opisuje problemy z jakimi możemy się spotkać podczas projektowania. Luke Hohmann poruszył wiele kwestii tak normalnych dla ryn-ku IT ale nie opisywanych w innych książkach. Książka nakreśla czytelnikowi procesy produkcyjne, rozbudowy, funkcjonalne, wdro-żeniowe oprogramowania. Przeczytamy tu nie tylko o problemach związanych z software’m, ale też o czynniku ludzkim, jak np. rozu-mowanie programisty, ich przyzwyczajenia i skłonności oraz relacje programistów do innych członków zespołu. Wszystko to jest po-parte licznymi przykładami wziętymi z wieloletniej pracy Hohmann’a jako programisty czy też szefa zespołu projektu. Mało jest pozy-cji na rynku, których charakter byłby bardziej praktyczny. Ciekawym pomysłem jest też umieszczenie po każdym rozdziale podsumo-wania oraz rad dotyczących co warto sprawdzić i co warto spróbować. Minusem pozycji jest zatrzymywanie się i rozprawianie na te-maty marketingowe co nie oznacza, że te kwestie są mniej znaczące, jednak wielu programistów ten fakt może denerwować. Nieste-ty spis treści nie do końca spełnia swoje role. Czego dowiemy się z haseł np: Tak, to jest potrzebne czy Chcę wiedzieć co jest grane? Nie za wiele. Czy jest to książka z której nauczymy się architektury oprogramowania? Z pewnością nie do końca, gdyż będziemy mu-sieli sięgnąć do pozycji bardziej technicznych. Czy zrozumiemy i nauczymy się analizować procesy i problemy związane z oprogra-mowaniem, o których mielibyśmy się dowiedzieć podczas naszej pracy w tej tematyce? Z pewnością tak.

Zrecenzował: Mariusz Ostapowicz

C# i .NET

Tytuł oryginalny: Core C# and .NETAutor: Stephen C. PerryWydawnictwo: Wydawnictwo Helion, czerwiec 2006ISBN: 83-246-0320-4Ocena: 5-

Po dość długim okresie posuchy na polskim rynku wydawniczym, jak grzyby po deszczu, zaczęły pojawiać się pozycje opisujące możliwości platformy .NET. I o ile jeszcze przed niespełna rokiem nie mieliśmy praktycznie wyboru, szukając pozycji, z pomocą której zdobywalibyśmy szlify w najnow-szej technologii firmy Microsoft, dziś możemy dość swobodnie przebierać wśród książek omawiają-cych tę tematykę. Trudno znaleźć na polskim rynku książkę, która bez zbędnego wprowadzenia w podstawy programowania omawia podstawowe konstrukcje języka, elementy biblioteki standardo-

wej .NET, kontrolki Windows Forms, GDI+, .NET Remoting, pracę z dokumentami XML, techniki zabezpieczania kodu i wiele innych aspektów, dość dobrze znanych każdemu, kto miał okazję spędzić trochę czasu w projektach realizowanych przy wykorzystaniu plat-formy .NET i języka C#. Chociaż nagromadzenie tak wielu tematów spowodowało, że kilka z nich jest omówionych zbyt pobieżnie, to programiście, który chce tylko zajrzeć za drugą stronę barykady, takie przekrojowe omówienie może przypaść do gustu. Mimo to, programista .NET skuszony numerem „2.0” na okładce, odnajdując w publikacji zaledwie wprowadzające informacje o możliwości niesionych przez nową wersję, może poczuć lekki niedosyt. Podsumowując, książkę „C# i .NET” z czystym sumieniem mogę pole-cić każdemu, kto ma zamiar poznać możliwości platformy .NET. Choć ostrzegam, że trzeba się uzbroić w odrobinę cierpliwości, aby nie usnąć nad tą publikacją. Wiedza w niej zawarta z pewnością wystarczy, aby samodzielnie wykorzystać tę technologię i sprawnie podjąć poszukiwania szczegółowych informacji o interesujących nas elementach platformy .NET. Programista, który ma już za sobą przygodę z tą technologią, niestety nie znajdzie tu wiele nowych informacji, a książka ta co najwyżej pomoże mu uporządkować już zdobytą wiedzę. Niemniej jednak na uznanie zasługuje wysiłek autora, aby przedstawić w ramach jednej publikacji tak szerokie spek-trum zastosowania „C# i .NET”, co niewątpliwie mu się udało. Głównie dzięki temu jest to aktualnie najlepsza, moim zdaniem, publi-kacja omawiająca możliwości platformy .NET na polskim rynku wydawniczym.

Zrecenzował: Stefan Turalski

Page 88: Software Developer's Journal 01/2007 PL

Zaprenumeruj swoje ulubione magazyny i zamów archiwalne numery!

Już teraz w kilka minut możesz zaprenumerować swoje ulubione pismo.Gwarantujemy:- preferencyjne ceny- bezpieczną płatność on-line- szybką realizację Twojego zamówienia Bezpieczna prenumerata on-line wszystkich tytułów Wydawnictwa Software!

www.buyitpress.com zamówienie prenumeraty

Page 89: Software Developer's Journal 01/2007 PL

Prosimy wypełnić czytelnie i przesłać faksem na numer: (22) 887 10 11 lub listownie na adres: Software-Wydawnictwo Sp. z o.o., Bokserska 1, 02-682 Warszawa, e-mail: [email protected]. Przyjmujemy też zamówienia telefoniczne: (22) 887 14 44

Imię i nazwisko............................................................................................ ID kontrahenta..........................................................................................

Nazwa firmy................................................................................................. Numer NIP firmy.......................................................................................

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

Telefon (wraz z numerem kierunkowym)................................................... Faks (wraz z numerem kierunkowym) ....................................................

E-mail (niezbędny do wysłania faktury)............................................................................................................................................................................

zamówienie prenumeraty

1 Cena prenumeraty rocznej dla osób prywatnych 2 Cena prenumeraty rocznej dla osób prenumerujących już Software Developer’s Journal lub Linux+3 Cena prenumeraty dwuletniej Aurox Linux

Jeżeli chcesz zapłacić kartą kredytową, wejdź na stronę naszego sklepu internetowego:

www.buyitpress.com

automatyczne przedłużenie prenumeraty

Suma

Tytuł Ilość numerów

Ilość zamawianych prenumerat

Od numeru pisma lub miesiąca

Opłata w zł

z VATSoftware Developer’s Journal (1 płyta CD)– dawniej Software 2.0Miesięcznik profesjonalnych programistów

12 250/1801

SDJ Extra (od 1 do 4 płyt CD lub DVD)– dawniej Software 2.0 Extra!Numery tematyczne dla programistów

6 150/1352

Linux+DVD (2 płyty DVD)Miesięcznik o systemie Linux 12 199/1791

Linux+Extra! (od 1 do 7 płyt CD lub DVD)Numery specjalne z najpopularniejszymi dystrybucjami Linuksa 8 232/1982

PHP Solutions (1 płyta CD)Dwumiesięcznik o zastosowaniach języka PHP 6 135

Hakin9, jak się obronić (1 płyta CD)Miesięcznik o bezpieczeństwie i hakingu 12 1991/219

.psd (1 płyta CD + film instruktażowy)Dwumiesięcznik użytkowników programu Adobe Photoshop 6 140

.psd numery specjalne (.psd Extra + .psd Starter Kit) 6 140

Page 90: Software Developer's Journal 01/2007 PL

Aktualne informacje o najbliższym numerze: http://www.sdjournal.org/pl/Redakcja zastrzega sobie prawo do zmiany zawartości pisma.

Biblioteka

miesiącaCLuceneCLucene to biblioteka C++ oferująca wysoko wydajne, bogate, przenośne i rozszerzalne API wspomagające proces indeksowania oraz przeszukiwania danych tekstowych. CLucene to port Lucene, popularnego silnika do przeszukiwania tekstu, stworzonego w języka Java. W odnie-sieniu od swojego pierwowzoru CLucene cechuje się bardzo dużą szybkością działania, co czy-ni ją idealnym kandydatem przy tworzeniu aplikacji o wysokich wymaganiach wydajnościowych. W następnym numerze, w ramach kolumny Biblioteka Miesiąca autor CLucene przedstawi możli-wości swojego rozwiązania i pokaże jak najłatwiej rozpocząć pracę z tą biblioteką.

Na CD:Na dołączonej do pisma płycie znajdziecie komplet materiałów do artykułów.

Zapraszamy do lektury!

nr 2/2007 (146)

Numer w sprzedaży już od 18-stego stycznia 2007r.

w następnym numerze między innymi:

Programowanie dla internetu

Warsztat

XHTMLPierwsza strona w XHTMLXHTML jest następcą nierozwijanego już oficjalnie języka HTML4 będąc równocześnie zgodny z zasa-dami XML. Powstał z myślą o rozwinięciu możliwości stron internetowych, których brakowało w HTML. Jako dokument (aplikacja) XML pozwala na korzystanie ze wszystkich jego możliwości. Oficjalny FAQ konsorcjum W3C opisuje podstawowe różnice między XHTML a HTML, zaznaczając przy tym, że różni-ce w korzyści z przejścia na XHTML mogą okazać się niewielkie dla początkujących projektantów stron lub w przypadku stron nieskomplikowanych.

Inżynieria

oprogramowaniaBiblioteka POSHBiblioteka POSH ułatwia tworzenie przenośnego kodu pomiędzy różnymi kompilatora-mi, systemami operacyjnymi i platformami sprzętowymi. Artykuł przedstawi zastosowanie POSH na prostym przykładzie biblioteki analizującej nagłówek pliku WAV (dźwiękowego).

Page 91: Software Developer's Journal 01/2007 PL
Page 92: Software Developer's Journal 01/2007 PL