10-08.doc

(230 KB) Pobierz
Wstęp

Co dalej?              271

 

10

 

XML-RPC

 

 

 

 

W tym rozdziale zostanie omówione kolejne ciekawe zastosowanie języka XML — model żądań i odpowiedzi XML-RPC. XML-RPC to po prostu specyficzna odmiana RPC, czyli technologii wy­wo­ływania zdalnych procedur. Jeśli Czytelnik nie jest doświadczonym programistą, bądź też do tej po­ry posługiwał się tylko językiem Java, pojęcie zdalnego wywoływania procedur może być mu obce; dla innych zaś poruszanie tego tematu może wydać się dziwne — RPC w ostatnich czasach stracił na popularności. W trakcie lektury niniejszego rozdziału Czytelnik dowie się, dlaczego te trzy nie­po­zorne literki przed skrótem RPC zrewolucjonizowały coś, co wydawało się być dinozau­rem w świe­cie programistycznym. Czytelnik nauczy się również korzystać z XML-RPC z poziomu pro­gramów w Javie. Zakończenie rozdziału poświęcone jest praktycznym zastosowaniom modeli XML-RPC.

Jeśli Czytelnik poddał się fali programowania obiektowego, tak popularnego w ostatnich latach, to pewnie wzdryga się na dźwięk słowa „procedura”. Języki proceduralne, takie jak PL/SQL czy ANSI C, nie są „modne” i jest ku temu wiele powodów. Zapewne niejednokrotnie Czytelnikowi zdarzyło się „oberwać” za nazwanie metody Javy funkcją lub procedurą; wie też, jak unikać „kodu spaghetti” — czyli kodu polegającego na łączeniu wielu metod w jeden długi łańcuch. Wraz z ty­mi językami i sposobami programowania odsunięto na bok technologię RPC — nowe, obie­ktowe techniki umożliwiają osiągnięcie tych samych rezultatów przy bardziej przejrzystej strukturze programu i większej wydajności. Jednak, co ciekawe, popularyzacja XML-a przyczyniła się do upowszechnienia interfejsów API zbudowanych z myślą o XML-RPC oraz do coraz częstszego wykorzystywania XML-RPC mimo niedobrych skojarzeń, jakie się z tym skrótem wiążą.

Zanim Czytelnik zacznie stosować te interfejsy, powinien przyjrzeć się technologii RPC i porów­nać ją z podobnymi rozwiązaniami Javy, a szczególnie z technologią RMI (Remote Method Invo­cation). Jeśli zdecydujemy się na wykorzystanie XML-RPC w aplikacji (a na pewnym etapie pracy z pewnością tak się stanie), na pewno będziemy musieli uzasadnić swój wybór innym progra­mi­stom — szczególnie tym, którzy mają właśnie za sobą lekturę o EJB czy RMI. Wszystkie te technologie mają na pewno swoje miejsce, ale zrozumienie właściwego ich stosowania jest bardzo isto­tne. Najbardziej popularnymi sposobami operowania na obiektach poprzez sieć są RPC i RMI.

RPC kontra RMI

