Aplikacje internetowe i rozproszone dr inż. Maciej Zakrzewicz Instytut Informatyki, Politechnika Poznańska mzakrz@cs.put.poznan.pl http://www.cs.put.poznan.pl/~mzakrz/ Serwery aplikacji Plan wykładów Funkcjonalność serwerów aplikacji Administrowanie serwerem WWW Przetwarzanie danych w aplikacjach internetowych: XPath, parsery DOM, parsery SAX Aplikacje rozproszone w architekturze CORBA Aplikacje rozproszone w architekturze EJB Aplikacje rozproszone w architekturze SOAP Serwer aplikacji Platforma dla uruchamiania komponentów aplikacji wielowarstwowych Odpowiada za obsługę interakcji z klientem (front-end) Odpowiada za obsługę interakcji z DBMS (back-end) Oferuje szereg usług systemowych (transakcje, serwis nazw, połączenia ze źródłami danych, rejestracja wywołań, autoryzacja, szyfrowanie, równoważenie obciążenia, itp.) warstwa komunikacji z klientem warstwa logiki biznesowej warstwa komunikacji z bazą danych klient usługi systemowe baza danych
Serwery aplikacji - przykłady BEA WebLogic: CGI, serwlety Java, JSP, EJB, CORBA, SOAP, SSI IBM WebSphere: CGI, serwlety Java, JSP, EJB, CORBA, SOAP, SSI Oracle Application Server: CGI, serwlety Java, JSP, EJB, CORBA, SOAP, SSI Apache: CGI, SSI Apache Tomcat: CGI, serwlety Java, JSP Orion: serwlety Java, JSP, EJB Administrowanie serwerem WWW Apache Architektura odporna na awarie - przykład Oracle HTTP Server OC4J OC4J Oracle WebCache HTTP Server OC4J OC4J oddzielna maszyna kod aplikacji J2EE replikowany na wszystkich węzłach OC4J Charakterystyka serwera Apache Najpopularniejszy serwer WWW, rozwijany w ramach projektu open source Stanowi podstawę implementacji wielu zaawansowanych serwerów aplikacji (np. Oracle9iAS) Konfiguracja opisana w tekstowym pliku konfiguracyjnym httpd.conf Uruchamianie, zatrzymywanie z wiersza poleceń: apachectl start apachectl restart apachectl stop
Budowa wewnętrzna serwera Apache interfejs HTTP mod_access mod_alias mod_status Prawie cała funkcjonalność serwera Apache jest zaimplementowana w postaci tzw. modułów, statycznie lub dynamicznie linkowanych z rdzeniem serwera. Podstawowe parametry serwera ServerRoot: nazwa katalogu domowego serwera Apache; stosowany jako ścieżka odniesienia dla innych parametrów PidFile: lokalizacja pliku, w którym nadrzędny proces serwera zapisuje swój własny numer procesu DocumentRoot: nazwa katalogu, w którym znajdują się dokumenty HTML udostępniane przez serwer ErrorLog: lokalizacja pliku, w którym zapisywane są komunikaty o błędach obsługi żądań StartServers: liczba równoległych procesów serwera, automatycznie uruchamianych podczas jego startu MaxClients: maksymalna liczba żądań, jakie mogą być obsługiwane współbieżnie MaxSpareServers: maksymalna liczba równoległych procesów serwera, jakie mogą pozostawać bezczynne MinSpareServers: minimalna liczba równoległych procesów serwera, jakie muszą pozostawać bezczynne Plik konfiguracyjny httpd.conf # ServerType is either inetd, or standalone. Inetd mode is only supported on # Unix platforms. ServerType standalone # ServerRoot: The top of the directory tree under which the server's # configuration, error, and log files are kept. ServerRoot "C:\oracle\ora90\Apache\Apache" # PidFile: The file in which the server should record its process # identification number when it starts. PidFile logs/httpd.pid # Timeout: The number of seconds before receives and sends time out. Timeout 300 # KeepAlive: Whether or not to allow persistent connections (more than # one request per connection). Set to "Off" to deactivate. KeepAlive On # MaxKeepAliveRequests: The maximum number of requests to allow # during a persistent connection. Set to 0 to allow an unlimited amount. # We recommend you leave this number high, for maximum performance. MaxKeepAliveRequests 100 Podstawowe parametry serwera - przykład Apache Apache Apache MaxClients=9 Apache Apache Port=80 DocumentRoot=/www/htdocs http://miner:8080/a/b.html MinSpareServers=2 A ServerRoot=/www B.html logs error.log ErrorLog=logs/error.log
Podstawowe parametry serwera KeepAlive: uaktywnia obsługę mechanizmu persistent connections protokołu HTTP 1.1 KeepAliveTimeout: określa maksymalny czas oczekiwania serwera podtrzymującego persistent connection, po upływie którego następuje zamknięcie połączenia HTTP MaxKeepAliveRequests: określa maksymalną liczbę żądań, jakie mogą zostać obsłużone w ramach jednego persistent connection Port: numer głównego portu TCP, na którym serwer nasłuchuje połączeń HTTP (domyślnie 80) Listen: alternatywne adresy IP i numery portów, na których serwer nasłuchuje połączeń HTTP CustomLog: lokalizacja pliku logu, w którym rejestrowane są wszystkie żądania otrzymane przez serwer LogFormat: określa format rekordów zapisywanych do pliku logu DirectoryIndex: nazwa pliku, który zostanie przesłany w odpowiedzi na żądanie z niepełnym adresem URL, np. http://www.abc.com/dir/ Parametry Alias i ScriptAlias Stosowane w celu umożliwienia dostępu do plików spoza DocumentRoot lub w celu skrócenia ścieżki dostępu do zagłębionych podkatalogów. Alias /products/ "C:/others/prodinfo/" http://www.abc.com/products/a.html C:\others\prodinfo\a.html Wszystkie pliki w katalogu zdefiniowanym przy użyciu ScriptAlias są traktowane jako programy CGI ScriptAlias /mycgi/ "C:/cgi/" Parametr LogFormat LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Refereri\" \"%{User-Agenti\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog logs/access.log common Znaczenie symboli: %h: adres IP klienta %l: nazwa użytkownika użyta podczas autoryzacji %u: nazwa użytkownika w systemie klienta %t: czas otrzymania żądania %r: pierwszy wiersz nagłówka żądania HTTP %s: status obsługi żądania (200=OK) %b: rozmiar odpowiedzi w bajtach %{Referer: adres dokumentu, z którego pochodzi link z żądaniem URL %{User-Agent: nazwa programu przeglądarki 150.254.31.11 - - [19/Mar/2003:19:05:35 +0100] "GET /manual/index.html HTTP/1.0" 200 9268 "http://localhost:7778/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" Parametr ErrorDocument ErrorDocument 404 "Przepraszamy, nie posiadamy dokumentu o takim URL ErrorDocument 401 /messages/accessdenied.html
Dyrektywy blokowe <Directory>: ogranicza zasięg parametrów do nazwanego katalogu fizycznego i jego wszystkich podkatalogów <DirectoryMatch>: jak wyżej, lecz zamiast nazwy katalogu podawane jest wyrażenie regularne <Files>: ogranicza zasięg parametrów do plików spełniających podany wzorzec nazwy <FilesMatch>: jak wyżej, lecz zamiast wzorca nazwy pliku podawane jest wyrażenie regularne <Location>: ogranicza zasięg parametrów do nazwanego katalogu wirtualnego <LocationMatch>: jak wyżej, lecz zamiast nazwy katalogu wirtualnego podawane jest wyrażenie regularne <VirtualHost>: ogranicza zasięg parametrów do podanego serwera wirtualnego Dyrektywy blokowe - przykład DirectoryIndex index.html <Directory C:\serv1\htdocs> Options -Indexes </Directory> DirectoryIndex index.html <Directory C:\serv1\htdocs> Options +Indexes </Directory> W przypadku, gdy we wskazanym katalogu nie znajduje się domyślny dokument opisany parametrem DirectoryIndex, serwer WWW może automatycznie wygenerować dokument z zawartością katalogu. Dyrektywy blokowe - przykład NameVirtualHost 150.254.31.10 http://www.abc.com/index.html <VirtualHost 150.254.31.10> ServerName www.abc.com DocumentRoot "C:\serv1\htdocs" C:\serv1\htdocs\index.html CustomLog "C:\serv1\logs\access.log" common ErrorLog "C:\serv1\logs\error.log" </VirtualHost> http://www.xyz.com/index.html <VirtualHost 150.254.31.10> ServerName www.xyz.com DocumentRoot "C:\serv2\htdocs" C:\serv2\htdocs\index.html CustomLog "C:\serv2\logs\access.log" common ErrorLog "C:\serv2\logs\error.log" </VirtualHost> Dzięki zastosowaniu mechanizmu serwerów wirtualnych, jeden fizyczny serwer WWW zachowuje się jak wiele odrębnych, niezależnych serwerów. Rozróżnianie żądań trafiających na ten sam adres IP następuje na podstawie adresów domenowych użytych w URL. Ochrona dostępu wg adresów allow from: określa adresy komputerów, z których możliwy jest dostęp do zasobów serwera deny from: określa adresy komputerów, z których niemożliwy jest dostęp do zasobów serwera order: określa kolejności ewaluacji wyrażeń allow from i deny from <Directory C:\serv1\htdocs\private> order deny, allow deny from all allow from 150.254.31.10 192.168.1.12 </Directory>
Autoryzacja użytkowników i ochrona dostępu Utworzenie pliku haseł htpasswd -c c:\temp\users.pwd scott Ochrona dostępu do katalogu <Directory C:\serv1\htdocs> Automatically using MD5 format on Windows. AuthName "Dostęp tylko dla pracowników" New password: ***** AuthType Basic Re-type new password: ***** AuthUserFile "C:\temp\users.pwd" Adding password for user scott Require user scott </Directory> htpasswd c:\temp\users.pwd guest Automatically using MD5 format on Windows. New password: ****** Re-type new password: ****** Adding password for user guest Przetwarzanie danych w aplikacjach internetowych Bezpieczne połączenia Aktywacja modułu SSL <VirtualHost 150.254.31.10> ServerName www.abc.com DocumentRoot "C:\serv1\htdocs" SSLEngine On SSLCertificateFile conf\ssl.crt\server.crt SSLCertificateKeyFile conf\ssl.key\server.key </VirtualHost> Motywacje: wybrane zastosowania Format przechowywania danych Aplikacja Format sieciowej wymiany danych Aplikacja Aplikacja Źródłowy format danych do prezentacji na różnych platformach HTML Aplikacja WML TXT
Drzewa DOM Przykład struktury drzewa DOM <katalog> <ksiazka isbn="83-7243-134-5"> <tytul> krok po kroku</tytul> <cena>43</cena> <autorzy> <autor>michael J. Young</autor> <autor>katarzyna Tryc</autor> </autorzy> <wydawnictwo>read Me</wydawnictwo> <rok>2000</rok> </ksiazka> </katalog> <ksiazka> <katalog> isbn="83-7243-134-5" <tytul> <cena> <autorzy> <wydawnictwo> <rok> korzeń węzeł elementu krok po kroku 43 <autor> <autor> Read Me 2000 węzeł tekstowy węzeł atrybutu Michael J. Young Katarzyna Tryc Document Object Model (DOM) Document Object Model jest standardem modelowania dokumentów przy użyciu struktury drzewa znaczniki i ich zawartość są modelowane przez węzły drzewa; zagnieżdżanie znaczników służy za podstawę do konstruowania hierarchii Document Object Model jest wykorzystywany jako forma reprezentacji dokumentów w pamięci komputera Transformacja dokumentu do postaci Document Object Model jest realizowana automatycznie przez parser DOM Implementacja, adresowanie i przeszukiwanie drzew Document Object Model mogą być realizowane przy użyciu biblioteki DOM API W3C DOM API: obiekt Node Obiekt klasy/typu Node reprezentuje węzeł w drzewie DOM (węzeł elementu, węzeł tekstowy, itd.) Atrybuty (W3C) Metody (W3C) attributes childnodes firstchild lastchild nextsibling nodename nodetype nodevalue parentnode tablica atrybutów węzła tablica węzłów potomnych pierwszy węzeł potomny ostatni węzeł potomny prawy węzeł sąsiedni nazwa węzła identyfikator typu węzła wartość węzła węzeł nadrzędny appendchild(n) clonenode(b) haschildnodes() insertbefore(n,n) removechild(n) replacechild(n,n) dołącza nowy węzeł jako ostatni węzeł potomny zwraca kopię węzła z/bez węzłami potomnymi zwraca prawdę, jeżeli węzeł zawiera węzły potomne dołącza nowy węzeł jako węzeł potomny przed wskazanym węzłem usuwa wskazany węzeł potomny zamienia istniejący węzeł potomny z podanym węzłem previoussibling lewy węzeł sąsiedni
W3C DOM API: obiekt NodeList Obiekt klasy/typu NodeList reprezentuje zbiór obiektów typu Node Atrybuty (W3C) Metody (W3C) length liczba elementów w zbiorze item(i) zwraca element i-ty element zbioru W3C DOM API: obiekt Element Obiekt klasy/typu Element modeluje węzeł reprezentujący znacznik Atrybuty (W3C) Metody (W3C) tagname nazwa węzła getattribute(s) zwraca wartość podanego atrybutu getattributenode(s) zwraca węzeł podanego atrybutu getelementsbytagname(s) zwraca zbiór węzłów o podanej nazwie removeattribute(s) usuwa wartość podanego atrybutu removeattributenode(n) usuwa podany węzeł atrybutu setattribute(s,s) ustawia nową wartość atrybutu setattributenode(n) wstawia nowy węzeł atrybutu W3C DOM API: obiekt Document Obiekt klasy/typu Document modeluje całe drzewo DOM; wszystkie węzły drzewa są jego potomkami Atrybuty (W3C) Metody (W3C) documentelement doctype element najwyższego poziomu w dokumencie DTD lub Schema dla dokumentu createattribute(s) createcomment(s) createelement(s) createtextnode(s) getelementsbytagname(s) tworzy nowy węzeł atrybutu tworzy nowy węzeł komentarza tworzy nowy element tworzy nowy węzeł tekstowy zwraca zbiór węzłów o podanej nazwie W3C DOM API: obiekt Attr i Text Obiekt klasy/typu Attr reprezentuje atrybut znacznika w formie tzw. węzła atrybutu; obiekt Attr posiada ogólne atrybuty i metody klasy/typu Node plus poniższe: Atrybuty (W3C) name specified value nazwa atrybutu prawda oznacza, że wartość atrybutu jest ustawiona w dokumencie wartość atrybutu Obiekt klasy/typu Text reprezentuje treść umieszczoną wewnątrz znacznika
Implementacja W3C DOM: Java Wszystkie typy DOM zostały zaimplementowane w języku Java jako interfejsy w pakiecie org.w3c.dom (posiadają nazwy jak w specyfikacji W3C) i jako klasy rzeczywiste w pakiecie oracle.xml.parser.v2 (posiadają nazwy z prefiksem ) Konstrukcja drzewa DOM w języku Java Document xmldoc = new Document(); Node katalognode = xmldoc.createelement("katalog"); xmldoc.appendchild(katalognode); Node ksiazkanode = xmldoc.createelement("ksiazka"); katalognode.appendchild(ksiazkanode); <katalog> Node tytulnode = xmldoc.createelement("tytul"); ksiazkanode.appendchild(tytulnode); <ksiazka> Node tytultext = xmldoc.createtextnode("zaawansowany "); tytulnode.appendchild(tytultext); <tytul> <cena> Node cenatext = xmldoc.createtextnode("85"); tytulnode.appendchild(tytultext); Zaawansowany 85 Java: funkcje konstrukcji drzew DOM createelement(string) [interfejs Document] tworzy nowy węzeł, reprezentujący znacznik o podanej nazwie; węzeł ten nie wchodzi jeszcze w skład drzewa dokumentu createtextnode(string) [interfejs Document] tworzy nowy węzeł tekstowy; węzeł ten nie wchodzi jeszcze w skład drzewa dokumentu appendchild(node) [interfejs Node] dodaje nowy węzeł jako ostatni węzeł potomny clonenode(boolean) [interfejs Node] wykonuje kopię wskazanego węzła wraz z lub bez jego węzłów potomnych removechild(node) [interfejs Node] odpina wskazany węzeł potomny od jego węzła nadrzędnego replacechild(node, Node) [interfejs Node] odpina istniejący węzeł potomny i na jego miejscu umieszcza nowy węzeł potomny setnodevalue(string) [interfejs Node] nadaje węzłowi wartość tekstową Java: funkcje nawigacyjne DOM API getdocumentelement() [interfejs Document] zwraca obiekt węzła reprezentującego znacznik najwyższego poziomu getelementsbytagname(string) [interfejs Document] zwraca tablicę obiektów węzłów reprezentujących podany znacznik getchildnodes() [interfejs Node] zwraca tablicę obiektów węzłów potomnych (bez węzłow atrybutowych) getattributes() [interfejs Node] zwraca tablicę obiektów potomnych węzłów atrybutowych getnodename() [interfejs Node] zwraca nazwę znacznika dla węzła getnodetype() [interfejs Node] zwraca numeryczny identyfikator typu węzła getnodevalue() [interfejs Node] zwraca treść węzła (tylko dla węzłów tekstowych) getfirstchild() [interfejs Node] - zwraca obiekt pierwszego węzła potomnego (z pominięciem węzłów atrybutowych) getlastchild() [interfejs Node] - zwraca obiekt ostatniego węzła potomnego (z pominięciem węzłów atrybutowych) getnextsibling() [interfejs Node] zwraca obiekt prawego sąsiada węzła (z pominięciem węzłów atrybutowych) getprevioussibling() [interfejs Node] zwraca obiekt lewego sąsiada węzła (z pominięciem węzłów atrybutowych) getparentnode() [interfejs Node] zwraca obiekt węzła nadrzędnego
DOM API: funkcje nawigacyjne #document D katalog E getdocumentelement() getchildnodes() getnodename() książka E getattributes() getchildnodes() isbn A 14-2887- tytul E #text T C++ autorzy E autor E #text T Fabio Arc getnodevalue() getchildnodes() rokwydania E #text T 2002 wydawnictwo E #text T Mikom cena E #text T 36 D DOCUMENT_NODE (9) E ELEMENT_NODE (1) A ATTRIBUTE_NODE (2) T TEXT_NODE (3) Java: nawigacja w drzewie DOM getchildnodes() Wyświetl tytuły wszystkich książek opisanych w dokumencie Document xmldoc; Node docnode = null, booknode = null, elementnode = null; Access 2002. Projektowanie baz NodeList docnodelist = null, booknodelist = null; danych. Księga eksperta try { Access 2002/XP PL dla każdego ASP.NET. Vademecum profesjonalisty docnode = xmldoc.getdocumentelement(); C++ docnodelist = docnode.getchildnodes(); Dane w sieci WWW for (int i=0; i<docnodelist.getlength(); i++) { Delphi 6. Praktyka programowania - tom 1,2 booknode = docnodelist.item(i); Delphi. Almanach booknodelist = booknode.getchildnodes(); for (int j=0; j<booknodelist.getlength(); j++) { elementnode = booknodelist.item(j); if (elementnode.getnodename().equals("tytul")) System.out.println(elementNode.getFirstChild().getNodeValue()); catch (Exception e) {System.out.println(e); Java: prosta nawigacja w drzewie DOM Document d e=d.getdocumentelement() Odczytaj węzeł reprezentujący znacznik najwyższego poziomu (np. <katalog>) c=e.getchildnodes() Pobierz listę elementów potomnych f=c.item(i) W pętli odczytuj kolejne węzły z listy (np. <ksiazka>) f.getnodename(), f.getnodevalue(), Przetwarzaj węzeł f.getnodetype() g=f.getchildnodes() Pobierz listę elementów potomnych h=g.item(j) Odczytaj kolejny węzeł z listy (np. <tytul>,<autorzy>,<cena>,<rok>, <wydawnictwo>) Java: nawigacja w drzewie DOM getattributes() Wyświetl wartość pierwszego atrybutu każdego znacznika <ksiazka> w dokumencie Document xmldoc; Node docnode = null, booknode = null, urlnode = null; NodeList docnodelist = null, booknodelist = null; try { docnode = xmldoc.getdocumentelement(); docnodelist = docnode.getchildnodes(); for (int i=0; i<docnodelist.getlength(); i++) { booknode = docnodelist.item(i); urlnode = booknode.getattributes().item(0); System.out.println(urlNode.getNodeValue()); catch (Exception e) {System.out.println(e); 83-7197-669-0 83-7197-786-7 83-7197-691-7 83-7279-215-1 83-7279-149-X 83-7279-214-3 83-7197-469-8 83-7197-377-2
Java: nawigacja w drzewie DOM getelementsbytagname() Wyświetl tytuły wszystkich książek opisanych w dokumencie ASP.NET. Vademecum profesjonalisty Document xmldoc; C++ Dane w sieci WWW Node titlenode = null; Delphi 6. Praktyka programowania - tom 1,2 NodeList titlenodelist = null; Delphi. Almanach try { titlenodelist = xmldoc.getelementsbytagname("tytul"); for (int i=0; i<titlenodelist.getlength(); i++) { titlenode = titlenodelist.item(i); System.out.println(titleNode.getFirstChild().getNodeValue()); catch (Exception e) {System.out.println(e); Access 2002. Projektowanie baz danych. Księga eksperta Access 2002/XP PL dla każdego Język XPath Java: konwersja drzewa DOM do pliku try { xmldoc.print(new FileOutputStream("C:\\katalog.xml")); catch (Exception e) {System.out.println(e); <?xml version = '1.0' encoding = 'WINDOWS-1250'?> <katalog> <ksiazka isbn="83-7197-669-0"> <tytul>c++ </tytul> <autorzy> <autor>fabio Arciniegas</autor> </autorzy> <rokwydania>2002</rokwydania> <wydawnictwo>mikom</wydawnictwo> <cena>36</cena> </ksiazka> <ksiazka isbn="83-7197-669-0"> Język XPath XPath to specyfikacja języka służącego do adresowania, odczytywania i przeszukiwania drzew DOM dokumentów XPath odgrywa podobną rolę w stosunku do drzew DOM, jak język SQL w stosunku do relacyjnych baz danych XPath stosuje notację przypominającą ścieżki dostępu w systemach plików Wynikiem ewaluacji wyrażenia XPath jest zbiór węzłów spełniających warunki selekcji XPath pozwala stosować dwa rodzaje zapisu wyrażeń: skrócony i pełny; rodzaje te mogą być mieszane
Przetwarzanie wyrażeń XPath Wyrażenie XPath Skrócone wyrażenia XPath (2/3) Wybór węzłów, które posiadają podany węzeł potomny: wybierz książki, które posiadają autorów //ksiazka[autorzy] wybierz książki, które napisał Serge Abiteboul //ksiazka[autorzy/autor="serge Abiteboul"] Alternatywa ścieżek: wybierz tytuły książek i wydawnictwa //tytul //wydawnictwo wybierz tytuły książek napisanych przez Serge'a Abiteboula lub Kurta Walla //tytul[..//autor="serge Abiteboul"] //tytul[..//autor="kurt Wall"] Skrócone wyrażenia XPath (1/3) Wybór węzłów w drzewie DOM: wybierz autorów wszystkich książek /katalog/ksiazka/autorzy wybierz wszystkie wydawnictwa dowolnie zagłębione w drzewie //wydawnictwo wybierz wszystkie węzły potomne (dzieci) każdego węzła książka //ksiazka/* Wybór n-tego węzła danego rodzaju: wybierz pierwszego autora każdej książki //autorzy/autor[1] wybierz drugiego autora pierwszej książki //ksiazka[1]//autor[2] wybierz ostatnią książke //ksiazka[last()] Skrócone wyrażenia XPath (3/3) Wybór węzłów zawierających atrybuty: wybierz książkę o numerze ISBN "83-7279-149-X" //ksiazka[@isbn="83-7279-149-x"] wybierz wszystkie numery ISBN //@isbn wybierz książki, które posiadają numer ISBN //ksiazka[@isbn] Odczyt treści węzła: odczytaj treści wszystkich tytułów książek //ksiazka/tytul/text()
Pełne wyrażenia XPath Wyrażenie ścieżkowe XPath składa się z tzw. kroków rozdzielonych ukośnikami W pełnym zapisie, każdy z kroków może składać się z: specyfikatora współrzędnych (axis), służącego do określenia miejsca w drzewie, począwszy od którego wyszukiwane będą węzły testu węzła (node test), służącego do określenia, które węzły są wyszukiwane w obszarze drzewa określonym przez specyfikator współrzędnych predykatów, dodatkowo zawężających test węzła, powodujących wybór tylko tych węzłów, które spełniają podany warunek Każdy krok pełnego wyrażenia XPath zapisywany jest przy użyciu następującej notacji: spec_współrzędnych::test_węzła[predykaty] Testy węzłów, operatory i funkcje node() dowolny węzeł text() węzeł tekstowy * dowolny element @* dowolny atrybut nazwa węzeł o podanej nazwie =,!=, <, >, <=, >= porównania or, and operatory logiczne +, -, *, div, mod operatory arytmetyczne count() liczba węzłów wybieranych przez wyrażenie last() liczba porządkowa ostatniego węzła wybieranego przez wyrażenie name() nazwa węzła wybieranego przez wyrażenie position() liczba porządkowa węzła wybieranego przez wyrażenie not() negacja logiczna true() zwraca prawdę logiczną false() zwraca fałsz logiczny Specyfikatory współrzędnych ancestor ancestor-or-self attribute child descendant obejmuje wszystkie węzły nadrzędne (ojciec, dziadek, itd.) bieżącego węzła obejmuje bieżący węzeł plus wszystkie węzły nadrzędne obejmuje wszystkie atrybuty bieżącego węzła obejmuje wszystkie węzły bezpośrednio podrzędne bieżącego węzła (dzieci) obejmuje wszystkie węzły podrzędne (syn, wnuk, itd.) bieżącego węzła descendant-or-self following following-sibling parent preceding preceding-sibling self obejmuje bieżący węzeł plus wszystkie węzły podrzędne obejmuje wszystkie węzły, które w dokumencie następują za węzłem bieżącym obejmuje wszystkie węzły sąsiednie, które w dokumencie następują za węzłem bieżącym obejmuje węzeł bezpośrednio nadrzędny bieżącego węzła (ojciec) obejmuje wszystkie węzły, które w dokumencie następują przed węzłem bieżącym obejmuje wszystkie węzły sąsiednie, które w dokumencie następują przed węzłem bieżącym obejmuje bieżący węzeł Funkcje - ciąg dalszy Funkcje operujące na tekstach concat() konkatenacja tekstów contains() starts-with() string() string-length() substring() substring-after() substring-before() translate() test zawierania tekstów sprawdzenie, czy tekst rozpoczyna się od podanego ciągu konwersja do tekstu długość tekstu ekstrakcja podciągu znaków zwraca ciąg znaków znajdujący się za wycinanym podciągiem zwraca ciąg znaków znajdujący się przed wycinanym podciągiem dokonuje zamiany wszystkich wystąpień podanego podciągu Funkcje operujące na liczbach ceiling() górne domknięcie całkowite floor() dolne domknięcie całkowite number() konwersja do liczby round() zaokrąglenie sum() suma zbioru wartości liczbowych
Przykłady wyrażeń XPath (1/2) Wybierz książki, których cena nie przekracza 20 zł //ksiazka[cena<=20] Wybierz tytuły książek o cenach w przedziale 30-40 zł //ksiazka/tytul[../cena>30 and../cena<40] Wybierz książki napisane przez więcej niż dwóch autorów //ksiazka[count(autorzy/autor)>2] Wybierz co drugą książkę //ksiazka[position() mod 2 = 1] Wybierz książki zawierające w tytule słowo //ksiazka[contains(tytul,"")] Wybierz autorów o imieniu "Stephen" //autor[starts-with(.,"stephen")] Wybierz tytuły złożone z ponad 20 znaków //tytul[string-length(.)>20] Transformacja wyrażeń skróconych do pełnych skrócone pełne przykład brak @ child:: attribute:: self::node() //ksiazka/cena => //ksiazka/child::cena //katalog/ksiazka[@isbn= "83-7197-786-7"] => //katalog/child::ksiazka[attribute::isbn= "83-7197-786-7"] //tytul[string-length(.)>10] => //tytul[string-length(self::node())>10]... parent::node() //autor/.. => //autor/parent::node() // /descendant-orself::node() //tytul => /descendant-or-self::node() Przykłady wyrażeń XPath (2/2) Wybierz książki, których numer ISBN spełnia wzorzec ***7197****** //ksiazka[substring(@isbn,4,4) = "7197"] Wybierz wszystkie węzły autorzy oraz wszystkie ich węzły potomne //autorzy/descendant-or-self::* Wybierz wszystkie książki, które w dokumencie znajdują się za książką o numerze ISBN "83-7197-786-7" //ksiazka[@isbn="83-7197-786-7"]/following::ksiazka Wybierz wszystkie atrybuty pierwszej książki //ksiazka[1]/attribute::* Wybierz cenę książki pt. " dla każdego" //ksiazka[tytul=" dla każdego"]/child::cena Funkcje XPath w DOM API Java selectnodes(string) [interfejs Node] zwraca tablicę obiektów węzłów spełniających podaną ścieżkę XPath selectsinglenode(string) [interfejs Node] zwraca pierwszy znaleziony obiekt węzła spełniającego podaną ścieżkę XPath valueof(string) [interfejs Node] zwraca treść pierwszego znalezionego obiektu węzła spełniającego podaną ścieżkę XPath
Java: zapytania XPath Wyświetl tytuły wszystkich książek wydanych w roku 2002 Document xmldoc; Node titlenode = null; NodeList querynodelist = null; C++ Flash i. Techniki zaawansowane HTML and dla początkujących Programowanie Microsoft SQL Server 2000 z Vademecum Kompendium programisty try { querynodelist = xmldoc.selectnodes("//ksiazka[rokwydania='2002']/tytul"); for (int i=0; i<querynodelist.getlength(); i++) { titlenode = querynodelist.item(i); System.out.println(titleNode.getFirstChild().getNodeValue()); catch (Exception e) {System.out.println(e); Java: zapytania XPath Wyświetl nazwisko pierwszego autora książki pt. "Java i " Brett McLaughlin try { System.out.println(xmlDoc.valueOf("//ksiazka[tytul='Java i ']//autor")); catch (Exception e) {System.out.println(e); Java: zapytania XPath Wyświetl tytuły wszystkich książek, których jeden z autorów ma imię "Fabio" Document xmldoc; Node titlenode = null; NodeList querynodelist = null; C++ Kompendium programisty try { querynodelist = xmldoc.selectnodes("//tytul[../autorzy[contains(autor,'fabio')]]"); for (int i=0; i<querynodelist.getlength(); i++) { titlenode = querynodelist.item(i); System.out.println(titleNode.getFirstChild().getNodeValue()); catch (Exception e) {System.out.println(e); Wykorzystywanie parsera DOM w programach Java
Parser DOM Aplikacja DOM API Parser DOM Dokument Drzewo DOM Parser DOM dokonuje przekształcenia dokumentu w drzewo DOM. Dostęp do funkcji parsera odbywa się w ramach interfejsu DOM API. Parser DOM jest dostępny w formie bibliotek programistycznych, m.in. Java (oracle.xml.parser.v2) Java: proces parsowania dokumentu new DOMParser() DOMParser.parse() DOMParser.getDocument() przetwarzanie drzewa DOM DOM API: struktura fizyczna drzewa DOM getdocument() #document D getdocumentelement() katalog E getchildnodes() getnodename() książka E getattributes() getchildnodes() isbn A 14-2887- tytul E autorzy E rokwydania E getchildnodes() #text T autor E #text T C++ 2002 #text T Fabio Arc getnodevalue() wydawnictwo E #text T Mikom cena E #text T 36 D DOCUMENT_NODE (9) E ELEMENT_NODE (1) A ATTRIBUTE_NODE (2) T TEXT_NODE (3) Java: konwersja pliku do drzewa DOM import org.w3c.dom.*; import oracle.xml.parser.v2.*; DOMParser dp = new DOMParser(); Node titlenode = null; NodeList titlenodelist = null; Document xmldoc = null; C++ Flash i. Techniki zaawansowane HTML and dla początkujących Java i Nauka języka Po prostu Poznaj w 24 godziny Programowanie Microsoft SQL Server 2000 z Vademecum Kompendium programisty dla każdego try { dp.parse("file://c:/katalog.xml"); catch (Exception e) {System.out.println(e); try { xmldoc = dp.getdocument(); titlenodelist = xmldoc.getelementsbytagname("tytul"); for (int i=0; i<titlenodelist.getlength(); i++) { titlenode = titlenodelist.item(i); System.out.println(titleNode.getFirstChild().getNodeValue()); catch (Exception e) {System.out.println(e);
Java: parsowanie zmiennej String import org.w3c.dom.*; import oracle.xml.parser.v2.*; import java.io.*; DOMParser dp = new DOMParser(); Node titlenode = null; NodeList titlenodelist = null; Document xmldoc = null; Zaawansowany SQL/ try { dp.parse(new StringReader("<katalog><ksiazka><tytul>Zaawansowany </tytul>"+ "</ksiazka><ksiazka><tytul>sql/</tytul></ksiazka></katalog>")); catch (Exception e) {System.out.println(e); try { xmldoc = dp.getdocument(); titlenodelist = xmldoc.getelementsbytagname("tytul"); for (int i=0; i<titlenodelist.getlength(); i++) { titlenode = titlenodelist.item(i); System.out.println(titleNode.getFirstChild().getNodeValue()); catch (Exception e) {System.out.println(e); Parser DOM: przekształcenia XSLT (Java) import org.w3c.dom.*; import oracle.xml.parser.v2.*; import java.net.*; XSLProcessor xslproc = new XSLProcessor(); XSLStylesheet xsl = xslproc.newxslstylesheet(new URL( "file://c:/messages.xsl")); DOMParser parser = new DOMParser(); parser.parse("file://c:/messages.xml"); Document xmldoc = parser.getdocument(); DocumentFragment htmldoc = xslproc.processxsl(xsl, xmldoc); htmldoc.print(system.out); Parser DOM: przekształcenia XSLT (Java) new DOMParser() DOMParser.parse() DOMParser.getDocument() new XSLProcessor() XSLProcessor.newXSLStylesheet() XSLProcessor.processXSL() przetwarzanie drzewa wynikowego Przykładowa aplikacja jako internetowa baza danych (DOM API, XSLT) XSL
Przykładowa aplikacja jako internetowa baza danych Serwlet Java <?xml version = '1.0' encoding = 'WINDOWS-1250'?> <wiadomosci> <wpis> <autor>znowicki</autor> <tytul>problem z wyświetlaniem polskich znaków</tytul> <tekst>w aplikacji pobory.fmx nie wyświetlają się polskie znaki w polu przyczyna.</tekst> </wpis> <wpis> Przykładowa aplikacja Dodawanie nowych wpisów przez serwlet String autor, tytul, tekst; Document xmldoc; DOMParser dp = new DOMParser(); Node nowy_tytul_txt = xmldoc.createtextnode(tytul); Node nowy_tekst_txt = xmldoc.createtextnode(tekst); nowy_autor.appendchild(nowy_autor_txt); autor = request.getparameter("autor"); tytul = request.getparameter("tytul"); tekst = request.getparameter("tekst"); try { dp.parse("file://c:/messages.xml"); xmldoc = dp.getdocument(); Node wiadomosci = xmldoc.getdocumentelement(); Node nowy_wpis = xmldoc.createelement("wpis"); nowy_tytul.appendchild(nowy_tytul_txt); nowy_tekst.appendchild(nowy_tekst_txt); nowy_wpis.appendchild(nowy_autor); nowy_wpis.appendchild(nowy_tytul); nowy_wpis.appendchild(nowy_tekst); wiadomosci.appendchild(nowy_wpis); xmldoc.print(new FileOutputStream("C:\\messages.xml")); catch (Exception e) {System.out.println(e); Node nowy_autor = xmldoc.createelement("autor"); Node nowy_tytul = xmldoc.createelement("tytul"); Node nowy_tekst = xmldoc.createelement("tekst"); Node nowy_autor_txt = xmldoc.createtextnode(autor); Przykładowa aplikacja Struktura dokumentu i drzewo DOM <?xml version = '1.0' encoding = 'WINDOWS-1250'?> <wiadomosci> <wpis> <autor>znowicki</autor> <tytul>problem z wyświetlaniem polskich znaków</tytul> <tekst>w aplikacji pobory.fmx nie wyświetlają się polskie znaki w polu przyczyna.</tekst> </wpis> <wpis> </wpis> wiadomosci wpis wpis </wiadomosci> autor tytul tekst autor tytul tekst #text zno #text Pro #text W a #text aks #text Kie #text Cze Przykładowa aplikacja Zastosowanie XSLT do prezentacji zawartości dokumentu response.setcontenttype("text/html"); PrintWriter out = response.getwriter(); xsl = new XSLStylesheet(xslDoc, xslurl); htmldoc = processor.processxsl(xsl, xmldoc); URL xmlurl, xslurl; Document xmldoc, xsldoc, result; XSLStylesheet xsl; DocumentFragment htmldoc; result = new Document(); result.appendchild(htmldoc); result.print(out); catch (Exception e) {out.println(e); XSLProcessor processor = new XSLProcessor(); DOMParser dp = new DOMParser(); try { xmlurl = new URL("file://C:/messages.xml"); xslurl = new URL("file://C:/messages.xsl"); dp.parse(xmlurl); xmldoc = dp.getdocument(); dp.parse(xslurl); xsldoc = dp.getdocument();
Przykładowa aplikacja Arkusz stylistyczny XSL <?xml version="1.0" encoding="windows-1250"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" version="1.0"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <meta http-equiv="content-type" content="text/html;charset=windows-1250"/> <title>wiadomości</title> </head> <body> <h2>wykaz wszystkich wiadomości</h2> <table border="1"> <tr> <th>nadawca</th> <th>tytuł</th> <th>tekst</th> </tr> <xsl:for-each select="/wiadomosci/wpis"> <tr> <td><xsl:value-of select="autor"/></td> <td><xsl:value-of select="tytul"/></td> <td><xsl:value-of select="tekst"/></td> </tr> </xsl:for-each> </table> <br/> <a href="../xmlform.html">nowy wpis</a> </body> </html> </xsl:template> </xsl:stylesheet> Parser SAX i SAX API SAX API to interfejs programistyczny wykorzystujący model zdarzeniowy do budowy parserów dokumentów Parser SAX odczytuje wskazany dokument i dla każdego zidentyfikowanego elementu składniowego wywołuje standardowe metody obiektu klasy przygotowanej przez programistę SAX API umożliwia konwersję dokumentu do dowolnej struktury danych, a nie wyłącznie do drzewa DOM Zadaniem programisty jest przygotowanie klasy dziedziczącej z DocumentHandler i oprogramowanie jej metod: startdocument() / enddocument() startelement() / endelement() characters() Wykorzystywanie parsera SAX w programach Java Parser SAX Parser SAX Dokument Klasa przetwarzania dokumentu Aplikacja
Sekwencja wywoływania metod klasy DocumentHandler <?xml version="1.0" encoding="windows-1250"?> startdocument() <katalog> <ksiazka url="http://dot.com/19821.html"> <tytul> C++ </tytul> <autorzy> <autor> Fabio Arciniegas startelement("katalog") startelement("ksiazka","http:/") startelement("tytul") characters("c++ ") endelement("tytul") startelement("autorzy") startelement("autor") characters("fabio Arciniegas") </autor> </autorzy> endelement("autor") endelement("autorzy") </katalog> endelement("katalog") enddocument() Wykorzystanie klasy DocumentHandler 1. Utwórz obiekt własnej klasy przetwarzania dokumentu 2. Utwórz obiekt parsera SAX (klasa SAXParser) 3. Za pomocą metody "setdocumenthandler" przyłącz obiekt własnej klasy przetwarzania dokumentu do obiektu parsera 4. Wywołaj metodę "parse" obiektu parsera, przekazując jej adres URL przetwarzanego dokumentu import org.xml.sax.*; import oracle.xml.parser.v2.*; MyHandler handler = new MyHandler(); Parser parser = new SAXParser(); parser.setdocumenthandler(handler); parser.parse("file://c:/katalog.xml"); Implementacja klasy DocumentHandler import org.xml.sax.*; public class MyHandler extends HandlerBase { public void startelement(string name, AttributeList atts) { // metoda wywoływana gdy parser SAX natrafi na znacznik otwierający // name nazwa znacznika, atts lista nazw i wartości atrybutów public void endelement(string name) { // metoda wywoływana gdy parser SAX natrafi na znacznik zamykający // name nazwa znacznika public void characters(char ch[], int start, int length) { String value = new String(ch, start, length); // metoda wywoływana gdy parser SAX zakończy odczyt treści znacznika // value odczytana treść Przykładowa aplikacja Dokument <?xml version="1.0" encoding="windows-1250"?> <katalog> <ksiazka isbn="83-7279-215-1"> <tytul>c++ </tytul> <autorzy> <autor>fabio Arciniegas</autor> </autorzy> <rok>2002</rok> <wydawnictwo>mikom</wydawnictwo> <cena>36</cena> </ksiazka> <ksiazka isbn="83-4579-335-1"> </ksiazka> </katalog>
Przykładowa aplikacja Model obiektowy Vector katalog Ksiazka String tytul Vector autorzy String wydawnictwo int rok float cena Ksiazka String tytul Vector autorzy String wydawnictwo int rok float cena Przykładowa aplikacja Klasa przetwarzania dokumentu (1/2) import org.xml.sax.*; import java.util.*; public class KatalogHandler extends HandlerBase { Vector katalog = new Vector(); Ksiazka tmp; int curr_tag; static final int TYTUL_TAG = 1; static final int ROK_TAG = 2; static final int WYDAWNICTWO_TAG = 3; static final int CENA_TAG = 4; static final int AUTOR_TAG = 5; public Vector getkatalog() { return katalog; public void startelement(string name, AttributeList atts) { if (name.equals("ksiazka")) { tmp = new Ksiazka(); else if (name.equals("tytul")) { curr_tag = TYTUL_TAG; else if (name.equals("rok")) { curr_tag = ROK_TAG; else if (name.equals("cena")) { curr_tag = CENA_TAG; Ksiazka String tytul Vector autorzy String wydawnictwo int rok float cena Przykładowa aplikacja Implementacja modelu obiektowego import java.util.*; public class Ksiazka extends Object { String tytul; Vector autorzy = new Vector(); String wydawnictwo; int rok; float cena; public void settytul(string t) { tytul = t; public void setwydawnictwo(string w) { wydawnictwo = w; public void setrok(int r) { rok = r; public void setcena(float c) { cena = c; public void addautor(string a) { autorzy.add(a); public String gettytul() { return tytul; public String getwydawnictwo() { return wydawnictwo; public int getrok() { return rok; public float getcena() { return cena; public int getnumautor() { return autorzy.size(); public String getautor(int i) { return (String)autorzy.get(i); Przykładowa aplikacja Klasa przetwarzania dokumentu (2/2) else if (name.equals("autor")) { curr_tag = AUTOR_TAG; else if (name.equals("wydawnictwo")) { curr_tag = WYDAWNICTWO_TAG; public void endelement(string name) { if (name.equals("ksiazka")) { katalog.add(tmp); public void characters(char ch[], int start, int length) { String value = new String(ch, start, length); switch (curr_tag) { case TYTUL_TAG: tmp.settytul(value); break; case AUTOR_TAG: tmp.addautor(value); break; case WYDAWNICTWO_TAG: tmp.setwydawnictwo(value); break; case ROK_TAG: tmp.setrok(integer.parseint(value)); break; case CENA_TAG: tmp.setcena(float.parsefloat(value)); break;
Przykładowa aplikacja Wykorzystanie parsera SAX import org.xml.sax.*; import oracle.xml.parser.v2.*; import java.util.*; public class PrintKatalog { public static void main(string[] args) { try { KatalogHandler handler = new KatalogHandler(); C++, Mikom, 2002 Flash i. Techniki zaawansowane, Helion, 2002 HTML and dla początkujących, Promise, 2002 Java i, Helion, 2001 Nauka języka, Read Me, 2001 Po prostu, Helion, 2001 Common Object Request Broker Architecture - CORBA Parser parser = new SAXParser(); parser.setdocumenthandler(handler); parser.parse("file://c:/katalog.xml"); Vector katalog = handler.getkatalog(); for (int i=0; i<katalog.size(); i++) { Ksiazka k = (Ksiazka)katalog.elementAt(i); System.out.println(k.getTytul()+", "+k.getwydawnictwo()+", "+k.getrok()); catch (Exception e) {System.out.println(e); Architektura CORBA CORBA - przykład aplikacji (1/4) Jedna z pierwszych architektur budowy heterogenicznych rozproszonych aplikacji komponentowych Specyfikacja obejmuje architekturę oraz język opisu interfejsów - IDL (Interface Description Language) Aplikacje CORBA składają się z programu klienta, współpracującego z programami serwerów poprzez warstwę komunikacyjną ORB (Object Request Broker) Opis interfejsu w języku IDL interface Multiplier { struct Factors { float val1; float val2; float multiply(in Factors factors); Serwer Klient Client Proxy wg IDL Szkielet serwera wg IDL Object Adapter IDL nie jest w pełni funkcjonalnym językiem programowania. Zawiera jedynie polecenia umożliwiające deklarowanie typów danych oraz metod. Object Request Broker
CORBA - przykład aplikacji (2/4) Client Proxy IDL automatyczna generacja Szkielet serwera Wygenerowany szkielet serwera class Multiplier_i { public: float multiply(const Factors &factors, CORBA::Environment &); Implementacja metod serwera float Multiplier_i::multiply(const Factors &factors, CORBA::Environment &) { return factors.val1 * factors.val2; CORBA - przykład aplikacji (4/4) Wygenerowane Client Proxy typedef Multiplier *MultiplierRef; Aplikacja klienta int main(void) { MultiplierRef multiplier; class Multiplier : public virtual CORBA::Object { Factors factors; public: static Multiplier *_bind(/* różne wersje wiązań */); multiplier = Multiplier::_bind(); virtual float multiply(const Factors &factors, factors.val1 = 2; CORBA::Environment &); factors.val2 = 3; try { cout << multiplier->multiply(factors); catch () { return 0; CORBA - przykład aplikacji (3/4) Kod aplikacji serwera int main(void) { Multiplier_i miltiplier(); try { CORBA::Orbix.impl_is_ready("Multiplier"); catch () { return 0; Rejestracja serwera % putit Logger /usr/svcs/multiplier.exe Enterprise JavaBeans
Enterprise JavaBeans Specyfikacja Enterprise JavaBeans definiuje architekturę i metodę budowy rozproszonych komponentów obiektowych uruchamianych po stronie serwera aplikacji Komponenty EJB są wykorzystywane do budowy złożonych aplikacji rozproszonych na zasadzie składania z klocków Kontener EJB Bezpośrednim środowiskiem uruchomieniowym dla każdego komponentu Enterprise JavaBeans jest kontener EJB Kontener EJB całkowicie pośredniczy w komunikacji pomiędzy komponentem EJB a światem zewnętrznym Kontener EJB oferuje komponentowi szereg usług o charakterze systemowym: ochrona dostępu, obsługa transakcji, itp. Komponent EJB może uzyskać dostęp do usług kontenera EJB korzystając z mechanizmu typu callback - w chwili powoływania do życia obiektu komponentu EJB, kontener EJB przekazuje komponentowi EJB pewien rodzaj uchwytu zwrotnego; za pomocą tego uchwytu obiekt komponentu EJB może wykonywać wywołania metod kontenera EJB Ogólna architektura EJB serwer aplikacji kontener EJB aplikacja klienta wywołania metod wyniki metod komponent EJB Program Java realizowany w technologii Enterprise JavaBeans składa się z dwóch rodzajów elementów składowych: lokalnej aplikacji klienta i zdalnych komponentów przetwarzania danych. Aplikacja klienta komunikuje się poprzez sieć komputerową z komponentami przetwarzania danych, przesyłając do nich żądania zdalnego wykonania metod. Wyniki działania tych metod są następnie tą samą drogą odsyłane do aplikacji klienta. Typy komponentów EJB Specyfikacja Enterprise JavaBeans 2.0 definiuje trzy typy komponentów EJB: sesyjne (Session Bean): sesyjny komponent EJB to krótkotrwały obiekt wykorzystywany przez pojedynczą aplikację klienta i nie współdzielony z innymi aplikacjami, stanowiący logiczne rozszerzenie kodu aplikacji klienta umieszczone po stronie serwera aplikacji encyjne (Entity Bean): encyjny komponent EJB reprezentuje dane, które są trwale przechowywane w systemie bazy danych; cechuje się długim czasem życia, pozwala na atomowe, transakcyjne modyfikacje bazy danych, współdzielony przez wielu klientów, dostępny dla wielu sesji komunikatowe (Message-Driven Bean): komunikatowy komponent EJB jest asynchronicznym konsumentem komunikatów JMS (Java Messaging Service) pochodzących ze środowisk kolejkowych; uruchamiany wtedy, kiedy nadchodzi komunikat od klienta, wykonywany asynchronicznie, może modyfikować zawartość bazy danych, bezstanowy
Ogólny proces tworzenia komponentu EJB Przygotowanie kodu źródłowego klasy Java, reprezentującej komponent EJB Utworzenie dwóch interfejsów Java, reprezentujących punkty kontaktu świata zewnętrznego z komponentem EJB: interfejs Home, służący do zarządzania cyklem życia komponentu EJB interfejs Remote/Local, służący do wywoływania metod logiki biznesowej komponentu EJB Przygotowanie -owego pliku konfiguracyjnego - deskryptora instalacji (Deployment Descriptor) Kompilacja całego przygotowanego kodu Java i utworzenie z niego pliku JAR/EAR o specjalnej wewnętrznej strukturze katalogów Umieszczenie przygotowanych plików w systemie plików serwera aplikacji; zarejestrowanie komponentu EJB Przykład Tworzenie sesyjnego komponentu EJB (1/5) Interfejs Remote import javax.ejb.ejbobject; import java.rmi.remoteexception; public interface Multiplicator1Remote extends EJBObject { float multiply(float factor1, float factor2) throws RemoteException; Interfejs Remote deklaruje metody komponentu EJB, które będą dostępne dla zdalnej aplikacji klienta. Metody te muszą zostać zaimplementowane przez programistę w klasie komponentu EJB. Sesyjne komponenty EJB Traktowane jako logiczna kontynuacja kodu aplikacji klienta, fizycznie zlokalizowana jednak po stronie serwera aplikacji Żyją jedynie przez czas trwania sesji aplikacji klienta Ich zastosowanie przypomina klasyczne rozwiązania mechanizmów zdalnego wołania procedury RPC Dwa rodzaje sesyjnych komponentów EJB: stanowe (stateful) komponenty EJB są przez cały czas życia skojarzone z jedną i tą samą aplikacją klienta i pamiętają swój stan obiektu bezstanowe (stateless) sesyjne komponenty EJB nie gwarantują pamiętania swojego stanu obiektu i mogą być przy każdym wywołaniu wykorzystywane przez inną aplikację klienta Przykład Tworzenie sesyjnego komponentu EJB (2/5) Interfejs Home import javax.ejb.ejbhome; import java.rmi.remoteexception; import javax.ejb.createexception; public interface Multiplicator1Home extends EJBHome { Multiplicator1Remote create() throws RemoteException, CreateException; Interfejs Home deklaruje metody zarządzania cyklem życia komponentu EJB, które będa dostępne dla zdalnej aplikacji klienta. Metody te nie będą implementowane przez programistę, lecz zostaną wygenerowane automatycznie.
Przykład Tworzenie sesyjnego komponentu EJB (3/5) Klasa komponentu EJB import javax.ejb.sessionbean; import javax.ejb.sessioncontext; public class Multiplicator1Bean implements SessionBean { public void ejbcreate() { public void ejbactivate() { public void ejbpassivate() { public void ejbremove() { public void setsessioncontext(sessioncontext ctx) { public float multiply(float factor1, float factor2) { return factor1 * factor2; Przykład Tworzenie sesyjnego komponentu EJB (5/5) Fragment kodu aplikacji klienta EJB Multiplicator1Home multiplicator1home; Multiplicator1Remote multiplicator1remote; Hashtable env = new Hashtable(); env.put(context.initial_context_factory, "com.evermind.server.rmi.rmiinitialcontextfactory"); env.put(context.security_principal, "scott"); env.put(context.security_credentials, "tiger"); env.put(context.provider_url, "ormi://miner:1811/ejbapp1"); Context ctx = new InitialContext(env); multiplicator1home = (Multiplicator1Home)ctx.lookup("multiplicator1"); multiplicator1remote = multiplicator1home.create(); System.out.println(multiplicator1Remote.multiply(2,2)); Przykład Tworzenie sesyjnego komponentu EJB (4/5) Plik deskryptora instalacji <?xml version = '1.0' encoding = 'windows-1252'?> <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd"> <ejb-jar> <enterprise-beans> <session> <description>session Bean ( Stateless )</description> <display-name>multiplicator1</display-name> <ejb-name>multiplicator1</ejb-name> <home>multiplicator1home</home> <remote>multiplicator1remote</remote> <ejb-class>multiplicator1bean</ejb-class> <session-type>stateless</session-type> <transaction-type>container</transaction-type> </session> </enterprise-beans> </ejb-jar> Encyjne komponenty EJB Służą do uzyskania efektu trwałości obiektów programowych Java poprzez ich automatyczne fizyczne składowanie w bazie danych; żyją aż do momentu jawnego ich usunięcia Wykorzystywane do budowy warstwy komunikacji logiki biznesowej z bazą danych lub też do implementacji takiej logiki biznesowej, która intensywnie eksploatuje bazę danych Pojedynczy encyjny komponent EJB może być współdzielony przez wiele aplikacji klientów Dwa typy: z trwałością obsługiwaną przez komponent (BMP - Bean-Managed Persistency): muszą same umieszczać swój stan w bazie danych, korzystając np. z biblioteki JDBC lub SQLJ z trwałością obsługiwaną przez kontener EJB (CMP - Container-Managed Persistency): polegają na funkcjonalności kontenera EJB, którego zadaniem jest w tym przypadku automatyczne zapisywanie i odczytywanie stanu komponentu do/z bazy danych
Przykład Tworzenie encyjnego komponentu EJB CMP (1/5) Tabela Emp EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ----- ---------- --------- ---------- --------- ---------- ---------- ---------- 7369 SMITH CLERK 7902 17-DEC-80 800 20 7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30 7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30 Tabela Emp będzie służyć do trwałego przechowywania obiektów EJB w bazie danych. Każdy obiekt EJB będzie reprezentować jednego pracownika. Przykład Tworzenie encyjnego komponentu EJB CMP (3/5) Interfejs Home import javax.ejb.ejbhome; import java.rmi.remoteexception; import javax.ejb.createexception; import javax.ejb.finderexception; import java.util.collection; Interfejs Home deklaruje metody zarządzania cyklem życia i wyszukiwania komponentu EJB, które będa dostępne dla zdalnej aplikacji klienta. Metody te nie będą implementowane przez programistę, lecz zostaną wygenerowane automatycznie. public interface Employee2Home extends EJBHome { Employee2Remote create() throws RemoteException, CreateException; Employee2Remote create(long empno) throws RemoteException, CreateException; Employee2Remote findbyprimarykey(employee2remotepk primarykey) throws RemoteException, FinderException; Collection findall() throws RemoteException, FinderException; Employee2Remote findbyname(string val) throws RemoteException, FinderException; Przykład Tworzenie encyjnego komponentu EJB CMP (2/5) Interfejs Remote import javax.ejb.ejbobject; import java.rmi.remoteexception; public interface Employee2Remote extends EJBObject { long getempno() throws RemoteException; void setempno(long newempno) throws RemoteException; long getdeptno() throws RemoteException; void setdeptno(long newdeptno) throws RemoteException; Interfejs Remote deklaruje metody komponentu EJB, które będą dostępne dla zdalnej aplikacji klienta. Metody te muszą zostać zaimplementowane przez programistę w klasie komponentu EJB. W powyższym przykładzie są to metody dostępu do obiektu pracownika. Przykład Tworzenie encyjnego komponentu EJB CMP (4/5) Klasa komponentu EJB import javax.ejb.*; public class Employee2Bean implements EntityBean { public long empno; public String ename; public String job; public long mgr; public String hiredate; public long sal; public long comm; public long deptno; public long getempno() {return empno; public void setempno(long newempno) {empno = newempno; public long getdeptno() {return deptno; public void setdeptno(long newdeptno) {deptno = newdeptno;