158 104 6MB
Polish Pages 594
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: •
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.
1 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 IfModified-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
*
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.
„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.
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 i wykorzystującego metody isRequestedSessionIdFromCookie() 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("
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 |
| |||||
Strona główna Hosting Mechanizmy
|