Technologia RMI zyskuje ogromną popularność wśród programistów Javy. Cała specyfikacja EJB (Enterprise JavaBeans) została oparta na bazie RMI; umiejętność pisania trzywarstwowych apli­ka­cji RMI jest koniecznością. Jeśli Czytelnik jeszcze tego nie potrafi, powinien sięgnąć po Java Enterprise in a Nutshell (autorzy: David Flanagan, Jim Farley, William Crawford i Kris Ma­gnusson) lub Java Distributed Computing Jima Farleya (obie książki wydawnictwa O'Reilly & As­sociates).

Co to jest RMI?

Technologia RMI to wywoływanie zdalnych metod (remote method invocation). Koncepcja wydaje się dość prosta — RMI umożliwia wywoływanie metod na obiekcie znajdującym się na innym komputerze niż program. Na tym opiera się całe programowanie rozproszone w Javie i to właśnie stanowi szkielet technologii EJB oraz wielu implementacji aplikacji dla przedsiębiorstw. Bez za­głę­biania się w detale można powiedzieć, że RMI za pomocą procedur pośredniczących (ang. stub) oraz szkieletów opisuje metody dostępne do zdalnego wywołania. Klient wykorzystuje owe pro­cedury pośredniczące (zazwyczaj mające postać interfejsów Javy), a RMI obsługuje całą „magię” tłumaczenia żądań wysyłanych do procedury pośredniczącej na wywołania sieciowe. Metoda działa na faktycznym obiekcie komputera zdalnego; wynik przesyłany jest z powrotem drogą sie­ciową. Na koniec procedura pośrednicząca zwraca wynik klientowi, który jako pierwszy wywołał metodę, i klient może działać dalej. Przede wszystkim trzeba pamiętać, że klienta „nie interesują” szczegółowe zasady działania RMI i sieci; procedura pośrednicząca wykorzystywana jest tak, jak gdyby był to faktyczny obiekt implementujący określone metody. Technologia RMI (za pomocą protokołu zdalnego JRMP™) działa tak, że cała komunikacja sieciowa odbywa się poza kulisami; klient ma dostęp do ogólnego wyjątku (java.rmi.RemoteException), a programista może skupić się na regułach biznesowych i logice aplikacji. Technologia RMI umożliwia również ko­rzys­tanie z różnych protokołów (np. Internet Inter-ORB Protocol) — dzięki temu można uru­cho­mić komunikację pomiędzy obiektami Java i CORBA, często także w innych językach, np. C lub C++.

Technologia RMI ma również jednak pewne wady. Po pierwsze, intensywnie wykorzystuje za­soby. Używanych jest całkiem sporo klas i choć stanowią one standardowe wyposażenie pakietu JDK, to przecież stworzenie ich egzemplarza pochłania pamięć i inne zasoby. Protokół JRMP cha­rakteryzuje się słabą wydajnością, a zastąpienie go wcale nie jest prostym zadaniem. Kiedy klienty wysyłają żądania RMI, muszą zostać otwarte i utrzymane gniazda, a im jest ich więcej, tym bar­dziej spada wydajność systemu — szczególnie wtedy, gdy system dostępny jest w sieci (wtedy dla dostępu HTTP konieczne jest otworzenie dalszych gniazd). Technologia RMI wymaga również istnienia serwera lub usługodawcy, do których można dowiązać obiekty. Dopóki obiekt nie zo­sta­nie dowiązany do nazwy odpowiadającej takiemu usługodawcy, dopóty nie będzie dostępny z po­zio­mu innych programów. To wymaga użycia rejestru RMI, serwera usług katalogowych LDAP lub innych usług typu Java Naming and Directory Interface (JNDI). I jeszcze jedno — korzystanie z RMI może wiązać się z koniecznością pisania dużej ilości kodu, nawet biorąc pod uwagę to, jak wiele pomocnych klas udostępnia JDK. Konieczne jest zaprogramowanie zdalnego interfejsu opi­su­jącego metody dostępne do wywołania oraz (jeśli korzystamy z EJB) szeregu innych inter­fej­sów. Oznacza to również, że oddanie kolejnej metody do klasy serwera powoduje zmianę interfejsu i przekompilowanie procedur pośredniczących, co często nie jest pożądane (a niejednokrotnie jest po prostu niemożliwe).

Co to jest RPC?

Technologia RPC to wywoływanie zdalnych procedur (remote procedure calls). RMI umożliwia bezpośrednie działanie na obiekcie Javy, natomiast RPC pozwala korzystać z metod samodziel­nych (tak, tutaj nazywane są one procedurami!) za pośrednictwem sieci. To ogranicza interaktywność, ale upraszcza interfejs, z którym komunikuje się klient. Technologię RPC można sobie wyobrazić jako sposób korzystania z „usług” komputerów zdalnych, z kolei RMI umożliwia korzystanie z „ser­werów”. Z tej subtelnej różnicy wynika fakt, że proces RMI jest zazwyczaj sterowany w całości przez klienta — zdarzenia następują po zdalnym wywołaniu metod. RPC to częściej klasa lub zestaw klas wykonujących zadania bez interwencji klienta; jednakże czasami klasy te obsługują żądania przesłane przez klienty i wykonują ich „minizadania”. Przedstawione w dalszej części roz­działu przykłady pomogą zrozumieć te teoretyczne wywody.

RPC nie jest środowiskiem tak interaktywnym jak RMI, ale oferuje szereg zalet względem tego ostatniego. Umożliwia współpracę oddzielnych systemów. Technologia RMI pozwala co prawda na łączenie Javy z serwerami i klientami CORBA (poprzez IIOP), ale RPC umożliwia komu­ni­ka­cję dosłownie dowolnych aplikacji — protokołem transportowym może być bowiem HTTP. Po­nie­waż niemal dowolny wykorzystywany obecnie język oferuje sposób komunikacji za pośrednictwem HTTP, RPC stanowi niezwykle atrakcyjne rozwiązanie w przypadku tych zastosowań, w których konieczne jest porozumiewanie się z systemami zastanymi. RPC jest zazwyczaj również mniej „zasobożerny” niż RMI (szczególnie wtedy, gdy do kodowania wykorzystywany jest XML — o czym za chwilę); RMI często wymaga przesłania przez sieć całych klas Javy (np. kodów apletów czy własnych klas pomocniczych EJB), a RPC musi tylko przekazać przez sieć parametry żądania i wy­nik działania, zazwyczaj w postaci danych tekstowych. RPC pasuje również świetnie do modelu interfejsów API — systemy nie stanowiące części określonej aplikacji i tak mogą pobierać z niej informacje; oznacza to, że zmiany poczynione w serwerze nie przekładają się na zmiany w kodzie aplikacji klientów. Przy transferze opartym na zwykłym tekście dodatkowe metody można do­da­wać bez konieczności rekompilacji klienta; użycie tych metod wymaga zaś tylko niewielkich zmian.

Odwieczny problem z technologią RPC związany jest z kodowaniem przesyłanych danych. Wy­obraźmy sobie, że chcemy stworzyć tekstową i niewielką objętościowo reprezentację struktur Javy Hastable lub Vector. Jeśli weźmiemy pod uwagę, że te struktury mogą z kolei zawierać inne obiekty Javy, taka reprezentacja nagle przestaje być zadaniem banalnym; stworzony format musi ponadto nadawać się do użycia przez dowolne języki programowania — inaczej umniejszymy ko­rzyści płynące z zastosowania technologii RPC. Do niedawna zachodziła odwrotnie proporcjonal­na relacja pomiędzy jakością i użytecznością kodowania w RPC a jego prostotą; innymi słowy, im prościej reprezentowane były złożone obiekty, tym trudniej było wykorzystać takie kodowanie w wielu językach bez tworzenia dodatkowego, własnego kodu. Rozbudowane tekstowe reprezen­ta­cje danych nie zostały ustandaryzowane i wymagały całkowicie nowych implementacji w po­szczególnych językach. W tej chwili Czytelnik zapewne domyśla się już, do czego zmierzam.

XML-RPC

Największą przeszkodą w używaniu technologii RPC był zawsze sposób kodowania. Kiedy pojawił się XML-RPC, wszystko uległo zmianie. XML oferował nie tylko prostą, tekstową re­pre­zen­tację danych; stanowił także standard strukturyzacji danych. Kiedy grupa W3C opublikowała specyfikację XML 1.0, zniknęły obawy o konieczność stosowania rozwiązań własnych — korzy­s­ta­jący z RPC mieli pewność, że XML w najbliższym czasie nie sprawi im żadnej niespodzianki. Co więcej, standard SAX stworzył możliwość uzyskania dostępu do XML-a w sposób wydajny i stan­dardowy; to uprościło implementację bibliotek RPC. Pozostała więc już tylko do uruchomienia tran­smisja poprzez HTTP (coś, co robimy już od ponad 10 lat) oraz specyficzne interfejsy kodowania i dekodowania. Po kilku implementacjach beta bibliotek XML-RPC stało się jasne, że oprócz pozostałych zalet, XML jest również szybki i mało wymagający — wydajność bibliotek XML-RPC była większa niż oczekiwano. Model XML-RPC stanowi obecnie prężne i stabilne roz­wiązanie zdalnego wywoływania procedur.

Czytelnikowi, jako programiście Javy, XML-RPC oferuje sposób prostego tworzenia „punktów zaczepienia” w aplikacji i usługach, zarówno do użytku własnego, jak i do wykorzystania przez klienty aplikacji w różnych oddziałach, a nawet firmach. Interfejsy API są odseparowane od Javy, klienty nie muszą więc korzystać bezpośrednio z tego języka. Ponadto dzięki XML-RPC nie trze­ba już się uczyć o RMI, aby korzystać z usług rozproszonych (przynajmniej na początku). Ni­niejszy rozdział stanowi opis implementacji serwera i klienta XML-RPC. Czytelnik przekona się również, że serwer może działać niezależnie od klientów, wciąż jednak udostępniając interfejsy współpracujące z XML-RPC i pozwalając na komunikację i pobieranie danych. Porównanie te­ch­no­logii RMI z XML-RPC pozwoli wykazać wyższość tego ostatniego w wielu zastosowaniach.

Powiedział „Witaj!”

Jeśli Czytelnikowi udało się przebrnąć przez te kilka stron wywodów o zdalnym wywoływaniu pro­cedur, z pewnością jest przekonany, że XML-RPC to narzędzie przydatne i że może rozwiązać wiele problemów programistycznych. Aby rozwinąć temat, spróbujemy teraz zbudować praw­dzi­wy program wykorzystujący tę technologię. Zgodnie z tradycją, zaczniemy od prostego programu „Wi­taj świecie!”. W naszym serwerze XML-RPC zostanie zarejestrowana procedura ob­sługi. Pro­cedura ta pobiera parametr String Javy (nazwę użytkownika) i zwraca łańcuch za­wie­ra­jący „Wi­taj” oraz pobraną nazwę, np. „Witaj Brett”. Następnie procedura ta zostanie udo­stęp­niona przez serwer klientom XML-RPC. Na koniec stworzymy prostego klienta łączącego się z ser­we­rem i żądającego wywołania tej metody.

W rzeczywistości serwer i procedura obsługi XML-RPC znajdowałyby się na jednym komputerze (zazwyczaj wydajnym serwerze), a klient na innym i cała operacja odbywałaby się zdalnie. Jed­nakże, jeśli nie mamy pod ręką kilku komputerów, przykłady możemy przećwiczyć lokalnie. Pro­ces bę­dzie przebiegał wtedy szybciej niż w rzeczywistym zastosowaniu, ale i tak będzie można zaob­ser­wować, jak poszczególne elementy układają się w jedną całość i jak ten cały XML-RPC działa.

Skąd wziąć biblioteki XML-RPC?

Jak to zostało powiedziane wcześniej, w rozwój RPC, a ostatnio XML-RPC, włożono już wiele pracy. Podobnie jak w przypadku używania interfejsów SAX, DOM i JDOM do obsługi XML-a, nie trzeba drugi raz wynajdywać koła — na pewno istnieją dobre, a nawet świetne pakiety Javy spełniające nasze potrzeby. Centrum informacji o XML-RPC, a także zasób odsyłaczy do od­po­wied­nich bibliotek Javy i innych języków stanowi witryna pod adresem http://www.xml-rpc.com. Serwis ten, sponsorowany przez Userland (http://www.userland.com), zawiera publiczną specy­fi­ka­cję XML-RPC, informacje o obsługiwanych typach danych i samouczki. Co ważniejsze jednak, można tam znaleźć odsyłacz do miejsca w sieci, z którego pobierzemy pakiet XML-RPC dla Javy, a mianowicie do strony Hannesa Wallnofera http://helma.at/hannes/xmlrpc.

Na stronie tej znajduje się opis klas zawartych w pakiecie XML-RPC Hannesa, a także instrukcja ich obsługi. Pobieramy archiwum i rozpakowujemy je w katalogu roboczym lub środowisku pro­gra­mistycznym IDE. Następnie kompilujemy klasy; jeden z przykładów serwletów wymaga obec­ności klas serwleta (servlet.jar dla interfejsu Servlet PI 2.2). Odpowiednią klasę dla mechanizmu serwletów Tomcat znaleźć można na stronie http://jakarta.apache.org. Jeśli Czytelnik nie za­mie­rza „bawić się” przykładem z serwletem, to nie musi go kompilować — nie jest on wymagany do wykonania przykładów w tym rozdziale.

 

Klasy XML-RPC są spakowane w pliku zip, xmlrpc-java.zip. Z tego archiwum trzeba wy­dobyć cały kod źródłowy znajdujący się w katalogu xmlrpc-java/src/. Nie do­łą­czo­no dystrybucji w postaci jar, więc wymagana jest ręczna kompilacja klas. Po skom­pilowaniu Czytelnik może sam utworzyć archiwum jar, co uprości włączanie klas do ścieżki. (W wersji pobranej przez tłumacza w styczniu 2001 r. odpowiedni plik jar był już dołączony — przyp. tłum.).

Zasadnicza dystrybucja (nie zawierająca przykładów apletów i wyrażeń regularnych) składa się z ośmiu klas pakietu helma.xmlrpc: klasa zasadnicza XmlRpc, klient XmlRpcClient, ser­wer XmlRpcServer, XmlRpcHandler (precyzyjne sterowanie kodowaniem i przetwarzaniem XML-a) oraz szereg klas pomocniczych. Klasy zgłaszają wyjątek XmlRpcException; nato­miast XmlRpcServlet demonstruje użycie serwleta jako procedury obsługi odpowiedzi HTTP; z kolei WebServer to „lekki” serwer HTTP zbudowany specjalnie do obsługi żądań XML-RPC; zaś Benchmark umożliwia zmierzenie czasu obsługi żądania XML-RPC z wykorzystaniem spe­cyficznego sterownika SAX. Wymagane do pracy całego mechanizmu, a nie zawarte w dystry­bu­cji, są klasy SAX (które Czytelnik powinien posiadać po wykonaniu wcześniejszych przykładów) oraz sterownik SAX; innymi słowy, trzeba mieć kompletną implementację parsera XML obsłu­gu­jącą SAX. W naszych przykładach będziemy ponownie korzystali z parsera Apache Xerces, ale biblioteki obsługują dowolny parser zgodny z SAX 1.0.

Po skompilowaniu plików źródłowych należy upewnić się, czy klasy XML-RPC, SAX i parsera XML znajdują się w ścieżce dostępu do klas. Po tym Czytelnik powinien już potrafić napisać pierwszy program. Warto trzymać gdzieś pod ręką pliki źródłowe XML-RPC, bo pozwalają one na podejrzenie, co dzieje się „pod maską” naszego przykładu.

Pisanie procedury obsługi

Po pierwsze, konieczne jest napisanie klasy i metody, która ma być uruchamiana zdalnie. Nazywa się ją zazwyczaj procedurą obsługi. Pamiętajmy jednak, że mechanizm XML-RPC obsługujący żą­dania często określany jest taką samą nazwą — znów daje się we znaki dwuznaczność przy­­tego nazewnictwa. Procedura obsługi XML_RPC to metoda lub metody pobierające żądanie XML-RPC, dekodujące jego zawartość i oddelegowujące to żądanie do jakiejś klasy lub metody. Procedura obsługi odpowiedzi, czy też po prostu procedura obsługi, to metoda wywoływana przez procedurę obsługi XML-RPC. Posiadając biblioteki XML-RPC dla Javy, nie musimy pisać procedury obsługi XML-RPC, ponieważ jest już ona zawarta w klasie helma.xmlrpc.Xml­Rpc­Server...

Zgłoś jeśli naruszono regulamin