Java Servlet. Programowanie [2 ed.]

W ciągu kilku ostatnich lat serwlety Javy zdobyły uznanie społeczności twórców oprogramowania działającego po stronie se

958 73 7MB

Polish Pages [595] Year 2002

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

Java Servlet. Programowanie [2 ed.]

Table of contents :
Wstęp (9)
Rozdział 1. Wprowadzenie (19)
Historia aplikacji WWW (20)
Obsługa serwletów (24)
Potęga serwletów (28)
Rozdział 2. Podstawy serwletów HTTP (31)
Podstawy HTTP (32)
Interfejs API (Servlet API) (34)
Tworzenie strony (36)
Aplikacje WWW (42)
Rozdział 3. Czas istnienia (cykl życia) serwletu (49)
Alternatywa serwletu (49)
Odnawianie (powtórne ładowanie) serwletu (55)
Metody "Init" i "Destroy" (56)
Model jednowątkowy (Single Thread Model) (63)
Przetwarzanie w tle (65)
Ładowanie i uruchamianie (67)
Buforowanie podręczne po stronie klienta (68)
Buforowanie podręczne po stronie serwera (70)
Rozdział 4. Pobieranie informacji (81)
Serwlet (82)
Serwer (85)
Klient (93)
Rozdział 5. Wysyłanie informacji HTML (131)
Struktura odpowiedzi (132)
Przesyłanie standardowej odpowiedzi (132)
Używanie trwałych połączeń (134)
Buforowanie odpowiedzi (135)
Kody statusu (138)
Nagłówki HTTP (140)
Rozwiązywanie problemów (147)
Sześć sposobów uzyskiwania korzyści z serwletów (158)
Rozdział 6. Wysyłanie zawartości multimedialnej (163)
WAP i WML (163)
Obrazki (171)
Zawartość skompresowana (187)
Serwer cykliczny (190)
Rozdział 7. Śledzenie sesji (195)
Uwierzytelnianie użytkownika (196)
Ukryte pola danych formularza (197)
Przepisywanie URL-u (200)
Trwałe cookies (202)
API - śledzenie sesji (206)
Rozdział 8. Bezpieczeństwo (223)
Uwierzytelnienie poprzez HTTP (224)
Uwierzytelnienie na podstawie formularza (230)
Uwierzytelnienie niestandardowe (233)
Certyfikaty cyfrowe (239)
Protokół bezpiecznej transmisji danych (SSL) (241)
Rozdział 9. Łączność z bazami danych (249)
Relacyjne bazy danych (251)
JDBC API (253)
Ponowne użycie obiektów bazy danych (265)
Transakcje (267)
Serwlet księgi gości (275)
Zaawansowane techniki JDBC (280)
Co dalej? (283)
Rozdział 10. Komunikacja aplet-serwlet (285)
Opcje komunikacji (285)
Serwer daytime (291)
Serwer chat (321)
Rozdział 11. Współpraca serwletów (339)
Dzielenie informacji (339)
Dzielenie kontroli (343)
Rozdział 12. Serwlety korporacyjne i J2EE (351)
Ładowanie rozproszone (352)
Integracja z J2EE (355)
Rozdział 13. Internacjonalizacja (361)
Języki zachodnioeuropejskie (362)
Hołdowanie lokalnym zwyczajom (365)
Języki spoza Europy Zachodniej (367)
Więcej języków (371)
Dynamiczna negocjacja języka (373)
Formularze HTML (382)
Rozdział 14. Szkielet Tea (389)
Język Tea (390)
Początki (391)
Informacja o żądaniu (393)
Administracja Tea (396)
Zastosowania Tea (400)
Aplikacja "Narzędzia" (405)
Ostatnie słowo (415)
Rozdział 15. WebMacro (417)
Szkielet WebMacro (418)
Instalacja WebMacro (421)
Dyrektywy WebMacro (426)
Szablony WebMacro (429)
Aplikacja "Narzędzia" (434)
Filtry (439)
Rozdział 16. Element Construction Set (441)
Elementy strony jako obiekty (441)
Wyświetlanie zbioru wyników (443)
Rozdział 17. XMLC (453)
Prosta kompilacja języka XML (454)
Klasa manipulacyjna (459)
Aplikacja "Narzędzia" (463)
Rozdział 18. JavaServer Pages (471)
Wykorzystywanie JavaServer Pages (472)
Zasady działania (473)
Wyrażenia i deklaracje (476)
Dyrektywy (477)
JSP i JavaBeans (482)
Dołączenia i przekazania (487)
Aplikacja "Narzędzia" (489)
Biblioteki własnych znaczników (493)
Rozdział 19. Informacje dodatkowe (499)
Analiza parametrów (499)
Wysyłanie poczty elektronicznej (504)
Stosowanie wyrażeń regularnych (507)
Uruchamianie programów (511)
Stosowanie metod rodzimych (514)
Występowanie jako klient RMI (515)
Usuwanie błędów (517)
Poprawa wydajności (524)
Rozdział 20. Zmiany w Servlet API 2.3 (527)
Zmiany w Servlet API 2.3 (527)
Konkluzja (541)
Dodatek A Krótki opis Servlet API (543)
Dodatek B Krótki opis HTTP Servlet API (571)
Dodatek C Krótki opis DTD deskryptora aplikacji WWW (597)
Dodatek D Kody statusu HTTP (627)
Dodatek E Encje znakowe (635)
Dodatek F Kodowania (643)
Skorowidz (647)

Citation preview

O Autorach Jason Hunter jest starszym technologiem w firmie CollabNet (http://collab.net), firmie dostarczającej narzędzia i usługi dla współpracy Open Source. Oprócz bycia autorem ksiąŜki „Java Servlet — programowanie” jest takŜe redaktorem witryny Servlets.com, twórcą biblioteki com.oreilly.servlet, współpracownikiem projektu Apache Jakarta, który tworzy serwer Tomcat (od czasów, kiedy projekt był jeszcze wewnętrzną częścią firmy Sun), członkiem grupy ekspertów odpowiedzialnej za tworzenie API Servlet/JSP i JAXP oraz jest członkiem Komitetu Wykonawczego JCP nadzorującego platformę Javy, jako reprezentant Apache Software Foundation. Pisze równieŜ artykuły dla JavaWorld oraz przemawia na wielu konferencjach programistycznych i Open Source. W ostatnich czasach współtworzył bibliotekę Open Source JDOM (http://jdom.org), pozwalającą na optymalizację integracji Javy i XML oraz przewodzi grupie ekspertów odpowiedzialnej za tworzenie JDOM. Jason poprzednio pełnił funkcję głównego technologa w firmie K&A Software, specjalizującej się w treningach i konsultacjach związanych z Javą i działał jako wynajęty ekspert dla wielu przedsiębiorstw włączając w to Sun Microsystems. Jeszcze wcześniej pracował w Silicon Graphics, gdzie był odpowiedzialny za tworzenie (i niszczenie) róŜnego rodzaju technologii WWW. Jason ukończył z najwyŜszym wyróŜnieniem kierunek nauki komputerowe w Willamette University (Salem, Oregon) w 1995. Rozpoczął programowanie w Javie w lecie 1995, a z serwletami i innymi technologiami programowania po stronie serwera jest związany od grudnia 1996. JeŜeli jakimś cudem nie pracuje, przypuszczalnie moŜna go znaleźć na górskiej wędrówce. William „Will” Crawford związał się z tworzeniem stron WWW w 1995. Pracował przy programie informatycznym szpitala Children's Hospital w Bostonie, gdzie pomagał przy tworzeniu pierwszego elektronicznego systemu zapisów medycznych opartego na sieci WWW i był związany z jednymi z pierwszych korporacyjnych zastosowań języka Java. Był konsultantem projektów sieci Intranet w między innymi Children's Hospital w Massachusetts, General Hospital w Brigham, Women's Hospital, Boston Anesthesia Education Foundation i Harvard Medical Center. Will obecnie przewodzi zespołowi projektanckiemu w firmie Invantage, Inc. w Cambridge, Massachusetts, która tworzy oparte na Javie narzędzia intranetowe dla przemysłu farmaceutycznego. W wolnym czasie jest zapalonym amatorem fotografii, pisarzem i studentem ekonomii na Yale University.

Kolofon Wygląd naszych ksiąŜek jest wynikiem komentarzy czytelników, naszych własnych eksperymentów oraz komentarzy od dystrybutorów. WyróŜniające się okładki dopełniają nasze wyróŜniające się podejście do tematów technicznych, tchnące osobowość i Ŝycie w potencjalnie suche tematy. Obrazek na okładce ksiąŜki „Java Servlet — programowanie. Wydanie drugie.” przedstawia miedziany imbryk. Collen Gorman była redaktorem produkcji, a Norma Emory edytorem kopii dla „Java Servlet — programowanie. Wydanie drugie.” Catherine Moris i Leanne Soylemez były odpowiedzialne za kontrolę jakości. Firma Frameworks Consulting dostarczyła obsługi produkcji. Ellen Troutman-Zaig napisała indeks.

Hanna Dyer zaprojektowała okładkę niniejszej ksiąŜki w oparciu o projekt serii autorstwa Ediego Freedmana. Obrazek został sfotografowany przez Kevina Thomasa i dostosowany przy pomocy Adobe Photoshop przez Michaela Snowa. Emma Colby utworzyła pozostałą część okładki w programie QuarkXPress 4.1 przy pomocy czcionki Bodoni Black firmy URW Software i Bodoni Bold Italic firmy Bitstream. David Futato zaprojektował wnętrze ksiąŜki w oparciu o projekt serii autorstwa Nancy Priest. Judy Hoer dokonała konwersji plików Microsoft Word na FrameMaker 5.5.6, przy pomocy narzędzi utworzonych przez Mike'a Sierra. Czcionka nagłówków to Bodoni BT, czcionka tekstu to New Baskerville, a czcionka kodu to Constant Willison. Rysunki pojawiające się w ksiąŜce zostały utworzone przez Roberta Romano przy pomocy Macromedia FreeHand 8 i Adobe Photoshop 5.

Wstęp Od czasu, kiedy napisane zostało pierwsze wydanie niniejszej ksiąŜki, serwlety i platforma Javy działająca po stronie serwera zyskała popularność, której nie moŜna było spodziewać się w najśmielszych marzeniach. Postępuje przyłączanie tych mechanizmów do istniejących. Producenci serwerów WWW oferują obecnie obsługę serwletów jako standardową własność swojego oprogramowania. W specyfikacji Java 2, Enterprise Edition (J2EE) serwlety istnieją jako podstawowy składnik, a niemoŜliwym jest obecnie znalezienie producenta serwerów aplikacji, którego produkt nie zawierałby skalowalnej implementacji serwletów. Jest to jednak więcej niŜ zjawisko napędzane przez producentów. Serwlety stały się podstawą dla JavaServer Pages (JSP) i innych szkieletów tworzenia stron WWW, a technologia serwletów obsługuje aktualnie tak często odwiedzane witryny, jak ESPN.com i AltaVista.com. W związku z tym nie jest zaskakującym fakt, Ŝe krajobraz serwletów wygląda nieco inaczej niŜ w czasach pierwszego wydania. Interfejs serwletów (Servlet API) został poddany dwóm przeglądom, a trzeci jest w trakcie przygotowań. Znajome z początków istnienia serwletów firmy Live Software i New Atlanta, które niegdyś zarabiały sprzedając mechanizmy serwletów (nazywane teraz kontenerami serwletów) Jrun i ServletExec, zostały zauwaŜone i wykupione przez większe firmy zorientowane na WWW, odpowiednio przez Allaire i Unify. Oferują one teraz wiele własności wykraczających poza podstawową obsługę serwletów w celu odróŜnienia się od innych. Co dziwne, oficjalne pakiety javax.servlet i javax.servlet.http były pierwszymi klasami Javy, które zostały oficjalnie rozprowadzone jako Open Source. Zostały one przeniesione do projektu Apache Software Foundation (ASF), i moŜna je aktualnie odnaleźć pod adresem http://jakarta.apache.org. Pakiety te dalej zgodne są ze specyfikacją Servlet API, jednak poprawa błędów i uaktualnianie specyfikacji znajduje się teraz w rękach w zaufanych programistów Open Source — włączając autora, który miał niedawno okazję poprawienia obsługi warunkowego Ŝądania GET w HttpServlet. Dodatkowo, serwer, który jest traktowany jako wzorcowa implementacja Servlet API, został równieŜ przeniesiony do ASF i udostępniony jako Open Source pod nazwą Apache Tomcat. Od tego czasu Tomcat stał się jednym z najpopularniejszych kontenerów serwletów. Większa ilość informacji na ten temat dostępna jest pod adresem http://opensource.org. Świat serwletów zmienił się, a niniejsza ksiąŜka zawiera uaktualnione informacje. Całą wiedzę potrzebną do programowania serwletów Javy, od początku do końca. Pierwsze pięć rozdziałów opisuje podstawy — czym są serwlety, jakie działania wykonują oraz w jaki sposób pracują. Następne 15 rozdziałów zawiera informacje zaawansowane — opisuje działania podejmowane najczęściej przy pomocy serwletów oraz najpopularniejsze narzędzia do tego słuŜące. MoŜna tam znaleźć wiele przykładów, kilka wskazówek i ostrzeŜeń, a nawet opisy kilku prawdziwych błędów, które umknęły uwagi korektorów technicznych.

Servlet API 2.2 Niniejsze wydanie ksiąŜki opisuje wersję 2.2 Servlet API, która osiągnęła stan „wersji publicznej” w sierpniu 1999, a stan „wersji ostatecznej” w grudniu 1999. Wydanie pierwsze opisywało wersje 2.0. Zmiany pomiędzy wersjami 2.0 i 2.2 są znaczne: •

Zostały wprowadzone zasady definiujące dystrybucje serwletów pomiędzy kilkoma serwerami wspierającymi.



Serwlety korzystają aktualnie z dołączanych aplikacji WWW, które mogą być konfigurowane i wdraŜane w sposób niezaleŜny od serwera.



Znacznie poprawione zostało bezpieczeństwo serwletów.



Serwlety mogą teraz przekazywać obsługę Ŝądań innym składnikom serwera.



Serwlety mogą teraz dzielić się informacjami przy pomocy ich ServletContext



Istnieje sposób przystosowania serwletów do obsługi dostępu rozproszonego.



Serwlety posiadają teraz ściślejszą kontrolę nad zarządzaniem sesją.



Dodane zostało buforowanie odpowiedzi.



Rozszerzona została kontrola nad nagłówkami HTTP.



Aktualnie moŜe być zastosowana bardziej zaawansowana obsługa błędów.



API został „wyczyszczony” w celu nadania większej spójności i przewidywalności nazwom metod.



Servlet API jest teraz zdefiniowany poprzez formalny dokument specyfikacji, a przyszłe uaktualnienia API są zarządzane przez formalny proces Java Specification Request (JSR).



Serwlety są teraz zintegrowane z podstawową specyfikacją platformy Java 2, Enterpise Edition (J2EE).

Wszystkie te zmiany, oraz wiele innych drobnych usprawnień, są w pełni opisane w niniejszym nowym wydaniu. Drugie wydanie zawiera równieŜ obszerny opis najciekawszego obszaru programowania serwletów — technik tworzenia prawdziwych dynamicznych witryn opartych na serwletach. W niniejszym wydaniu znajdują się samouczki pięciu najpopularniejszych technologii tworzenia zawartości opartej na serwletach, naleŜących do Open Source: •

JavaServer Pages (JSP), standard firmy Sun, tworzony i udostępniany w połączeniu z serwletami



Tea, technologia utworzona przez Walt Disney Internet Group (dawniej GO.com), zastosowany w wielu bardzo często odwiedzanych stronach, takich jak ESPN.com, NFL.com, Disney.com, DisneyLand.com, GO.com i Movies.com



WebMacro, utworzony przez Semiotek i wykorzystywany przez wyszukiwarkę AltaVista



XMLC, utworzony przez Lutris Technologies w celu udostępnienia mocy technologii XML sieci WWW, wykorzystywany przez innowacyjne witryny takie jak customatix.com



Element Construcion Set (ECS), utworzony przez Apache w celu obsługi najbardziej wymagających potrzeb programistycznych

Niniejsze drugie wydanie opisuje równieŜ WAP, Wireless Application Protocol (Protokół Aplikacji Bezprzewodowych) oraz wyjaśnia, jak tworzyć oparte na serwletach aplikacje WWW dla urządzeń bezprzewodowych.

Servlet API 2.3 W czasie pisania niniejszej ksiąŜki, Servlet API 2.3 jest w trakcie tworzenia. Jednak nie został on jeszcze ukończony. W związku z tym tekst niniejszego wydania zawiera w róŜnych miejscach krótkie uwagi na temat zmian spodziewanych w z Servlet API 2.3. Dodatkowo, ostatni rozdział ksiąŜki zawiera dokładniejszy opis próbnej specyfikacji Servlet API 2.3, udostępnionej w październiku 2000, który pozwala na zapoznanie się z najnowszymi własnościami Servlet API 2.3. NaleŜy jednak zaznaczyć, Ŝe specyfikacje te ciągle podlegają zmianom, a ostateczna wersja moŜe się nieco róŜnić od materiału tu przedstawionego.

Czytelnicy pierwszego wydania Czytelnicy ksiąŜki „Java Servlet Programming, 1st ed.” zorientują się, Ŝe niniejsza ksiąŜka została obszernie uaktualniona do Servlet API 2.2 i, gdzie to tylko moŜliwe, Servlet 2.3. KaŜdy rozdział został znacząco poprawiony w porównaniu z pierwszym wydaniem, a takŜe dodano sześć nowych rozdziałów opisujących techniki tworzenia zawartości opartej na serwletach, jak równieŜ nowy rozdział siódmy, „Serwlety korporacyjne i J2EE”, który opisuje integrację serwletów w platformie J2EE. Ze względu na znaczący wpływ modelu aplikacji WWW na wszystkie aspekty programowania serwletów, poleca się czytelnikom pierwszego wydania przeczytanie kaŜdego interesującego ich rozdziału oraz zwrócenie

uwagi na nowe mechanizmy, które pozwalają na wykonanie tradycyjnych zadań. Czytelnicy dysponujący ograniczonym czasem powinni przejrzeć listę najbardziej znaczących zmian w podrozdziale „Organizacja”.

Czytelnicy Dla kogo jest ta ksiąŜka? Dla osób zainteresowanych tworzeniem aplikacji umieszczanych w sieci WWW. Dokładniej rzecz biorąc, niniejszą ksiąŜką powinni zainteresować się: •

Programiści J2EE — serwlety są integralną częścią standardu Java 2, Enterpise Edition. Programiści tworzący aplikacje dla serwerów J2EE mogą nauczyć się jak najlepiej zintegrować serwlety z innymi podobnymi technologiami.



Programiści JSP — JavaServer Pages (JSP) tworzone są na podstawie serwletów. Wykorzystanie pełnej mocy JSP wymaga zrozumienia serwletów, co teŜ umoŜliwia niniejsza ksiąŜka. Zawiera ona równieŜ samouczek JSP oraz czterech podstawowych konkurencyjnych technologii.



Programiści apletów Javy — porozumiewanie się apletów z serwerem zawsze sprawiało problemy. Serwlety ułatwiają to zadanie poprzez dostarczenie apletom prostego w połączeniu agenta na serwerze.



Programiści CGI — CGI jest popularną metodą rozszerzania funkcjonalności serwera WWW. Serwlety są elegancką i wydajną alternatywą tej techniki.



Programiści innych technik serwerów — istnieje wiele alternatyw dla CGI, między innymi FastCGI, PHP, NSAPI, WAI, ISPAI, ASP, a teraz ASP+. KaŜda z nich posiada ograniczenia związane z przenośnością, bezpieczeństwem, wydajnością i/lub integracją z innymi źródłami danych. Serwlety przewyŜszają je w kaŜdym z tych obszarów.

Co naleŜy wiedzieć Podczas rozpoczynania pracy z niniejszą ksiąŜką, niespodzianką dla autorów okazało się, Ŝe jedną z najtrudniejszych do określenia rzeczy jest docelowy czytelnik. Czy zna on Javę? Czy ma doświadczenie w programowaniu CGI lub innych aplikacji WWW? Czy miał juŜ kontakt z serwletami? Czy zna HTTP i HTML, czy te skróty brzmią dla niego zupełnie niezrozumiale? NiezaleŜnie od przyjmowanego poziomu doświadczenia, zawsze okazywało się, Ŝe ksiąŜka będzie zbyt uproszczona dla jednych uŜytkowników, a zbyt zaawansowana dla drugich. Ostatecznie zdecydowano się na zasadę, Ŝe niniejsza ksiąŜka powinna zawierać w przewaŜającej części materiał oryginalny — moŜna pominąć obszerne opisy tematów i koncepcji dobrze opisanych w sieci lub innych ksiąŜkach. W tekście znaleźć moŜna odwołania do tych zewnętrznych źródeł informacji. Oczywiście zewnętrzne źródła informacji nie są wystarczające. Niniejsza ksiąŜka zakłada, Ŝe czytelnicy dobrze znają język Java oraz podstawowe techniki programowania obiektowego. JeŜeli nie spełnia się tych załoŜeń, polecane jest przygotowanie się poprzez przeczytanie ogólnej ksiąŜki na temat programowania w Javie, takiej jak „Learning Java” autorstwa Patricka Niemeyera i Jonathana Knudsena (O'Reilly). W ksiąŜce tej moŜna jedynie krótko zapoznać się z rozdziałami na temat apletów i programowania Swing (graficznego), a skupić się na sieci i programowaniu wielowątkowym. Aby zacząć od razu naukę serwletów i uczyć się Javy w trakcie, polecane jest przeczytanie niniejszej ksiąŜki równocześnie z „Java in a Nutshell” autorstwa Davida Flanagana (O'Reilly) lub innym podręcznikiem. Niniejsza ksiąŜka nie wymaga od czytelników doświadczenia w programowaniu WWW, HTTP i HTML. Nie zawiera jednak pełnego wprowadzenia lub wyczerpującego opisu tych technologii. Opisane zostaną podstawy potrzebne do efektywnego programowania serwletów, a szczegóły (takie jak pełna lista znaczników HTML i nagłówków HTTP 1.1) pozostawione zostaną innym źródłom.

Przykłady W niniejszej ksiąŜce znaleźć moŜna ponad 100 przykładów serwletów. Ich kod jest całkowicie zawarty wewnątrz tekstu, moŜliwe jest jednak takŜe pobranie przykładów zamiast ręcznego ich wpisywania. Kod przykładów, spakowany i gotowy do pobrania, moŜna znaleźć pod adresem

http://www.oreilly.com/catalog/jservlet2. Wiele z tych serwletów moŜna zobaczyć w działaniu pod adresem http://www.servlets.com. Wszystkie przykłady zostały przetestowane przy pomocy serwera Apache Tomcat 3.2 działającego w trybie samodzielnym, wirtualnej maszyny Javy (Java Virtual Machine — JVM) zawartej w Java Development KIT 1.1.8 i 1.2.2, zarówno pod Windows jak i Uniksem. Kilka zaawansowanych przykładów wymaga własności, których nie obsługuje Tomcat w trybie samodzielnym. W tym przypadku przykłady były testowane na róŜnych innych serwerach, jak opisano w tekście. Serwer Apache Tomcat jest oficjalną wzorcową implementacją Servlet API, i jest dostępny w licencji Open Source pod adresem http://jakarta.apache.org. Niniejsza ksiąŜka zawiera równieŜ zbiór klas narzędziowych — wykorzystywane są one przez serwlety przykładowe, mogą się takŜe okazać przydatne przy tworzenie własnych. Klasy te zawarte są w pakiecie com.oreilly.servlet. Między innymi są to klasy pomagające serwletom w analizie parametrów, obsłudze wysyłania plików, generowaniu wieloczęściowych odpowiedzi (przepychanie serwera), negocjacji ustawień lokalnych i internacjonalizacji, zwracaniu plików, zarządzaniu połączeniami i pracy jako serwer RMI. Pakiet te zawiera równieŜ klasę wspomagającą komunikację apletów z serwletami. Od czasu pierwszego wydania dodane zostały nowe klasy pomagające serwletom w wysyłaniu wiadomości poczty elektronicznej, przechowywaniu odpowiedzi w pamięci podręcznej oraz automatycznym wykrywaniu obsługi Servlet API. Kod źródłowy większości pakietu com.oreilly.servlet zawarty jest w tekście, a pełna, aktualna wersja jest dostępna w formie elektronicznej (razem z dokumentacją javadoc) pod adresem http://www.servlets.com.1

Organizacja Niniejsza ksiąŜka składa się z 20 rozdziałów i 6 dodatków, są one następujące:

1



Rozdział 1, „Wprowadzenie”. Wyjaśnia rolę i zalety serwletów Javy w tworzeniu aplikacji WWW. W drugim wydaniu dodane zostały dodatkowe informacje na temat serwerów.



Rozdział 2, „Podstawy serwletów HTTP”. Zawiera krótkie wprowadzenie do HTTP i funkcji, jakie mogą pełnić serwlety HTTP. Przedstawia tworzenie prostej strony i wprowadza pojęcie dołączanej aplikacji WWW. Drugie wydanie opisuje aplikacje WWW i ich deskryptory oparte na XML.



Rozdział 3, „Cykl Ŝycia serwletów”. Wyjaśnia szczegółowe informacje na temat sposobu i czasu ładowania serwletów, sposobu i czasu ich wykonywania, zarządzania wątkami oraz obsługi kwestii synchronizacji w systemie wielowątkowym. Opisane są równieŜ stany trwałe. Drugie wydanie zawiera nowe zasady kontekstowego przeładowywania i rejestracji serwletów, nowy podrozdział na temat pamięci podręcznej po stronie serwera oraz uwagę na temat super.init(config).



Rozdział 4, „Pobieranie informacji”. Wprowadza najpopularniejsze metody wykorzystywane przez serwlety w celu pobrania informacji — na temat klienta, serwera, Ŝądań klienta oraz samego siebie. Przedstawia równieŜ działanie ogólnej klasy słuŜącej do wysyłania plików. Drugie wydanie opisuje ustawianie informacji w deskryptorze, pobieranie nazwy serwletu, dostęp do katalogów tymczasowych, obsługę kontekstowych parametrów początkowych, określanie wersji Servlet API, przypisywanie odwzorowania serwletów oraz dostęp do zasobów abstrakcyjnych. Przestawia równieŜ poprawiony, bardziej elastyczny składnik słuŜący do wysyłania plików.



Rozdział 5, „Wysyłanie informacji HTML”. Opisuje sposoby tworzenia kodu HTML przez serwlet, zwracania błędów, buforowania odpowiedzi, przekierowywania Ŝądań, zapisywania danych w dzienniku zdarzeń serwera oraz wysyłania dostosowanych nagłówków HTML. Drugie wydanie zawiera nowy opis buforowania odpowiedzi, bardzo przydatny przykład przekierowywania oraz nowe podrozdziały na temat konfiguracji stron zawierających błędy i obsługi błędów.

Niniejsza ksiąŜka nie zawiera CD-ROM-u. Dołączenie CD-ROM-u podnosi koszty produkcji a w związku z tym cenę ksiąŜki. ZałoŜono, Ŝe kaŜdy Czytelnik posiada dostęp do Internetu, a w związku z tym moŜe oszczędzić pewną ilość pieniędzy poprzez pobranie kodu przykładów przez sieć WWW. Nie uwaŜa się równieŜ za sensowne dołączanie wersji próbnych róŜnych serwerów WWW i aplikacji. ZwaŜywszy na nieustanny szybki postęp na rynku serwletów, dołączone serwery stałyby się przestarzałe jeszcze przed wydrukowaniem ksiąŜki. Te same wersje próbne dostępne są w sieci i poleca się pobranie ich własnoręcznie. Proszę pamiętać, Ŝe jeŜeli zamierza się czytać niniejszą ksiąŜkę offline, polecane jest pobranie kodu przykładów i serwera WWW Apache Tomcata, kiesy tylko będzie to moŜliwe. Łącza do pobrań umieszczone są pod adresem http://www.servlets.com.



Rozdział 6, „Wysyłanie zawartości multimedialnej”. Opisuje róŜne interesujące dane, które moŜe zwracać serwlet — zawartość WAP/WML dla urządzeń bezprzewodowych, dynamicznie tworzone obrazki, zawartość skompresowana oraz odpowiedzi wieloczęściowe. W drugim wydaniu dodano opis WAP/WML, listy plików powitalnych, dyskusję na temat PNG, usprawnioną pamięć podręczną rysunków po stronie serwera oraz więcej szczegółów na temat tworzenia zawartości skompresowanej.



Rozdział 7, „Śledzenie sesji”. Opisuje sposoby tworzenia śledzenia stanu w bezstanowym protokole HTTP. Pierwsza część rozdziału opisuje tradycyjne techniki śledzenia sesji stosowane przez programistów CGI. Druga część opisuje sposoby zastosowania wbudowanej w Servlet API obsługi śledzenia sesji. Drugie wydanie zawiera zasady tworzenia sesji aplikacji WWW, materiał na temat nowych nazw metod sesji, dyskusję na temat zarządzania przekraczaniem czasu oraz śledzenie sesji oparte na apletach.



Rozdział 8, „Bezpieczeństwo”. Wyjaśnia kwestie bezpieczeństwa związane z programowanie rozproszonym. Opisuje sposoby korzystania ze standardowych funkcji serwletów związanych z zarządzaniem kontami uŜytkowników oraz sposoby tworzenia bardziej zaawansowanego systemu przy pomocy dodatkowego uwierzytelniania i autoryzacji. Wyjaśni równieŜ rolę serwletów w bezpiecznej komunikacji SSL. W drugim wydaniu całkowicie przeredagowany.



Rozdział 9, „Łączność z bazami danych”. Opisuje sposoby wykorzystania serwletów w wysokowydajnej łączności z bazami danych WWW. Zawiera samouczek JDBC. Drugie wydanie zawiera przykłady konfiguracji połączeń z plikami właściwości, nowy przykład księgi gości oraz nowy podrozdział opisujący JDBC 2.0.



Rozdział 10, „Komunikacja aplet-serwlet”. Opisuje sposoby wykorzystania serwletów przez aplet, który musi porozumieć się z serwerem. Uaktualniony w drugim wydaniu.



Rozdział 11, „Współpraca serwletów”. Opisuje powody komunikacji serwletów i sposoby ich współpracy przez dzielenie się informacjami lub wywoływanie sienie nawzajem. W drugim wydaniu całkowicie przeredagowany.



Rozdział 12, „Serwlety korporacyjne i J2EE”. Opisuje zaawansowane własności serwletów wykorzystywane w witrynach korporacyjnych — dystrybucję ładunku i integrację składników J2EE. Nowość w drugim wydaniu.



Rozdział 13, „Internacjonalizacja”. Opisuje sposoby, dzięki którym serwlet moŜe odczytywać i tworzyć zawartość w róŜnych językach. Drugie wydanie opisuje zastosowanie javadoc w zarządzaniu kodowaniem i sposoby wykorzystywania nowych metod API w zarządzaniu wersjami lokalnymi.



Rozdział 14, „Szkielet Tea”. Przedstawia szkielet Tea, elegancki, ale zarazem potęŜny mechanizm szablonów. Nowość w drugim wydaniu.



Rozdział 15, „WebMacro”. Opisuje szkielet WebMacro, podobny do Tea lecz z kilkoma innymi decyzjami projektanckimi. Nowość w drugim wydaniu.



Rozdział 16, „Element Construction Set”. Zawiera krótki opis ECS, obiektowego podejścia do tworzenia strony. Nowość w drugim wydaniu.



Rozdział 17, „XMLC”. Przegląd XMLC, podejścia do tworzenia strony opartego na XML. Nowość w drugim wydaniu.



Rozdział 18, „JavaServer Pages”. Wyjaśnia JSP, standardową technologię firmy Sun, w której strony WWW są automatycznie wkompilowane w serwer. Nowość w drugim wydaniu.



Rozdział 19, „Informacje dodatkowe”. Przedstawia dodatkowe przykłady serwletów i podpowiedzi, które nie zmieściły się w Ŝadnym z poprzednich rozdziałów. Drugie wydanie zawiera analizator parametrów zlokalizowanych, nową klasę poczty elektronicznej oraz uaktualniony podrozdział na temat wyraŜeń regularnych, nowy podrozdział na temat dodatkowych narzędzi oraz dodatkowe podpowiedzi na temat wydajności.



Rozdział 20, „Zmiany w Servlet API 2.3”. Opisuje zmiany w nadchodzącej wersji 2.3 Servlet API, który ma zostać udostępniony w połowie 2001. Nowość w drugim wydaniu.



Dodatek A, „Krótki opis Servlet API”. Zawiera pełny opis klas, metod i zmiennych w pakiecie javax.servlet. W drugim wydaniu uaktualniony do Servlet API 2.2



Dodatek B, „Krótki opis HTTP Servlet API”. Zawiera pełny opis klas, metod i zmiennych w pakiecie javax.servlet.http. W drugim wydaniu uaktualniony do Servlet API 2.2



Dodatek C, „Krótki opis deskryptorów DTD”. Przedstawia opis deskryptora Document Type Definition (Definicja Typu Dokumentu) web.xml. Nowość w drugim wydaniu.



Dodatek D, „Kody stanu HTTP”. Lista kodów stanu określonych przez HTTP, a takŜe stałe mnemoniczne wykorzystywane przez serwlety.



Dodatek E, „Encje znakowe”. Lista encji znakowych zdefiniowanych w HTML, a takŜe równowaŜne do nich wartości kodów ucieczkowych Uniksa.



Dodatek F, „Kodowania”. Lista sugerowanych kodowań wykorzystywanych przez serwlety w celu tworzenia zawartości w róŜnych językach.

Proszę czuć się swobodnie i czytać rozdziały w niniejszej ksiąŜce w dowolnej kolejności. Czytanie prosto od początku do końca zapewnia uniknięcie wszelkich niespodzianek, jako Ŝe starano się unikać odwołań do dalszych części ksiąŜki. Przeskakiwanie jest jednak moŜliwe, zwłaszcza po rozdziale 5 — pozostała część rozdziałów została zaprojektowana w celu oddzielonego istnienia. Jedna ostatnia sugestia — proszę przeczytać podrozdział „Usuwanie błędów” w rozdziale 19, jeŜeli kiedykolwiek napotka się fragment kodu pracujący nieprawidłowo.

Konwencje wykorzystywane w tej ksiąŜce Kursywa wykorzystywana jest do: •

ŚcieŜek, nazw plików i programów



Nowych terminów podczas ich definiowania



Adresów internetowych, takich jak nazwy domen i URL-e

Czcionka pogrubiona wykorzystywana jest do: •

Konkretnych klawiszy na klawiaturze



Nazw przycisków interfejsu uŜytkownika i menu

Czcionka o stałej szerokości wykorzystywana jest do: •

Wszystkich danych pojawiających się dokładanie w programie Javy, takich jak słowa kluczowe, typy danych, stałe, nazwy metod, zmienne, nazwy klas oraz nazwy interfejsów



Wszystkich wydruków kodu Javy



Dokumentów HTML, znaczników i atrybutów

Czcionka o stałej szerokości z kursywą wykorzystywana jest do: •

Ogólnych obszarów zablokowanych wskazujących, Ŝe dany element jest zastępowany w programie przez konkretną wartość.

Pogrubiona czcionka o stałej szerokości wykorzystywana jest do: •

Wpisów w wierszu poleceń

Prośba o komentarze Prosimy o pomoc w poprawieniu następnych wydań poprzez zgłaszanie wszystkich błędów, nieścisłości, niejasnych lub niewłaściwych wyraŜeń oraz zwykłych literówek, które moŜna odnaleźć w dowolnym miejscu niniejszej ksiąŜki. Proszę wysyłać komunikaty o błędach i komentarze pod adres [email protected]. (Przed wysłaniem komunikatu o błędzie prosimy sprawdzić erratę na stronie http://www.oreilly.com/catalog/jservlet2 w celu sprawdzenia, czy dany błąd nie został juŜ opisany.)

Prosimy równieŜ o opinie, co powinno znaleźć się w tej ksiąŜce, aby stała się ona bardziej przydatna. Wydawnictwo traktuje takie komentarze bardzo powaŜnie i próbuje dołączyć rozsądne sugestie do przyszłych wydań ksiąŜki.

Podziękowania Kiedy pracowałem nad niniejszą ksiąŜką, przyjaciel powiedział mi „Łatwiej musi być pisać drugie wydanie; napisałeś juŜ raz tę ksiąŜkę”. Pomyślałem nad tym przez chwilę, roześmiałem się i odpowiedziałem, „To jest łatwiejsze, ale ani trochę nie aŜ tak łatwe, jak się spodziewałem!”. Patrząc wstecz, myślę Ŝe powód tego ma niewiele wspólnego z ksiąŜkami, a bardziej z technologią. Pierwsze wydanie opisywało Servlet API 2.0, specyfikację tworzoną przez około dwa lata. Niniejsze drugie wydanie przedstawia Servlet API 2.2 i 2.3, co daje mniej więcej dwa dodatkowe lata pracy projektantów. Tak więc jedynie z tej perspektywy moŜna dostrzec, Ŝe jeŜeli pierwsze wydanie zabrało mniej więcej rok aktywnego pisania, to drugie powinno zabrać mniej więcej tyle samo czasu. I rzeczywiście tak było — około 9 miesięcy. Wiele osób pomogło mi w tworzeniu tej ksiąŜki. Jestem im głęboko wdzięczny. Po pierwsze są to redaktorzy techniczni ksiąŜki — James Duncan Davidson, przewodniczący specyfikacji Servlet API 2.1 i 2.2, oraz Danny Coward, przewodniczący nadchodzącej wersji 2.3. Wszystko, co moŜna o nich powiedzieć dobrego, to za mało. Nie tylko dostarczyli mi nieocenionej pomocy i rad w trakcie pisania ksiąŜki, lecz stworzyli wszystkim doskonałą platformę do programowania dla WWW. Dziękuję równieŜ wielu programistom, którzy swoim doświadczeniem wspomogli tworzenie rozdziałów na temat tworzenia zawartości (i w wielu przypadkach tworzyli opisywaną technologię) — Reece Wilton i Brian O'Neill dla Tea, Justin Wells dla WebMacro, Jon Stevens dla ECS, Mark Diekhnas i Christian Cryder dla XMLC oraz Hans Bergsten i Craig McClanahan dla JSP. Chciałbym równieŜ podziękować Bobowi Ecksteinowi, redaktorowi ksiąŜki, którego ręczne notatki były zawsze celne, choć czasami niemoŜliwe do odcyfrowania. Bob przejął obowiązki redaktorskie od Pauli Ferguson, po tym, jak zajęła się ona zarządzaniem ksiąŜkami O'Reilly na temat WWW i skryptów. Dziękuję równieŜ Jimowi Grishamowi, który pomógł zlokalizować wszystkie rodzaje komputerów i przeglądarek wykorzystywane przy testowaniu przykładów; Magnusowi Stenmanowi z firmy Orion, który wyjaśnił mi implementację J2EE w serwerze Orion; Justynie Horwat, zwanej przez niektórych Boginią Biblioteki Znaczników, za odpowiedzi na pytania dotyczący biblioteki znaczników JSP oraz Ethanowi Henry, który pomógł sugestiami na temat poprawiania wydajności serwletów. Nie mogę zapomnieć o Brett'cie McLaughlinie, autorze ksiąŜki „Java and XML” (O'Reilly) i współtwórcy JDOM. Jego współpraca ze mną na temat JDOM właściwie spowolniła pisanie tej ksiąŜki, lecz prędkość, z jaką on pisze inspiruje mnie, a poniewaŜ wspomniał mnie on w swojej ksiąŜce, muszę napisać coś tutaj. I ostatecznie dziękuję mojej dziewczynie, Kathlyn Bautista, która nie narzekała, kiedy pracowałem w niedziele, lecz sprawiała, Ŝe wcale pracować nie chciałem. Jason Hunter Listopad 2000

Podziękowania z wydania pierwszego Historia tej ksiąŜki rozpoczęła się właściwie 20 marca 1997, w księgarni „Computer Literacy” w San Jose w Kalifornii. Tam — po ciekawej rozmowie z Larrym Wallem i Randallem Schwartzem, w której Larry wyjaśniał, jak automatyzuje swój dom przy pomocy Perla — spotkałem po raz pierwszy szacownego Tima O'Reilly. Przedstawiłem się i bezczelnie powiedziałem, Ŝe pewnego dnia (w dalekiej przyszłości, myślałem), planuję napisać ksiąŜkę dla O'Reilly. Czułem się jakbym mówił Stevenowi Spielbergowi, Ŝe chcę zagrać główną rolę w jego filmie. Ku mojemu kompletnemu zaskoczeniu, Tim odpowiedział, „Na jaki temat?”. Tak rozpoczęła się szaleńcza jazda prowadząca do powstania tej ksiąŜki. Wystąpiło w tym czasie kilka jasnych punktów, które z dumą pamiętam — poznanie mojej redaktorki (świetnie, teŜ jest młoda!), podpisania oficjalnego kontraktu (czy wiecie, Ŝe cały papier firmowy O'Reilly jest ozdobiony zwierzętami?), napisanie pierwszego zdania (znowu i znowu), drukowanie pierwszego rozdziału (i sprawienie,

Ŝeby wyglądał on jak ksiąŜka O'Reilly), po czym oglądanie rosnącej sterty wydruków, do momentu, kiedy nie zostało juŜ nic do napisania (oprócz podziękowań). Było równieŜ kilka trudnych chwil. W pewnym momencie, kiedy ksiąŜka była ukończona w połowie, uświadomiłem sobie, Ŝe Servlet API zmieniał się szybciej, niŜ mogłem nadąŜyć. Wierzę w powiedzenie „JeŜeli coś się nie udaje, poproś o pomoc”, tak więc po krótkich poszukiwaniach poprosiłem Williama Crawforda, który pracował w tym czasie nad ksiąŜką „Java Enterprise in a Nutshell”, czy pomógłby mi w przyśpieszeniu pracy nad ksiąŜką. Wspaniałomyślnie zgodził się on i pomógł w napisaniu dwóch rozdziałów, a takŜe części dodatków. Wielu innych ludzi pomogło mi w napisaniu niniejszej ksiąŜki, zarówno bezpośrednio jak i pośrednio. Chciałbym podziękować Pauli Ferguson, redaktorowi ksiąŜki oraz Mike'owi Loukidesowi, redaktorowi serii Java, za ich starania o zapewnienie (i poprawę) jakości tej ksiąŜki. Oraz Timowi O'Reilly za danie mi szansy spełnienia marzeń. Dziękuję równieŜ moim menedŜerom w firmie Silicon Graphics, Kathy Tansill i Waltowi Johnsonowi, za dostarczenie większej pomocy i elastyczności niŜ miałem prawo się spodziewać. KaŜde podziękowania są niewystarczające dla inŜynierów firmy Sun, którzy odpowiadali na niezliczone pytania, informowali mnie o zmianach w Servlet API i naprawiali niemal kaŜdy błąd, jaki zgłosiłem — są to James Duncan Davidson (Wyglądający niemal jak James Gosling), Jim Driscoll, Rob Clark i Dane Brownell. Dziękuję równieŜ członkom listy dystrybucyjnej jserv-interest, których pytania i odpowiedzi ukształtowały zawartość tej ksiąŜki; Willowi Rameyowi, staremu przyjacielowi, który nie pozwolił, aby przyjaźń przesłoniła jego krytyczne oko; Mike'owi Engberowi, człowiekowi, do którego zwróciłem się po ucieczce z eleganckich miejsc pracy i byłem gotowy na zaakceptowanie jego szalonych pomysłów; Dave'owi Vandergriftowi, pierwszej osobie, która przeczytała wiele rozdziałów; Billowi Dayowi, autorowi „Java Media Players”, który pomagał poprzez przechodzenie przez proces tworzenia ksiąŜki równolegle ze mną; Michaelowi O'Connellowi i Jill Steinberg, redaktorom „JavaWorld”, dzięki którym napisałem mój pierwszy profesjonalny tekst; Dougowi Youngowi, który dzielił się za mną technicznymi sztuczkami poznanymi przy pisaniu siedmiu własnych ksiąŜek technicznych oraz Shoji Kuwabara'rze, Mieko Aono, Song'owi Yung'owi, Matthew Kim'owi oraz Alexandrowi Pashintsev'owi za ich pomoc w przetłumaczeniu skryptu „Witaj Świecie” w rozdziale 13. Chciałbym gorąco podziękować recenzentom technicznym ksiąŜki, których konstruktywny krytycyzm pomógł znacznie w usprawnieniu pracy — są to Mike Slinn, Mike Hogarth, James Duncan Davison, Dan Protchett, Dave McMurdie i Rob Clark. Ciągle jestem w szoku, po tym jak dowiedziałem się, Ŝe jednemu recenzentowi zabrało trzy dni, aby przeczytać to, nad czego stworzeniem pracowaliśmy rok! Ostatecznie, dziękuję Mamie i Tacie, za ich miłość i wsparcie i za czas, który poświęciliście dawno temu dna nauczenie mnie podstaw pisania. Dziękuję teŜ Kristi Taylor, która sprawiła, Ŝe ta niewielka część czasu, która nie była wypełniona pracą, stała się przyjemnością. Oraz Dziadkowi, chciałbym, Ŝebyś mógł to zobaczyć. Jason Hunter Czerwiec 1998 Po pierwsze dziękuję Shelley Norton, dr Isaacowi Kohane, dr Jamesowi Facklerowi i dr Richardowi Kitzowi (a takŜe pozostałej części zespołu, której wkład pozostaje nieoceniony), których pomoc i wsparcie sprawiła, Ŝe wszystko to stało się moŜliwe. A takŜe Martinowi Streeterowi z firmy Invantage, Inc., za jego wsparcie w trakcie trwania tego projektu. Bez Roba Leitha, Rogera Stacey i Freda Sterbeigha, przypuszczalnie ciągle trwałbym w stronie biernej. Dale Dogherty zaoferował mi pieniądze w zamian za słowa, wydarzenie, którego ciągle nie potrafię pojąć. Andy Kwak, Joel Pomerantz i Matthew Proto, wspaniali ludzie, zechcieli przeczytać próbne wydruki i słuchać skarg o godzinie pierwszej w nocy. I, oczywiście Mamie i Tacie za ich lata wsparcia, oraz mojej siostrze Faith za (zazwyczaj) wybaczanie mi bycia durniem. William Crawford Lipiec 1998

W niniejszym rozdziale: •

Historia aplikacji WWW



Obsługa serwletów



Moc serwletów

Rozdział 1.

Wprowadzenie Rozwój aplikacji Javy działających po stronie serwera — wszystko od działających samodzielnie serwletów do pełnej platformy Java 2, Enterprise Edition (J2EE) — był jednym z najbardziej ekscytujących trendów w programowaniu Javy. Język Java został utworzony pierwotnie w celu zastosowania w małych, osadzonych urządzeniach. Był on opisywany jako język do tworzenia zawartości WWW po stronie klienta w formie apletów. Jednak aŜ do kilku ostatnich lat potencjał Javy jako platformy do programowania po stronie serwera był niestety pominięty. Aktualnie Java jest uwaŜana za język idealnie nadający się do programowania po stronie serwera. Szczególnie szybko rozpoznały potencjał Javy w serwerach firmy biznesowe — Java idealnie pasuje do duŜych aplikacji typu klient-serwer. NiezaleŜna od platformy natura Javy jest niezwykle uŜyteczna dla organizacji posiadających heterogeniczny zbiór serwerów pracujących pod róŜnymi odmianami systemów operacyjnych UNIX i Windows (oraz coraz bardziej Mac OS X). Nowoczesny, obiektowy i chroniący pamięć projekt Javy pozwala programistom na skrócenie cyklów programistycznych i zwiększenie niezawodności. Dodatkowo, wbudowana w Javę obsługa sieci i interfejsów korporacyjnych dostarcza moŜliwości dostępu do starych danych, ułatwiając przejście ze starszych systemów klient-serwer. Serwlety Javy są kluczowym składnikiem programowania Javy po stronie serwera. Serwlet to małe, dołączane rozszerzenie serwera, które rozszerza jego funkcjonalność. Serwlety pozwalają programistom na rozszerzanie i dostosowywanie kaŜdego serwera WWW lub aplikacji z obsługą Javy do wcześniej nieznanego poziomu przenośności, elastyczności i łatwości. Jednak przed przejściem do szczegółów, naleŜy spojrzeć na sprawę z pewnej perspektywy.

Historia aplikacji WWW ChociaŜ serwlety mogą być wykorzystywane do rozszerzenia funkcjonalności kaŜdego serwera z obsługą Javy, najczęściej uŜywane są do rozszerzania serwerów WWW, stanowiąc potęŜny i wydajny zamiennik dla skryptów CGI. Kiedy wykorzystuje się serwlet do utworzenia dynamicznej zawartości strony WWW lub podniesienia w inny sposób funkcjonalności serwera WWW, w efekcie tworzy się aplikację WWW. Podczas, gdy strona WWW wyświetla jedynie zawartość statyczną i pozwala uŜytkownikowi na nawigację poprzez tę zawartość, aplikacja WWW dostarcza doświadczenia bardziej interaktywnego. Aplikacja WWW moŜe być tak prosta jak

wyszukiwanie słowa kluczowego w archiwum dokumentów lub tak złoŜona, jak sklep elektroniczny. Aplikacje WWW są umieszczane w Internecie oraz korporacyjnych sieciach intranet i extranet, w których posiadają one potencjał do zwiększania produktywności i zmiany sposobu prowadzenia biznesu przez małe i duŜe firmy. Aby zrozumieć potęgę serwletów, naleŜy cofnąć się i spojrzeć na pewne inne podejścia do tworzenia aplikacji WWW.

Common Gateway Interface Common Gateway Interface (Wspólny Interfejs Bramek), w skrócie CGI, był jednym z pierwszych praktycznych technik tworzenia zawartości dynamicznej. Przy pomocy CGI serwer WWW przekazuje konkretne Ŝądania do programu zewnętrznego. Wynik tego programu jest później przesyłany do klienta w miejscu statycznego pliku. Powstanie CGI pozwoliło na implementację wielu nowych rodzajów funkcjonalności na stronach WWW, a CGI szybko stał się de facto standardem, zaimplementowanym w ogromnej ilości serwerów WWW. Interesujący jest fakt, Ŝe moŜliwość tworzenia przez programy CGI dynamicznych stron WWW jest ubocznym efektem ich początkowego przeznaczenia — zdefiniowania standardowej metody porozumiewania się serwera informacji z aplikacjami zewnętrznymi. To źródło wyjaśnia, dlaczego CGI posiada przypuszczalnie najgorszy do wyobraŜenia okres trwałości. Kiedy serwer otrzymuje Ŝądanie, które uzyskuje dostęp do programu CGI, musi on utworzyć nowy proces w celu uruchomienia programu CGI i potem przekazania mu, poprzez zmienne środowiskowe i standardowe wpisy, kaŜdego bitu informacji, który moŜe być potrzebny do wygenerowania odpowiedzi. Tworzenie procesu dla kaŜdego takiego Ŝądania wymaga czasu i znaczących zasobów serwera, co ogranicza liczbę Ŝądań, które serwer moŜe obsługiwać równocześnie. Rysunek 1.1 przedstawia okres trwałości CGI.

Rysunek 1.1. Okres trwałości CGI ChociaŜ program CGI moŜe być utworzony w prawie kaŜdym języku, język programowania Perl stał się podstawową opcją. Zaawansowane moŜliwości formatowania tekstu Perla stanowią ogromną pomoc w zarządzaniu szczegółami interfejsu CGI. Tworzenie skryptu CGI w Perlu pozwala na uniezaleŜnienie o platformy, ale wymaga równieŜ uruchomienia osobnego interpretatora Perla dla kaŜdego Ŝądania, co zabiera jeszcze więcej czasu i wymaga dodatkowych zasobów. Innym często przeoczonym problemem z CGI jest niemoŜność interakcji programu CGI z serwerem WWW lub skorzystania z moŜliwości serwera po rozpoczęciu działania tego programu, poniewaŜ działa on jako osobny proces. Na przykład, skrypt CGI nie potrafi zapisywać informacji w dzienniku zdarzeń serwera. Większa ilość informacji na temat programowania CGI jest dostępna w ksiąŜce „CGI Programming on the World Wide Web” autorstwa Shishira Gundavarama (O'Reilly).

FastCGI Firma o nazwie OpenMarket stworzyła alternatywę dla standardu CGI o nazwie FastCGI. W większości aspektów, FastCGI działa podobnie do CGI — waŜną róŜnicą jest tworzenie przez FastCGI jednego trwałego procesu dla kaŜdego programu FastCGI, jak przedstawiono na rysunku 1.2. Eliminuje to konieczność tworzenia nowego procesu dla kaŜdego Ŝądania.

Rysunek 1.2. Okres trwałości FastCGI ChociaŜ FastCGI jest krokiem we właściwym kierunku, ciągle posiada on problem z mnoŜeniem się procesów — istnieje co najmniej jeden proces dla kaŜdego programu FastCGI. JeŜeli program FastCGI musi obsługiwać Ŝądania równoległe, potrzebuje puli procesów, jednego na kaŜde Ŝądanie. Pamiętając, Ŝe kaŜdy proces moŜe wykonywać interpretator Perla, podejście na to nie jest skalowalne na tyle, na ile moŜna się tego spodziewać. (ChociaŜ trzeba przyznać, Ŝe FastCGI moŜe rozkładać procesy pomiędzy wieloma serwerami.) Innym problemem z FastCGI jest to, Ŝe nie pozwala on swoim programom na bliŜszą interakcję z serwerem. Poza tym, programy FastCGI są przenośne jedynie tak, jak język, w którym zostały napisane. Większa ilość informacji na temat FastCGI jest dostępna pod adresem http://www.fastcgi.com.

PerlEx PerlEx, utworzony przez ActiveState, zwiększa wydajność skryptów CGI napisanych w Perlu pracujących na serwerach WWW pod Windows NT (Internet Information Server Microsoftu, Website Professional O'Reilly oraz FastTrack Server i Enterpise Server iPlanet). Posiada on zalety i wady podobne do FastCGI. Większa ilość informacji na temat PerlEx dostępna jest pod adresem http://www.activestate.com/plex.

mod_perl Przy korzystaniu z serwera WWW Apache, inną opcją zwiększenia wydajności CGI jest wykorzystanie mod_perl. mod_perl jest modułem serwera Apache osadzającym kopię interpretatora Perla w pliku wykonywalnym Apache'a, dostarczającym pełnej funkcjonalności Perla wewnątrz Apache'a. Jego efektem jest prekompilowanie skryptów CGI przez serwer i wykonywanie ich bez rozdzielania, a związku z tym ich praca jest duŜo szybsza i wydajniejsza. Jego wadą jest moŜliwość wykorzystania jedynie w serwerze Apache. Większa ilość informacji na temat mod_perl jest dostępna pod adresem http://perl.apache.org.

Inne rozwiązania CGI/Perl posiada zaletę bycia mniej lub bardziej niezaleŜnym od platformy sposobem na tworzenie dynamicznej zawartości WWW. Inne dobrze znane technologie tworzenia aplikacji WWW takie jak ASP i JavaScript działający po stronie serwera, są opatentowanymi rozwiązaniami pracującymi jedynie z określonymi serwerami WWW.

Interfejsy rozszerzeń serwera Kilka firm utworzyło własne interfejsy API rozszerzeń serwera dla swoich serwerów WWW. Na przykład, iPlanet/Netscape dostarcza wewnętrzny API o nazwie WAI (dawniej NSAPI), a Microsoft dostarcza ISAPI. Przy pomocy kaŜdego z tych interfejsów, moŜna utworzyć rozszerzenia serwera zwiększające lub zmieniające jego podstawową funkcjonalność, pozwalającą mu na obsługę zadań wcześniej delegowanych do zewnętrznych programów CGI. Jak moŜna dostrzec na rysunku 1.3, rozszerzenia serwera występują wewnątrz głównego procesu serwera WWW.

Rysunek 1.3. Okres trwałości rozszerzeń serwera PoniewaŜ specyficzne dla serwera interfejsy wykorzystują połączony kod C lub C++, rozszerzenia serwera działają niezwykle szybko i w pełni wykorzystują zasoby serwera. Nie są one jednak rozwiązaniem doskonałym. Poza tym, Ŝe są one cięŜkie w tworzeniu i utrzymaniu, stanowią powaŜne zagroŜenia dla bezpieczeństwa i niezawodności — załamanie rozszerzenia moŜe prowadzić do załamania całego serwera, złośliwe rozszerzenie moŜe kraść hasła uŜytkowników i numery kart kredytowych. Oraz, oczywiście konkretne rozszerzenia są nierozerwalnie związane z API serwera, dla którego zostały napisane, a takŜe do konkretnego systemu operacyjnego.

JavaScript działający po stronie serwera iPlanet/Netscape posiada równieŜ technikę skryptów działających po stronie serwera, nazywaną server-side JavaScript, w skrócie SSJS. Podobnie jak ASP, SSJS pozwala na osadzanie fragmentów kodu w stronach HTML w celu utworzenia dynamicznej zawartości WWW. RóŜnica jest taka, Ŝe SSJS wykorzystuje JavaScript jako język skryptowy. Z SSJS, strony są prekompilowane w celu poprawienia wydajności. Obsługa SSJS jest moŜliwa jedynie w serwerach iPlanet/Netscape. Większa ilość informacji na temat programowania przy pomocy JavaScript działającego po stronie serwera dostępna jest pod adresem http://developer.netscape.com/tech/javascript/ssjs/ssjs.html.

Active Server Pages Microsoft posiada technikę tworzenia dynamicznej zawartości WWW o nazwie Active Server Pages (Aktywne Strony Serwera), w skrócie ASP. Przy pomocy ASP, strona HTML moŜe zawierać fragmenty osadzonego kodu (zazwyczaj VBScript lub Jscript — chociaŜ moŜliwe jest zastosowanie niemal kaŜdego języka). Kod ten jest odczytywany i wykonywany przez serwer WWW przed wysłaniem strony do klienta. ASP został optymalizowany do tworzenia niewielkich porcji zawartości dynamicznej, większe pozostawiając składnikom COM. Obsługa ASP jest wbudowana w Internet Information Server Microsoftu w wersji 3.0 i wyŜszych, dostępnym bezpłatnie pod adresem http://www.microsoft.com/iis. Obsługa innych serwerów WWW jest dostępna jako komercyjny produkt firmy Chili!Soft pod adresem http://www.chilisoft.com. Proszę pamiętać, Ŝe strony ASP działające na platformie nie będącej Windows mogą mieć problemy z powodu braku biblioteki Windows COM. Większa ilość informacji na temat programowania ActiveServerPages jest dostępna pod adresem http://www.microsoft.com/workshop/server/default.asp oraz http://www.activeserverpages.com/.

JavaServer Pages JavaServer Pages, często nazywana po prostu JSP, jest opartą na Javie alternatywą dla ASP, utworzoną i wystandaryzowaną przez firmę Sun. JSP wykorzystuje składnię podobną do ASP poza tym, Ŝe językiem skryptowym w tym przypadku jest Java. Odwrotnie niŜ ASP, JSP jest otwartym standardem implementowanym przez wielu producentów na wszystkich platformach. JSP jest ścisłe związana z serwletami, poniewaŜ strona JSP jest przetwarzana do serwletu, co stanowi część jej wykonania. JSP jest bardziej szczegółowo opisana w dalszych częściach niniejszej ksiąŜki. Większa ilość informacji na temat JSP jest dostępna pod adresem http://java.sun.com/products/jsp.

Serwlety Javy W tym miejscu pojawiają się serwlety Javy. Jak wspomniano wcześniej, serwlet jest ogólnym rozszerzeniem serwera — klasą Javy, która moŜe być dynamicznie ładowana w celu rozszerzenia funkcjonalności serwera. Serwlety są często uŜywane w serwerach WWW, gdzie zajmują miejsce skryptów CGI. Serwlet jest podobny do poprzednio omawianego rozszerzenia serwera, poza tym, Ŝe działa on wewnątrz wirtualnej maszyny Javy (Java Virtual Machine — JVM) na serwerze (proszę spojrzeć na rysunek 1.4), tak więc są one bezpieczne i przenośne. Serwlety działają wyłącznie w domenie serwera — inaczej niŜ aplety, nie wymagają one obsługi Javy przez przeglądarkę WWW.

Rysunek 1.4. Okres trwałości serwletu Inaczej niŜ CGI i FastCGI, które muszą wykorzystywać wiele procesów w celu obsługi oddzielnych programów i/lub oddzielnych Ŝądań, serwlety mogą być obsługiwane przez osobne wątki w tym samym procesie, z wieloma procesami rozciągniętymi na klika serwerów wspierających. Oznacza to, Ŝe serwlety są równieŜ wydajne i skalowalne. PoniewaŜ serwlety działają z komunikacją dwustronną do serwera WWW, mogą bardzo ściśle współpracować z serwerem w celu wykonania działań niemoŜliwych dla skryptów CGI. Inną zaletą serwletów jest ich przenośność — zarówno pomiędzy systemami operacyjnymi jak w przypadku Javy, jak i pomiędzy serwerami WWW. Jak zostanie to opisane poniŜej, większość głównych serwerów WWW obsługuje serwlety. UwaŜa się, Ŝe serwlety stanowią najlepszą moŜliwą platformę dla tworzenia aplikacji WWW, a więcej informacji na ten temat zostanie podane w dalszej części tego rozdziału.

Obsługa serwletów Podobnie jak sama Java, serwlety zostały zaprojektowane w celu zapewnienia maksymalnej przenośności. Serwlety obsługiwane są przez wszystkie platformy obsługujące równieŜ Javę, oraz pracują w większości podstawowych serwerów WWW1. Serwlety Javy zdefiniowane przez dział Java Software firmy Sun Microsystems (dawniej znany jako JavaSoft), stanowią Pakiet Opcjonalny (Optional Package) dla Javy (dawniej znany jako Rozszerzenie Standardowe — Standard Extension). Oznacza to, Ŝe serwlety zostały oficjalnie pobłogosławione przez Sun'a i stanowią część języka Java, lecz nie są częścią podstawowego API Javy. Zamiast tego, są one znane jako część platformy J2EE. W celu ułatwienia tworzenia serwletów, Sun i Apache udostępniły klasy API niezaleŜnie od Ŝadnego mechanizmu WWW. Pakiety javax.servlet i javax.servlet.http składają się na Servlet API. Najnowsza wersja tych klas jest dostępna do pobrania pod adresem http://java.sun.com/products/servlet/download.html2. Wszystkie serwery WWW obsługujące serwlety muszą

1 Proszę zauwaŜyć, Ŝe niektórzy producenci serwerów WWW posiadają swoje własne implementacje Javy działającej po stronie serwera, niektóre z nich noszą równieŜ nazwę serwletów. Są one generalnie niekompatybilne z serwletami Javy utworzonymi przez Sun'a. Większość z tych producentów konwertuje swoją obsługę Javy do standardowych serwletów lub wprowadzają obsługę standardowych serwletów równolegle, w celu zapewnienia wstecznej kompatybilności. 2

W pewnym momencie planowano dołączenie tych klas do JDK 1.2. Później jednak zdecydowano na utrzymanie ich niezaleŜności od JDK w celu ułatwienia dokonywania poprawek do Servlet API.

wykorzystywać te klasy wewnętrznie (chociaŜ mogą stosować alternatywną implementację), tak więc generalnie ten plik JAR moŜe zostać znaleziony gdzieś wewnątrz dystrybucji serwera WWW obsługującego serwlety. Nie jest waŜne, skąd pobiera się klasy serwletów, naleŜy posiadać je jednak w swoim systemie w celu kompilowania serwletów. Dodatkowo konieczny jest program uruchamiający serwlety (technicznie nazywany kontenerem serwletów, czasami mechanizmem serwletów), w celu przetestowania i udostępnienia serwletów. Wybór kontenera serwletów zaleŜy po części od działającego w danym systemie serwera(ów) WWW. Istnieją trzy odmiany kontenerów serwletów — samodzielne, dołączane i osadzane.

Samodzielne kontenery serwletów Samodzielny kontener serwletów to serwer zawierający wbudowaną obsługę serwletów. Taki kontener posiada tę przewagę, Ŝe wszystko w nim działa niejako od razu. Jednak wadą jest konieczność oczekiwania na nową wersję serwera WWW w celu uzyskania obsługi najnowszych serwletów. Inną wadą jest takŜe fakt, Ŝe producenci serwerów generalnie obsługują jedynie JVM dostarczoną przez samych siebie. Serwery WWW dostarczające samodzielnej obsługi to między innymi:

3



Tomcat Server Apache, oficjalna wzorcowa implementacja sposobu obsługi serwletów przez kontener. Napisany całkowicie w Javie, dostępny bezpłatnie w licencji Open Source. Dostępny jest cały kod źródłowy i kaŜdy moŜe pomóc w jego tworzeniu. Serwer ten moŜe działać samodzielnie lub jako dodatek dostarczający obsługi serwletów Apache'owi lub innym serwerom. MoŜe być równieŜ wykorzystywany jako kontener osadzony. Równolegle z Tomcatem, Apache tworzy standardową implementację pakietów javax.servlet i javax.servlet.http. W trakcie pisania niniejszej ksiąŜki serwlety są jedynymi pakietami java.* lub javax.* utrzymywanymi jako Open Source3. Proszę zobaczyć http://jakarta.apache.org.



iPlanet Web Server Enterprise Edition Netscape'a (wersja 4.0 i późniejsze), przypuszczalnie najpopularniejszy serwer WWW zawierający wbudowaną obsługę serwletów. Niektóre testy wykazują, Ŝe posiada on najszybszą implementację serwletów. Proszę pamiętać, Ŝe chociaŜ wersje 3.51 i 3.6 zawierały wbudowaną obsługę serwletów, to jednak był to wczesny Servlet API 1.0 i zawierały one duŜą liczbę błędów tak powaŜnych, Ŝe obsługa serwletów była praktycznie bezuŜyteczna. W celu wykorzystania serwletów z serwerami Netscape'a w wersji 3.x naleŜy wykorzystać dołączany kontener. Proszę zobaczyć http://www.iplanet.com.



WebSite Professional O'Reilly, o podobnej funkcjonalności do Enterprise Server iPlanet, lecz za niŜszą cenę. Proszę zobaczyć http://website.oreilly.com.



Zeus Web Server, serwer WWW uwaŜany przez niektórych za najszybszy z dostępnych. Jego lista własności jest dość długa i zawiera obsługę serwletów. Proszę zobaczyć http://www.zeus.co.uk.



Resin Caucho, kontener Open Source, uwaŜany za bardzo wydajny. MoŜe być uruchamiany w trybie samodzielnym lub jako dodatek do wielu serwerów. Proszę zobaczyć http://www.caucho.com.



LiteWebServer Gefion Software, niewielki (nieco ponad 100 KB) kontener serwletów utworzony dla zastosowań, takich jak dołączanie do wersji demonstracyjnych, gdzie niewielki rozmiar ma znaczenie. Proszę zobaczyć http://www.gefionsoftware.com/LiteWebServer.



Jigsaw Server World Wide Web Consortium Open Source, napisany całkowicie w Javie. Proszę zobaczyć http://www.w3.org/Jigsaw.



Java Web Server firmy Sun, serwer, od którego wszystko się rozpoczęło. Serwer ten był pierwszym serwerem implementującym serwlety oraz działał jako efektywna wzorcowa implementacja dla Servlet API 2.0. Jest on napisany całkowicie w Javie (poza dwoma bibliotekami kodu macierzystego, które powiększają funkcjonalność, lecz nie są konieczne). Sun nie kontynuuje juŜ prac nad serwerem, koncentrując się na produktach iPlanet/Netscape w ramach sojuszu Sun-Netscape. Proszę zobaczyć http://java.sun.com/products.

Implementacja javax.servlet i javax.servlet.http w standardzie Open Source spowodowała naprawienie wielu błędów (na przykład, autor miał okazję poprawić obsługę warunkowego GET w HttpServlet) i kwestii niekompatybilności. Istnieje nadzieja, Ŝe przykład ten wspomoŜe w udostępnieniu większej ilości oficjalnych pakietów Javy jako Open Source

Serwery aplikacji są rosnącym obszarem tworzenia. Serwer aplikacji oferuje obsługę po stronie serwera dla tworzenia aplikacji korporacyjnych. Większość aplikacji opartych na Javie obsługuje serwlety i pozostałą część specyfikacji Java 2, Enterprise Edition (J2EE).Serwery te to miedzy innymi: •

WebLogic Application Server BEA System, jeden z pierwszych i najsłynniejszych opartych na Javie serwerów aplikacji. Proszę zobaczyć http://www.beasys.com/products/weblogic.



Orion Application Server, wysoko wydajny serwer o stosunkowo niskiej cenie, napisany całkowicie w Javie. Proszę zobaczyć http://www.orionserver.com.



Enhydra Application Server, serwer Open Source firmy Lutris. Proszę zobaczyć http://www.enhydra.org.



Borland Application Server 4, serwer ze specjalnym naciskiem na technologię CORBA. Proszę zobaczyć http://www.borland.com/appserver.



WebSphere Application Server IBM, wysokowydajny serwer oparty w części na kodzie Apache'a. Proszę zobaczyć http://www-4.ibm.com/software/webservers.



Dynamo Application Server 3 ATG, kolejny wysokowydajny serwer napisany całkowicie w Javie. Proszę zobaczyć http://www.atg.com.



Application Server Oracle, serwer zaprojektowany do integracji z bazą danych Oracle. Proszę zobaczyć http://www.oracle.com/appserver.



iPlanet Application Server, zgodny z J2EE większy brat iPlanet Web Server Enterprise Edition. Proszę zobaczyć http://www.iplanet.com/products/infrastructure/app_servers/nas.



GemStone/J Application Server, serwer Javy stworzony przez firmę poprzednio znaną z serwera Smalltalk. Proszę zobaczyć http://www.gemstone.com/products/j.



Jrun Server Allaire (poprzednio Live Software), prosty kontener serwletów, który rozrósł się do zaawansowanego kontenera dostarczającego wiele technologii J2EE włączając w to EJB, JTA i JMS. Proszę zobaczyć http://www.allaire.com/products/jrun.



Silverstream Application Server, w pełni zgodny z J2EE serwer, który rozpoczął równieŜ od skupienia się na serwletach. Proszę zobaczyć http://www.silverstream.com.

Dołączane kontenery serwletów Dołączany kontener serwletów działa jako moduł rozszerzający do istniejącego serwera — dodaje obsługę serwletów do serwera, który w oryginale nie był do tego przeznaczony, lub do serwera ze słabą lub nieaktualną implementacją serwletów. Dołączane kontenery serwletów zostały utworzone dla wielu serwerów, między innymi Apache'a, FastTrack Server i Enterprise Server iPlanet, Internet Information Server i Personal Web Server Microsoftu, Website O'Reilly, Go Webserver Lotus Domino, WebSTAR StarNine oraz AppleShare IP Apple. Dołączane kontenery serwletów to między innymi: •

ServletExec New Atlanta — moduł rozszerzający zaprojektowany do obsługi serwletów we wszystkich popularnych serwerach na wszystkich popularnych systemach operacyjnych. Zawiera bezpłatny program uruchomieniowy. Proszę zobaczyć http://www.servletexec.com.



Jrun Allaire (dawniej Live Software), dostępny jako moduł rozszerzający do obsługi serwletów we wszystkich popularnych serwerach na wszystkich popularnych systemach operacyjnych. Proszę zobaczyć http://www.allaire.com/products/jrun/.



Moduł Jserv projektu Java-Apache, bezpłatny kontener serwletów Open Source, który dodaje obsługę serwletów do niezwykle popularnego serwera Apache. Tworzenie Jserv zakończyło się, a Tomcat Server (działający jako moduł rozszerzający) jest jego następcą. Proszę zobaczyć http://java.apache.org/.



Tomcat Server Apache, jak opisano poprzednio. Tomcat moŜe być dołączony do innych serwerów takich jak Apache, iPlanet/Netscape i IIS.

Osadzane kontenery serwletów Osadzany kontener jest ogólnie niewielką platformą programistyczną, która moŜe być osadzana w innych aplikacjach. Aplikacja ta staje się prawdziwym serwerem. Osadzane kontenery serwletów to między innymi: •

Tomcat Server Apache, podczas gdy ogólnie uŜywany samodzielnie lub dołączany, moŜe być równieŜ osadzany w innej aplikacji, kiedy jest to potrzebne. PoniewaŜ serwer ten to Open Source, tworzenie większości innych osadzanych serwerów zatrzymano.



Nexus Web Server autorstwa Andersa Kristensena, dostępny bezpłatnie program uruchamiający serwlety, implementujący większą część Servlet API, który moŜe być w łatwy sposób dołączany do aplikacji Javy. Proszę zobaczyć http://www-uk.hpl.hp.com/people/ak/java/nexus/.

Uwagi dodatkowe Przed przejściem do następnej części naleŜy zapamiętać, Ŝe nie wszystkie kontenery serwletów są tworzone w jednakowy sposób. Tak więc przed wybraniem kontenera serwletów (i prawdopodobnie serwera) przy pomocy którego udostępniane będą serwlety, naleŜy go wypróbować, prawie do granic moŜliwości. Sprawdzić listy dystrybucyjne. NaleŜy zawsze sprawdzać, czy serwlety zachowują się tak, jak we wzorcowej implementacji Tomcata. MoŜna równieŜ sprawdzić, jakie narzędzia programistyczne są dostarczane, które technologie J2EE są wspierane i jak szybko moŜna uzyskać pomoc u producenta. W przypadku serwletów nie trzeba się martwić o zgodność z najsłabszą implementacją, tak więc naleŜy pobrać kontener serwletów, który posiada wszystkie poŜądane właściwości. Kompletna, aktualna lista dostępnych kontenerów serwletów razem z ich obecnymi cenami jest dostępna pod adresem http://www.servlets.com.

Potęga serwletów Jak dotychczas serwlety zostały opisane jako alternatywa dla innych technologii dynamicznej zawartości WWW, lecz nie zostało tak naprawdę powiedziane, dlaczego powinny być one, zdaniem autorów, stosowane. Co sprawia, Ŝe serwlety są jednym z najlepszych sposobów programowania WWW? Zdaniem autorów posiadają one kilka zalet ponad innymi podejściami, włączając w to przenośność, moc, wydajność, wytrzymałość, bezpieczeństwo, elegancję, integrację, rozszerzalność i elastyczność. KaŜda z tych własności zostanie kolejno omówiona.

Przenośność PoniewaŜ serwlety są pisane w Javie według dobrze zdefiniowanego i szeroko akceptowanego API, są one w duŜym stopniu przenośne pomiędzy systemami operacyjnymi i implementacjami serwerów. MoŜna stworzyć serwlet na komputerze pod Windows NT i z serwerem Tomcat, po czym bez problemu udostępnić go na wysoko wydajnym serwerze Uniksowym z iPlanet/Netscape Application Server. Stosując serwlety moŜna naprawdę „napisać raz, udostępniać wszędzie”. Przenośność serwletów nie jest tak waŜną sprawą jak w przypadku apletów, z dwóch powodów. Po pierwsze, przenośność serwletów nie jest obowiązkowa. Inaczej niŜ w przypadku apletów, które muszą zostać przetestowane na wszystkich moŜliwych platformach klientów, serwlety muszą pracować jedynie na serwerach, które są wykorzystywane do tworzenia i udostępniania. Dopóki nie sprzedaje się swoich serwletów, nie trzeba się martwić o kompletną przenośność. Po drugie, serwlety unikają najbardziej pełnej błędów i niespójnie zaimplementowanej części języka Java — Abstract Windowing Toolkit (AWT), który stanowi bazę graficznych interfejsów Javy, takich jak Swing.

Moc Serwlety mogą wykorzystywać pełną moc jądra API Javy — pracę w sieci i dostęp do URL-i, wielowątkowość, kompresję danych, łączność z bazami danych (JDBC), serializację obiektów, zdalne wywoływanie metod (RMI)

oraz integrację ze starymi programami (CORBA). Serwlety mogą równieŜ korzystać z platformy J2EE, która zawiera obsługę Enterprise JavaBeans (EJBs), transakcji rozproszonych (JTS), standaryzowanych wiadomości (JMS), wyszukiwania katalogów (JNDI) oraz zaawansowanego dostępu do baz danych (JDBC 2.0). Lista standardowych API dostępnych serwletom rośnie, czyniąc tworzenie aplikacji WWW szybszym, łatwiejszym i bardziej niezawodnym. Jako autor serwletów, moŜna wykorzystać dowolną z mnóstwa niezaleŜnych klas Javy i składników JavaBeans. Serwlety mogą uŜywać niezaleŜnego kodu w celu obsługi zadań takich jak wyszukiwanie według wyraŜeń regularnych, tworzenie wykresów danych, dostosowany dostęp do baz danych, zaawansowana praca w sieci, analiza składniowa XML oraz tłumaczenia XSLT. Serwlety są równieŜ sprawne w umoŜliwianiu komunikacji klient-serwer. Posiadając oparty na Javie aplet i oparty na Javie serwlet, moŜna wykorzystać RMI i serializację obiektu w komunikacji klient-serwer, co oznacza, Ŝe ten sam kod moŜna wykonać zarówno na maszynie klienta, jak i na serwerze. Wykorzystywanie po stronie serwera języków innych niŜ Java jest znacznie bardziej skomplikowane, jako Ŝe konieczne jest tworzenie swoich własnych protokołów do obsługi komunikacji.

Wydajność i wytrzymałość Wywoływanie serwletów charakteryzuje się bardzo wysoką wydajnością. Kiedy serwlet zostaje załadowany, pozostaje w pamięci serwera jako pojedynczy egzemplarz obiektu. Następnie serwer wywołuje serwlet do obsługi Ŝądania przy pomocy prostego wywołania metody. Inaczej niŜ w przypadku CGI, nie trzeba wywoływać procesu ani interpretatora, tak więc serwlet moŜe rozpocząć obsługę Ŝądania niemal natychmiast. Wielokrotne, równoległe Ŝądania są obsługiwane przez osobne wątki, tak więc serwlety są w wysokim stopniu skalowalne. Serwlety są obiektami z natury trwałymi. PoniewaŜ serwlet zostaje w pamięci serwera jako pojedynczy egzemplarz obiektu, automatycznie zachowuje swój stan i moŜe utrzymywać kontakt z zasobami zewnętrznymi, takimi jak połączenia z bazami danych. W innym przypadku przywrócenie połączenia mogłoby zabrać kilkanaście sekund.

Bezpieczeństwo Serwlety obsługują bezpieczne praktyki programowania na róŜnych poziomach. PoniewaŜ są one pisane w Javie, dziedziczą po niej silne bezpieczeństwo typów. Podczas gdy większość wartości w programie CGI, włączając w to element numeryczny taki, jak numer portu serwera, są traktowane jako łańcuchy, wartości w Servlet API są manipulowane przy pomocy ich naturalnych typów, tak więc numer portu serwera jest reprezentowany jako integer. Automatyczne zbieranie śmieci przez Javę i brak wskaźników oznaczają, Ŝe serwlety są generalnie bezpieczne od problemów z zarządzaniem pamięcią, takich, jak uszkodzone wskaźniki, niewłaściwe odwołania do wskaźników oraz uszczerbki pamięci. Serwlety mogą bezpiecznie obsługiwać błędy, dzięki mechanizmowi obsługi wyjątków lub kontrolerowi dostępu Javy. JeŜeli serwlet wykona dzielenie przez zero lub inne nieprawidłowe działanie, wyrzuca wyjątek, który moŜe być bezpiecznie wychwycony i obsłuŜony przez serwer, który zapisze błąd w dzienniku zdarzeń i przeprosi uŜytkownika. JeŜeli podobny wyjątek napotkałoby rozszerzenie serwera oparte na C++, przypuszczalnie nastąpiłoby załamanie serwera. Serwer moŜe chronić siebie w większym stopniu poprzez zastosowanie menedŜera bezpieczeństwa lub kontrolera dostępu Javy. Serwer moŜe wykonywać swoje serwlety pod ochroną dokładnego kontrolera dostępu który, na przykład wymusza politykę bezpieczeństwa zaprojektowaną do strzeŜenia przed złośliwym lub źle zaprojektowanym serwletem dąŜącym do zniszczenia systemu plików serwera.

Elegancja Elegancja kodu serwletów jest uderzająca. Kod serwletów jest czysty, obiektowy, modularny i zadziwiająco prosty. Jednym z powodów tej prostoty jest sam Servlet API, który zawiera metody i klasy obsługujące wiele rutynowych elementów programowania serwletów. Nawet zaawansowane operacje, takie jak obsługa cookies i śledzenie sesji, są rozkładane na odpowiednie klasy. Kilka bardziej zaawansowanych, lecz takŜe popularnych zadań zostało pozostawione poza API, i w tych przypadkach autorzy próbowali to naprawić i tak powstał zbiór przydatnych klas w pakiecie com.oreilly.servlet.

Integracja Serwlety są ściśle zintegrowane z serwerem. Ta integracja pozwala serwletowi na współpracę z serwerem w sposób niedostępny dla programów CGI. Na przykład, serwlet moŜe wykorzystywać serwer w celu przetłumaczenia ścieŜek plików, dokonania logowania, sprawdzenia uwierzytelnienia oraz wykonania odwzorowania typu MIME. Właściwe dla konkretnego serwera rozszerzenia mogą wykonać większość tej pracy, lecz proces ten jest zazwyczaj znacznie bardziej złoŜony i obfity w błędy.

Rozszerzalność i elastyczność Servlet API jest zaprojektowany w celu zapewnienia łatwej rozszerzalności. W obecnym czasie, API zawiera klasy z wyspecjalizowaną obsługą serwletów HTTP. Lecz w późniejszym okresie moŜe być ona rozszerzona i zoptymalizowana dla innego typu serwletów, czy to produkcji Suna, czy innej firmy. Jest równieŜ moŜliwe, Ŝe jego obsługa serwletów HTTP moŜe być dalej rozwijana. Serwlety cechują się równieŜ elastycznością w tworzeniu zawartości. Mogą tworzyć prostą zawartość przy pomocy wyraŜeń out.println(), lub generować skomplikowany zbiór stron przy pomocy mechanizmu szablonów. Mogą tworzyć stronę HTML przez traktowanie strony jako zestawu obiektów Javy, lub tworzyć stronę HTML przez wykonanie transformacji XML do HTML. Serwlety mogą być nawet łączone w celu utworzenia całkowicie nowych technologii takich jak JavaServer Pages. Nie wiadomo, do czego jeszcze zostaną wykorzystane.

W tym rozdziale: •

Podstawy HTTP



Interfejs API (Servlet API)



Tworzenie strony



Aplikacje WWW



Przejdźmy dalej

Rozdział 2.

Aplety Http — wprowadzenie Ten rozdział to krótki samouczek pisania i uruchamiania prostych apletów HTTP. Opisane tutaj zostanie jak wdroŜyć aplet do standardowej aplikacji WWW i jak skonfigurować jego zachowanie przy uŜyciu XML-owego deskryptora rozmieszczenia. W przeciwieństwie do pierwszej edycji niniejszej ksiąŜki, ten rozdział obecnej nie opisuje opartych na apletach plików dołączanych serwera (SSI) lub wiązania łańcuchowego oraz filtrowania apletu. Mimo tego, iŜ techniki te były bardzo przydatne oraz zostały umieszczone w serwerze WWW (Java Web Server), nie zostały zatwierdzone w specyfikacji apletu, (która ukazała się po pierwszej edycji niniejszej pozycji). SSI zostały zastąpione przez nowe techniki tworzenia plików dołączanych programu. Wiązanie łańcuchowe apletu zostało uznane za zbyt nieczytelne dla oficjalnego zatwierdzenia, mimo tego jest wielce prawdopodobne, Ŝe sama jego idea zostanie wykorzystana w Interfejsie API 2.3 (Servlet API 2.3) jako część oficjalnego mechanizmu ogólnego zastosowania przed i po — filtrującego.

Zwróćmy uwagę, iŜ moŜliwe jest ściągnięcie kodów dla kaŜdego z przykładów zamieszczonych w tym oraz innych rozdziałach tej ksiąŜki, zarówno w formie źródłowej jak i skompilowanej (jak zostało to opisane w przedmowie). JednakŜe, co się tyczy tego rozdziału, wydaje się, iŜ rzeczą najbardziej pomocną w nauce będzie zapisanie przykładów ręcznie (za pomocą klawiatury). Lektura tego rozdziału moŜe prowadzić do wniosku, iŜ niektóre zagadnienia zostały potraktowane zbyt ogólnie. Aplety to narzędzia dające wiele moŜliwości i czasem bywają skomplikowane, dlatego teŜ rozdział ten ma na celu wprowadzenie w ogólne zasady ich działania i zorientowania się w temacie. Czytelnik po lekturze niniejszej ksiąŜki będzie w stanie samodzielnie tworzyć najrozmaitsze aplety.

Podstawy HTTP Zanim przejdziemy do omawiania prostych apletów HTTP, musimy sprawdzić znajomość podstaw działania protokołu HTTP. Będąc doświadczonym w programowaniu w CGI (lub mając doświadczenie w tworzeniu stron WWW na serwerach) moŜna z powodzeniem pominąć czytanie tego podrozdziału. W takim przypadku korzystnym wydaje się zatrzymanie się na istotnych zagadnieniach metod GET i POST. JednakŜe będąc osobą stawiającą pierwsze kroki w tworzeniu stron WWW na serwerach, naleŜy przeczytać wspomniany materiał uwaŜnie, poniewaŜ zrozumienie dalszej części ksiąŜki wymaga znajomości protokołu HTTP. Protokół HTTP został szczegółowo omówiony w „Pocket Reference” Clintona Wong’a (wydawnictwo O’Reilly).

Zlecenia, odpowiedzi, nagłówki HTTP jest prostym, międzynarodowym protokołem. Klient, np. przeglądarka WWW składa zlecenie, serwer WWW odpowiada i dokonywana jest tzw. „obsługa zlecenia”. Kiedy klient składa zlecenie, pierwszą rzeczą którą wykonuje, jest komenda HTTP zwana metodą, za pomocą której serwer orientuje się jaki rodzaj zlecenia jest składany. Pierwszy wiersz zlecenia określa adres dokumentu (URL) oraz uŜywaną wersję protokółu HTTP. Oto przykład: GET/intro.html Http/1.0

W tym zleceniu chodzi o uzyskanie dokumentu o nazwie intro.html za pomocą wersji 1.0 HTTP. Po przesłaniu zlecenia klient moŜe przesłać informacje nagłówkową w celu dostarczenia serwerowi dodatkowych informacji o zleceniu, takich jak: jakie oprogramowanie jest uŜywane przez klienta oraz jaka forma informacji potrzebna jest klientowi do jej zrozumienia. Takie informacje nie odnoszą się bezpośrednio do tego, co było przedmiotem zlecenia, jednakŜe mogą być wykorzystane przez serwer w tworzeniu odpowiedzi. Oto dwa przykłady nagłówków zleceń: User-Agent : Mozilla/4.0 (compatabile; MSIE 4.0; Windows 95) Accept : image/gif, image/jpeg, text/*, */*

Nagłówek User-Agent dostarcza informacji o oprogramowaniu klienta, podczas gdy nagłówek Accept określa rodzaj nośnika (MIME) najkorzystniejszy dla klienta (nagłówki zleceń zostaną

omówione szerzej przy omawianiu apletów, w rozdziale 4 „Odczytywanie informacji”). Celem zaznaczenia końca sekcji nagłówkowej, po przesłaniu nagłówków, klient przesyła nie zapisany wiersz. JeŜeli wymaga tego uŜywana metoda, klient moŜe równieŜ przesłać inne dodatkowe dane, tak jak w przypadku metody POST, która zostanie zaraz omówiona. JeŜeli zlecenie nie zawiera Ŝadnych danych, to kończy się nie zapisanym wierszem. Po przesłaniu przez klienta zlecenia, serwer przetwarza je i przesyła odpowiedź. Pierwszy wiersz odpowiedzi zawiera wiersz statusu oraz jego opis. Oto przykład: HTTP/1.0 200 OK.

PowyŜszy wiersz statusu zawiera kod statusu 200, co oznacza Ŝe zlecenie zostało wykonane, stąd opis OK. Kolejny często spotykany kod to 404 z opisem Not Found (nie znaleziono), jak łatwo się domyśleć opis ten oznacza, Ŝe dokument nie został odnaleziony. W rozdziale 5 „Przesyłanie informacji HTML” zostały omówione najczęściej spotykane kody statusu oraz w jaki sposób moŜna je wykorzystać w apletach. Dodatek D „Kody statusu HTTP” zawiera kompletną listę kodów statusu HTTP. Po przesłaniu wiersza statusu serwer przesyła nagłówki odpowiedzi, które są informacją dla klienta taką jak np.: jakiego oprogramowania uŜywa serwer oraz nośnika informacji uŜytego do zapisania odpowiedzi serwera. Oto przykład: Date: Saturday, 23-May-00 03:25:12 GMT Server: Tomcat Web Server/3.2 MIME-version:1.0 Content-type: text/html Content-length: 1029 Last-modified: Thursday, 7-May-00 12:15:35 GMT

Nagłówek Server dostarcza informacji o oprogramowaniu serwera, nagłówek Content-type określa rodzaj rozszerzenia MIME odnośnie danych zawartych w odpowiedzi (nagłówki odpowiedzi zostaną omówione szerzej w rozdziale 5). Po nagłówkach serwer przesyła „czysty wiersz” celem zakończenia sekcji nagłówkowej. JeŜeli zlecenie zostało wykonane, Ŝądane dane są następnie przesyłane jako część odpowiedzi. W przeciwnym wypadku odpowiedź moŜe zawierać informację tekstową dla osoby obsługującej przeglądarkę, która będzie wyjaśniała dlaczego serwer nie mógł wykonać zlecenia.

Metody GET i POST Klient łącząc się z serwerem moŜe złoŜyć zlecenie w kilku róŜnych formach, zwanych metodami. Najczęściej uŜywane metody to GET i POST. Metoda GET słuŜy do uzyskiwania informacji (dokumentów, wykresów, informacji bez danych), podczas, gdy metoda POST została zaprojektowana z myślą o wysyłaniu informacji (numerów kart kredytowych, danych statystycznych lub informacji baz danych). Wykorzystując analogię elektronicznego biuletynu informacyjnego, GET słuŜy do czytania a POST do zamieszczania w nim tekstu. GET to metoda uŜywana do wprowadzania URL-u bezpośrednio do przeglądarki lub podczas klikania na hiperlink; jednakŜe zarówno metoda GET jak i POST mogą być uŜywane do dostarczania formularzy HTML. Mimo, iŜ metoda GET została zaprojektowana w celu odczytywania informacji, moŜe zawierać jako część zlecenia informacje własne, które dokładniej precyzują to zlecenie. MoŜe to być np. układ współrzędnych x,y dla wykresów. Takie informacje są przesyłane jako ciąg znaków dołączonych do URL-u w formie znanej ciągiem zapytań. Ten sposób zamieszczania dodatkowych informacji w URL-u umoŜliwia przesłanie strony e-mailem bądź utworzenie z niej zakładki.

PoniewaŜ zlecenia GET nie są przeznaczone do przesyłania duŜych partii informacji, niektóre serwery ograniczają długość URL-ów i ciągów zapytań do około 240 znaków. W metodzie POST uŜywana jest odmienna technika przesyłania informacji do serwera, poniewaŜ niekiedy metody tej uŜywa się do przesyłania większych partii informacji. Zlecenie złoŜone za pomocą metody POST przesyła bezpośrednio wszystkie informacje (nie ograniczone co do długości) w nim zawarte za pomocą połączenia gniazdowego jako część swego zlecenia HTTP. Klient nie jest informowany o tej zamianie, URL nie ulega w ogóle zmianie. W efekcie zlecenia POST nie mogą być ani zapisane jako zakładki, ani wysłane e-mailem, ani teŜ w niektórych przypadkach nie mogą być w ogóle powtórnie załadowane. Powód jest prosty — sytuacja taka wynika z odpowiedniego zaprojektowania — informacja jak np. numer naszej karty kredytowej, powinna być przesyłana do serwera tylko raz. Stosując metodę POST uzyskujemy dodatkowo pewien stopień zabezpieczenia przy przesyłaniu poufnych informacji, poniewaŜ dziennik zdarzeń, który zapisuje wszystkie zgłoszenia URL-ów, nie rejestruje danych metody POST. W praktyce uŜycie metod GET i POST odbiega od celu, dla którego zostały zaprojektowane. Powszechną praktyką przy składaniu długich parametryzowanych zleceń na informacje jest uŜycie POST zamiast GET w celu uniknięcia problemów związanych z nadmiernie długimi URL-ami. Metoda GET jest równieŜ często wykorzystywana do ładowania informacji przez proste formularze poniewaŜ, no cóŜ, po prostu da się to w ten sposób zrobić. PowyŜsze problemy nie są jednak aŜ tak dramatyczne, wystarczy tylko pamiętać, iŜ zlecenia GET (z powodu tego, iŜ mogą być w prosty sposób zamieniane na zakładki) mogą wywołać zmianę na serwerze, za którą odpowiedzialny będzie klient. Chodzi o to, Ŝe zlecenia GET nie powinny być uŜywane do składania zleceń, uaktualniania baz danych oraz do innych działań umoŜliwiających identyfikację klienta (w przypadku wystąpienia zmian na serwerze).

Pozostałe metody Http Poza GET i POST istnieje jeszcze wiele, rzadziej uŜywanych metod HTTP, takich jak na przykład metoda HEAD. Metoda ta jest uŜywana przez klienta tylko do uzyskiwania nagłówków odpowiedzi, w celu określenia rozmiaru dokumentu, czasu modyfikacji lub ogólnej dostępności. Inne metody to PUT — do zamieszczania dokumentów bezpośrednio na serwerze, DELETE — wykorzystywana do ich usuwania stamtąd. Dwie ostatnie metody nie współpracują ze wszystkimi serwerami z powodu skomplikowanych procedur. Metoda TRACE jest powszechnie uŜywana do usuwania błędów — umoŜliwia przesłanie klientowi dokładnej treści jego zlecenia. Metoda OPTIONS moŜe być uŜyta do zapytania serwera, z którymi metodami współpracuje lub jak dotrzeć do poszczególnych jego zasobów.

Interfejs API (Servlet API) Po zapoznaniu się z podstawami HTTP, moŜemy przejść do omówienia interfejsów API, których z kolei uŜywa się do tworzenia apletów HTTP, lub innych rodzajów apletów odpowiednich dla tej materii. Aplety uŜywają klas i interfejsów z dwóch pakietów: javax.servlet i javax.servlet.http. Pakiet javax.servlet zawiera klasy i współpracuje ze standardowymi protokołowo–niezaleŜnymi apletami. Klasy te są rozszerzane przez klasy w pakiecie

java.servlet.http w celu dodania funkcjonalności specyficznej dla HTTP. Pakiet najwyŜszej klasy nazywa się javax zamiast zwykłego java, aby zasygnalizować, iŜ Interfejs API jest

pakietem dodatkowym (uprzednio zwanym Standardowym Rozszerzeniem). KaŜdy aplet musi wdroŜyć interfejs javax.servlet. Większość apletów wdraŜa ten interfejs przez rozszerzenie jednej z dwóch specjalnych klas: javax.servlet.GenericServlet lub javax.servlet.http.HttpServlet. Aplet niezaleŜny protokołowo powinien być podrzędny do GenericServlet, a aplet HTTP powinien być podrzędny w stosunku do HTTPservlet, który sam jest podklasą GenericServlet z dodana funkcjonalnością HTTP. W przeciwieństwie do zwykłego programu Java, i dokładnie tak jak zwykły aplet, aplet wykonywany na serwerze nie zawiera metody main(). Zamiast tego pewne metody apletów wywoływane są przez serwer w procesie obsługi zleceń. Za kaŜdym razem, kiedy serwer wysyła zlecenie do apletu, wywołuje jego metodę service(). Standardowy aplet w celu poprawnej obsługi zlecenia powinien zignorować swoją metodę service(). Metoda service() akceptuje dwa parametry: obiekt zlecenia i obiekt odpowiedzi. Obiekt zlecenia informuje aplet o zleceniu, a obiekt odpowiedzi uŜywany jest do wysyłania odpowiedzi. Rysunek 2.1. ukazuje jak standardowy aplet obsługujący zlecenie.

Rysunek 2.1. Standardowy aplet obsługujący zlecenie

Aplet HTTP zwykle nie ignoruje metody service(), tylko metodę doGet() (do obsługi zleceń GET) i metodę doPost() (do obsługi zleceń POST). Aplet HTTP moŜe zignorować jedną z powyŜszych metod lub obie, w zaleŜności od tego, jaki jest typ zlecenia, które ma obsłuŜyć. Metoda service() HttpServlet obsługuje instalację oraz transfer do wszystkich metod doXXX(), dlatego właśnie zwykle nie powinna być ignorowana. Na rysunku 2.2 został ukazany sposób, w jaki aplet HTTP obsługuje zlecenia metod GET i POST.

Rysunek 2.2. Aplet HTTP obsługujący zlecenia GET i POST Aplet HTTP moŜe zignorować odpowiednio metody doPut() i doDelete() celem obsłuŜenia zleceń PUT i DELETE. JednakŜe aplety HTTP generalnie nie modyfikują metod doTrace() czy doOptions(). Dla nich prawie zawsze wystarczające są implementacje domyślne. Pozostałe klasy w pakietach javax.servlet i javax.servlet.http to w większości klasy wspomagające. Na przykład klasy ServletRequest i ServletResponse w javax.servlet umoŜliwiają dostęp do zleceń i odpowiedzi standardowych serwerów, natomiast klasy HttpServletRequest i HttpServletResponse w javax.servlet.http umoŜliwiają dostęp do zleceń i odpowiedzi HTTP. Pakiet javax.servlet.http zawiera równieŜ klasę HttpSession, która oferuje wbudowaną funkcjonalność śledzenia sesji oraz klasę Cookie, która pozwala na szybkie instalowanie i przetwarzanie cookies.

Tworzenie strony Najbardziej podstawowy typ apletu HTTP tworzy pełną stronę HTML. Taki aplet ma zwykle dostęp do takich samych informacji, co przesyłane do skryptu CGI oraz do pewnej partii innych. Aplet, który tworzy strony HTML moŜe zostać uŜyty do wykonywania wszystkich zadań, tych które obecnie są wykonywane przy pomocy CGI, jak np. przetwarzanie formularzy HTML, tworzenie listy z bazy danych, przyjmowanie zamówień, sprawdzanie zamówień, sprawdzanie identyfikacji, itd.

Pisanie „Hello World” Przykład 2.1 ukazuje aplet HTTP tworzący kompletną stronę HTML. Dla uproszczenia sprawy aplet ten ,za kaŜdym połączeniem się z nim za pomocą przeglądarki WWW, wyświetla napis „Hello World”.*

*Pierwszy przykład zarejestrowanego programu „Hello World” pojawił się w „A Tutorial Introduction to the Language B”, napisanym przez Braiana Kernighana w 1973. Dla tych z czytelników, zbyt młodych, by pamiętać, język B był prekursorem języka C. Więcej informacji o języku programowania B oraz link do tej ksiąŜki moŜna znaleźć na stronie: http://cm.bell-labs.com/who/dmr/bintro.html.

Przykład 2.1. Aplet, który wyświetla „Hello World” import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HellWorld extends HttpServlet

{

public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType ("text/html"); PrintWriter out = res.getWriter ( ); out.println(""); out.println("Hello World"); out.println ("") ; out.println (Hello World"); out.println (""); } }

PowyŜszy aplet rozszerza klasę HttpServlet oraz ignoruje odziedziczoną z niej metodę doGet(). Kiedy serwer WWW otrzymuje zlecenie GET z tego apletu, kaŜdorazowo wywołuje metodę doGet(), przekazując mu obiekty HttpServletRequest oraz HttpServletResponse. Obiekt HttpServletRequest reprezentuje zlecenie klienta. Obiekt ten daje apletowi dostęp do informacji o kliencie, parametrach zlecenia, nagłówkach HTTP przekazywanych razem ze zleceniem oraz inne. W rozdziale 4. omówione zostały wszystkie moŜliwości obiektu zlecenia. Dla tego przykładu moŜemy jednak je pominąć jako, ze niezaleŜnie od typu zlecenia aplet ten wyświetla „Hello World”. Obiekt HttpServletResponse reprezentuje odpowiedź apletu. Aplet moŜe wykorzystać ten obiekt do dostarczenia danych klientowi. Mogą to być dane róŜnego typu, typ ten jednak powinien być określony jako część odpowiedzi. Aplet moŜe równieŜ uŜyć tego obiektu do ustalenia nagłówków odpowiedzi HTTP. W rozdziałach 5. i 6 „Przesyłanie treści multimedialnej” zostało omówione wszystko co moŜe zrobić aplet jako część odpowiedzi. Nasz aplet ustala najpierw za pomocą metody setContentType() typ zawartości swojej odpowiedzi do text/html, standardowego typu zawartości MIME dla stron HTML. Następnie uŜywa metody getWriter() w celu odczytania PrintWriter, międzynarodowego odpowiednika PrintStream. PrintWriter przekształca kod UNICODE Javy na kodowanie specyficzne lokalnie. Dla kodowania lokalnego — angielskiego zachowuje się tak jak PrintStream. Aplet uŜywa wreszcie PrintWriter do wysłania swojego HelloWorld HTML do klienta.

Uruchamianie „Hello World” Do tworzenia apletów potrzebne są dwie rzeczy: pliki klasy interfejsu API, które uŜywane są w tłumaczeniu programu źródłowego na język wynikowy oraz pojemnik apletu np. serwer WWW, który uŜywany jest z kolei przy uruchamianiu apletów. Wszystkie popularne pojemniki apletów oferują pliki klasy Interfejsu API, więc moŜna spełnić oba warunki (potrzebne do tworzenia apletów) za jednym ładowaniem.

Istnieją dziesiątki parametrów dostępnych pojemników apletów dla wdraŜania apletów, kilkanaście z nich zostało zamieszczonych w rozdziale 1 „Wprowadzenie”. Dokonując wyboru serwera naleŜy pamiętać, Ŝe musi on współpracować z wersją 2.2 Interfejsu API (Servlet API 2.2) lub późniejszą. Wersja 2.2 była pierwszą wersją Interfejsu API, która zapewniała dostęp do aplikacji WWW, jak zostało to omówione w tym rozdziale. Aktualna lista pojemników apletów oraz tego do jakiego poziomu API zapewniają one dostęp i jest dostępna pod adresem: http://www.servlets.com. Tak więc zapytajmy, co naleŜy zrobić z naszym kodem, aby zadziałał w serwerze WWW? — to zaleŜy od rodzaju serwera. W przykładach zaprezentowanych w tej ksiąŜce występuje serwer „Apache Tomcat 3.2”, serwer implementacji odniesienia API, napisany całkowicie w Javie, dostępny pod adresem: http://jakarta.apache.org. Serwer „Tomcat” zawiera mnóstwo dokumentacji, w której jest wyjaśnione jego zastosowanie. W niniejszej ksiąŜce dlatego właśnie omówione zostaną tylko ogólne zasady dotyczące pracy z serwerem. PoniŜsze omówienia powinny być takŜe zgodne z innymi serwerami (niŜ „Tomcat”) jednakŜe nie moŜna tego zagwarantować. JeŜeli uŜywamy serwera „Apache Tomcat”, to powinniśmy umieścić kod źródłowy dla apletu w katalogu server_root/webapps/ROOT/WEB-INF/classes (gdzie server_root jest katalogiem , w którym zainstalowaliśmy nasz serwer), jest to standardowa lokalizacja plików klasy apletu. Powód, dla którego aplety występują w tym katalogu zostanie omówiony później w tym rozdziale. Kiedy juŜ mamy właściwie umiejscowiony kod źródłowy HelloWorld, musimy go skompilować. To zadanie moŜemy wykonać przy pomocy standardowego kompilatora javac (lub naszego ulubionego środowiska graficznego Javy). NaleŜy się tylko upewnić, Ŝe mamy pakiety javax.servlet i javax.servlet.http w naszej ścieŜce klasy. Pracując z serwerem „Tomcat”, wystarczy tylko zamieścić server_root/lib/servlet.jar (lub przyszły odpowiednik) gdzieś w naszej ścieŜce klasy. Nazwa pliku oraz lokalizacja zaleŜą od serwera, więc w razie problemów trzeba zajrzeć do dokumentacji serwera, z którym mamy do czynienia. JeŜeli wyświetlony zostanie komunikat informujący o błędzie taki jak np. Package javax.server not found in import, oznacza to, Ŝe pakiety apletów nie są odnajdywane przez nasz kompilator, naleŜy więc sprawdzić nasza ścieŜkę klasy i spróbować jeszcze raz. Teraz, kiedy juŜ skompilowaliśmy nasz pierwszy aplet, moŜemy uruchomić nasz serwer i wejść do apletu. Uruchomienie serwera nie jest rzeczą trudną, naleŜy uaktywnić skrypt startup.sh (lub plik startowy startup.bat w Windows) znajdujący się w katalogu server_root/bin. To powinno wystarczyć do uruchomienia naszego serwera, jeŜeli pracujemy w Solairs lub w Windows. W przypadku pracy na innych systemach operacyjnych moŜe zdarzyć się sytuacja, Ŝe będziemy musieli dokonać pewnych modyfikacji w skryptach startowych. W przypadku konfiguracji domyślnych, serwer oczekuje na porcie 8080. Istnieje wiele sposobów dostępu do apletów. Dla przykładu moŜemy zrobić to przez wyraźne wprowadzenie do URL-u nazwy klasy apletu. MoŜemy wprowadzić URL do swojej ulubionej przeglądarki:http://server:8080/servlet/HelloWorld. Wyraz server zamieniamy na nazwę naszego komputera — serwera lub na localhost — jeŜeli serwer jest na naszym lokalnym komputerze. Powinna zostać wyświetlona strona podobna do tej poniŜej.

Rysunek 2.3. Aplet „HelloWorld” JeŜeli aplet byłby częścią pakietu musiałby zostać umieszczony w server_root/webapps/ROOT/WEB-INF/package/name.HelloWorld. Nie wszystkie serwery zezwalają automatycznie na dostęp do apletów przez uŜycie rodzajowego przedrostka /servlet/. Funkcja ta moŜe zostać wyłączona ze względów bezpieczeństwa, aby zapewnić, Ŝe dostęp do apletów jest moŜliwy tylko przez określoną konfigurację URL-u, w czasie administrowania serwerem. W celu zapoznania się ze szczegółami wyłączania i załączania przedrostka /servlet/ naleŜy zapoznać się z dokumentacją serwera, na którym pracujemy.

Przetwarzanie danych formularzowych Aplet „HelloWorld” nie jest zbyt skomplikowany, przejdźmy więc do rzeczy bardziej zaawansowanych. Tym razem utworzymy aplet, który będzie pozdrawiał uŜytkownika jego imieniem (i nazwiskiem). Nie jest to rzecz specjalnie skomplikowana, potrzebny jest nam najpierw formularz HTML, który spyta uŜytkownika o jego imię i nazwisko. Następująca strona powinna być w tym celu wystarczająca:

Introductions

Pozwól Ŝe spytam, jak się nazywasz?





Na rysunku 2.4 został ukazany sposób, w jaki strona ta zostanie wyświetlona na stronie uŜytkownika.

Rysunek 2.4. Formularz HTML Formularz ten powinien znaleźć się w pliku HTML, w katalogu serwera document_root. Jest to miejsce, w którym serwer szuka plików statycznych. Dla serweru „Tomcat” katalog ten to server_root/webapps/ROOT. Dzięki umieszczeniu pliku w tym katalogu, moŜe być on dostępny bezpośrednio pod adresem: http://server:8080/form.html. Kiedy uŜytkownik przesyła ten formularz, jego imię (i nazwisko) jest przesyłane do apletu „Hello” poniewaŜ uprzednio zainstalowaliśmy atrybut ACTION celem wskazania ich apletowi. Formularz uŜywa metody GET, więc jakiekolwiek dane są dodawane do URL-u zlecenia jako pasmo zapytań. JeŜeli np. uŜytkownik wprowadzi imię, nazwisko „Inigo Montoya”, URL zlecenia będzie wyglądał następująco: http://server:8080/servlet/Hello?name=Inigo+Montoya. Przerwa pomiędzy imieniem a nazwiskiem jest wyjątkowo kodowana przez przeglądarkę jako znak „+”, poniewaŜ URL nie moŜe zawierać spacji. Obiekt apletu: HttpServletRequest umoŜliwia dostęp do danych formularzowych w paśmie zapytań. Na przykładzie 2.2 została ukazana zmodyfikowana wersja naszego apletu „Hello”, która uŜywa swojego obiektu zlecenia do odczytywania parametru name. Przykład 2.2. Aplet, który „wie” kogo pozdrawia import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class Hello extends HttpServlet

{

public void doGet (HttpServletRequest req, HttpServletResponse res) throwsServletException, IOException { res.setContentType ("text/html"); PrintWriter out = res.getWriter ( ); String name = req.getParameter ("imię i nazwisko"); out.println(""); out.println("Hello, " + name + ""); out.println(" do hasła , deskryptora wdroŜenia, tak jak na przykładzie 3.8. Przykład 3.8. Ładowanie apletu przy rozruchu



ps

PrimeSearcher



PowyŜsze komendy „mówią serwerowi”, Ŝeby utworzył kopię PrimeSearcher pod rejestrowaną nazwą ps oraz Ŝeby zainicjował aplet podczas sekwencji uruchamiania serwera. Z apletem moŜna połączyć się wtedy na URL-u /servlet/ps. Zwróćmy uwagę, iŜ kopia apletu obsługująca URL /servlet/PrintWriter meSearcher nie jest ładowana przy rozruchu. Na przykładzie 3.8 znacznik jest pusty. Znacznik moŜe równieŜ zawierać dodatnią liczbę całkowitą, oznaczającą kolejność, w której aplet powinien być załadowany w odniesieniu do innych apletów kontekstu. Aplety z niŜszymi liczbami ładowane są przed tymi z liczbami większymi. Aplety z wartościami ujemnymi lub nie-całkowitymi mogą być ładowane w kaŜdym momencie sekwencji uruchamiania, dokładna kolejność zaleŜna jest wtedy od serwera. Dla przykładu, web.xml ukazany na przykładzie 3.9 gwarantuje, Ŝe first będzie załadowany przed second, podczas gdy anytime moŜe zostać załadowany w kaŜdym momencie rozruchu serwera. Przykład 3.9. PokaŜ moŜliwości apletu

first

First

10

second

Second

20

anytime

Anytime



Buforowanie podręczne po stronie klienta Do tej pory nauczyliśmy się, Ŝe aplety obsługują zlecenia GET przy pomocy metody doGet(). I jest to niemal prawda. Cała prawda, jednakŜe jest taka, Ŝe nie do kaŜdego zlecenia konieczne jest wywoływanie metody doGet(). Dla przykładu, przeglądarka WWW, która stale łączy się z PrimeSearcher będzie musiała wywołać doGet() tylko po tym jak wątek wyszukujący znajdzie nową liczbę pierwszą. Do tego czasu wszystkie wywołania doGet() generują po prostu stronę, którą uŜytkownik juŜ oglądał, stronę prawdopodobnie przechowywaną w pamięci podręcznej przeglądarki. To co jest na ten moment najbardziej potrzebne, to sposób w jaki aplet mógłby informować o zmianach w jego wydruku wyjściowym. I tutaj właśnie pomocne będzie omówienie metody getlastModified(). Większość serwerów zawiera, jako część swojej odpowiedzi, nagłówek Last-Modified, wtedy kiedy odsyła dokument. Przykład wartości nagłówka Last-Modified mógłby wyglądać w następujący sposób: Tue, 06-May-98 15:41:02 GMT

PowyŜszy nagłówek informuje klienta o tym, kiedy ostatnio została zmieniona strona. Informacja sama w sobie nie jest specjalnie wartościowa, jednak zyskuje na wartości w momencie kiedy przeglądarka powtórnie ładuje stronę. Większość przeglądarek WWW, podczas odnawiania strony, zawiera w swoich zleceniach nagłówek If-Modified-Since, którego struktura jest identyczna z nagłówkiem LastModified: Tue, 06-May-98 15:41:02 GMT

Nagłówek ten informuje serwer o czasie, w którym nagłówek Last-Modified strony, był po raz ostatni ładowany przez przeglądarkę. Serwer moŜe odczytać ten nagłówek oraz stwierdzić czy plik był zmieniany od określonego czasu. JeŜeli okaŜe się, Ŝe plik został zmieniony, serwer musi przesłać nową treść. JeŜeli okaŜę się, Ŝe plik nie uległ zmianie, wtedy serwer moŜe wysłać przeglądarce krótką odpowiedź, informującą ją o tym oraz o tym, Ŝe wystarczy powtórnie wyświetlić wersję dokumentu schowaną w schowku (ta odpowiedź to: kod stanu 304 Not Modified). Technika ta działa najlepiej w przypadku stron statycznych: serwer moŜe uŜyć systemu plików w celu sprawdzenia kiedy określony plik został zmodyfikowany po raz ostatni. JednakŜe dla treści tworzonej dynamicznie, takiej jaka jest odsyłana przez aplety, serwer potrzebuje dodatkowej pomocy. Jednak wszystko co moŜe zrobić to odtwarzać je bezpiecznie zakładając jednocześnie, Ŝe zawartość ulega zmianie z kaŜdym połączeniem, eliminując w ten sposób konieczność uŜycia nagłówków Last-Modified oraz If-Modified-Since. Dodatkową pomocą aplet moŜe słuŜyć poprzez implementację (wdroŜenie) metody getLastModified(). Aplet wdroŜy tą metodę, aby przesłać dane dotyczące czasu, w którym po raz ostatni zmienił swój wydruk wyjściowy. Serwery wywołują tą metodę dwa razy, pierwszy raz kiedy odsyłają odpowiedzi (w celu wstawienia nagłówka odpowiedzi Last-Modified). Drugi raz, podczas obsługi zleceń GET, które zawierają nagłówek If-Modified-Since, dzięki temu serwer moŜe odpowiedzieć w sposób inteligentny. JeŜeli czas odesłania przez getLastModified() jest taki sam, bądź wcześniejszy niŜ czas nadesłania nagłówka If-

Modified-Since, wtedy serwer przesyła kod stanu Not Modified. W przeciwnym wypadku serwer wywołuje metodę doGet() oraz odsyła wydruk wyjściowy apletu*.

Niektórym apletom moŜe sprawiać trudność ustalenie czasu ostatniej modyfikacji. Dlatego w takich sytuacjach najlepszym wyjściem jest uŜycie zachowania domyślnego „play-it-safe”. Większość apletów jednakŜe doskonale daje sobie z tym radę. RozwaŜmy przypadek apletu „bulletin board” („elektroniczny biuletyn informacyjny”), aplet taki moŜe zarejestrować i odesłać kiedy, po raz ostatni treść biuletynu została zmieniona. Nawet gdy ten sam aplet obsługuje kilka biuletynów, nadal moŜe przesyłać róŜne czasy modyfikacji, odpowiednie dla parametrów podanych w zleceniu. Oto metoda get-Last-Modified dla naszego przykładu PrimeSearcher, która przesyła czas znalezienia ostatniej liczby pierwszej: public long getLastModified(HttpServletRequest req) { return lastprimeModified.getTime() /1000 * 1000; }

Zwróćmy uwagę, iŜ metoda ta przesyła wartość długą, która przedstawia czas jako liczbę milisekund, która upłynęła od 1 stycznia 1970 roku GMT. Takiej samej reprezentacji uŜywa Java w celu przechowywania wartości czasowych. Dzięki temu aplet uŜywa metody getTime() do wczytania LastprimeModified() jako long. Aplet zanim odeśle tą wartość czasową, zaokrągla ją do najbliŜszej sekundy, dzieląc ją przez tysiąc a następnie mnoŜąc przez tysiąc. Wszystkie czasy odesłane przez getLastModified() powinny być zaokrąglone w ten sposób. Powodem tego jest fakt, Ŝe nagłówki Last-Modified oraz If-Modified-Since są przypisane do najbliŜszej sekundy. JeŜeli get-Last-Modified odeśle ten sam czas lecz z wyŜszą rozdzielczością, czas ten moŜe błędnie wydawać się parę milisekund późniejszy niŜ podany przez If-Modified-Since. ZałóŜmy dla przykładu, Ŝe PrimeSearcher znalazł liczbę pierwszą dokładnie 869.127.442.359 milisekund od wyŜ. wsp. daty. Fakt ten przekazywany jest przeglądarce lecz tylko do najbliŜszej sekundy: Thu, 17 – Jul – 97

09:17:22 GMT

Teraz załóŜmy znowu., Ŝe uŜytkownik powtórnie ładuje stronę i, Ŝe przeglądarka podaje serwerowi poprzez nagłówek If-Modified-Since, czas który uwaŜa za czas ostatniej modyfikacji: Thu, 17-Jul-97

09:17:22 GMT

Niektóre serwery przyjmują ten czas, przeliczają go na dokładnie 869 127 442 000 milisekundy, uznają iŜ jest on 359 milisekund wcześniejszy od odesłanego przez getLastModified(), a następnie fałszywie zakładają, Ŝe treść apletu uległa zmianie. Dlatego właśnie, Ŝeby zachować bezpieczeństwo („to play it safe”), getLastModified() powinna zawsze zaokrąglać do najbliŜszego tysiąca milisekund. Obiekt HttpServletRequest jest przekazywany do getLastModified() w razie jakby aplet potrzebował oprzeć swoje rezultaty na informacjach specyficznych dla określonego zlecenia. Standardowy aplet elektronicznego biuletynu informacyjnego moŜe to wykorzystać np. do określenia który biuletyn jest przedmiotem zlecenia.

*

Aplet moŜe wstawić bezpośrednio swój nagłówek LastModified, w doGet(), przy uŜyciu technik omówionych w rozdziale 5.(„Przesyłanie informacji HTML”). JednakŜe do czasu kiedy nagłówek zostanie wstawiony w doGet() jest juŜ zbyt późno by zdecydować o tym czy wywoływać doGet() czy nie.

Buforowanie zewnętrzne po stronie serwera Metoda getLastModified() moŜe, przy odrobinie pomysłowości, być pomocna w zarządzaniu pamięcią podręczną wydruku zewnętrznego apletu. Aplety stosujące taki chwyt mogą mieć swój wydruk zewnętrzny przechwycony i umieszczony w pamięci podręcznej na stronie serwera, a następnie odesłany do klientów jak to ma miejsce przy metodzie getLastModified(). Taka procedura moŜe znacznie przyspieszyć tworzenie strony apletu, szczególnie w przypadku apletów, którym zajmuje duŜo czasu tworzenie wydruku wyjściowego, zmieniającego się rzadko, takich jak np. aplety wyświetlające dane z bazy danych. Celem wdroŜenia buforowania zewnętrznego po stronie serwera, aplet musi: •

Rozszerzyć com.oreilly.servlet.CacheHttpServlet zamiast HttpServlet



WdroŜyć metodę getLastModified (HttpServletRequest)

Przykład 3.10 ukazuje aplet korzystający z CacheHttpServlet. Jest to księga gości apletu, która wyświetla przedłoŜone przez uŜytkowników komentarze. Aplet przechowuje komentarze uŜytkowników w pamięci jako obiekty Vector of GuestbookEntry.W rozdziale 9 „Dołączalność bazy danych” poznamy wersję tego apletu działającą poza bazą danych. W celu stymulacji czytania z wolnej bazy danych, pętla wyświetlacza ma pół-sekundowe opóźnienie na hasło. Im dłuŜsza lista haseł tym wolniejsza wizualizacja strony. JednakŜe z powodu tego, Ŝe aplet rozszerza CacheHttpServlet, wizualizacja musi mieć miejsce tylko podczas pierwszego zlecenia GET, po dodaniu nowego komentarza. Wszystkie późniejsze zlecenia GET wysyłają odpowiedź z pamięci podręcznej. Przykładowy wydruk wyjściowy został pokazany na rycinie 3.4. Przykład 3.10. Lista gości uŜywająca apletu „CacheHttpServlet” import import import import import

java.io.*; java.util.*; javax.servlet.*; javax.servlet.http.*; com.oreilly.servlet.CacheHttpServlet;

public class Guestbok

extends HttpServlet {

private Vector entries = new Vector(); // Lista haseł uŜytkownika private long lastModified = 0; // Czas, w którym zostało // dodane ostatnie hasło // Wyświetl aktualne hasła, następnie poproś out.println nowe hasło public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType ("text / zwykły"); PrintWriter out = res.getWriter(); printHeader(out); printForm(out); printMassages(out); printFooter(out); } // Dodaj nowe hasło, następnie odeślij z powrotem do doGet()

public void doPost (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { handleForm(req, res); doGet(req, res); } private void printHeader(PrintWriter out) throws ServletException { out.println ("

wml

text /vnd. wap. wml



wmls

text /vnd. wap. wmlscript



wbmp

image /vnd. wap. wbmp

< /mime-mapping>

index.html

index.htm

index.wml





Znacznik utrzymuje wartość limitu czasu (terminu waŜności) podaną w minutach. Dla przykładu, ustaliliśmy, Ŝe jeŜeli uŜytkownik nie złoŜy Ŝadnego zlecenia do aplikacji WWW, wtedy serwer moŜe uniewaŜnić sesję uŜytkownika i „rozwiązać” obiekty w niej przechowywane. Specyfikacja apletu wymaga, aby wartość terminu waŜności wyraŜona była liczbą całkowitą, co wyklucza wartości ujemne, jednak niektóre serwery uŜywają takich wartości, aby zasygnalizować, Ŝe sesja nigdy nie ulegnie przeterminowaniu.

Wartości limitu czasu mogą być równieŜ dla sesji konfigurowane indywidualnie. Obiekt HttpSession dysponuje metodą setMaxInactivateInterval() do takiego precyzyjnego sterowania: public void HttpSession.setMaxInactiveInterval(int secs)

Metoda ta określa wartość terminu waŜności dla sesji, podanego w sekundach. Wartość ujemna przedziału oznacza iŜ sesja nie ulegnie nigdy przeterminowaniu. Tak, jednostki nie pokrywają się z tymi ze znacznika , nie jest to niczym uwarunkowane, jest to po prostu przypadek. Aby łatwiej zapamiętać, które jednostki naleŜy zastosować, stosujmy następujący schemat myślenia: „Dla precyzyjnej kontroli uŜywamy precyzyjnych jednostek”. Aktualna (bieŜąca) wartość limitu czasu moŜe być uzyskana przy wykorzystaniu metody getMaxInactiveInterval(): public int HttpSession.getMaxInactiveInterval()

Metoda ta odsyła wartość terminu waŜności dla kaŜdej sesji, w sekundach. JeŜeli nie określimy znacznika moŜemy wywołać tą metodę na nową sesję, aby określić domyślny limit czasu naszego serwera. Na przykładzie 7.6 zaprezentowaliśmy omawiane metody, w aplecie, który wyświetla bieŜącą wartość limitu czasu, a następnie ustawia nową wartość terminu waŜności na dwie godziny. Podczas pierwszego wywołania, bieŜąca wartość limitu czasu wyświetla ogólno-aplikacyjne ustawienia. Podczas drugiego wywołania aktualny limit czasu wyświetla dwie godziny — poniewaŜ jest to limit czasu ustawiony podczas pierwszego wywołania.

Przykład 7.6. Ustawianie terminu waŜności import import import import

java.io.*; java.util.*; javax.servlet.*; javax.servlet.http.*;

public class SessionTimer extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IQException { res.setContentType("tekst/html") ; PrintWriter out = res.getWriter(); // Pobierz aktualny obiekt sesji, w razie konieczności utwórz go HttpSession session = req.getSession(); out.println("SessionTimer") ; out.println("Session Timer") ; // Wyświetl poprzedni termin waŜności out.println("Poprzedni termin waŜności to " + session. getMaxInactiveInterval ()) ; out.println("
") ; // Ustaw nowy termin waŜności session.setMaxInactiveInterval(2*60*60); // dwie godziny // Wyświetl nowy termin waŜności out.println("Nowo ustalony termin waŜności to " + session.getMaxInactiveInterval()) ; out.println("") ; } }

Wybieranie właściwego terminu waŜności Tak więc znamy, na ten moment, kilka sposobów na kontrolowanie terminu waŜności sesji, lecz jaka wartość limitu czasu jest najlepsza? Odpowiedź brzmi: to (oczywiście) zaleŜy. Pierwszą sprawą, którą trzeba zapamiętać, jest fakt iŜ wartość limitu czasu sesji nie determinuje jak długo sesja będzie trwała. Limit ten determinuje tylko jak długo będzie czekał z uniewaŜnieniem sesji pomiędzy zleceniami. Sesje z półgodzinnym limitem czasu mogłaby trwać godzinami. Określenie prawidłowego okresu bez-aktywności musi być kompromisem pomiędzy wygodą uŜytkownika, jego bezpieczeństwem a jego skalownością. DłuŜsze terminy waŜności dają uŜytkownikowi większą wygodę, poniewaŜ moŜe on robić dłuŜsze przerwy pomiędzy zleceniami, uzyskując czas aby np. wykonać telefon lub aby sprawdzić pocztę elektroniczną — bez utraty stanu. Krótsze limity czasu zwiększają bezpieczeństwo uŜytkownika, poniewaŜ ograniczają czas wraŜliwości (jeŜeli uŜytkownik np. zapomniał się wylogować) jednocześnie zwiększają skalowalność serwera, jako Ŝe serwer moŜe wtedy uwolnić obiekty w sesji duŜo wcześniej. Na wstępie zadajmy sobie pytanie jaki jest maksymalny czas oczekiwania naszego uŜytkownika pomiędzy zleceniami? Zwykle odpowiedź brzmi: pół godziny. RozwaŜmy sobie tą odpowiedź i poznajmy parę niezmiennych zasad: •

Bezpieczne aplikacje WWW, takie jak bankowość „on line”, powinny mieć krótsze niŜ zwykłe limity czasu aby umoŜliwić serwerowi odzyskanie lub „wypuszczenie” artykułów tak szybko jak to moŜliwe.



Sesje nie przechowujące „kosztownych” artykułów, mogą mieć dłuŜsze niŜ zwykłe terminy waŜności.



Sesje przechowujące zawartości koszyków zakupów (kosztowne lub nie) powinny mieć dłuŜsze limity czasu, poniewaŜ moŜe się zdarzyć, Ŝe uŜytkownicy nie będą pamiętali zawartości swych koszyków zakupów, co, w przypadku wczesnego uniewaŜnienia, oznaczałoby dla nas koszty finansowe!



Sesje przechowujące w pamięci podręcznej informacje bazy danych powinny mieć, w przypadku gdy pamięć podręczna ma duŜą objętość, krótsze terminy waŜności, jednak terminy te powinny być dłuŜsze dla tych sesji jeŜeli połączenie z bazą danych jest wyjątkowo wolne.



JeŜeli wymagamy od naszych uŜytkowników, aby wylogowywali się kiedy kończą pracę, domyślny limit czasu moŜe być ustawiony na dłuŜszy.

Pamiętajmy równieŜ, iŜ termin waŜności nie musi być taki sam dla kaŜdego uŜytkownika. W celu ustawienia własnego limitu czasu, opartego na preferencjach uŜytkownika lub nawet w celu jego zmiany w czasie trwania sesji — np. aby uczynić limit czasu krótszym po przechowywaniu „kosztownego” artykułu, moŜemy posłuŜyć się metodą setMaxInactiveInterval().

Metody czasu trwania Istnieje wiele dodatkowych metod związanych z obsługą czasu trwania sesji: public boolean HttpSession.isNew()

Metoda ta odsyła informację odnośnie tego czy sesja jest nowa czy nie. Sesja jest uznawana za nową, jeŜeli została utworzona przez serwer, lecz klient nie potwierdził jeszcze połączenia z nią. public void HttpSession.invalidate()

Metoda ta powoduje, iŜ sesja jest natychmiast uniewaŜniana. Wszystkie obiekty przechowywane w sesji zostają „rozwiązane”. Metodę tą wywołuje się w celu wdroŜenia wylogowania. public long HttpSession.getCreationTime()

Metoda ta odsyła czas, w którym sesja została utworzona, jako wartość long reprezentującą liczbę milisekund, która upłynęła od północy, 1 stycznia, 1970, czasu GMT. public long HttpSession.getLastAccessedTime()

Metoda ta odsyła czas, w którym klient przesłał ostatnie zlecenie związane z sesją, jako wartość long reprezentującą liczbę milisekund, która upłynęła od północy, 1 stycznia, 1970 roku. BieŜące zlecenie nie jest uznawane jako ostatnie. KaŜda z metod moŜe zgłosić wyjątek java.lang.IllegalStateException w przypadku gdy sesja, do której uzyskiwany jest dostęp jest niewaŜna.

„Ręczne” uniewaŜnianie starej sesji Aby zademonstrować działanie omawianych metod, na przykładzie 7.7 został zaprezentowany aplet „ręcznie” uniewaŜniający sesję — jeŜeli istnieje ona dłuŜej niŜ jeden dzień lub jeŜeli nie była aktywna przez okres dłuŜszy niŜ jedną godzinę.

Przykład 7.7. UniewaŜnianie starej sesji import import import import public

java. io. *; java.uti1.*; javax.servlet.*; javax.servlet.http.*; class ManualInvalidate extends HttpServlet {

public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("tekst/html") ; PrintWriter out = res.getWriter() ; // Pobierz bieŜący obiekt sesji, w razie konieczności utwórz go HttpSession session = reg.getSession() ; UniewaŜnij sesję, jeŜeli istnieje dłuŜej niŜ jeden dzień lub nie była // aktywna dłuŜej niŜ jedną godzinę. if (! session. isNew()) { // pomiń nowe sesje Date dayAgo = new Date(System.currentTimeMillis() - 24*60*60*1000); Date hourAgo = new Date (System.currentTiineMillis () 60*60*1000); Date created = new Date (session.getCreationTime ()); Date accessed = new Date (session.getLastAccessedTtme ()); if (created.before(dayAgo) || accessed.before(hourAgo)) { session.invalidate() ; session = reg.getSession() ; // pobierz nową sesję } } // Kontynuuj przetwarzanie } }

Zasada działania sesji Tak więc zastanówmy się jak serwer WWW wdraŜa śledzenie sesji? Kiedy uŜytkownik po raz pierwszy uruchamia aplikację WWW, jest mu przypisywany nowy obiekt sesji HttpSession oraz niepowtarzalna identyfikacja sesji (ID sesji). ID sesji identyfikuje uŜytkownika i jest wykorzystywana do dopasowania uŜytkownika z obiektem HttpSession w kolejnych zleceniach. Niektóre serwery wykorzystują pojedynczą identyfikację sesji dla całego serwera, z kaŜdą aplikacją WWW odwzorowującą to ID do innej kopii HttpSession. Z kolei inne serwery przypisują jedną identyfikację sesji do jednej aplikacji WWW, jako dodatkowe zabezpieczenie przed złośliwymi aplikacjami WWW, pomagającymi intruzowi w „zdepersonalizowaniu” nas.

W tle, ID sesji jest zwykle zapisywane po stronie klienta w cookie zwanym JSESSIONID. Dla klientów, którzy nie obsługują „Ciasteczek”, identyfikacja sesji moŜe zostać przesłana jako część przepisanego URL-u, zakodowanego przy uŜyciu parametru ścieŜki jsessionid, np. http://www.servlets.com/catalog/servlet/ItemDisplay;jsession=123?item=156592391X. Inne implementacje, takie jak wykorzystanie SSL — protokołu bezpiecznej transmisji danych sesji, są równieŜ moŜliwe. Aplet moŜe poznać ID sesji za pomocą metody getId(): public String HttpSession.getId()

Metoda ta odsyła niepowtarzalny identyfikator String, przypisany do sesji. Dla przykładu, ID serwera „Tomcat” mogłoby wyglądać w następujący sposób awj4gyhsn2. Metoda zgłasza wyjątek IllegalStateException w przypadku gdy sesja nie jest waŜna.

Pamiętajmy, iŜ identyfikacja sesji powinna być traktowana jako tajna informacja serwera. Zwracajmy uwagę na to, co robimy z tą wartością.

Wycofanie Obiektu HttpSessionContext W Interfejsie API 2.0 istniał obiekt HttpSessionContext, który był wykorzystywany do „tropienia” aktualnych sesji (oraz odpowiadającym im ID sesji), wykonywanych przez serwer. Prawie zawsze klasa była wykorzystywana do „debagowania” i sprawdzania jakie sesje jeszcze istnieją. Klasa ciągle jeszcze istnieje — dla zachowania kompatybilności binarnej, jednak począwszy od wersji 2.1 Interfejsu API, jest wycofana i określana jako pusta. Powodem jest fakt, iŜ identyfikacje sesji muszą być pilnie strzeŜone, więc nie powinny być przechowywane w łatwo dostępnej, pojedynczej lokalizacji, zwłaszcza jeŜeli istnienie takiej lokalizacji nie daje Ŝadnych znaczących korzyści, poza „debagowaniem”.

Apletowe śledzenie sesji Niemal kaŜdy serwer obsługujący aplety wdraŜa śledzenie sesji oparte na „Ciasteczkach”, gdzie identyfikacja sesji jest zapisywana po stronie klienta w trwałym cookie. Serwer odczytuje ID sesji z cookie JSESSIONID, a następnie determinuje który obiekt sesji uczynić dostępnym podczas kaŜdego zlecenia. Dla klientów apletu taka sytuacja moŜe przedstawiać problem. Większość środowisk apletowych wdraŜa HttpURLConnection w taki sposób, Ŝe kiedy aplet tworzy połączenie HTTP, środowisko automatycznie dodaje zawierające cookies przeglądarki, do zlecenia. Pozwala to apletowi na uczestniczenie w tej samej, co inne zlecenia przeglądarki, sesji. Problemem jest jednak, iŜ inne środowiska apletowe, takie jak starsze wersje środowiska „Java Plug-In enviroment” nie są zintegrowane z przeglądarką i dlatego zlecenia apletów jawią się jako oddzielone od normalnej sesji przeglądarki. Rozwiązanie dla sytuacji, w której aplety muszą działać w podobnych środowiskach jest przesyłane identyfikacji sesji do apletu oraz pozwalanie apletowi na przekazanie

tego ID z powrotem do serwera, jako sztucznie utworzone cookie JSESSIONID. W rozdziale 10 „Komunikacja aplet zwykły — aplet tworzony na serwerze” została zamieszczona klasa HttpMessage — aby pomagać w tego typu sytuacjach. Aplet moŜe otrzymać identyfikację sesji jako zwykły parametr apletu (dodany dynamicznie do strony HTML zawierającej aplet).

Awaryjne zmiany trybu pracy — „nie-ciasteczkowe” Specyfikacja apletu mówi, iŜ serwery WWW muszą obsługiwać śledzenie sesji równieŜ dla przeglądarek, które nie akceptują cookies, których tak wiele wykorzystuje przepisywanie URL-u jako awaryjną zmianę trybu pracy. Wymaga to dodatkowej pomocy ze strony apletów, które generują strony zawierające URL-e. W celu obsłuŜenia śledzenia sesji poprzez przepisywanie URL-u, aplet musi przepisać kaŜdy lokalny URL, zanim odeśle go klientowi. Interfejs API zawiera dwie metody, aby wykonać to zadanie: encode() oraz encodeRedirectURL():

public String HttpServlrtresponse.encodeURL(String url)

Metoda ta koduje (przepisuje) określony URL aby dołączyć ID sesji, a następnie odsyła nowy URL lub, jeŜeli kodowanie nie jest potrzebne albo nie obsługiwane, pozostawia URL niezmienionym. Zasady decydujące o tym kiedy i jak ma być zakodowany URL są domeną serwera. Wszystkie URL-e wychodzące z serwera, powinny być uruchamiane poprzez tą właśnie metodę. Zwróćmy uwagę, iŜ metoda encodeURL() mogłaby być bardziej precyzyjnie nazwana rewriteURL() — aby nie myliła się z procesem kodowania URL-u, który koduje specjalne znaki w strumieniu URL-u.

public String HttpServlrtresponse.encodeRedirectURL(String url)

Metoda ta koduje (przepisuje) określony URL aby dołączyć identyfikację sesji, a następnie odsyła nowy URL lub, jeŜeli kodowanie nie jest potrzebne albo nie obsługiwane — pozostawia URL niezmienionym. Zasady decydujące o tym kiedy i jak ma być zakodowany URL są domeną serwera. Metoda ta moŜe uŜywać odmiennych zasad niŜ metoda encodeURL(). Wszystkie URL-e przekazane do metody HttpServletResponse — sendDirect(), powinny być uruchamiane poprzez tą metodę.

PoniŜszy fragment kodu ukazuje aplet piszący łącznik do samego siebie, który jest kodowany tak, aby zawierał bieŜącą identyfikację sesji: out.println("Click here"); out.println("aby powtórnie załadować tą stronę.");

Na serwerach, które nie obsługują przepisywania URL-u lub mają wyłączoną tą funkcję, końcowy URL pozostaje bez zmian. PoniŜej przedstawiamy fragment kodu, na którym jest zaprezentowany aplet przekierowujący uŜytkownika do URL-u zakodowanego tak, aby zawierał ID sesji:

res.sendRedirect(res.encodeRedirectURL("/servlet/NewServlet")) ;

Aplet jest w stanie wykryć czy identyfikacja sesji, wykorzystywana do zidentyfikowania aktualnego obiektu HttpSession, pochodzi od cookie czy od zakodowanego URL-u wykorzystującego metody isRequestedSessionIdFromCookie() i isRequestedSessionIdFromURL(): public boolean HttpServletRequest.isRequestedSessionIdFromCookie() public boolean HttpServletRequest.isRequestedSessionIdFromURL()

Określenie czy identyfikacja sesji pochodzi z innego źródła, takiego jak sesja SSL, nie jest aktualnie moŜliwe.

ID sesji będące przedmiotem zlecenia moŜe nie pokrywać się z identyfikacją sesji, odesłaną przez metodę getSession(), tak jak ma to miejsce kiedy ID sesji jest niewaŜne. Aplet moŜe jednak ustalić czy identyfikacja sesji będąca przedmiotem zlecenia jest waŜna, przy pomocy metody isRequestedSessionIdValid(): public boolean HttpServletRequest.isRequestedSessionIdValid()

Miejmy równieŜ świadomość, iŜ kiedy uŜywamy śledzenia sesji opartego na przepisywaniu URLu, wielokrotne okna przeglądarki mogą naleŜeć do róŜnych sesji lub do tej samej sesji, w zaleŜności od tego w jaki sposób okna te zostały utworzone oraz czy tworzący je łącznik miał zastosowane przepisywanie URL-u.

Aplet „SessionSnoop” Zaprezentowany na przykładzie 7.8 aplet SessionSnoop wykorzystuje większość opisanych w rozdziale metod, aby „podsłuchać” informację o aktualnej sesji. Rysunek 7.3 prezentuje przykładowy wydruk wyjściowy apletu.

Przykład 7.8. „Podsłuchiwanie” informacji sesji import import import import

java.io.*; java.util.*; javax.servlet.*; javax.servlet.http.*;

public class SessionSnoop extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("tekst/html");

PrintWriter out = res.getWriter() ; // Pobierz aktualny obiekt sesji, w razie konieczności utwórz go HttpSession session = req.getSession(); // Zwiększ o jeden liczbę wejść na tą stronę. Wartość jest zapisana // w sesji klienta pod nazwą "snoop.count". Integer count = (Integer)session.getAttribute("snoop.count"); if (count == null) count = new Integer(1); else count = new Integer(count.intValue() + 1) ; session.setAttribute("snoop.count", count) ; out.println("SessionSnoop"); out.println("Session Snoop"); // Wyświetl ilość wejść na tą stronę out.println("Odwiedziłeś juŜ tą " + count + ((count.intValue() == 1) ? " raz." : " razy.")); out.println("

") ; out.println("Oto twoje zachowane dane sesji:"); Enumeration enum = session.getAttributeNames(); while (enum.hasMoreElements()) { name = (String) enum.nextElement(); intln (name + ": " + session.getAttribute (name) + ""); } out.println("Oto parę waŜniejszych stanów twojej sesji:"); out.println("ID sesji: " + session.getid() + " (keep it secret )
"); out.println("Now sesja: " + session.isNew() + "
"); out.println("Termin waŜności: " + session.getMaxInactiveInterval()); out.println("(" + session.getMaxInactiveInterval() / 60 + " minut) < / Ix>
") ; out.println("Czas utworzenia: " + session. getCreationTime() ); out. println ("(" + new Date (session.getCreationTime ()) + ")>
") ; out.println("Ostatni czas wejścia: " + session.getLastAccessedTime()); out.println("(" + new Date(session.getLastAccessedTime()) + ")
") ; out.println("ID sesji będące przedmiotem zlecenia z URL: " + req. isRequestedSessionIdFromURL () + "
") ; out.println("ID sesji, będące przedmiotem zlecenia jest waŜne: " + req.isRequestedSessionIdValid() + "
"); out.println("Test URL Rewriting"); out.println("Kliknij here") ; out.println("Aby sprawdzić czy śledzenie sesji działa poprzez przepisywanie"); out.println("URL-u, nawet wtedy gdy cookies nie są obsługiwane."); out.println("") ; } }

Aplet rozpoczyna tym samym kodem, który został zamieszczony w przykładzie 7.4, w aplecie SessionTracker. Następnie przechodzi do dalszego wyświetlania bieŜącego ID sesji, tego czy jest to sesja nowa, wartości limitu czasu, czasu utworzenia sesji oraz czas ostatniego połączenia z sesją. Później aplet wyświetla czy identyfikacja sesji (jeŜeli jest taka), będąca przedmiotem zlecenia, pochodzi od cookie czy od URL-u oraz czy to ID jest waŜne. W końcu aplet drukuje zakodowany URL, który moŜe zostać wykorzystany do powtórnego załadowania tej strony, w celu sprawdzenia czy przepisywanie URL-u działa nawet wtedy kiedy cookies nie są obsługiwane.

Zdarzenia wiąŜące sesję Niektóre obiekty mogą „chcieć” przeprowadzić operację zarówno wtedy, kiedy są związane z sesją, jak i wtedy kiedy nie są z nią związane. Dla przykładu, połączenie z bazą danych moŜe rozpoczynać transakcję (obsługę zlecenia) w stanie związania z sesją, a kończyć kiedy nie są z nią związane. Wszystkie obiekty, które wdraŜają interfejs javax.servlet.http.HttpSessionBindingListner, są powiadamiane o związaniu z sesją oraz o tym, Ŝe nie są z nią związane. Interfejs deklaruje dwie metody: valueBound() oraz valueUnbound(), które muszą zostać wdroŜone: public void HttpSessionBindingListener.valueBound( HttpSessionBindingEvent event) public void HttpSessionBindingListener.valueUnbound ( HttpSessionBindingEvent event)

Metoda valueBound() jest wywoływana, kiedy odbiornik jest związany z sesją, a metoda valueUnbound() kiedy odbiornik nie jest z nią związany — poprzez usunięcie, zastąpienie albo poprzez uniewaŜnienie sesji.

Argument javax.servlet.http.HttpSessionBindingEvent zapewnia dostęp do nazwy pod którą obiekt jest wiązany (lub odwiązywany od niej) z metodą getName(): public String HttpSessionBindingEvent.getName()

Rysunek 7.3. Przykładowy wydruk wyjściowy apletu „SessionSnoop”

Obiekt HttpSessionBindingEvent zapewnia równieŜ dostęp do obiektu, do którego jest wiązany (lub od którego jest „odwiązywany”) odbiornik, wykorzystując w tym celu metodę getSession(): public HttpSession HttpSessionBindingEvent.getSession()

Na

przykładzie 7.9 zaprezentowano uŜycie HttpSessionBindingListner oraz HttpSessionBindingEvent, z odbiornikiem rejestrującym w czasie związania jak i w czasie rozwiązania z sesją.

Przykład 7.9. Zdarzenia wiąŜące śledzenie sesji import import import import

java.io.*; java.util.*; javax.servlet.* ; javax.servlet.http.*;

public class SessionBindings extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IQException { res.setContentType("tekst/zwykły") ; PrintWriter out = res.getWriter(); // Pobierz aktualny obiekt sesji. w razie potrzeby utwórz go HttpSession session = reg.getSession(); // Dodaj CustomBindingListener session.setAttribute("bindings.listener", new CustomBindingListener(getServletContext())); out.println("Ta strona jest celowo pozostawiona pustą"); ) } class CustomBindingListener inplements HttpSessionBindingListener { // Zapisz ServletContext dla uŜytku jego metody log () ServletContext context; public CustomBindingListener(ServletContext context) { this.context = context; } public void valueBound(HttpSessionBindingEvent event) { context.log("[" + new Dated + "] BOUND as " + event.getName() + " to " + event. getSession () . getid ()) ; } public void valueUnbound(HttpSessionBindingEvent event) { context.log("[" + new Date() + "] UNBOUND as " + event.getName () + " from " + event. getSession().getId() ); } }

Za kaŜdym razem kiedy obiekt CustomBindingListner jest wiązany z sesją, jego metoda valueBound(), jest wywoływana i zdarzenie jest rejestrowane. Za kaŜdym razem kiedy obiekt ten jest „odwiązywany” od sesji, wywoływana jest jego metoda valueUnbound(), tak Ŝe zdarzenie jest równieŜ rejestrowane. MoŜemy śledzić sekwencję zdarzeń poprzez obserwowanie dziennika zdarzeń serwera.

ZałóŜmy, iŜ aplet ten jest wywołany jeden raz, powtórnie ładowany 30 sekund później i następnie nie wywoływany co najmniej przez następne pół godziny. Dziennik zdarzeń mógłby wyglądać w następujący sposób:

[Tue Sep 27 22:46:48 PST 2000] BOUND as bindings.listener to awj4qyhsn2 [Tue Sep 27 22:47:18 PST 2000] UNBOUND as bindings.listener from awj4qyhsn2 [Tue Sep 27 22:47:18 PST 2000] BOUND as bindings.listener to awj4qyhsn2 [Tue Sep 27 23:17:18 PST 2000] UNBOUND as bindings.listener from awj4qyhsn2

Pierwsza pozycja występuje podczas zlecenia pierwszej strony, kiedy odbiornik jest związany z nową sesją. Pozycje: druga oraz trzecia występują podczas ponownego ładowania, poniewaŜ odbiornik jest „odwiązywany” i powtórnie wiązany z sesją, w czasie tego samego wywołania setAttribute(). Czwarta pozycja ma miejsce pół godziny później, kiedy limit czasu sesji kończy się, a ona sama jest uniewaŜniana.

Robienie zakupów przy uŜyciu śledzenia sesji Zakończmy ten rozdział spojrzeniem na to, jak zadziwiająco prostym moŜe stać się nasz aplet „shopping cart viewer, przy zastosowaniu śledzenia sesji. Na przykładzie 7.10 zaprezentowano aplet zapisujący kaŜdy artykuł z koszyka, w sesji uŜytkownika, pod nazwą cart.items. Zwróćmy uwagę, iŜ URL-e, znajdujące się na stronie, zostały przepisane tak, aby obsługiwać klientów z zablokowanymi „Ciasteczkami”.

Przykład 7.10. Wykorzystanie Śledzenia Sesji API import java.io.*; import javax.servlet.* ; import javax.servlet.http.*; public class ShoppingCartViewerSession extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res. setContentType ("tekst/html") ; PrintWriter out = res.getWriter () ; // Pobierz obiekt bieŜącej sesji. HttpSession session = req.getSession(); // Artykuły z koszyka są utrzymywane w obiekcie sesji. String [] items = (String []) session. getAttribute ("cart. items") ; out.println("SessionTracker"); out.println("Session Tracking Demo");

// Drukuj aktualne artykuły z koszyka. out.println("Aktualnie masz w swoim koszyku następuje artykuły:
"); if (items == null) { out.println("None") ; } else ( out.println("

    ") ; for (int i = 0; i < items.length; i++) { out.println("
  • " + items[i]); } out.println("
") ; } // Spytaj czy chcą dodać jeszcze do koszyka jakieś artykuły, czy teŜ // chcą zakończyć. out.println("Test ECSWitaj!

Aktualny czas to FRI OCT 25 23:17:37 GMT 2001

Domyślnie wszystkie dane wyświetlane przez ECS pojawiają się w jednej linii bez wcięć i powrotów karetki. Przyśpiesza to transfer podczas komunikacji z przeglądarką klienta. Aby otrzymać zawartość łatwiejszą do odczytania naleŜy dokonać edycji pliku ecs.properties, który jest dołączony do dystrybucji oraz zmienić wartość pretty_print na true. Następuje teraz trudniejsza część: naleŜy upewnić się, Ŝe plik ecs.properties zostanie odnaleziony w ścieŜce serwera przed plikiem JAR ECS, tak aby wyedytowany plik powodował pominięcie pliku ecs.properties zawartego w pliku JAR. Plik ecs.properties jest poszukiwany jako org/apache/ecs/ecs.properties, tak więc plik nie moŜe zostać umieszczony bezpośrednio w ścieŜce klas, ale w podkatalogu org/apache/ecs katalogu wewnątrz ścieŜki klas (na przykład WEBINF/classes/org/apache/ecs/ecs.properties). Serwlet importuje dwa pakiety ECS — org.apache.ecs zawierający podstawowe klasy ECS i org.apache.ecs.html zawierający klasy specyficzne dla HTML. (Istnieją inne pakiety odpowiedzialne za XML, WML i RTF.)1 Pakiet org.apache.ecs.html zawiera prawie sto klas reprezentujących wszystkie elementy HTML 4.0. Większość klas HTML nosi nazwy odpowiadające nazwom znaczników HTML — Big, Small, P, Table, TR, TD, TH, H1, H2, H3, Frame, A, Head, Body i tak dalej. KaŜda klasa HTML posiada metody słuŜące do konfiguracji elementu. Na przykład klasa TD posiada metodę setBackground(String url), która ustawia tło tej komórki tabeli. Klasa Body równieŜ posiada podobną metodę słuŜącą do ustawiania tła dla całej strony. śaden inny element ECS nie posiada metody setBackground(), poniewaŜ Ŝaden inny element nie posiada moŜliwości ustawienia swojego tła, co pozwala ECS na upewnienie się, Ŝe programowo utworzone elementy zawsze zawierają prawidłowo utworzony HTML.

1

Osoby zainteresowane programowym tworzeniem XML przy pomocy Javy powinny się raczej skupić na wykorzystaniu JDOM (http://jdom.org), poniewaŜ JDOM jest lepiej zintegrowany z technologiami XML.

Aby dodać elementy głównej części, serwlet wykorzystuje łączenie metod w łańcuchy, w których kilka metod jest wywoływanych na tym samym obiekcie. W ECS moŜna dotrzeć wiele takich konstrukcji. Na przykład, w celu utworzenia tabeli: Table tab = new Table() .setCellPadding(0) .setCellSpacing(0);

Puste miejsca nie mają znaczenia. PowyŜszy kod jest równy następującemu: Table tab = new Table().setCellPadding(0).setCellSpacing(0);

PowyŜszy łańcuch jest moŜliwy do utworzenia, poniewaŜ kaŜda metoda set i append zwraca odwołanie do obiektu, na którym została wywołana — odwołanie to jest wykorzystywane do wywołania następnej metody. Sztuczka ta często okazuje się przydatna przy korzystaniu z ECS.

Wyświetlanie zbioru wyników Wykorzystanie ECS do pełnego tworzenia strony wypadło z łask po ulepszeniu opartych na serwletach technologii szablonów. Po prostu dynamiczne tworzenie czegoś, co w większości jest statyczną zawartością strony zajmuje zbyt wiele czasu. Jednak ECS ciągle posiada swoje miejsce. ECS sprawdza się w przypadku tych części strony, które są wyjątkowo dynamiczne, w których do określenia zawartości do utworzenia konieczna jest pełna moc Javy. Jak powiedział Jon Stevens, jeden z jego twórców, „naleŜy wykorzystywać ECS wszędzie tam, gdzie w innym przypadku wystąpiłoby wyj.println().” Na przykład, proszę wyobrazić sobie aplikację WWW pozwalającą klientom na wykonywanie ad hoc zapytań w bazie danych. Na przykład mógł zostać zaimplementowany system śledzenia błędów i potrzebny jest serwlet dający zaawansowanym uŜytkownikom moŜliwość wykonywania swoich własnych zapytań w bazie danych (przy pomocy połączenia z uprawnieniami tylko-do-odczytu). ECS sprawdza się w tworzeniu strony wyświetlającej wyniki z baz danych, programowo tworząc tabelę dostosowaną do danych. Przykład 16.2 przedstawia prosty element przeglądający ResultSet. Przypomina on klasę HtmlSQLWynik przedstawioną w rozdziale 9, „Łączność z bazą danych”, która wykorzystywała wyj.println(). Zastosowanie ECS zamiast wyj.println() pozwala na uproszczenie i większe moŜliwości dostosowania kodu. Przykład 16.1. Ulepszona tabela ZbiorWynik import java.io.*; import java.sql.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*;

import org.apache.ecs.*; import org.apache.ecs.html.*;

public class ProstaTabelaResultSet extends Table {

public ProstaTabelaResultSet(ResultSet rs) throws SQLException { setBorder(1);

ResultSetMetaData rsmd = rs.getMetaData(); int colCount = rsmd.getColumnCount();

TR rzad = new TR();

for (int i = 1; i JeŜeli ten napis jest widoczny, to utworzono nowy komponent!

JeŜeli nie jest konieczne umieszczenie głównej części, moŜe zostać wykorzystany skrót XML dla pustego znacznika />:













(Nowość!)

(Uaktualniony!)








Na początku wewnątrz skryptletu, jako łańcuchy String, definiowane są tytuły i opis strony. Następnie wykorzystana jest instrukcja include w celu dołączenia standardowej zawartości nagłówka z pliku naglowek.jsp oraz standardowej zawartości stopki (na końcu pliku) z pliku stopka.jsp. Instrukcja include umieszcza zawartość plików nagłówka i stopki do pliku podczas fazy tłumaczenia, tak więc zmienne tytul, tytul2 i opis są widoczne wewnątrz dołączanych plików, i plik naglowek.jsp wykorzystuje te zmienne. Pliki naglowek.jsp i stopka.jsp są przedstawione w przykładach 18.9 i 18.10. Przykład 18.9. Plik naglowek.jsp

















Strona główna
Hosting
Mechanizmy














Przykład 18.10. Plik stopka.jsp





Strona główna   Hosting   Mechanizmy  





Własność © 2000 Jason Hunter
Wszystkie prawa zastrzeŜone.


Kontakt: [email protected]






Następnie na stronie widoknarz.jsp wykorzystana zostaje akcja w celu osadzenia komponentu JavaBean o nazwie narzkomp, będącego egzemplarzem klasy NarzKomp. Komponent posiada zakres application, tak więc pojedynczy egzemplarz danych zostanie automatycznie zachowany w kontekście i udostępniony wszystkim stronom. Wewnątrz głównej części znacznika umieszczona została akcja , która ustawia własność komponentu plikNarz na wartość parametru inicjacji kontekstu plikNarz, wykorzystując wyraŜenie atrybutu czasu uruchomienia w celu odczytania wartości. Informuje to komponent, którego pliku powinien uŜyć do pobrania informacji na temat narzędzi. Idealnym rozwiązaniem byłoby, jeŜeli komponent mógłby uzyskać bezpośredni dostęp do zmiennej aplikacji w celu odczytania tych wartości, ale komponenty mają dostęp jedynie do informacji udostępnionych przez stronę JSP. Eleganckim rozwiązaniem byłaby moŜliwość akceptowania przez komponent nazwy pliku jako argumentu jego konstruktora, ale egzemplarze komponentów są tworzone przy pomocy domyślnego, nie posiadającego argumentów konstruktora, tak więc to równieŜ nie jest moŜliwe. Metoda zastosowana powyŜej to dołączenie akcji do głównej części znacznika tak więc podczas pierwszego konstruowania komponentu bezpośrednio otrzymuje on nazwę pliku, z którego powinien pobierać informacje. NaleŜy zauwaŜyć dwie sprawy dotyczące wyraŜenia atrybutu czasu uruchomienia. Po pierwsze, konieczne było wykorzystanie pojedynczych nawiasów dookoła wartości, poniewaŜ podwójne cudzysłowy zostały zastosowane wewnątrz wyraŜenia. Pozwala to na uniknięcie błędów analizatora JSP. MoŜliwe jest równieŜ wyłączenie podwójnych cudzysłowów z wyraŜenia przy pomocy lewych ukośników. Po drugie, jeŜeli parametr inicjacji nie

istnieje i getInitParameter() zwraca null, wywołany zostaje wyjątek JspException, poniewaŜ wartość null nie jest dozwolona w wyraŜeniu atrybutu czasu uruchomienia4. Po znaczniku skryptlet wykorzystany zostaje w celu pobrania tablicy narzędzi z komponentu, co wykonywane jest poprzez wywołanie metody pobierzNarzedzia() z wartością parametru stan, na wypadek gdyby uŜytkownik chciał przeglądać jedynie narzędzia o określonym stanie. Kuszące moŜe być pragnienie napisania akcji , która umoŜliwiłaby komponentowi bezpośredni dostęp do wartości parametru stan ale, poniewaŜ komponent posiada zakres application, nie jest to moŜliwe — wykonanie tego spowodowałoby problemy z współbieŜnością, gdyby klika Ŝądań próbowało ustawić tę samą własność pojedynczego współdzielonego egzemplarza komponentu. Po odczytaniu tablicy narzędzi, wykorzystany zostaje kolejny fragment kodu skryptletu w celu rozpoczęcia pętli for dokonującej iteracji na tablicy. Wewnątrz pętli for umieszczona zostaje logika wyświetlająca kaŜde osobne narzędzie. WyraŜenia zostają wykorzystane do wyświetlenia prostych wartości takich, jak nazwa narzędzia, URL i komentarz. Skryptlety słuŜą do wyświetlania uwag na temat stanu — Nowość lub Uaktualnienie.5 Kod klasy NarzKomp przedstawiony jest w przykładzie 18.11. Kod klasy Narzedzie jest identyczny jak ten przedstawiony w rozdziale 14, „Szkielet Tea”. Przykład 18.11. Klasa wspierająca NarzKomp import java.util.*;

public class NarzKomp {

private Narzedzie[] narzedzia; private String stan;

public NarzKomp() { }

public void ustawPlikNarz(String plikNarz) throws Exception { // Nie ma sposobu dostępu do kontekstu aplikacji bezpośrednio z komponentu narzedzia = Narzedzie.ladujNarz(plikNarz); }

public Narzedzie[] pobierNarz(String stan) throws Exception { if (narzedzia == null) { throw new IllegalStateException( "Zawsze naleŜy ustawić własność plikNarz NarzKomp"); 4

Z technicznego punktu widzenia, specyfikacja JSP nie określa sposobu postępowania z zerowymi wartościami wyraŜeń atrybutów czasu uruchomienia. W związku z tym modelem staje się wzorcowa implementacja Tomcata, a Tomcat 3.2 zgłasza wyjątek.

5

Z uwagi na zachowujące puste miejsca zasady JSP naleŜy być ostroŜnym podczas tworzenia wyraŜeń if/else wewnątrz skryptletów. PoniŜszy kod nie działałby:

(Nowość!)

(Uaktualniony!)

W przypadku powyŜszego kodu, serwlet działający w tle próbowałby wstawić nową linię pomiędzy klauzulami if i else, powodując paskudny błąd kompilacji — 'else' without 'if'.

}

if (stan == null) { return narzedzia; } else { // Zwrócenie jedynie narzędzi posiadających dany „stan” List lista = new LinkedList(); for (int i = 0; i < narzedzia.length; i++) { if (narzedzia[i].getStateFlag().equalsIgnoreCase(stan)) { lista.add(narzedzia[i]); } } return (Narzedzie[]) lista.toArray(new Narzedzie[0]); } } }

Metoda ustawPlikNarz() jest automatycznie wywoływana przez akcję zaraz po skonstruowaniu elementu. Pobiera ona informacje na temat narzędzi z określonego pliku. Metoda pobierzNarz() jest wywoływana przez stronę JSP bezpośrednio wewnątrz skryptletu. Metoda pobiera jako parametr stan narzędzi, według którego będą one sprawdzane. JeŜeli stan posiada wartość null, zwracana jest pełna lista. JeŜeli zmienna narzędzi posiada wartość null oznacza to, Ŝe ustawPlikNarz() nie zakończyła się sukcesem, a komponent zgłasza wyjątek IllegalStateException, który ostrzega uŜytkownika przed problemem.

Biblioteki własnych znaczników Na koniec opisany zostanie najbardziej interesujący aspekt JavaServer Pages — obsługa bibliotek własnych znaczników. Własne znaczniki (znane takŜe jako własne akcje) pozwalają stronie JSP na zawieranie znaczników XML które, chociaŜ wyglądają jak HTML, tak naprawdę pozwalają na wykonywanie konkretnego kodu Javy, kiedy wystąpi znacznik. MoŜliwe zastosowania bibliotek własnych znaczników są naprawdę interesujące. Na przykład, firma Live Software (twórca Jrun) wykorzystała własne znaczniki JSP do zaimplementowania całkowicie przenośnej wersji znaczników Cold Fusion Allaire o nazwie CF_Anywhere. (Krótko później Live Software została wykupiona przez Allaire.) Szczegółowe zasady tworzenia biblioteki własnych znaczników są dość skomplikowane i wykraczają poza zakres niniejszego rozdziału. Na szczęście tworzonych i juŜ przydatnych jest kilka bibliotek znaczników Open Source. Dwie najbardziej znane to Apache Taglibs i Apache Struts, obie pochodzące z projektu Apache Jakarta znajdującego się pod adresem http://jakarta.apache.org. Apache Taglibs zawiera biblioteki znaczników o ogólnym przeznaczeniu; Apache Struts zawiera bibliotekę znaczników przeznaczoną do obsługi architektury w stylu Model 2, ale duŜa ilość znaczników jest ogólnie przydatna. Lista bibliotek znaczników JSP jest dostępna pod adresem http://jsptags.com. Podejmowane są równieŜ próby stworzenia standardowej biblioteki znaczników występujące jako formalny proces Ŝądania specyfikacji Javy o kodzie JSR-052. Większa ilość informacji na temat JSR-052 jest dostępna pod adresem http://java.sun.com/aboutJava/communityprocess/jsr/jsr_052_jsptaglib.html.

Stosowanie bibliotek własnych znaczników Własne akcje umoŜliwiają osadzanie logiki aplikacji na stronach JSP przy pomocy znaczników podobnych do HTML. Przy pomocy odpowiedniego zestawu znaczników logika, która wcześniej musiała być utworzona przy pomocy skryptletów moŜe być napisana przy pomocy znaczników. Na przykład, projekt Apache Struts posiada

znacznik , który moŜe zastąpić pętlę for. Znacznik powtarza główną część znacznika raz dla kaŜdego elementu ze zbioru (List, Set, Vector, Map, tablica itp.). Podczas kaŜdej iteracji umieszcza element, który moŜe zostać wykorzystany w głównej części, w zakresie page6. Struts posiada równieŜ znacznik , który działa jak z dodatkowym usprawnieniem takim, Ŝe filtruje zawartość wyświetlaną przez HTML poprzez konwersję wszystkich znaków specjalnych HTML na odpowiadające im encje znakowe. Na przykład < staje się %lt;. Poprzez wspólne wykorzystanie i moŜna utworzyć poniŜszy fragment strony wyświetlający wszystkie cookies wysłane w Ŝądaniu — z właściwie przefiltrowanymi wszystkimi znakami specjalnymi:

=


Aby zainstalować i korzystać z biblioteki takiej jak Struts naleŜy wykonać kilka czynności: 1.

Pobrać i rozpakować dystrybucje biblioteki znaczników. Struts, na przykład, jest dostępny pod adresem http://jakarta.apache.org.

2.

Umieścić klasy biblioteki znaczników Javy tak, aby mogły zostać odnalezione przez serwer. Na przykład umieścić plik struts.jar w katalogu WEB-INF/lib lub umieścić skompilowane klasy w WEBINF/classes.

3.

Umieścić plik Tag Library Descriptor (Deskryptor Biblioteki Znaczników — TLD) wewnątrz katalogu WEB-INF. Zazwyczaj umieszcza się go w WEB-INF/tlds lub bezpośrednio WEB-INF, dokładne umiejscowienie nie jest waŜne. Na przykład proszę umieścić struts.tld w WEB-INF. Plik TLD to plik danych XML dostarczający serwerowi informacji na temat kaŜdego znacznika w bibliotece — jego nazwy, klasy, sposoby wykorzystania jego atrybutów i części głównej itd. Posiadanie plików TLD ma dodatkową zaletę — na podstawie TLD moŜna utworzyć stronę dokumentującą bibliotekę znaczników (na przykład przy pomocy arkusza stylów XSL).

4.

Dodać pozycję do pliku web.xml. Następnie wewnątrz niej umieścić pozycję podającą nazwę do poszukiwań biblioteki znaczników, a takŜe podającą umiejscowienie pliku TLD. Krok ten nie jest konieczny, jeŜeli pozycja jest równowaŜna pozycji . Na przykład: /WEB-INF/struts.tld /WEB-INF/struts.tld

Pozycja musi być ścieŜką URI, tak więc jej prawidłowe wartości to struts, http://jakarta.apache.org/struts, i /WEB-INF/struts.ltd. ŚcieŜka URI tradycyjnie odnosi się do prawdziwego umiejscowienia zasobów, ale w powyŜszym przykładzie została zastosowana jedynie jako unikatowy identyfikator biblioteki znaczników. 5.

Na kaŜdej stronie JSP wykorzystującej bibliotekę własnych znaczników naleŜy dodać poniŜszą instrukcję taglib. Nakazuje ona serwerowi pobranie biblioteki znaczników o podanym „URI poszukiwań” i umieszczenie tych znaczników pod przedrostkiem nazwy XML struts:

6.

NaleŜy wykorzystać znaczniki na stronie JSP, upewniając się, Ŝe przedrostek nazw XML jest taki, jak zadeklarowany w instrukcji taglib:

6

Znacznik wymaga JDK 1.2 lub późniejszego. W JDK 1.1 występuje znacznik .

Kreator biblioteki znaczników moŜe połączyć TLD z plikiem JAR biblioteki znaczników. W tym przypadku, zamiast wskazywać na .tld naleŜy wskazać bezpośrednio na .jar.

Aplikacja „Narzędzia” wykorzystująca bibliotekę własnych znaczników Wykorzystanie znaczników Struts i moŜe uprościć stronę widoknarz.jsp. Przy okazji zademonstrowana zostanie oparta na serwletach architektura Model 2, w której serwlet otrzymuje Ŝądanie, dodaje atrybuty do obiektu Ŝądania i przekazuje Ŝądanie do JSP, która działa jak szablon. Przykład 18.12 przedstawia serwlet kontrolujący. Przykład 18.12. Serwlet kontrolujący Model 2 import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*;

public class SerwletNarz extends HttpServlet {

Narzedzie[] narzedzia = null;

public void init() throws ServletException { // Pobranie danych narzędzi w init w celu zachowania prostoty String plikNarz = getServletContext().getInitParameter("plikNarz"); // z web.xml if (plikNarz == null) { throw new ServletException("Plik danych narzędzi musi być określony jako " + "parametr inicjacji kontekstu plikNarz"); } log("Pobieranie narzędzi z " + plikNarz); try { narzedzia = Narzedzie.ladujNarz(plikNarz); if (narzedzia.length == 0) { log("Nie odnaleziono narzędzi w " + plikNarz); } else { log(narzedzia.length + " narzędzi znaleziono w " + plikNarz); } } catch (Exception w) { throw new ServletException(w); } }

public void doGet(HttpServletRequest zad, HttpServletResponse odp) throws ServletException, IOException { Narzedzie[] narzedzia = null;

// Umieszczenie właściwego atrybutu „narzedzia” w kontekście String stan = zad.getParameter("stan"); if (stan == null) { zad.setAttribute("narzedzia", pobierzNarz()); } else { zad.setAttribute("narzedzia", pobierzNarz(stan)); }

// Przesłanie Ŝądania do JSP w celu dalszego przetworzenia RequestDispatcher disp = zad.getRequestDispatcher("/widoknarz-znacznik.jsp"); disp.forward(zad, odp); }

public Narzedzie[] pobierzNarz() { return narzedzia; }

public Narzedzie[] pobierzNarz(String stan) { List lista = new LinkedList(); for (int i = 0; i < narzedzia.length; i++) { if (narzedzia[i].getStateFlag().equalsIgnoreCase(stan)) { lista.add(narzedzia[i]); } } return (Narzedzia[]) lista.toArray(new Narzedzia[0]); } }

Serwlet zachowuje się podobnie do NarzedziaAp w Tea i SerwletNarz w WebMacro. Pobiera informacje o narzędziach w swojej metodzie init(), a dla kaŜdego Ŝądania dokłada do obiektu Ŝądania odpowiedni podzbiór narzędzi. Serwlet przekazuje kaŜde Ŝądanie plikowi JSP, który właściwie tworzy stronę. Posiada on dostęp do narzędzi w kaŜdym obiekcie Ŝądania przy pomocy znacznika . Przykład 18.13 przedstawia plik JSP noszący nazwę widoknarz-znacznik.jsp. Przykład 18.13. Aplikacja „Narzędzia” przystosowana do bibliotek znaczników



", RE.MATCH_CASEINDEPENDENT); boolean maBase = wr.match(strona);

if (maBase) { // Wykorzystanie istniejącego wyj.println(wr.getParen(0)); } else { // Obliczenie BASE z URL-a, wykorzystanie wszystkiego do ostatniego '/' wr = new RE("http://.*/", RE.MATCH_CASEINDEPENDENT); boolean odczytBase = wr.match(url); if (odczytBase) { // Sukces, wyświetlenie odczytanego BASE wyj.println(""); } else { // Brak wiodącego ukośnika, dodanie go wyj.println(""); }

}

wyj.println("");

wyj.println("Łącza na " + url + "" + " są następujące:
"); wyj.println("
    ");

    String szukaj = " Tomcat v3.2

    ...

    Wykorzystanie niezaleŜnego narzędzia NiezaleŜne narzędzia dają nowe moŜliwości i łatwość wykorzystania zadaniu usuwania błędów. IBM AlphaWorks produkuje program o nazwie Distributed Application Tester (DAT), który przegląda Ŝądania HTTP i HTTPS, umoŜliwiając przeglądanie i zapisywanie obu stron ruchu klient-serwer. DAT zawiera moŜliwość

    wykonywania testów funkcjonalności wydajności aplikacji WWW poprzez automatyczne generowanie Ŝądań i przeglądanie odpowiedzi. Program jest utworzony całkowicie w Javie, ale jest udostępniany z programem instalacyjnym działającym jedynie pod Windows. Jego jedyną licencją jest bezpłatny 90-dniowy czas testowania, poniewaŜ oprogramowanie to występuje w wersji „alpha”, a co dziwne w wersji tej jest od stycznia 199. DAT jest dostępny pod adresem http://www.alphaworks.ibm.com. Firma Allaire, twórca popularnej „wtyczki” serwletów Jrun (po wykupieniu Live Software), posiada mało znane narzędzie słuŜące do usuwania błędów z serwletów o nazwie ServletDebugger. Narzędzie to jest zaprojektowane programowego wspomagania testów i usuwania błędów z serwletów. ServletDebugger nie wymaga wykorzystania serwera WWW lub przeglądarki do wykonania Ŝądania. Zamiast tego, wykorzystuje się zbiór klas do stworzenia niewielkiej klasy-końcówki, która przygotowuje i wykonuje Ŝądanie serwletu. Końcówka określa wszystko — parametry inicjacji serwletu, nagłówki HTTP Ŝądania oraz parametry Ŝądania. ServletDebugger jest stosunkowo prosty i dobrze przystosowany do zautomatyzowanego testowania. Jego największą wadą jest konieczność wykonania sporej ilości pracy w celu właściwego przygotowania realistycznego Ŝądania. ServletDebugger moŜna odnaleźć w cenniku Allaire pod adresem http://www.allaire.com3.

    Ostatnie wskazówki JeŜeli wszystkie powyŜsze porady nie pomogły w odnalezieniu i usunięciu błędu, proszę obejrzeć poniŜsze ostateczne wskazówki dotyczące suwania błędów z serwletów: •

    Proszę wykorzystać System.getProperty("java.class.path") przy pomocy serwletu w celu uzyskania pomocy w rozwiązywaniu problemów związanych ze ścieŜką klas. PoniewaŜ serwlety są często uruchamiane na serwerach WWW z osadzonymi wirtualnymi maszynami Javy, trudne moŜe być dokładne określenie ścieŜki klas poszukiwanej przez JVM. Określić to moŜe właściwość java.class.path.



    Proszę pamiętać, Ŝe klasy odnalezione w bezpośredniej ścieŜce klas serwera (katalog_macierzysty/classes) przypuszczalnie nie są przeładowywane podobnie jak, w większości serwerów niezwiązanych z serwletami, klasy wspierające w katalogu klas aplikacji WWW (WEBINF/classes). Zazwyczaj przeładowywane są jedynie klasy serwletów w katalogu klas aplikacji WWW.



    NaleŜy zaŜądać od przeglądarki pokazania surowej zawartości wyświetlanej strony. MoŜe to pomóc w zidentyfikowaniu problemów z formatowaniem. Zazwyczaj jest to opcja w menu Widok.



    NaleŜy upewnić się, Ŝe przeglądarka nie przechowuje w pamięci podręcznej wyników poprzedniego Ŝądania poprzez wymuszenie pełnego przeładowania strony. W przeglądarce Netscape Navigator, naleŜy zastosować Shift-Reload; W Internet Explorer naleŜy zastosować Shift-Refresh.



    JeŜeli pomija się wersję init(), która pobiera ServletConfig naleŜy upewnić się, Ŝe pomijająca metoda od razu wywołuje super.init(config).

    Poprawa wydajności Serwlety poprawiające wydajność wymagają nieco innego podejścia niŜ aplikacje lub aplety Javy wykonujące to samo działanie. Powodem tego jest fakt, Ŝe JVM uruchamiająca serwlety zazwyczaj obsługuje kilkadziesiąt, jeŜeli nie kilkaset wątków, z których kaŜdy uruchamia serwlet. Te współistniejące serwlety muszą dzielić się zasobami JVM w sposób inny, niŜ zwykłe aplikacje. Tradycyjne sztuczki poprawiające wydajność oczywiście działają, ale posiadają mniejszy wpływ, kiedy zostają wykorzystane w systemie wielowątkowym. PoniŜej przedstawiono niektóre sztuczki najczęściej wykorzystywane przez programistów serwletów.

    3

    Nie byłoby zaskakujące, jeŜeli w najbliŜszym czasie firma Allaire zrzuciłaby obsługę ServletDebugger. JeŜeli się to zdarzy, a nawet jeŜeli się nie wydarzy, moŜna poszukać wersji Open Source.

    Tworzyć, ale nie przesadzać NaleŜy unikać niepotrzebnego tworzenia obiektów. To zawsze była dobra rada — tworzenie niepotrzebnych obiektów marnuje pamięć i duŜą ilość czasu. W przypadku serwletów to jest rada jeszcze lepsza. Tradycyjnie wiele JVM wykorzystywało globalną stertę obiektów, która musi zostać przypisana do kaŜdej nowej alokacji pamięci. Kiedy serwlet tworzy nowy obiekt lub alokuje dodatkową pamięć, działania tego nie moŜe wykonać Ŝaden inny serwlet.

    Nie łączyć NaleŜy unikać łączenia kilku łańcuchów. Zamiast StringBuffer poleca się zastosowanie metody append(). To równieŜ zawsze była dobra rada, ale w przypadku serwletów szczególnie pociągające jest napisanie kodu przygotowującego łańcuch do późniejszego wyświetlania w następujący sposób: String wyswietl; wyswietl += ""; wyswietl += "Witaj, " + uzyt; wyswietl += "";

    ChociaŜ powyŜszy kod wygląda miło i sprawnie, w trakcie uruchomienia działa, jak gdyby wyglądał mnie więcej tak jak poniŜej, z nowymi StringBuffer i String tworzonymi w kaŜdej linii: String wyswietl; wyswietl = new StringBuffer().append("").toString();; wyswietl = new StringBuffer(wyswietl).append("Witaj, ").toString(); wyswietl = new StringBuffer(wyswietl).append(uzyt).toString(); wyswietl = new StringBuffer(wyswietl).append("").toString();

    Kiedy wydajność jest waŜną kwestią, naleŜy przepisać oryginalny kod tak, aby wyglądał jak poniŜszy, tak aby utworzone zostały tylko pojedyncze StringBuffer i String: StringBuffer buf = new StrngBuffer(); buf.append(""); buf.append("Witaj, "").append(uzyt); buf.append(""); wyswietl = buf.toString();

    Proszę zauwaŜyć, Ŝe jeszcze bardziej wydajne jest zastosowanie tablicy bajtów.

    Ograniczać synchronizację NaleŜy synchronizować bloki, kiedy jest to konieczne, ale nic poza tym. KaŜdy zsynchronizowany blok w serwlecie wydłuŜa czas odpowiedzi serwletu. PoniewaŜ ten sam egzemplarz serwletu moŜe obsługiwać wiele współbieŜnych Ŝądań, musi, oczywiście, zająć się ochroną swojej klasy i zmiennych egzemplarza przy pomocy zsynchronizowanych bloków. Jednak przez cały czas jeden wątek Ŝądania znajduje się w zsynchronizowanym bloku i Ŝaden inny wątek nie moŜe zostać do bloku wprowadzony. W związku z tym najlepiej jest uczynić te bloki jak najmniejszymi. NaleŜy takŜe przyjrzeć się najgorszemu z moŜliwych wyników sporu między wątkami. JeŜeli najgorszy przypadek jest znośny (jak w przykładzie licznika w rozdziale 3, „Okres trwałości serwletów”), moŜna rozwaŜyc całkowite usuniecie bloków synchronizacji. MoŜna równieŜ rozwaŜyć zastosowanie interfejsu znaczników SingleThreadModel, w którym serwer zarządza pulą egzemplarzy serwletów, aby zagwarantować, Ŝe kaŜdy egzemplarz jest wykorzystywany przez co najwyŜej jeden wątek w jednym czasie. Serwlety będące implementacją SingleThreadModel nie muszą synchronizować dostępu do swoich zmiennych egzemplarza. W końcu naleŜy równieŜ pamiętać, Ŝe java.util.Vector i java.util.Hashtable są zawsze wewnętrznie zsynchronizowane, podczas gdy równowaŜne im java.util.ArrayList i java.util.HashMap, wprowadzone w JDK 1.2, nie są zsynchronizowane, jeŜeli nie nastąpi odpowiednie

    Ŝądanie. Tak wiec jeŜeli dany Vector lub Hashtable nie potrzebuje synchronizacji, moŜna go zastąpić ArrayList lub HashMap.

    Buforować dane wprowadzane i wyświetlane NaleŜy buforować dane wprowadzane i wyświetlane, wszystkie pliki magazynowe, wszystkie potoki pobrane z bazy danych itd. To prawie zawsze podnosi wydajność, ale poprawa ta moŜe być szczególnie widoczna w przypadku serwletów. Jej powód jest taki, Ŝe odczyt i zapis jednego elementu za jednym razem moŜe spowolnić cały serwer w związku z koniecznością dokonywania częstych przełączeń kontekstu. Na szczęście ogólnie buforowanie podczas zapisu do PrintWriter lub ServletOutputStream lub podczas odczytywania z BufferedReader lub ServletInputStream nie jest konieczne. Większość implementacji serwerów sama buforuje te potoki.

    Spróbować wykorzystania OutputStream W przypadku stron WWW wykorzystujących kodowanie znaków Latin-1, technicznie moŜliwe jest wykorzystanie PrintWriter lub ServletOutputStream. Rekomendowanym podejściem jest wykorzystanie PrintWriter, poniewaŜ obsługuje on internacjonalizację, ale na niektórych serwerach wykorzystanie ServletOutputStream powoduje zauwaŜalny wzrost wydajności, a ServletOutputStream posiada takŜe ułatwiające pracę metody print() i println() będące dziedzictwem Servlet API 1.0, w którym nie występowała opcja PrintWriter. Proszę jednak uwaŜać. W przypadku wielu serwerów zaleŜność jest odwrotna i to PrintWriter powoduje wyŜszą wydajność. Osoby, które nie są pewne swojej platformy programistycznej i nie przeprowadzały porównywalnych prób czasowych powinny trzymać się PrintWriter.

    Wykorzystać narzędzie profilujące Dostępnych jest kilka narzędzi profilujących Javy które mogą wspomóc w odnalezieniu wąskich gardeł w kodzie. Większość problemów z wydajnością w Javie działającej po stronie serwera jest powodowana nie przez język czy JVM, ale kilka wąskich gardeł. Sztuką jest odnalezienie tych wąskich gardeł. Narzędzia analizujące pracują w tle, obserwując obsługę Ŝądań przez serwer i zwracając dokładne podsumowanie spędzonego czasu, a takŜe opis alokacji pamięci. Dwa popularne narzędzia to OptimizeIT! Firmy Intuitive Systems (http://www.optimizeit.com) i Jprobe formy Sitraka, dawniej KL Group (http://sitraka.com/jprobe). DuŜa ilość JVM moŜe przyjmować równieŜ znaczniki z linii poleceń (-prof w JDK 1.1 i Xrunhproof() w JDK 1.2). Aby uruchomić obciąŜony serwer, moŜna wykorzystać narzędzie takie jak Apache JMeter (http://java.apache.org).

    W niniejszym rozdziale: •

    Zmiany w Servlet API 2.3



    Konkluzja

    Rozdział 20.

    Zmiany w Servlet API 2.3 Krótko przed przekazaniem niniejszej ksiąŜki do druku firma Sun Microsystems opublikowała Proposed Final Draft (Proponowaną Ostateczną Próbę) specyfikacji Servlet API 2.31. Nie jest to ostateczna wersja specyfikacji; Proposed Final Draft to krok do formalnej Final Release (Wersji Ostatecznej), tak więc szczegóły techniczne ciągle mogą ulec zmianie. Jednak zmiany te nie powinny być znaczące — tak naprawdę producenci serwerów juŜ rozpoczęli implementację nowych funkcji. W niniejszym rozdziale opisane zostaną w skrócie wszystkie zmiany, jakie zaszły pomiędzy API 2.2 i 2.3. Wyjaśnione takŜe zostaną powody zmian i przedstawione zostaną sposoby tworzenia serwletów przy pomocy nowych funkcji2.

    Zmiany w Servlet API 2.3 Servlet API 2.3 właściwie pozostawia nietknięte jądro serwletów, co oznacza, Ŝe serwlety osiągnęły wysoki poziom dojrzałości. Większość działań związana była z dodaniem nowych funkcji poza jądrem. Zmiany te to między innymi: •

    Serwlety wymagają teraz JDK 1.2 lub późniejszego.



    Utworzony został (nareszcie) mechanizm filtrów.



    Dodane zostały nowe zdarzenia okresu trwałości aplikacji.



    Dodana została nowa obsługa internacjonalizacji.



    Sformalizowana została technika wyraŜania zaleŜności pomiędzy plikami JAR.

    1 ChociaŜ specyfikacja ta została opublikowana przez firmę Sun, Servlet API 2.3. został tak naprawdę utworzony przez wiele osób i przedsiębiorstw działających jako grupa ekspertów JSR-053, zgodnie z procesem Java Community Process (JCP) 2.0. Ta grupa ekspertów działała pod przewodnictwem Danny'ego Cowarda z Sun Microsystems. 2

    Niniejszy materiał pojawił się po raz pierwszy w artykule „Servlet 2.3: New Features Exposed” autorstwa Jasona Huntera, opublikowanym przez JavaWorld (http://www.javaworld.com), własność ITworld.com, Inc., styczeń 2001. Przedruk za pozwoleniem. (Proszę zobaczyć takŜe http://www.javaworld.com/j2-01-2001/jw-0126-servletapi.html).



    Wyjaśnione zostały zasady ładowania klas.



    Dodane zostały nowe atrybuty błędów i bezpieczeństwa.



    Opuszczona została klasa HttpUtils.



    Dodane zostały róŜne nowe pomocne metody.



    Rozszerzone i wyjaśnione zostało kilka zachowań DTD.

    Wykonane zostały takŜe inne wyjaśnienia, ale skupiają się one głównie na producentach serwerów, nie ogólnie na programistach serwletów (poza faktem, Ŝe programiści ujrzą poprawioną przenośność), tak więc te szczegóły zostaną tu ominięte. Przed rozpoczęciem przyglądania się zmianom naleŜy zaznaczyć, Ŝe wersja 2.3 została udostępniona jedynie jako specyfikacja próbna. Większość opisanych tu funkcji nie będzie działać na wszystkich serwerach. Aby przetestować te funkcje, poleca się pobranie oficjalnego wzorcowego serwera, Apache Tomcat 4.0. Jest to Open Source i moŜe być pobrany za darmo. Tomcat 4.0 jest aktualnie dostępny w wersji beta; obsługa Servlet API 2.3 staje się coraz lepsza, ale ciągle jest niekompletna. Proszę przeczytać plik NEW_SPECS.txt dołączony do Tomcata 4.0 w celu poznania jego poziomu wsparcia dla wszystkich funkcji nowej specyfikacji.

    Serwlety w J2SE i J2EE Jedną z pierwszych rzeczy, jakie zazwyczaj zauwaŜa się na temat Servlet API 2.3 jest fakt, Ŝe serwlety zaleŜą teraz od platformy Java 2, Standard Edition (znanej takŜe jako J2SE 1.2 lub JDK 1.2). Ta mała, ale waŜna zmiana oznacza, Ŝe w serwletach moŜna teraz wykorzystywać funkcje J2SE 1.2 z gwarancją, Ŝe serwlety te będą działać na wszystkich kontenerach. Poprzednio funkcje J2SE mogły być wykorzystywane, ale ich obsługa przez serwery nie była obowiązkowa. Servlet API2.3 ma stać się częścią platformy Java 2, Enterprise Edition 1.3 (J2EE 1.3). Poprzednia wersja, Servlet API 2.2 była częścią J2EE 1.2. Jedyną zauwaŜalną róŜnicą jest fakt dodania kilku stosunkowo obskurnych znaczników deskryptora związanych z J2EE w deskryptorze web.xml — obsługującego „obiekty administrowane”, takie jak te wymagane przez Java Messaging System (JMS), pozwalający na współdzielony lub wyłączny dostęp do odwołania do zasobów oraz określający identyfikator bezpieczeństwa dla wywołującego EJB. Większość autorów serwletów nie powinna przejmować się tymi znacznikami J2EE; pełny ich opis dostępny jest w specyfikacji J2EE 1.3.

    Filtry Najbardziej znaczącą częścią API 2.3 jest dodanie filtrów. Filtry są obiektami potrafiącymi zmieniać kształt Ŝądania lub modyfikować odpowiedź. Proszę zauwaŜyć, Ŝe nie są to serwlety; tak naprawdę nie tworzą one odpowiedzi. Przetwarzają one wstępnie Ŝądanie zanim dotrze ono do serwletu, oraz przetwarzają odpowiedź opuszczającą serwlet. W skrócie, filtry są dojrzałą wersją starego pomysłu „łańcuchów serwletów”. Filtr potrafi: •

    Przechwycić wywołanie serwletu przed jego wywołaniem.



    Sprawdzić Ŝądanie przed wywołaniem serwletu.



    Zmodyfikować nagłówki i dane Ŝądania poprzez dostarczenie własnej wersji obiektu Ŝądania, który zostaje dołączony do prawdziwego Ŝądania.



    Zmodyfikować nagłówki i dane odpowiedzi poprzez dostarczenie własnej wersji obiektu odpowiedzi, który zostaje dołączony do prawdziwej odpowiedzi.



    Przechwycić wywołanie serwletu po jego wywołaniu.

    Filtr moŜe być skonfigurowany tak, by działał jako serwlet lub grupa serwletów; ten serwlet lub grupa moŜe zostać przefiltrowana przez dowolną ilość filtrów. Niektóre praktyczne idee filtrów to między innymi filtry uwierzytelniania, filtry logowania i nadzoru, filtry konwersji obrazków, filtry kompresji danych, filtry kodowania, filtry dzielenia na elementy, filtry potrafiące wywołać zdarzenia dostępu do zasobów, filtry XSLT przetwarzające zawartość XML lub filtry łańcuchowe typu MIME (podobne do łańcuchów serwletów). Filtr jest implementacją javax.servlet.filter i definiuje trzy metody tej klasy:

    void setFilterConfig(FilterConfig konfig) Ta metoda ustawia obiekt konfiguracyjny filtra. FilterConfig getFilterConfig() Ta metoda zwraca obiekt konfiguracyjny filtra. void doFilter(ServletRequest zad, ServletResponse odp, FilterChain lancuch) Ta metoda wykonuje właściwą pracę filtra. Serwer wywołuje jeden raz setFilterConfig() w celu przygotowania filtru do działania, następnie wywołuje doFilter() dowolną ilość razy dla róŜnych obiektów. Interfejs FilterConfig posiada metody pobierające nazwę filtra, jego parametry inicjacji oraz aktywny kontekst filtra. Serwer moŜe równieŜ przekazać setFilterConfig() wartość null aby wskazać, Ŝe filtr zostaje wyłączony.

    UWAGA!!!! Przewiduje się, Ŝe w ostatecznej wersji 2.3 metoda getFilterConfig() zostanie usunięta, a metoda setFilterConfig(FilterConfig konfig)zostanie zastąpiona przez init(FilterConfig) i destroy().

    KaŜdy filtr pobiera aktualne Ŝądanie i odpowiedź w swojej metodzie doFilter(), a takŜe FilterChain zawierający filtry, które muszą stale być przetwarzane. W metodzie doFilter() filtr moŜe wykonać dowolne działanie Ŝądania i odpowiedzi. (Na przykład moŜe zbierać dane przez wywoływanie ich metod, dołączać informacje nadające im nowe zachowanie). Filtr następnie wywołuje lancuch.doFilter() w celu przekazania kontroli następnemu filtrowi. Kiedy wywołanie to wraca, filtr moŜe, na końcu swojej własnej metody doFilter(), wykonać dodatkowe działania na odpowiedzi; na przykład moŜe zapisać informacje na temat odpowiedzi w dzienniku. JeŜeli filtr chce całkowicie zatrzymać przetwarzanie Ŝądania i zyskać pełną kontrolę nad odpowiedzią, moŜe specjalnie nie wywoływać następnego filtra. Filtr moŜe zmieniać obiekty Ŝądania i odpowiedzi w celu dostarczenia własnego zachowania, zmiany konkretnej metody wywołują implementację wpływającą na późniejsze działania obsługujące Ŝądania. Serwlet API 2.3 dostarcza nowych klas HttpServletRequestWrapper i HttpServletResponseWrapper w tym pomagających. Posiadają one domyślną implementację wszystkich metod Ŝądań i odpowiedzi oraz domyślnie przekazują wywołania do oryginalnych Ŝądań i odpowiedzi. PoniŜej przedstawiony jest kod prostego filtra logowania, który zapamiętuje czas trwania wszystkich Ŝądań: import javax.servlet.*; import javax.servlet.http.*;

    public class FiltrDziennik implements Filter {

    FilterConfig konfig;

    public void setFilterConfig(FilterConfig konfig) { this.konfig = konfig; }

    public FilterConfig getFilterConfig() { return konfig; }

    public void doFilter(ServletRequest zad, ServletResponse odp, FilterChain lancuch) {

    ServletContext kontekst = getFilterConfig().getServletContext(); long przed = System.currentTimeMillis(); lancuch.doFilter(zad, odp); // nie jest potrzebny Ŝaden parametr łańcucha long po = System.currentTimeMillis(); kontekst.log("śądanie" + zad.getRequestURI() + ": " + (przed-po)); } }

    Kiedy serwer wywołuje setFilterConfig(), filtr zapamiętuje w swojej zmiennej konfig odwołanie do konfiguracji filtra, które później zostanie wykorzystane w metodzie doFilter() w celu pobrania ServletContext. Logika doFilter() jest prosta — obliczenie czasu obsługi Ŝądania i zapamiętanie czasu po zakończeniu przetwarzania. Aby wykorzystać powyŜszy filtr, trzeba wcześniej zadeklarować go w deskryptorze DTD przy pomocy znacznika , jak przedstawiono poniŜej:

    dziennik

    FiltrDziennik

    PowyŜszy fragment kodu przekazuje serwerowi informację, Ŝe filtr o nazwie dziennik jest zaimplementowany w klasie FiltrDziennik. MoŜna przypisać zarejestrowany filtr do konkretnych wzorów URL-i lub nazw serwletów przy pomocy znacznika :

    log /*

    PowyŜszy fragment konfiguruje filtr tak, aby był stosowany do wszystkich Ŝądań serwera (statycznych lub dynamicznych), co jest działaniem odpowiednim dla filtra zapisującego informacje w dzienniku. JeŜeli nastąpi połączenie, dziennik mógłby wyglądać następująco: śądanie /indeks.jsp: 10

    Zdarzenia okresu trwałości Drugą bardzo powaŜną zmianą w Servlet API 2.3 jest dodanie zdarzeń okresu trwałości aplikacji, które umoŜliwiają powiadomienie obiektów „nasłuchujących", kiedy inicjowane bądź niszczone są konteksty serwletów i sesje, a takŜe kiedy dodawane lub usuwane z kontekstu lub sesji są atrybuty. Okres trwałości serwletu jest podobny do zdarzeń Swing. KaŜdy obiekt nasłuchujący zainteresowany obserwacją okresu trwałości ServletContext moŜe zaimplementować interfejs ServletContextListener. Interfejs ten posiada dwie metody: void contextInitialized(ServletContextEvent z) Wywoływana z aplikacji WWW, kiedy jest ona po raz pierwszy gotowa o przetwarzania Ŝądań (tzn. podczas uruchomienia serwera lub dodania albo przeładowania kontekstu). śądania nie są obsługiwane, dopóki metoda nie zwróci swoich wartości. void contextDestroyed(ServletContextEvent z)

    Wywoływana z aplikacji WWW, która powinna zostać zakończona (tzn. podczas wyłączania serwera lub usuwania albo przeładowania kontekstu). Obsługa Ŝądań zostaje zatrzymana przed wywołaniem tej metody. Klasa ServletContextEvent przekazywana obu metodom zawiera jedynie metodę pobierzZrodloKontekst(), która zwraca kontekst, który jest inicjowany lub niszczony. Obiekt nasłuchujący zainteresowany obserwacją okresem trwałości atrybutu ServletContext moŜe zaimplementować interfejs ServletContextAttributesListener, który posiada trzy metody: void attributeAdded(ServletContextAttributeEvent z) Wywoływana, kiedy atrybut zostaje dodany do kontekstu serwletu. void attributeRemoved(ServletContextAttributeEvent z) Wywoływana, kiedy atrybut zostaje usunięty z kontekstu serwletu. void attributeReplaced(ServletContextAttributeEvent z) Wywoływana, kiedy atrybut w kontekście serwletu zostaje wymieniony na inny. Klasa ServletContextAttributeEvent jest rozszerzeniem ServletContextEvent i dodaje metody getName() i getValue(), tak więc obiekt nasłuchujący moŜe uzyskać informacje na temat zmieniających się atrybutów. Jest to przydatna własność, poniewaŜ aplikacje WWW które muszą zsynchronizować stan aplikacji (atrybuty kontekstu) z czymś w rodzaju bazy danych mogą to teraz uczynić w jednym miejscu. Model obiektu nasłuchującego sesji jest podobny do modelu obiekt nasłuchującego okresu trwałości. W modelu sesji występuje interfejs HttpSessionListener posiadający dwie metody: void SessionCreated(HttpSessionEvent z) Wywoływana podczas tworzenia sesji. void SessionDestroyed(HttpSessionEvent z) Wywoływana podczas zniszczenia (uniewaŜnienia) sesji. PowyŜsze metody przyjmują egzemplarz HttpSessionEvent z metodą dostępu getSession() w celu zwrócenia sesji, która jest tworzona bądź niszczona. Metody te mogą być zastosowane podczas implementacji interfejsu administratora, który śledzi wszystkich aktywnych uŜytkowników w aplikacji WWW. Model sesji posiada równieŜ interfejs HttpSessionAttributesListener posiadający trzy metody. Metody te informują obiekt nasłuchujący, kiedy zmieniają się atrybuty i mogłyby być zastosowane, na przykład przez aplikację synchronizującą dane profilu przechowywane w sesji do bazy danych: void attributeAdded(HttpSessionBindingEvent z) Wywoływana, kiedy atrybut zostaje dodany do sesji. void attributeRemoved(HttpSessionBindingEvent z) Wywoływana, kiedy atrybut zostaje usunięty z sesji. void attributeReplaced(HttpSessionBindingEvent z) Wywoływana, kiedy atrybut w sesji zostaje wymieniony na inny. Jak moŜna się było spodziewać, klasa HttpSessionBindingEvent jest rozszerzeniem HttpSessionEvent i dodaje metody getName() i getValue(). Jedyna dość niezwykła własność jest taka, Ŝe klasa zdarzeń nosi nazwę HttpSessionBindingEvent, a nie HttpSessionAttributeEvent. Dzieje się tak z powodu tradycji — API posiadał juŜ klasę HttpSessionBindingEvent, tak więc została ona wykorzystana ponownie. Ten nieco mylący aspekt API moŜe zostać poprawiony w ostatecznej wersji. MoŜliwym praktycznym zastosowaniem dla zdarzeń okresu trwałości jest współdzielone połączenie z bazą danych zarządzane przez obiekt nasłuchujący kontekstu. Obiekt ten deklarowany jest w pliku web.xml, w następujący sposób:

    com.firma.MojZarzadcaPolaczen

    Serwer tworzy egzemplarz klasy nasłuchującej słuŜącej do otrzymywania zdarzeń i wykorzystuje introspekcje w celu określenia, jaki interfejs (lub interfejsy) nasłuchu powinien zostać wykorzystany przez klasę. NaleŜy pamiętać, Ŝe poniewaŜ mechanizm nasłuchujący jest konfigurowany w deskryptorze, moŜna dodawać nowe mechanizmy bez konieczności zmiany kodu. Sam obiekt nasłuchujący mógłby wyglądać następująco: import javax.servlet.*; import javax.servlet.http.*;

    public class MojZarzadcaPolaczen implements ServletContextListener {

    public void contextInitialized(ServletContextEvent z) { Connection pol =

    // utworzenie połączenia

    z.getServletContext().setAttribute("pol", pol); }

    public void contextDestroyed(ServletContextEvent z) { Connection pol = (Connection) z.getServletContext().getAttribute("pol"); try { pol.close(); } catch (SQLException ignored) { } // zamknięcie połączenia } }

    PowyŜszy obiekt nasłuchujący zapewnia dostępność połączenia z bazą danych w kaŜdym nowym kontekście serwletu oraz zamknięcie wszystkich połączeń po zamknięciu kontekstu. Interfejs HttpSessionActivationListener, kolejny nowy interfejs nasłuchu w API 2.3 jest zaprojektowany do obsługi sesji wędrujących z jednego serwera do drugiego. Obiekt nasłuchujący będący implementacją HttpSessionActivationListener jest powiadamiany o gotowości kaŜdej sesji do wędrówki oraz kiedy sesja gotowa jest do aktywacji na drugim komputerze. Metody te dają aplikacji szansę przesuwania danych niemoŜliwych do zserializowania pomiędzy wirtualnymi maszynami Javy, lub doklejania i odklejania obiektów zserializowanych pomiędzy pewnego rodzaju modelem obiektów przed lub po migracji. Interfejs ten posiada dwie metody: void sessionWillPassivate(HttpSessionEvent z) Sesja ma zamiar dokonać wędrówki. Sesja jest juŜ niedostępna kiedy następuje to wywołanie. void sessionDidActivate(HttpSessionEvent z) Sesja została aktywowana. Sesja nie jest jeszcze w uŜytku, kiedy następuje to wywołanie. Taki obiekt nasłuchujący jest rejestrowany tak, jak inne. Jednak róŜnica pomiędzy nimi jest taka, Ŝe wywołania migracji i aktywacji najprawdopodobniej będą występować na dwóch róŜnych serwerach!

    Wybranie kodowania znaków Servlet API 2.3 dostarcza tak bardzo potrzebnej obsługi formularzy wysyłanych w róŜnych językach. Nowa metoda, zadanie.setCharacterEncoding(String kodowanie) pozwala na poinformowanie serwera o kodowaniu znaków Ŝądania. Kodowanie znaków (albo po prostu kodowanie) to sposób odwzorowania bajtów na znaki. Serwer moŜe wykorzystać określone kodowanie, aby prawidłowo zanalizować parametry i dane POST. Domyślnie serwer analizuje parametry przy pomocy popularnego kodowania Latin-1 (ISO 8859-1) Niestety jest ono odpowiednie tylko dla języków zachodnioeuropejskich. Kiedy przeglądarka wykorzystuje inne kodowanie,

    powinna wysyłać informacje o kodowaniu w nagłówku Ŝądania Content-Type, ale prawie Ŝadna przeglądarka nie stosuje się do tej zasady. Metoda setCharacterEncoding() pozwala serwletowi na poinformowanie serwera, które kodowanie jest wykorzystywane (zazwyczaj jest to kodowanie strony, która zawiera formularz); serwer zajmuje się resztą. Na przykład, serwlet pobierający japońskie parametry z formularza zakodowanego przy pomocy Shift_JIS powinien odczytywać parametry w następujący sposób: // ustawienie kodowania na Shift_JISD zad.setCharacterEncoding("Shift_JIS");

    // Odczytanie parametru przy pomocy tego kodowania String nazwa = zad.getParameter("nazwa");

    Proszę pamiętać o ustawieniu kodowania przed wywołaniem getParameter() lub getReader(). Wywołanie setCharacterEncoding() moŜe zgłosić wyjątek java.io.UnsupportedEncodingException, jeŜeli dane kodowanie nie jest obsługiwane. Funkcjonalność ta jest równieŜ dostępna uŜytkownikom API 2.2 i wcześniejszych, jako część klasy com.oreilly.servlet.ParameterParser.

    ZaleŜności plików JAR Plik WAR (plik Web Application Archive — Archiwum Aplikacji WWW, dodane w Servlet API 2.2) często wymaga istnienia i prawidłowego działania na serwerze innych bibliotek JAR. Na przykład, aplikacja WWW wykorzystująca klasę ParameterParser wymaga w ścieŜce klas serwera pliku cos.jar. Aplikacja WWW wykorzystująca WebMacro wymaga webmacro.jar. Przed powstaniem API 2.3, zaleŜności te musiały być udokumentowane (ale czy ktoś tak naprawdę czyta dokumentację!), lub kaŜda aplikacja WWW musiała zawierać wszystkie wymagane pliki JAR w swoim własnym katalogu WEB-INF/lib. Servlet API 2.3 pozwala na zadeklarowanie zaleŜności JAR w WAR przy pomocy pozycji META-INF/MANIFEST.MF archiwum WAR. Jest to standardowy sposób deklarowania zaleŜności plików JAR, ale od API 2.3 pliki WAR muszą oficjalnie obsługiwać ten mechanizm. JeŜeli zaleŜność nie moŜe zostać wypełniona, serwer moŜe delikatnie odrzucić aplikację WWW w trakcie tworzenia zamiast wywoływać obskurne komunikaty o błędach w trakcie uruchomienia. Mechanizm ten pozwala na wysoki stopień ziarnistości. Na przykład moŜna wyrazić zaleŜność w konkretnej wersji opcjonalnego pakietu, a serwer musi ją odnaleźć przy pomocy algorytmu wyszukiwania.

    Mechanizmy ładowania klas Nastąpiła tu mała zmiana, posiadająca jednak ogromne znaczenie — w API 2.3, kontener serwletów (czyli serwer) musi blokować moŜliwość dostrzeŜenia klas implementacji serwera przez klasy aplikacji WWW. Innymi słowy, mechanizmy ładowania klas powinny być od siebie oddzielone. Nie brzmi to jak wielka zmiana, ale eliminuje moŜliwość kolizji pomiędzy klasami aplikacji WWW i klasami serwera. Stały się one powaŜnym problemem z powodu konfliktów analizatora XML. KaŜdy serwer potrzebuje analizatora XML w celu zinterpretowania plików web.xml, a obecnie wiele aplikacji WWW wykorzystuje analizator XML do obsługi odczytu, manipulacji i zapisu danych XML. JeŜeli analizatory obsługiwały róŜne wersje DOM lub SAX, powodowało to nienaprawialny konflikt. Oddzielenie zakresów klas elegancko ten problem rozwiązuje.

    Nowe atrybuty błędów Poprzednia wersja interfejsu, Servlet API 2.2 wprowadziła kilka atrybutów Ŝądania, które mogą być wykorzystywane przez serwlety i strony JSP pełniące funkcję celu zasady . Wcześniej w niniejszej ksiąŜce opisano, Ŝe zasady pozwalają na skonfigurowanie aplikacji WWW tak, aby konkretne kody stanu lub typy wyjątków powodowały wyświetlenie konkretnych stron:



    Serwlet umieszczony w zasady mógł otrzymywać następujące trzy atrybuty: javax.servlet.error.status_code Liczba Integer przekazująca kod stanu błędu, jeŜeli taki istnieje. javax.servlet.error.exception_type Egzemplarz Class wskazujący na typ wyjątku, który spowodował błąd, jeŜeli taki istnieje. javax.servlet.error.message Łańcuch String przekazujący wiadomość o błędzie, przekazywany do konstruktora wyjątku. Przy pomocy powyŜszych atrybutów serwlet mógł wygenerować stronę błędu dostosowaną do błędu, jak przedstawiono poniŜej: import java.io.*; import javax.servlet.*; import javax.servlet.http.*;

    public class WyswietlBlad extends HttpServlet {

    public void doGet(HttpServletRequest zad, HttpServletResponse odp) throws ServletException, IOException { odp.setContentType("text/html"); PrintWriter wyj = odp.getWriter();

    String kod = null, wiadomosc = null, typ = null, uri = null; Object kodObi, wiadomoscObi, typObi;

    // Odczytanie trzech moŜliwych atrybutów błędów. Niektóre mogą mieć wartość null kodObi = zad.getAttribute("javax.servlet.error.status_code"); wiadomoscObi = req.getAttribute("javax.servlet.error.message"); typObi = req.getAttribute("javax.servlet.error.exception_type");

    // Konwersja atrybutów na wartości łańcuchowe // Dlatego, Ŝe niektóre stare typy serwerów zwracają typy String // a nowe typy Integer, String i Class

    if (kodObi != null) kod = kodObi.toString(); if (wiadomoscObi != null) wiadomosc = wiadomoscObi.toString(); if (typObi != null) typ = typObi.toString();

    // Powód błędu to kod stanu lub typ wyjątku String powod = (kod != null ? kod : typ);

    wyj.println(""); wyj.println("" + powod + ": " + wiadomosc + ""); wyj.println(""); wyj.println("" + powod + ""); wyj.println("" + wiadomosc + ""); wyj.println(""); } wyj.println(""); wyj.println(""); wyj.println("Błąd przy dostępie do " + zad.getRequestURI() + ""); wyj.println(""); } }

    Ale co by się stało, gdyby strona błędu mogła zawierać ścieŜkę stosu wyjątku lub URI serwletu, który naprawdę spowodował problem, (poniewaŜ nie zawsze jest to początkowo zaŜądany URI)? W API 2.2 nie było to moŜliwe. W API 2.3 informacje te są dostępne poprzez dwa nowe atrybuty: javax.servlet.error.exception Obiekt Throwable, zawierający właściwy zgłoszony wyjątek. javax.servlet.error.request_uri Łańcuch String przekazujący URI zasobu sprawiającego problem. Atrybuty te pozwalają na dołączenie do strony błędu ścieŜki stosu wyjątku oraz URI zasobu sprawiającego problem. Serwlet przedstawiony poniŜej został ponownie napisany tak, aby wykorzystywał nowe atrybuty. Proszę zauwaŜyć, Ŝe elegancko przerywa działanie, jeŜeli one nie istnieją. Dzieje się tak w celu zachowania wstecznej kompatybilności. import java.io.*; import javax.servlet.*; import javax.servlet.http.*;

    public class WyswietlBlad extends HttpServlet {

    public void doGet(HttpServletRequest zad, HttpServletResponse odp) throws ServletException, IOException { odp.setContentType("text/html"); PrintWriter wyj = odp.getWriter();

    String kod = null, wiadomosc = null, typ = null, uri = null; Object kodObi, wiadomoscObi, typObi; Throwable throwable;

    // Odczytanie trzech moŜliwych atrybutów błędów. Niektóre mogą mieć wartość null kodObi = zad.getAttribute("javax.servlet.error.status_code"); wiadomoscObi = req.getAttribute("javax.servlet.error.message"); typObi = req.getAttribute("javax.servlet.error.exception_type"); throwable = (Throwable) zad.getAttribute("javax.servlet.error.exception"); uri = (String) zad.getAttribute("javax.servlet.error.request_uri");

    if (uri == null) { uri = zad.getRequestURI(); // gdyby nie podano URI }

    // Konwersja atrybutów na wartości łańcuchowe if (kodObi != null) kod = kodObi.toString(); if (wiadomoscObi != null) wiadomosc = wiadomoscObi.toString(); if (typObi != null) typ = typObi.toString();

    // Powód błędu to kod stanu lub typ wyjątku String powod = (kod != null ? kod : typ);

    wyj.println(""); wyj.println("" + powod + ": " + wiadomosc + ""); wyj.println(""); wyj.println("" + powod + ""); wyj.println("" + wiadomosc + ""); wyj.println(""); if (throwable != null) { throwable.printStackTrace(wyj); } wyj.println(""); wyj.println(""); wyj.println("Błąd przy dostępie do " + uri + ""); wyj.println(""); } }

    Nowe atrybuty bezpieczeństwa Servlet API 2.3 dodaje równieŜ dwa nowe atrybuty Ŝądania, które mogą pomóc serwletowi w podejmowaniu dobrze umotywowanych decyzji dotyczących obsługi bezpiecznych połączeń HTTPS. Do Ŝądań wykonanych przy pomocy HTTPS serwer dołączy następujące nowe atrybuty Ŝądania: javax.servlet.request.cipher_suite Łańcuch String reprezentujący typ szyfrowania stosowany przez HTTPS, jeŜeli taki występuje. javax.servlet.request.key_size Liczba Integer reprezentująca wielkość algorytmu w bitach, jeŜeli taka występuje. Serwlet moŜe wykorzystać powyŜsze atrybuty do programowej decyzji, czy połączenie jest na tyle bezpieczne, Ŝe moŜna z niego skorzystać. Aplikacja moŜe odrzucić połączenia o niewielkiej liczbie bitów, lub algorytmy niegodne zaufania. Na przykład, serwlet mógłby wykorzystać poniŜszą metodę w celu upewnienia się, Ŝe jego połączenie wykorzystuje klucz przynajmniej 128-bitowy: public boolean czyPonad128(HttpServletRequest zad) { Integer wielkosc = (Integer) zad.getAttribute("javax.servlet.request.key_size");

    if (wielkosc == null || wielkosc.intValue() < 128) { return false; } else { return true; } }

    UWAGA!!!! Nazwy atrybutów w wersji próbnej wykorzystują myślniki zamiast kresek dolnych. Jednak zostaną one zmienione w wersji ostatecznej, jak przedstawiono powyŜej, w celu uzyskania większej spójności z nazwami istniejących atrybutów.

    Niewielkie poprawki W Servlet API 2.3 znajdzie się takŜe pewna ilość drobnych zmian. Po pierwsze, metoda getAuthType(), która zwraca typu uwierzytelnienia wykorzystywanego do identyfikacji klienta została zdefiniowana tak, aby zwracać jedną z czterech nowych stałych typu String klasy HttpServletRequest — BASIC_AUTH, DIGEST_AUTH, CLIENT_AUTH i FORM_AUTH. UmoŜliwia to wykorzystanie uproszczonego kodu: if (zad.getAuthType() == zad.BASIC_AUTH) { //obsługa uwierzytelniania podstawowego }

    Oczywiście cztery stałe posiadają ciągle tradycyjne wartości String, tak więc poniŜszy kod z API 2.2 równieŜ działa, ale nie jest ani tak szybki, ani elegancki. Proszę zwrócić uwagę na odwrócone sprawdzenia equals() w celu uniknięcia wyjątku NullPointerException, jeŜeli getAuthType() zwróci null: if ("BASIC".equals(zad.getAuthType())) { //obsługa uwierzytelniania podstawowego }

    Inną zmianą w API 2.3 jest opuszczenie HttpUtils. Klasa HttpUtils była zawsze uwaŜana za zbiór róŜnych statycznych metod — wywołań, które mogły być czasami uŜyteczne, ale równie dobrze mogły się znaleźć w innych miejscach. Klasa ta zawierała metody słuŜące do zrekonstruowania oryginalnego URL-a z

    obiektu Ŝądania i do przeformatowania danych parametrów do tablicy asocjacyjnej. API 2.3 przesuwa tę funkcjonalność do obiektu Ŝądania, co jest miejscem bardziej odpowiednim i opuszcza HttpUtils. Nowe metody obiektu Ŝądania wyglądają następująco: StringBuffer zad.getRequestURL() Zwraca StringBuffer zawierający URL oryginalnego Ŝądania, odtworzony na podstawie informacji Ŝądania. java.util.Map zad.getParameterMap() Zwraca niemodyfikowalne odwzorowanie Map parametrów Ŝądania. Nazwy parametrów pełnią funkcję kluczy, a wartości parametrów funkcję wartości odwzorowania. Nie zapadła decyzja co do obsługi parametrów o wielu wartościach; najprawdopodobniej wszystkie wartości zostaną zwrócone jako String[]. Metody te wykorzystują nową metodę setCharacterEncoding() do obsługi konwersji znaków. API 2.3 dodaje równieŜ dwie nowe metody do ServletContext, które pozwalają na odczytanie nazwy kontekstu i wyświetlenia wszystkich przechowywanych przez niego zasobów: String kontekst.getServletContextName() Zwraca nazwę kontekstu zadeklarowaną w pliku web.xml. java.util.Set kontekst.getResourcePaths() Zwraca ścieŜki do wszystkich zasobów dostępnych w kontekście, jako niemodyfikowalny zbiór obiektów String. KaŜdy String posiada wiodący ukośnik (/) i powinien być uwaŜany za względny do katalogu macierzystego kontekstu. Pojawiła się takŜe nowa metoda obiektu odpowiedzi zwiększająca kontrolę programisty nad buforem odpowiedzi. API 2.2 wprowadził metodę odp.reset() pozwalającą na usunięcie odpowiedzi i wyczyszczenie jej głównej części, nagłówków i kodu stanu. API 2.3 dodaje odp.resetBuffer(), który czyści jedynie główną część odpowiedzi: void resetBuffer() Czyści bufor odpowiedzi, ale pozostawia nagłówki i kod stanu. JeŜeli odpowiedź został juŜ wysłana, zgłasza wyjątek IllegalStateException. I wreszcie, po długich naradach grupy ekspertów, Servlet API 2.3 wyjaśnia raz na zawsze, co dokładnie dzieje się podczas wywołania odp.sendRedirect("indeks.html") w przypadku serwletu nie działającego w kontekście macierzystym serwera. Niejasność wynikała z tego, Ŝe Servlet API 2.2 wymaga, aby niekompletna ścieŜka taka jak "/indeks.html" została przetłumaczona przez kontener serwletów na ścieŜkę kompletną, nie określa jednak zasad obsługi ścieŜek kontekstów. JeŜeli serwlet wykonujący wywołanie znajduje się w kontekście o ścieŜce "/sciezkakontekstu", czy URI przekierowania powinien być określony względem katalogu macierzystego kontenera (http://serwer:port/indeks.html), czy katalogu macierzystego kontekstu (http://serwer:port/sciezkakontekstu/indeks.html)? W celu zapewnienia maksymalnej przenośności zdefiniowanie zachowania jest konieczne. Po długiej debacie eksperci wybrali tłumaczenie ścieŜek względem katalogu macierzystego serwera. Osoby pragnące tłumaczenia względem kontekstu powinny dodać na początku URI wynik wywołania getContextPath().

    Wyjaśnienia deskryptora DTD Servlet API 2.3 rozwiewa kilka niejasności związanych z zachowaniem deskryptora web.xml. Obowiązkowe stało się przycięcie wartości tekstowych w pliku web.xml przed jego zastosowaniem. (W standardowym nie sprawdzanym XML wszystkie miejsce są ogólnie rzecz biorąc zachowywane.) Zasada ta zapewnia, Ŝe się poniŜsze pozycje będą traktowane identycznie: witaj

    i

    witaj

    Servlet API 2.3 zezwala równieŜ na wykorzystanie zasady , tak więc specjalna wartość „*” moŜe zostać wykorzystana jako wieloznacznik zezwalający na wszystkie role. Pozwala to na utworzenie zasady podobnej do poniŜszej, która pozwala na wejście wszystkim uŜytkownikom, jeŜeli zostali oni poprawnie rozpoznani jako posiadający dowolną rolę w aplikacji WWW:

    *

    Ostatnią zmianą jest dopuszczenie nazwy roli zadeklarowanej przez zasadę jako parametru metody isUserInRole(). Na przykład, proszę spojrzeć na następujący fragment pozycji web.xml:

    sekret

    PrzegladPensji

    men





    1

    Oryginalny komentarz do tego znacznika błędnie deklaruje, Ŝe znacznik „zawiera oczekiwany typ klasy Javy EJB, do którego występuje odwołanie”.

    Zestawienie

    Opis Element określa nazwę pozycji środowiskowej aplikacji słuŜącą do poszukiwań.

    Wysyłanie kodu PIN pocztą pocztaPIN false java.lang.Boolean



    Zestawienie

    Opis Element zawiera domyślną wartość pozycji środowiskowej aplikacji.

    Wysyłanie kodu PIN pocztą pocztaPIN false java.lang.Boolean



    Zestawienie

    Opis Element definiuje domyślny czas przedawnienia sesji dla wszystkich sesji utworzonych w aplikacji WWW. Dany czas przedawnienia musi być określony w pełnych minutach.

    60

    Zestawienie

    Opis Element określa połoŜenie wewnątrz aplikacji WWW pliku zawierającego mały (16 x 16 pikseli) obrazek ikony. Narzędzia przyjmują formaty przynajmniej GIF i JPEG.

    /obrazki/maly.gif /obrazki/duzy.gif

    Zestawienie

    Opis Element jest wykorzystywany w celu opisania biblioteki znaczników JSP.

    /WEB-INF/struts.tld /WEB-INF/struts.tld

    Zestawienie

    Opis Element zawiera umiejscowienie (jako zasobu względnego do katalogu macierzystego aplikacji WWW) pliku biblioteki znaczników (TLD).

    /WEB-INF/struts.tld /WEB-INF/struts.tld

    Zestawienie

    Opis Element opisuje URI względny do połoŜenia dokumentu web.xml, który identyfikuje bibliotekę znaczników wykorzystaną w aplikacji WWW.

    /WEB-INF/struts.tld

    /WEB-INF/struts.tld

    Zestawienie

    Opis Element określa sposób komunikacji pomiędzy klientem i serwerem jako NONE, INTEGRAL lub CONFIDENTIAL. NONE oznacza, Ŝe aplikacja nie potrzebuje Ŝadnych gwarancji transportu. Wartość INTEGRAL oznacza, Ŝe dane przesyłane pomiędzy klientem i serwerem powinny być wysyłane w ten sposób, aby nie mogły zostać zmienione podczas transportu. CONFIDENTIAL oznacza, Ŝe aplikacja wymaga przesyłania danych w ten sposób, aby zawartość transmisji nie mogła zostać zaobserwowana przez Ŝaden inny program lub egzemplarz programu. W większości przypadków obecność znacznika INTEGRAL lub CONFIDENTIAL oznacza konieczność wykorzystania SSL.

    CONFIDENTIAL

    Zestawienie

    Opis Element zawiera wzór URL-a będącego odwzorowaniem serwletu. Wzór ten musi być zgodny z zasadami wymienionymi w części 10 specyfikacji Servlet API, wyjaśnionymi w rozdziale 2, „Podstawy serwletów HTTP”.

    witaj /witaj.html

    Zestawienie

    Opis Element jest wykorzystywany w celu wskazania sposobu ochrony danych przesyłanych pomiędzy klientem i kontenerem.

    ...



    CONFIDENTIAL



    Zestawienie

    Opis Element jest podstawowym elementem deskryptora aplikacji WWW.



    witaj WitajSwiecie



    Zestawienie

    Opis Element jest wykorzystywany w celu zidentyfikowania podzbioru zasobów i metod HTTP tych zasobów, do których odnoszą się ograniczenia dostępu. JeŜeli nie zostały określone Ŝadne metody HTTP, ograniczenia dostępu odnoszą się do wszystkich metod HTTP.

    TajnaOchrona /servlet/SerwerPlac

    /servlet/sekret GET POST



    Zestawienie

    Opis określa nazwę zbioru zasobów WWW.

    TajnaOchrona /servlet/SerwerPlac /servlet/sekret GET POST

    Zestawienie

    Opis Element zawiera nazwę pliku, który powinien zostać wykorzystany jako domyślny plik powitalny.

    indeks.html indeks.htm

    Zestawienie

    Opis określa listę plików, które powinien wyszukać kontenener, kiedy przeglądarka zaŜąda katalogu, a nie strony WWW lub serwletu.

    indeks.html indeks.htm

    Dodatek D.

    Kody stanu HTTP Kody stanu HTTP są pogrupowane w sposób przedstawiony w tabeli D.1. Tabela D.1. Grupy kodów stanu HTTP Zakres kodów

    Znaczenie odpowiedzi

    100-199

    Informacyjne

    200-299

    śądanie klienta pomyślne

    300-399

    śądanie klienta przekierowane, konieczne następne działanie

    400-499

    śądanie klienta niekompletne

    500-599

    Błąd serwera

    Tabela D.2 wylicza stałe kodów stanu zdefiniowane w interfejsie HttpServletResponse i wykorzystywane jako parametry metod setStatus() i sendError(). Numer wersji w ostatniej kolumnie odnosi się do wersji protokołu HTTP, która pierwsza zdefiniowała dany kod stanu. Servlet API 2.0 dodał stałe dla kodów stanu HTTP w wersji 1.1, jak opisano w proponowanym standardzie RFC 2068. Servlet API 2.2 dodał kody stanu 416 i 417, jak opisano w próbnym standardzie RFC 2616. Proszę zauwaŜyć, Ŝe kody stanu HTTP/1.1 wymagają przeglądarki zgodnej z HTTP/1.1. Większa ilość informacji na temat HTTP jest dostępna w ksiąŜce „Web Client Programming” autorstwa Clintona Wonga (O'Reilly). Najnowsza specyfikacja HTTP/1.1 jest dostępna w dokumencie RFC 2616 pod adresem http://www.ietf.org/rfc/rfc2616.txt. Tabela D.2. Stałe kodów stanu HTTP Stała

    Kod

    Domyślna wiadomość

    Znaczenie

    Wersja HTTP

    SC_CONTINUE

    100

    Continue

    Serwer otrzymał początkową część Ŝądania, klient moŜe kontynuować z dalszymi częściami.

    1.1

    SC_SWITCHING_PROTOCOLS

    101

    Switching Protocols

    Serwer chce wypełnić Ŝądanie klienta zmiany protokołu na określony w nagłówku Ŝądania Upgrade.

    1.1

    Działanie to moŜe zawierać przełączenie na nowszą wersję HTTP lub własny synchroniczny kanał wideo. SC_OK.

    201

    OK

    śądanie klienta zakończyło się 1.0 sukcesem i odpowiedź serwera zawiera Ŝądane dane. Jest to domyślny kod stanu.

    SC_CREATED

    201

    Created

    Na serwerze został utworzony zasób, 1.0 przypuszczalnie w odpowiedzi na Ŝądanie klienta. Główna część odpowiedzi powinna zawierać URL (e), pod którym moŜna ten nowy zasób odnaleźć, z najbardziej specyficznym URL-em zawartym w nagłówku Location. JeŜeli zasób nie moŜe zostać utworzony natychmiast, powinien zamienne zostać zwrócony kod stanu SC_ACCEPTED.

    SC_ACCEPTED

    202

    Accepted

    śądanie zostało przyjęte do przetwarzania, ale nie zostało jeszcze ukończone. Serwer powinien opisać aktualny stan Ŝądania w głównej części odpowiedzi. Serwer nie jest zobligowany do działania na ani kończenia wykonywania Ŝądania.

    NonAuthoritative Information

    Nagłówki odpowiedzi HTTP nadeszły 1.1 z lokalnego lub niezaleŜnego źródła, a nie z oryginalnego serwera. Zwykłe serwlety nie mają powodów, by wykorzystywać ten kod stanu śądanie powiodło się, ale nie istnieje główna część nowej odpowiedzi. Przeglądarki przyjmujące ten kod powinny zachować swój aktualny widok dokumentów. Kod ten jest przydatny serwletowi, kiedy otrzymuje on dane z formularza, ale chce, aby przeglądarka zatrzymała się na formularzu, w ten sposób unikając komunikatu o błędzie „Dokument nie zawiera Ŝadnych danych”.

    SC_NON_AUTHORITATIVE_INF 203 ORMATION

    1.0

    SC_NO_CONTENT

    204

    No Content

    1.0

    SC_RESET_CONTENT

    205

    Reset Content śądanie powiodło się i przeglądarka powinno wyczyścić (ponownie pobrać) aktualnie przeglądany dokument. Kod ten jest przydatny serwletowi, który pobiera dane z formularza i chce, aby został on wyświetlony w czystej formie.

    1.1

    SC_PARTIAL_CONTENT

    206

    Partial Content

    Serwer ukończył częściowe Ŝądanie GET i zwrócił część dokumentu określoną w nagłówku Range klienta.

    1.1

    SC_MULTIPLE_CHOICES

    300

    Multiple Choices

    śądany URL odnosi się do więcej niŜ jednego zasobu. Na przykład, URL moŜe odnosić się do dokumentu

    1.1

    przetłumaczonego na wiele języków. Główna część odpowiedzi powinna wyjaśniać klientowi opcje w formie odpowiedniej do typu zawartości Ŝądania. Serwer moŜe zasugerować wybór przy pomocy nagłówka Location. SC_MOVED_PERMANENTLY

    301

    Moved Permanently

    śądany zasób został na stałe przeniesiony do nowej lokacji. Przyszłe odwołania powinny wykorzystywać w Ŝądaniach nowy URL. Nowe umiejscowienie jest podane w nagłówku Location. Większość przeglądarek automatycznie przekierowuje do nowej lokacji.

    1.0

    SC_MOVED_TEMPORARILY

    302

    Moved Temporarily

    śądany zasób został czasowo przeniesiony do innej lokacji, ale przyszłe Ŝądania powinny dalej wykorzystywać oryginalny URI w celu uzyskania dostępu do zasobu. Nowe umiejscowienie jest podane w nagłówku Location. Większość przeglądarek automatycznie przekierowuje do nowej lokacji.

    1.0

    SC_SEE_OTHER

    303

    See Other

    śądany zasób przetworzył Ŝądanie, 1.1 ale klient powinien pobrać swoją odpowiedź poprzez wykonanie GET na URL-u określonym w nagłówku Location. Kod ten jest przydatny serwletowi, który chce otrzymywać dane POST, po czym przekierowywać klienta do innego zasobu w celu wygenerowania odpowiedzi.

    SC_NOT_MODIFIED

    304

    Not Modified śądany dokument nie został 1.0 zmieniony od daty wymienionej w nagłówku Ŝądania If-ModifiedSince. Zwykłe serwlety nie powinny być zmuszone do korzystania z tego kodu stanu. Zamiast tego implementują one getLastModified().

    SC_USE_PROXY

    305

    Use Proxy

    Dostęp do Ŝądanego zasobu musi być uzyskiwany poprzez serwer proxy podany w nagłówku Location.

    1.1

    SC_BAD_REQUEST

    400

    Bad Request

    Serwer nie mógł zrozumieć Ŝądania, prawdopodobnie z powodu błędu składni.

    1.0

    SC_UNAUTHORIZED

    401

    Unauthorized śądaniu brakuje właściwego uwierzytelnienia. Wykorzystywany w połączeniu z nagłówkami WWWAuthenticate i Authorization.

    SC_PAYMENT_REQUIRED

    402

    Payment

    1.0

    Zarezerwowany do przyszłego uŜytku. 1.1 Istnieją propozycje, by

    Required

    wykorzystywać ten kod w połączeniu z nagłówkiem Charge-To, ale nie stał się on jeszcze standardem w czasie oddawania niniejszej ksiąŜki do druku.

    SC_FORBIDDEN

    403

    Forbidden

    śądanie zostało zrozumiane, ale serwer nie chce go wypełnić. Serwer moŜe wyjaśnić powody swojego oporu w głównej części odpowiedzi.

    1.0

    SC_NOT_FOUND

    404

    Not Found

    śądany zasób nie mógł zostać odnaleziony, lub jest niedostępny.

    1.0

    SC_METHOD_NOT_ALLOWED

    405

    Method Not Allowed

    Metoda wykorzystywana przez klienta 1.1 nie jest obsługiwana w tym URL-u. Metody obsługiwane muszą zostać wymienione w nagłówku odpowiedzi Accept.

    SC_NOT_ACCEPTABLE

    406

    Not Acceptable

    śądany zasób istnieje, ale w formacie nie przyjmowanym przez klienta (jak wskazano w nagłówku (ach) Ŝądania Accept.

    SC_PROXY_AUTHENTICATION_ 407 REQUIRED

    Proxy Serwer proxy musi dokonać Authenticatio uwierzytelnienia, zanim umoŜliwi n Required przejście dalej. Wykorzystywany z nagłówkiem ProxyAuthenticate. Zwykłe serwlety nie powinny być zmuszone do korzystania z tego kodu stanu.

    1.1

    1.1

    SC_REQUEST_TIMEOUT

    408

    Request Timeout

    Klient nie dokończył swojego Ŝądania 1.1 w czasie, w którym serwer był skłonny go słuchać.

    SC_CONFLICT

    409

    Conflict

    śądanie nie mogło zostać wypełnione, 1.0 poniewaŜ nastąpił konflikt z innym Ŝądaniem lub konfiguracją serwera. Kod ten występuje najczęściej w przypadku Ŝądań HTTP PUT. W których plik jest poddawany kontroli oraz w przypadku konfliktów nowych wersji z poprzednimi. Serwer moŜe wysłać opis konfliktu w głównej części odpowiedzi

    SC_GONE

    410

    Gone

    Zasób nie jest juŜ dostępny na danym serwerze, a Ŝaden alternatywny adres nie jest znany. Kod ten powinien być wykorzystywany jedynie w przypadku, kiedy zasób został trwale usunięty. Zwykłe serwlety nie powinny być zmuszone do korzystania z tego kodu stanu.

    1.1

    SC_LENGTH_REQUIRED

    411

    Length Required

    Serwer nie przyjmie Ŝądania bez nagłówka Content-Length.

    1.1

    SC_PRECONDITION_FAILED

    412

    Precondition Failed

    Wynik wstępnego warunku określonego w jednym lub więcej nagłówku If... wynosi false.

    1.1

    SC_REQUEST_ENTITY_TOO_LA 413 RGE

    Request Entity Too Large

    Serwer nie przetworzy Ŝądania, poniewaŜ zawartość Ŝądania jest zbyt duŜa. JeŜeli ograniczenie to jest tymczasowe, serwer moŜe dołączyć nagłówek Retry-After.

    1.1

    414

    Request-URI Too Long

    Serwer nie przetworzy Ŝądania, poniewaŜ URI Ŝądania jest dłuŜsze, niŜ moŜe przyjąć. MoŜe to nastąpić, kiedy klient przypadkowo przekonwertował Ŝądanie POST na GET. Zwykłe serwlety nie powinny być zmuszone do korzystania z tego kodu stanu.

    1.1

    SC_UNSUPPORTED_MEDIA_TYP 415 E

    Unsupported Media Type

    Serwer nie przetworzy Ŝądania, poniewaŜ jego główna część posiada format nieobsługiwany przez Ŝądany zasób.

    1.1

    SC_REQUESTED_RANGE_NOT_S 416 ATISFYABLE

    Requested Range Not Satisfiable

    Zakres zawartości Ŝądanej przez klienta poprzez nagłówek Range koliduje z wielkością Ŝądanego zasobu

    1.1 (RFC 2616)

    417

    Expectation Failed

    Oczekiwanie podane przez klienta poprzez nagłówek Expect nie mogło zostać spełnione.

    1.1 (RFC 2616)

    SC_INTERNAL_SERVER_ERROR 500

    Internal Server Error

    Wewnątrz serwera nastąpił 1.0 niespodziewany błąd, który przeszkodziła w wypełnieniu Ŝądania.

    SC_NOT_IMPLEMENTED

    501

    Not Implemented

    Serwer nie obsługuje funkcjonalności potrzebnej do wypełnienia Ŝądania.

    SC_BAD_GATEWAY

    502

    Bad Gateway Serwer działający jako brama lub proxy nie otrzymał prawidłowej odpowiedzi od głównego serwera.

    1.0

    SC_SERVICE_UNAVAILABLE

    503

    Service Unavailable

    Usługa (serwer) jest tymczasowo niedostępna, ale powinna zostać przywrócona w przyszłości. JeŜeli serwer wie, kiedy będzie ponownie dostępny, moŜe dołączyć nagłówek Retry-After.

    1.0

    SC_GATEWAY_TIMEOUT

    504

    Gateway Timeout

    Serwer działający jako brama lub proxy nie otrzymał prawidłowej odpowiedzi od głównego serwera w czasie oczekiwania.

    1.1

    HTTP Version Not Supported

    Serwer nie obsługuje wersji protokołu 1.1 HTTP wykorzystanej w Ŝądaniu. Główna część odpowiedzi powinna określać protokoły obsługiwane przez serwer. Zwykłe serwlety nie powinny być zmuszone do korzystania z tego kodu stanu.

    SC_REQUEST_URI_TOO_LONG

    SC_EXPECTATION_FAILED

    SC_HTTP_VERSION_NOT_SUPP 505 ORTED

    1.0

    Dodatek E.

    Encje znakowe PoniŜsza tablica wymienia róŜne kody ucieczkowe Unicode, encje nazwane i numeryczne HTML dla wszystkich moŜliwych do wyświetlenia znaków ISO-8859 (Latin-1). Encje nazwane i numeryczne mogą zostać wykorzystane na stronach HTML; są one konwertowane na symbole przez przeglądarki WWW. Kody ucieczkowe Unicode mogą zostać wykorzystane w kodzie serwletów; są one interpretowane przez kompilator Javy. Na przykład, znak funta (£) moŜe zostać osadzony na stronie HTML jako £ lub £. MoŜe równieŜ zostać osadzony bezpośrednio w kodzie Javy jako \u00A3. Proszę zauwaŜyć, Ŝe nie kaŜdy znak HTML jest uniwersalnie obsługiwany. Kolumna Obsługa pokazuje poziom obsługi znaku. Wartość S oznacza, Ŝe numeryczne i nazwane wartości encji dla danego symbolu są częścią standardu HTML. P wskazuje, Ŝe wartości encji są proponowanym standardem — nie są częścią standardu HTML, ale większości przypadków są powszechnie obsługiwane. N w tej kolumnie oznacza, Ŝe wartości encji nie są standardem i w związku z tym ich obsługa jest ograniczona. W przypadku tych symboli najlepiej jest zastosować kody ucieczkowe Unicode.

    Kod ucieczkowy Unicode

    Encja numeryczna

    Encja nazwana

    Symbol

    Opis

    Obsługa

    \u0009



    \t

    Tabulator poziomy

    S

    \u000A



    \n

    Koniec linii

    S

    \u000D



    \r

    Powrót karetki

    S

    \u0020



    Spacja

    S

    \u0021

    !

    !

    Wykrzyknik

    S

    \u0022

    "

    "

    Cudzysłów

    S

    \u0023

    #

    #

    Płotek

    S

    \u0024

    $

    $

    Znak dolara

    S

    \u0025

    %

    %

    Znak procent

    S

    \u0026

    &

    &

    Znak łączący

    S

    \u0027

    '

    '

    Apostrof

    S

    "

    &

    \u0028

    (

    (

    Lewy nawias

    S

    \u0029

    )

    )

    Prawy nawias

    S

    \u002A

    *

    *

    Gwiazdka

    S

    \u002B

    +

    +

    Znak dodawania

    S

    \u002C

    ,

    ,

    Przecinek

    S

    \u002D

    -

    -

    Myślnik

    S

    \u002E

    .

    .

    Kropka

    S

    \u002F

    /

    /

    Ukośnik

    S

    \u0030-

    0-

    0-9

    Cyfry 0-9

    S

    \u0039

    9

    \u003A

    :

    :

    Dwukropek

    S

    \u003B

    ;

    ;

    Średnik

    S

    \u003C




    Znak większości

    S

    \u003F

    ?

    ?

    Znak zapytania

    S

    \u0040

    @

    @

    „Małpa”

    S

    \u0041-

    A-

    A-Z

    Litery A-Z

    S

    \u005A

    Z

    \u005B

    [

    [

    Lewy nawias kwadratowy

    S

    \u005C

    \

    \

    Lewy ukośnik

    S

    \u005D

    ]

    ]

    Prawy nawias kwadratowy

    S

    \u005E

    ^

    ^

    Karetka

    S

    \u005F

    _

    _

    Kreska dolna

    S

    \u0060

    `

    `

    Akcent grave

    S

    \u0061-

    a-

    a-z

    Litery a-z

    S

    \u007A

    z

    \u007B

    {

    {

    Lewy nawias klamrowy

    S

    \u007C

    |

    |

    Kreska pionowa

    S

    \u007D

    }

    }

    Prawy nawias klamrowy

    S

    \u007E

    ~

    ~

    Tylda

    S

    \u0082





    Dolny lewy nawias pojedynczy N

    \u0083

    ƒ

    f

    Floren

    N

    \u0084





    Lewy dolny nawias podwójny

    N

    \u0085





    Trzykropek

    N

    \u0086





    Sztylet

    N

    \u0087





    Podwójny sztylet

    N

    \u0088

    ˆ

    ˆ

    circumflex

    N

    \u0089





    Promil

    N




    \u008A

    Š

    Š

    DuŜe S, caron

    N

    \u008B





    Znak mniejszości

    N

    \u008C

    Œ

    Œ

    DuŜe OE, ligatura

    N

    \u0091





    Lewy pojedynczy cudzysłów

    N

    \u0092





    Prawy pojedynczy cudzysłów

    N

    \u0093





    Lewy podwójny cudzysłów

    N

    \u0094





    Prawy podwójny cudzysłów

    N

    \u0095





    Pocisk

    N

    \u0096





    Krótki myślnik

    N

    \u0097





    Długi myślnik

    N

    \u0098

    ˜

    ~

    Tylda

    N

    \u0099





    Znak towarowy

    N

    \u009A

    š

    š

    Małe s, caron

    N

    \u009B





    Znak większości

    N

    \u009C

    œ

    œ

    Małe oe, ligatura

    N

    \u009F

    Ÿ

    Ÿ

    DuŜe Y, umlaut

    N

    \u00A0

     

     

    Spacja niełamiąca

    P

    \u00A1

    ¡

    ¡

    ¡

    Odwrócony wykrzyknik

    P

    \u00A2

    ¢

    ¢

    ¢

    Znak centa

    P

    \u00A3

    £

    £

    £

    Znak funta

    P

    \u00A4

    ¤

    ¤

    ¤

    Ogólny znak waluty

    P

    \u00A5

    ¥

    ¥

    ¥

    Znak jena

    P

    \u00A6

    ¦

    ¦

    ¦

    Złamana pionowa kreska

    P

    \u00A7

    §

    §

    §

    Paragraf

    P

    \u00A8

    ¨

    ¨

    ¨

    Umlaut

    P

    \u00A9

    ©

    ©

    ©

    Prawa autorskie

    P

    \u00AA

    ª

    ª

    ª

    śeński liczebnik porządkowy

    P

    \u00AB

    «

    «

    «

    Lewy cudzysłów kątowy

    P

    \u00AC

    ¬

    ¬

    ¬

    Znak zaprzeczenia

    P

    \u00AD

    ­

    ­

    -

    „Miękki” myślnik

    P

    \u00AE

    ®

    ®

    ®

    Zarejestrowany znak towarowy P

    \u00AF

    ¯

    ¯

    ¯

    Akcent macron

    P

    \u00B0

    °

    °

    °

    Znak stopnia

    P

    \u00B1

    ±

    ±

    ±

    Plus lub minus

    P

    \u00B2

    ²

    ²

    ²

    Indeks górny 2

    P

    \u00B3

    ³

    ³

    ³

    Indeks górny 3

    P

    \u00B4

    ´

    ´

    ´

    Akcent acute

    P

    \u00B5

    µ

    µ

    µ

    Znak mikro (greckie mi)

    P

    \u00B6







    Znak akapitu

    P

    \u00B7

    ·

    ·

    ·

    Kropka centralna

    P

    \u00B8

    ¸

    ¸

    ¸

    Cedilla

    P

    \u00B9

    ¹

    ¹

    ¹

    Indeks górny 1

    P

    \u00BA

    º

    º

    º

    Męski liczebnik porządkowy

    P

    \u00BB

    »

    »

    »

    Prawy cudzysłów kątowy

    P

    \u00BC

    ¼

    ¼

    ¼

    Ułamek jedna czwarta

    P

    \u00BD

    ½

    ½

    ½

    Ułamek jedna druga

    P

    \u00BE

    ¾

    ¾

    ¾

    Ułamek trzy czwarte

    P

    \u00BF

    ¿

    ¿

    ¿

    Odwrócony znak zapytania

    P

    \u00C0

    À

    À

    À

    DuŜe A, akcent grave

    S

    \u00C1

    Á

    Á

    Á

    DuŜe A, akcent acute

    S

    \u00C2

    Â

    Â

    Â

    DuŜe A, akcent circumflex

    S

    \u00C3

    Ã

    Ã

    Ă

    DuŜe A, tylda

    S

    \u00C4

    Ä

    Ä

    Ä

    DuŜe A, umlaut

    S

    \u00C5

    Å

    Å

    Å

    DuŜe A, okrąg

    S

    \u00C6

    Æ

    &Aelig;

    Æ

    DuŜe A, ligatura

    S

    \u00C7

    Ç

    Ç

    Ç

    DuŜe C, cedilla

    S

    \u00C8

    È

    È

    È

    DuŜe E, akcent grave

    S

    \u00C9

    É

    É

    É

    DuŜe E, akcent acute

    S

    \u00CA

    Ê

    Ê

    Ê

    DuŜe E, akcent circumflex

    S

    \u00CB

    Ë

    Ë

    Ë

    DuŜe E, umlaut

    S

    \u00CC

    Ì

    Ì

    Ì

    DuŜe I, akcent grave

    S

    \u00CD

    Í

    Í

    Í

    DuŜe I, akcent acute

    S

    \u00CE

    Î

    Î

    Î

    DuŜe I, akcent circumflex

    S

    \u00CF

    Ï

    Ï

    Ï

    DuŜe I, umlaut

    S

    \u00D0

    Ð

    Ð

    Ð

    DuŜe eth, islandzki

    S

    \u00D1

    Ñ

    Ñ

    Ñ

    DuŜe N, tylda

    S

    \u00D2

    Ò

    Ò

    Ò

    DuŜe O, akcent grave

    S

    \u00D3

    Ó

    Ó

    Ó

    DuŜe O, akcent acute

    S

    \u00D4

    Ô

    Ô

    Ô

    DuŜe O, akcent circumflex

    S

    \u00D5

    Õ

    Õ

    Õ

    DuŜe O, tylda

    S

    \u00D6

    Ö

    Ö

    Ö

    DuŜe O, umlaut

    S

    \u00D7

    ×

    ×

    ×

    Znak mnoŜenia

    P

    \u00D8

    Ø

    Ø

    Ø

    DuŜe O, ukośnik

    S

    \u00D9

    Ù

    Ù

    Ù

    DuŜe U, akcent grave

    S

    \u00DA

    Ú

    Ú

    Ú

    DuŜe U, akcent acute

    S

    \u00DB

    Û

    Û

    Û

    DuŜe U, akcent circumflex

    S

    \u00DC

    Ü

    Ü

    Ü

    DuŜe U, umlaut

    S

    \u00DD

    Ý

    Ý

    Ý

    DuŜe Y, akcent acute

    S

    \u00DE

    Þ

    Þ

    Þ

    DuŜe thorn, islandzki

    S

    \u00DF

    ß

    ß

    ß

    Małe sz, ligatura, niemiecki

    S

    \u00E0

    à

    à

    à

    Małe a, akcent grave

    S

    \u00E1

    á

    á

    á

    Małe a, akcent acute

    S

    \u00E2

    â

    â

    â

    Małe a, akcent circumflex

    S

    \u00E3

    ã

    ã

    ã

    Małe a, tylda

    S

    \u00E4

    ä

    ä

    ä

    Małe a, umlaut

    S

    \u00E5

    å

    å

    å

    Małe a, okrąg

    S

    \u00E6

    æ

    æ

    æ

    Małe a, ligatura

    S

    \u00E7

    ç

    ç

    ç

    Małe c, cedilla

    S

    \u00E8

    è

    è

    è

    Małe e, akcent grave

    S

    \u00E9

    é

    é

    é

    Małe e, akcent acute

    S

    \u00EA

    ê

    ê

    ê

    Małe e, akcent circumflex

    S

    \u00EB

    ë

    ë

    ë

    Małe e, umlaut

    S

    \u00EC

    ì

    ì

    ì

    Małe i, akcent grave

    S

    \u00ED

    í

    í

    í

    Małe i, akcent acute

    S

    \u00EE

    î

    î

    î

    Małe i, akcent circumflex

    S

    \u00EF

    ï

    ï

    ï

    Małe i, umlaut

    S

    \u00F0

    ð

    ð

    ð

    Małe eth, islandzki

    S

    \u00F1

    ñ

    ñ

    ñ

    Małe n, tylda

    S

    \u00F2

    ò

    ò

    ò

    Małe o, akcent grave

    S

    \u00F3

    ó

    ó

    ó

    Małe o, akcent acute

    S

    \u00F4

    ô

    ô

    ô

    Małe o, akcent circumflex

    S

    \u00F5

    õ

    õ

    õ

    Małe o, tylda

    S

    \u00F6

    ö

    ö

    ö

    Małe o, umlaut

    S

    \u00F7

    ÷

    ÷

    ÷

    Znak dzielenia

    P

    \u00F8

    ø

    ø

    ø

    Małe o, ukośnik

    S

    \u00F9

    ù

    ù

    ù

    Małe u, akcent grave

    S

    \u00FA

    ú

    ú

    ú

    Małe u, akcent acute

    S

    \u00FB

    û

    û

    û

    Małe u, akcent circumflex

    S

    \u00FC

    ü

    ü

    ü

    Małe u, umlaut

    S

    \u00FD

    ý

    ý

    ý

    Małe y, akcent acute

    S-

    \u00FE

    þ

    þ

    þ

    Małe thorn, islandzki

    S

    \u00FF

    ÿ

    ÿ

    ÿ

    Małe y, umlaut

    S

    Dodatek F.

    Kodowania PoniŜsza tabela zawiera sugerowane kodowania dla duŜej ilości języków. Kodowania są wykorzystywane przez serwlety generujące informacje w wielu językach; określają one, które kodowanie znaków powinien wykorzystać PrintWriter serwletów. Domyślnie PrintWriter wykorzystuje kodowanie ISO-8859-1 (Latin-1), właściwe dla większości języków zachodnioeuropejskich. Aby określić alternatywne kodowanie, wartość kodowania musi zostać przekazana metodzie setContentType() zanim serwlet pobierze swój PrintWriter, na przykład: odp.setContentType("text/html; charset=Shift_JIS"); // Kodowanie japońskie PrintWriter wyj = odp.getWriter; // Zapisuje japoński Shift_JIS

    Kodowanie moŜe być równieŜ ustawione pośrednio, przy pomocy metody setLocale(), na przykład: odp.setContentType("text/html"); odp.setLocale(new Locale("ja", "")); // Ustawia kodowanie na Shift_JIS PrintWriter wyj = odp.getWriter; // Zapisuje japoński Shift_JIS

    Metoda setLocale() przypisuje odpowiedzi kodowanie zgodnie z poniŜszą tabelą. W przypadku, gdy moŜliwe jest więcej niŜ jedno kodowanie, wybierane jest kodowanie umieszczone w tabeli na pierwszej pozycji. Proszę zauwaŜyć, Ŝe nie wszystkie przeglądarki WWW obsługują wszystkie kodowania, lub posiadają czcionki, dzięki którym istnieje moŜliwość wyświetlania wszystkich znaków, chociaŜ wszystkie klienty obsługują przynajmniej ISO-8859-1. Proszę takŜe pamiętać, Ŝe kodowanie UTF-8 moŜe reprezentować wszystkie znaki Unicode, a w związku z tym moŜe być uznane za właściwe dla wszystkich języków. Język

    Kod języka

    Sugerowane kodowania

    angielski

    en

    ISO-8859-1

    Albański

    sq

    ISO-8859-2

    Arabski

    ar

    ISO-8859-6

    białoruski

    be

    ISO-8859-5

    Bułgarski

    bg

    ISO-8859-5

    chiński (tradycyjny / Tajwan)

    zh (kraj TW)

    Big5

    chiński (uproszczony / kontynentalny

    zh

    GB2312

    Chorwacki

    hr

    ISO-8859-2

    czeski

    cs

    ISO-8859-2

    duński

    da

    ISO-8859-1

    holenderski

    nl

    ISO-8859-1

    estoński

    et

    ISO-8859-1

    fiński

    fi

    ISO-8859-1

    francuski

    fr

    ISO-8859-1

    grecki

    el

    ISO-8859-7

    hebrajski

    he (dawniej iw)

    ISO-8859-8

    hiszpański

    es

    ISO-8859-1

    islandzki

    is

    ISO-8859-1

    japoński

    ja

    Shift_JIS, ISO-2022-JP, EUC-JP1

    kataloński (hiszpański)

    ca

    ISO-8859-1

    koreański

    ko

    EUC-KR2

    litewski

    lt

    ISO-8859-2

    łotewski

    lv

    ISO-8859-2

    macedoński

    mk

    ISO-8859-5

    niemiecki

    de

    ISO-8859-1

    polski

    pl

    ISO-8859-2

    portugalski

    pt

    ISO-8859-1

    rosyjski

    ru

    ISO-8859-5, KOI8-R

    rumuński

    ro

    ISO-8859-2

    serbski

    sr

    ISO-8859-5, KOI8-R

    serbsko-chorwacki

    sh

    ISO-8859-5, ISO-8859-2, KOI8-R

    słowacki

    sk

    ISO-8859-2

    słoweński

    sl

    ISO-8859-2

    szwedzki

    sv

    ISO-8859-1

    turecki

    tr

    ISO-8859-9

    ukraiński

    uk

    ISO-8859-5, KOI8-R

    węgierski

    hu

    ISO-8859-2

    włoski

    it

    ISO-8859-1

    1

    Obsługiwany po raz pierwszy w JDK 1.1.6. Poprzednie wersje JDK znają zestaw znaków EUC-JP pod nazwą EUCJIS, tak więc w celu zapewnienia przenośności moŜna ustawić kodowanie na EUC_JP i samodzielnie skonstruować PrintWriter EUCJIS. 2 Obsługiwany po raz pierwszy w JDK 1.1.6. Poprzednie wersje JDK znają zestaw znaków EUC-KR pod nazwą KSC_5601, tak więc w celu zapewnienia przenośności moŜna ustawić kodowanie na EUC_KR i samodzielnie skonstruować PrintWriter KSC_5601.