JAVA - kurs (cz.2)

 

JAVA  -  kurs  (cz.2)


SPIS TEMATÓW


W części pierwszej czytaliście

1. Język Java
  1.1. Elementarny program: tekst źródłowy, kompilacja, interpretacja
  1.2. Klasy: definicja, dziedziczenie, tworzenie obiektów
  1.3. Interfejsy
  1.4. Pliki źródłowe i pakiety
  1.5. Polimorfizm
  1.6. Obsługa wyjątków
  1.7. Zarządzanie pamięcią
  1.8. Współbieżność
  1.8.1 Synchronizacja wątków
  1.9. Obiekty sieciowe


Druga część kursu

2. Aplety - programy Javy na stronach WWW
3. Standardowe klasy Javy
4. Servlety - programy Javy na serwerze WWW
5. Podsumowanie
6. Programy - ćwiczenia


2. Aplety - programy Javy na stronach WWW

Aplet jest niewielkim programem Javy przeznaczonym do uruchamiania w obrębie innej aplikacji - przeglądarki WWW lub Java Applet Viewer. Najprostszy aplet drukujący jedno zdanie na ekranie może mieć następującą postać:

 HelloWorld.java

 import java.applet.*;
 import java.awt.*;

 public class HelloWorld extends Applet {
     public void init() {
        add(new Label("Hello World!"));
     }
 }

 Podobnie jak aplikację, kompilujemy aplet poleceniem:

     javac HelloWorld.java

 w wyniku czego otrzymamy plik ze skompilowaną klasą o nazwie HelloWorld.class.
 Następnie tworzymy prostą stronę HTML zawierającą TAG <applet> wywołujący aplet Java i otwieramy tę stronę przeglądarką WWW.

 HelloWorld.html

 <html>
 <head>
 <title>HelloWorld</title>
 </head>
 <body>
 <h1>Aplet HelloWorld</h1>
 <applet code=HelloWorld.class width=200 height=50>
 </applet>
 </body>
 </html>

 Wynik działania apletu możemy również obejrzeć używając przeglądarki apletów dostarczanej przez Suna razem z całym środowiskiem JDK:

    appletviewer HelloWorld.html


Każdy aplet tworzony jest jako podklasa klasy java.applet.Applet, dostarczającej interfejs do środowiska, w obrębie którego jest on uruchamiany i znajdującej się na dole następującej hierarchii standardowych klas Javy:

 java.lang.Object
    |
    +----java.awt.Component
            |
            +----java.awt.Container
                    |
                    +----java.awt.Panel
                            |
                            +----java.applet.Applet

 W cyklu życia apletu występują cztery istotne zdarzenia. Gdy one następują, wywoływane są odpowiednie metody klasy Applet, które mogą być przesłonięte przez metody zdefiniowane w jej podklasie, jak w poniższym przykładzie:

 public class MyApplet extends Applet {
 . . .
 public void init() { . . . }
 public void start() { . . . }
 public void stop() { . . . }
 public void destroy() { . . . }
 . . .
 }

 Metody te są wywoływane przez środowisko, w którym uruchamiany jest aplet, w momentach wystąpienia następujących zdarzeń:
 init - po załadowaniu apletu (lub jego przeładowaniu) w celu jego zainicjowania,
 start - w momencie uruchamiania apletu, po jego załadowaniu lub po ponownym odwiedzeniu strony zawierającej aplet,
 stop - w momencie zatrzymywania pracy apletu, gdy opuszczana jest strona lub następuje wyjście z przeglądarki,
 destroy - przed wyjściem z przeglądarki.

Aplet nie musi przesłaniać wszystkich z tych metod, może tylko niektóre albo żadnej. W metodzie init powinno się zamieszczać kod, który normalnie powinien być zawarty w konstruktorze klasy. Jednak w momencie wykonywania konstruktora klasy apletu nie ma gwarancji, że jest już zdefiniowane całe jego środowisko. Dlatego takie zadania jak na przykład jednokrotne załadowanie obrazów wykorzystywanych przez aplet powinny być zawarte właśnie w metodzie init. W metodach start i stop można na przykład odpowiednio uruchamiać i zatrzymywać animację tak, żeby w czasie gdy użytkownik nie ogląda strony z apletem niepotrzebnie nie zużywać zasobów komputera.

 Aplet dziedziczy metody interfejsu użytkownika z nadrzędnych klas AWT (Abstract Window Toolkit) Component, Container i Panel.
 Z klasy Component dziedziczy metody paint i update, które odpowiadają za graficzną reprezentację apletu na stronie przeglądarki. Metody te aplet może przesłonić:

 class MyApplet extends Applet {
 . . .
 public void paint(Graphics g) { . . . }
 . . .
 }

 Z klasy Component aplet dziedziczy również metody obsługi zdarzeń, zarówno dotyczące konkretnych wydarzeń, takie jak action czy mouseDown, jak i ogólną metodę handleEvent przechwytującą wszystkie zdarzenia.
 Aplet jest podklasą klasy Container, może więc zawierać inne obiekty klasy Component, takie jak klawisze, etykiety, listy wyboru itd. Jak w innych obiektach klasy Container wzajemne rozłożenie komponentów kontrolowane jest poprzez klasę LayoutManager.
 Aplety są uruchamiane w środowisku przeglądarki, która narzuca im pewne ograniczenia związane z zachowaniem bezpieczeństwa. Różnią się one nieco pomiędzy różnymi przeglądarkami. Aplet ściągnięty do przeglądarki poprzez sieć:

  • nie może czytać i pisać do plików znajdujących się na komputerze, który go wykonuje,

  • nie może tworzyć połączeń sieciowych do komputerów innych niż ten, z którego został ściągnięty,

  • nie może uruchamiać żadnych programów na komputerze, który go wykonuje,

  • może czytać tylko wybrane parametry systemowe,

  • nie może ładować bibliotek ani definiować metod w kodzie maszynowym.

 Ograniczeniem (choć nie związanym z bezpieczeństwem) jest również graficzny interfejs użytkownika apletu. Aplet może przedstawiać swoją reprezentację graficzną tylko w obrębie prostokąta na stronie WWW o z góry zadanych wymiarach, bądź w postaci generowanych okienek, które różnią się od tych generowanych przez aplikacje.

 Pliki składające się na aplet: klasy, pliki z grafikami, dźwiękami i inne pliki pomocnicze mogą być połączone w jeden plik o formacie Java Archive (JAR), co pozwala uzyskać wiele korzyści:

  • bezpieczeństwo - zawartość pliku JAR można podpisać cyfrowo; dzięki temu mogą być złagodzone niektóre z wcześniej wymienionych ograniczeń związane z dostępem do lokalnych zasobów dyskowych oraz z pełnym dostępem do sieci,

  • skrócenie czasu ładowania - cały aplet może ściągnięty przez przeglądarkę w jednej transakcji HTTP bez konieczności otwierania nowego połączenia dla każdego pliku,

  • kompresja - pliki są kompresowane zgodnie z formatem ZIP.

Do obsługi plików JAR służy standardowe narzędzie jar zawarte w pakiecie JDK. Sposób jego użycia jest analogiczny do programu tar z systemu Unix.
 

Operacja

Polecenie

Tworzenie pliku JAR

jar cf jar-file input-file(s)

Oglądanie zawartości pliku JAR

jar tf jar-file

Rozpakowywanie pliku JAR

jar xf jar-file

Uruchamianie apletu spakowanego w postaci pliku JAR

<applet   code=AppletClassName.class   archive="JarFileName.jar"   width=width height=height></applet>

Uwaga. Internet Explorer używa własnego standardu kompresji - CAB. Netscape Communicator obsługuje format JAR..

Tag <applet> na stronie HTML może więcej parametrów niż podane wcześniej w prostym przykładzie. Bardziej złożone wywołanie może mieć następującą postać:

<applet code=AppletSubclass.class codebase="directory/" width=anInt height=anInt align=left>
<param name=parameter1Name value=aValue>
<param name=parameter2Name value=anotherValue>
Wymagana jest przeglądarka obsługująca aplety Javy!
</applet>

Domyślnie przeglądarka szuka klas apletu oraz plików skompresowanych w tym samym katalogu, z którego został ściągnięty plik HTML zawierający tag <applet>. Można jednak wskazać inne miejsce podając parametr codebase. Wartością parametru może być ścieżka względna wobec strony HTML, ścieżka bezwzględna lub w ogólności dowolny URL. Klasy apletu mogą więc być ściągane z innego serwera niż strona HTML. Opcje width i height określają rozmiary prostokąta na stronie przeglądarki, w obrębie którego wizualizowany jest aplet. Opcja align określa położenie apletu, podobnie jak dla tagu <img>: left, right, top, texttop, middle, absmiddle, baseline, bottom, absbottom. Do apletu można przekazywać parametry definiując tagi <param> w obrębie tagu <applet>. Wartości tych parametrów można następnie odczytywać w kodzie apletu wywołując metodę klasy Applet
public String getParameter(String name)

Opcjonalny tekst w obrębie tagu <applet> jest pisany w okienku przeglądarki, gdy ta nie potrafi obsługiwać Javy lub obsługa została wyłączona.

 

3. Standardowe klasy Javy

Nazwy standardowych pakietów Javy rozpoczynają się od prefiksu  java. W skład JDK 1.1 wchodzą następujące pakiety: java.applet, java.awt, java.beans, java.io, java.lang, java.math, java.net, java.rmi, java.security, java.sql, java.text, java.util. Zostaną one omówione pokrótce, najpierw te najczęściej wykorzystywane.

W pakiecie java.lang zdefiniowana jest klasa Object, która jest klasą nadrzędną wobec wszystkich innych klas Javy.
Pakiet zawiera także klasy opakowujące (kopertowe) zmienne podstawowych typów języka Java takie jak Boolean, Byte, Integer, Long, Double, Character itd., definiując użyteczne metody operujące na zmiennych tych typów, metody konwersji pomiędzy typami, zamianę na łańcuchy znaków i inne.
Klasa Math zawiera metody wykonujące podstawowe operacje numeryczne takie jak funkcje eksponencjalne, logarytmiczne, trygonometryczne.

W pakiecie java.lang zawarte są dwie klasy obsługujące łańcuchy znaków: String i StringBuffer. Klasa String używana jest do przechowywania i wykonywania operacji na stałych łańcuchach; po utworzeniu obiektu tej klasy nie można zmienić jego wartości. Klasa ta zawiera metody do sprawdzania poszczególnych znaków, porównywania łańcuchów, wyodrębniania podłańcuchów, tworzenia kopii z zamianą na małe albo duże litery. Klasa StringBuffer implementuje łańcuchy znaków, które mogą być zmieniane. Podstawowe metody tej klasy to append dodająca znaki na końcu bufora i insert wstawiająca znaki w określonym miejscu. Każdy obiekt przydziela bufor na przechowywany łańcuch znaków. Jeżeli całkowita długość łańcucha wzrośnie powyżej rozmiaru bufora, automatycznie przydzielany jest większy.

Dostęp do zasobów systemowych można uzyskać poprzez niezależne od systemu API zdefiniowane w finalnej klasie System oraz zależne od systemu API zawarte w Runtime. Można uzyskać dostęp do parametrów systemowych, standardowych strumieni: wyjściowego, wejściowego i błędów, metod ładowania bibliotek, odczytu czasu komputera, szybkiego kopiowania tablic itd.
Klasa Thread definiuje wątki programu Javy pozwalające na jego współbieżną pracę.

Pakiet java.io definiuje klasy implementujące operacje wejścia-wyjścia. W pakiecie tym (jak również i w innych) występują klasy i metody pochodzące z JDK 1.0 równolegle z nowymi klasami wprowadzonymi wraz z wejściem JDK 1.1. Pozostawiono stare klasy w celu zapewnienia zgodności dla dawniej pisanych programów. Często przestarzałe (deprecated) konstrukcje  są odradzane i proponowane są ich udoskonalone odpowiedniki.

Podstawowymi klasami pozwalającymi czytać i pisać z plików, łańcuchów znaków i innych strumieni, są:
Reader wraz z podklasami BufferedReader, CharArrayReader, InputStreamReader, FileReader, StringReader oraz Writer wraz z podklasami BufferedWriter, CharArrayWriter, OutputStreamWriter, FileWriter, PrintWriter, StringWriter. Ich starsze odpowiedniki to InputStream i OutputStream wraz z ich podklasami.

Strumień wejściowy znaków może być dzielony na jednostki logiczne - tokeny, poprzez skonstruowanie na nim obiektu klasy StreamTokenizer. Można zdefiniować składnię, według której wyróżniane będą tokeny typu słowo, liczba, znaczniki końca linii i pliku oraz pomijane komentarze.
Zdefiniowane są również klasy wspierające obsługę struktury drzewa plików w systemie - File oraz czytanie i pisanie do plików o dostępie swobodnym - RandomAccessFile.

W pakiecie java.util można znaleźć m.in. szereg klas definiujących różne struktury danych przechowujące inne obiekty. Klasa Vector implementuje tablicę obiektów, która może rosnąć lub zmniejszać się w miarę jak obiekty są dodawane lub usuwane. Tak jak w zwykłej tablicy dostęp do jej elementów może odbywać się poprzez całkowity indeks, można również szukać wystąpienia obiektu w wektorze, którego wartość jest równa podanemu. Wszystkie elementy wektora najwygodniej jest przeglądać wykorzystując interfejs Enumeration:

   Vector v;
   for(Enumeration e = v.elements(); e.hasMoreElements() ;)
      System.out.println(e.nextElement());

Każdy wektor stara się optymalizować zarządzanie rozmiarem zajmowanej pamięci. Gdy wektor zajmuje całą przydzieloną pamięć, przed dodaniem kolejnego elementu jego rozmiar jest automatycznie zwiększany o wartość capacityIncrement. Program może jednak sam zwiększyć rozmiar wektora przed wstawieniem dużej porcji danych, aby uniknąć wielu realokacji. Podklasą klasy Vector jest Stack realizujący kolejkę LIFO obiektów z metodami push i pop.

Klasa Dictionary jest abstrakcyjnym rodzicem dowolnej klasy implementującej odwzorowanie  kluczy na wartości. Jej podklasą jest Hashtable, której konstrukor posiada dwa parametry initialCapacity i loadFactor. Gdy liczba elementów w tablicy mieszającej (hash table) osiąga wartość iloczynu tych parametrów, rozmiar tablicy jest automatycznie zwiększany i przeliczane są pozycje elementów. Większy współczynnik wypełnienia pozwala oszczędniej gospodarować pamięcią kosztem dłuższego czasu potrzebnego do wyszukiwania elementów. Efektywniej jest również zawczasu przydzielić odpowiedniej wielkości tablicę, niż potem zdać się na automatyczne przeładowywania. Poniżej przedstawiono przykład tablicy mieszającej obiektów typu Integer posiadających nazwy jako klucze:

   Hashtable numbers = new Hashtable();
   numbers.put("one", new Integer(1));
   numbers.put("two", new Integer(2));
   numbers.put("three", new Integer(3));

Aby wydobyć element z tablicy można posłużyć się następującym kodem:

   Integer n = (Integer)numbers.get("two");
   if(n != null)
      System.out.println("two = " + n);

Obiekty przechowywane w tablicy mieszającej muszą implementować metody hashCode i equals dziedziczone z klasy java.lang.Object.
Przy użyciu klasy BitSet można tworzyć zbiory bitów i wykonywać na nich operacje logiczne.
Klasa StringTokenizer pozwalająca dzielić łańcuchy znaków na tokeny jest znacznie prostsza w użyciu niż klasa java.io.StreamTokenizer. Określa się w niej tylko jakie znaki rozdzielają kolejne tokeny, domyślnie są to znaki z łańcucha " \t\n\r", na przykład:

   StringTokenizer st = new StringTokenizer("To jest tylko test");
   while (st.hasMoreTokens())
      System.out.println(st.nextToken());

Można również znaleźć klasy obsługujące daty - Date i Calendar, ustawiające parametry specyficzne dla kraju, regionu lub języka - Locale, TimeZone.
W pakiecie java.util.zip znajdują się klasy pozwalające tworzyć i czytać pliki skompresowane w formatach ZIP i GZIP.

Pakiet java.net zawiera klasy realizujące połączenia sieciowe zarówno na poziomie gniazd, jak i adresów URL wskazujących zasoby w WWW. Podstawowe klasy to Socket, URL, URLConection. Poniższy przykład pokazuje jak z apletu można w prosty sposób przejść do wybranej strony WWW:

try {
   URL task = new URL("http://www.task.gda.pl/");
   getAppletContext().showDocument(task);
} catch (MalformedURLException e) {}     // new URL() failed

Aplety i aplikacje Javy komunikują się z użytkownikiem wykorzystując klasy z pakietu java.awt składające się na graficzny interfejs użytkownika AWT (Abstract Window Toolkit). AWT dostarcza typowe komponenty graficzne takie, jak klawisze, pola do wprowadzania tekstu, listy wyboru itd. poprzez klasy Button, Checkbox, Choice, Label, List, Menu, Scrollbar, TextArea, TextField będące pochodnymi klasy Component. Wykorzystując klasę Canvas, można rysować dowolne obrazy graficzne na ekranie, a po dodaniu odpowiedniej obsługi zdarzeń można zdefiniować dowolny własny komponent.

Wraz z JDK 1.1 został wprowadzony nowy model obsługi zdarzeń, który jest znacznie bardziej elastyczny i wydajny w porównaniu z modelem z JDK 1.0. Stary model dla zachowania zgodności jest również obsługiwany, choć jego użycie jest odradzane. W modelu 1.1 AWT zdarzenia są generowane przez źródła, którymi mogą być komponenty interfejsu użytkownika, myszka, klawiatura itd. Może być wydelegowany jeden lub więcej odbiorców zdarzenia pochodzącego od określonego źródła, który jest obiektem dowolnej klasy implementującej przynajmniej jeden z interfejsów obsługi zdarzeń takich, jak ActionListener, KeyListener czy MouseListener. Zasadę działania tego modelu można prześledzić w poniższym przykładzie:

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class URLButton extends Applet implements ActionListener {
   public void init() {
      Button button = new Button("TASK Home");
      add(button);
      button.addActionListener(this);
   }
   public void actionPerformed(ActionEvent event) {
      . . .
   }
}

Zastosowanie klas Applet i AppletContext z pakietu java.applet było już demonstrowane we wcześniejszych przykładach. Definiują one środowisko, w którym uruchamiane są aplety. Pozwalają również na komunikację pomiędzy apletami znajdującymi się na tej samej stronie.

Środowisko budowania niezależnych od platformy, modyfikowalnych wizualnych komponentów JavaBeans API zawarte jest w pakiecie java.beans. Wykorzystując przeznaczone do tego narzędzia programistyczne, można wizualnie z komponentów konstruować aplikacje, aplety, servlety lub komponenty złożone. Narzędzie tego typu pozwala wybrać z zestawu potrzebny nam komponent, wstawić go do okienka programu, zmodyfikować jego wygląd i zachowanie, zdefiniować interakcję z innymi komponentami; wszystko to nie pisząc ani jednej linii kodu.

JDBC API (Java DataBase Conectivity) zdefiniowane w pakiecie java.sql wprowadza jednolity standard dostępu do dowolnych relacyjnych baz danych. Klasy z tego pakietu implementują połączenia z bazą danych, zapytania SQL, wyniki tych zapytań itp. Dostęp do bazy odbywa się za pośrednictwem drivera, który może być napisany całkowicie w Javie i wtedy może być np. ściągnięty jako część apletu, może być też napisany z wykorzystaniem kodu maszynowego określonej platformy, aby uzyskać dostęp do istniejących już bibliotek dostępu do baz danych. Drivery JDBC można podzielić na cztery kategorie:

  1. Pomost JDBC-ODBC, który zapewnia dostęp do bazy poprzez binarne drivery ODBC.

  2. Driver w Javie zamieniający odwołania JDBC na odwołania do binarnego drivera dostępowego konkretnej bazy danych znajdującego się na lokalnym komputerze.

  3. Całkowicie w Javie napisany driver komunikujący się poprzez sieć z oprogramowaniem pośredniczącym w dostępie do bazy (middleware). Protokół dostępowy zależy od producenta tego oprogramowania, producent ten jest też najczęściej dostawcą odpowiedniego drivera JDBC.

  4. Całkowicie w Javie napisany driver komunikujący się poprzez sieć bezpośrednio z serwerem bazy danych. Dostawcą drivera często jest producent bazy danych.

RMI (Remote Method Invocation) zawarty w java.rmi umożliwia tworzenie rozproszonych aplikacji w Javie. Aplikacja taka złożona jest z serwera, który tworzy obiekty posiadające metody mogące być wywoływane zdalnie, udostępnia odnośniki do tak zdefiniowanych obiektów i czeka na wywołania tych metod przez klientów; klient ściąga odnośniki do zdalnych obiektów i wywołuje ich metody. RMI zapewnia mechanizm, poprzez który odbywa się komunikacja pomiędzy serwerem i klientem oraz przesyłane są dane w obie strony.

W pakiecie java.math znajdują się klasy BigInteger i BigDecimal pozwalające na tworzenie i operacje na liczbach całkowitych dowolnej precyzji. BigInteger implementuje operacje arytmetyki modularnej, obliczanie największego wspólnego podzielnika, generator liczb pierwszych, operacje na bitach itd. Z liczb zdefiniowanych w tej klasie korzysta pakiet java.security wprowadzający jednolity model kryptografii i ochrony danych. Znajdują się tam abstrakcyjne klasy definiujące kody zapewniające integralność danych (message digests) oparte na jednokierunkowych funkcjach mieszających (one-way hash functions), podpisy cyfrowe oparte na parze kluczy jawnego i tajnego, zarządzanie kluczami i certyfikaty. Jest to tylko ramowy szkielet koncepcji kryptograficznych, pod który producenci oprogramowania mogą podłączać konkretne algorytmy i metody. Razem z JDK Sun dostarcza jedynie klasy do cyfrowego podpisywania dokumentów opartego na algorytmie DSA oraz obliczania kodów dokumentów metodami MD5 i SHA-1.

W pakiecie java.text znajdziemy klasy obsługujące różne formaty danych tekstowych, np. DateFormat obsługujący daty w różnych standardach czy NumberFormat tworzący i analizujący różne formaty liczb.

4. Servlety - programy Javy na serwerze WWW

Servlety są modułami, które są uruchamiane wewnątrz serwerów przetwarzających zapytania i generujących odpowiedzi, takich jak np. rozszerzone o obsługę Javy serwery WWW. Rozszerzają one funkcjonalność tych serwerów. Można w uproszczeniu powiedzieć, że servlety dla serwerów są tym, czym aplety dla przeglądarek.

Servlety stanowią alternatywę dla skryptów CGI, umożliwiając łatwą metodę dynamicznego tworzenia dokumentów HTML. Są one łatwiejsze do pisania dzięki wykorzystaniu środowiska Javy. Są również szybciej wykonywane, gdyż wywołanie servletu odbywa się nie poprzez uruchomienie nowego procesu, co jest kosztowne ze względu na czas procesora i zasoby pamięciowe, lecz jako wątek. Co więcej, kod wykonywalny dla servletu jest ładowany do serwera tylko raz, gdy po raz pierwszy żądana jest usługa oferowana przez dany servlet lub automatycznie, gdy zostanie zmieniony kod servleta. Potem servlet pozostaje w pamięci serwera i może równolegle obsługiwać wiele zapytań z możliwością komunikacji pomiędzy nimi.

Klasy implementujące funkcje servletów znajdują się w pakiecie javax.servlet dostępnego z firmy Sun jako Java Servlet Development Kit. Zawierają one abstrakcyjną klasę GenericServlet oraz interfejs Servlet, które definiują podstawowe własności ogólnych servletów, czyli modułów przetwarzających zapytania i generujących odpowiedzi. Jednak najczęściej korzysta się z podklas znajdujących się w pakiecie javax.servlet.http definiujących servlety HTTP. Klasa HttpServlet posiada m.in. takie metody jak doGet i doPost obsługujące typowe zapytania CGI, czy uniwersalną metodę service obsługującą wszystkie rodzaje zapytań. Najprostszy servlet może wyglądać następująco:

HelloWorldServlet.java

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

public class HelloWorldServlet extends HttpServlet {
   public void doGet (HttpServletRequest req,
      HttpServletResponse res)
      throws ServletException, IOException {

      res.setContentType("text/html");
      ServletOutputStream out = res.getOutputStream();
      out.println("<html>");
      out.println("<head><title>Hello World</title></head>");
      out.println("<body>");
      out.println("<h1>Hello World</h1>");
      out.println("</body></html>");
   }
}

Większość użytecznych servletów czyta parametry wejściowe przekazane im z przeglądarki poprzez metody GET lub POST i na ich podstawie tworzy odpowiedni dokument HTML. Prosty przykład takiego servletu przedstawiono poniżej.

Hello.java

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

public class Hello extends HttpServlet {
   public void service(HttpServletRequest req,
      HttpServletResponse res)
      throws ServletException, IOException {

      res.setContentType("text/html");
      PrintWriter toClient = res.getWriter();
      toClient.println("<html><head>");
      toClient.println("<title>Hello</title>");
      toClient.println("</head>");
      toClient.println("<h1>Hello " +
         req.getParameterValues("name")[0] + "!</h1>");
      toClient.println("</body></html>");
      toClient.close();
   }
}

Powyższy servlet można wywołać na kilka sposobów. Można podać w przeglądarce URL

    http://www.task.gda.pl/servlet/Hello?name=Darek

i wywołać servlet przekazując parametry metodą GET. Można na stronie HTML umieścić formularz:

<form action=http://www.task.gda.pl/servlet/Hello method=POST>
Podaj swoje imię: <input type=text name=name>
<input type=submit value=Wyślij>
</form>

i wywołać servlet przekazując parametry metodą POST. Można również wykorzystać tag <servlet> na stronie HTML zapisanej w pliku z rozszerzeniem shtml.

Hello.shtml

...
<servlet code=Hello>
<param name=name value=Darek>
</servlet>
...

Wtedy serwer WWW rozszerzony o funkcjonalność servletów zastąpi na stronie HTML powyższy tag wynikiem generowanym przez servlet Hello i tak przetworzoną stronę prześle do przeglądarki.
Dostępnych jest już wiele serwerów WWW obsługujących servlety Javy. Przykładami mogą być Java Web Server firmy Sun lub darmowy dla celów niekomercyjnych JRun firmy Live Software. Ten ostatni może pracować jako samodzielny serwer WWW, bądź jako moduł rozszerzający funkcjonalność innych znanych serwerów WWW np. Apache, Microsoft IIS, Netscape.
 

5. Podsumowanie

Zalety języka Java:

  • "ożywienie" WWW - swego rodzaju "lingua franca" Internetu

  • język pozwala łatwo pisać aplikacje sieciowe

  • przenośność - niezależność od platformy dzięki JVM; Java poprzez swój B-kod staje się najbliższą aproksymacją (zbudowaną raczaej z software niż z hardware, chociaż anonsowane są już "Java chips") jednego z najstarszych marzeń przemysłu komputerowego: prawdziwie uniwersalna maszyna  wirtualna

  • prawie czysta implementacja paradygmatu obiektowego

  • usunięcie arbitralnego pojęcia wskaźnika jak w C++

  • wsparcie dla zbierania nieużytków

  • brak samodzielnych (tj. definiowanych poza klasami) funkcji zewnętrznych

  • weryfikacja kodu w fazie kompilacji i w fazie wykonania na zgodność ze standardem języka

  • dynamiczne ładowanie klas (w locie)

  • biblioteki klas dla GUI, sieciowe i WWW


Wady:

  • Brak definiowanych przez użytkownika przeciążonych operatorów

  • złamanie zasad obiektowości w standardowych bibliotekach klas: w klasach opakowań (kopertowych), w klasach kolekcji i w klasach łańcuchów

  • Komunikaty są rzadko polimorficzne i rzadko trafiają na oczekiwaną strukturę dziedziczenia

  • brak klas parametryzowanych (genericity, templates)

  • dziedziczenie tylko pojedyncze

  • usunięcie instrukcji assert znanej w C i C++

  • pogmatwana (zawikłana) struktura modularna z trzema wpływającymi wzajemnie na siebie (interagującymi) koncepcjami (klasy, pakiety zagnieżdżone, pliki źródłowe)

 

6. Programy - ćwiczenia

Plik Squares.java
class Squares {
    /** Print out the squares of integers from 1 to 10 */
    public static void main(String[] args) {
 int x = 1;

 System.out.println("Squares of integers from 1 to 10:");
 while (x <= 10) {
     System.out.println(x * x); // print x squared
     x = x + 1;   // add 1 to x
 }
    }
}


Plik StringDemo.java

class StringsDemo {
    static public void main(String[] args) {
 String   myName = "Archibald";

 myName = myName + " Tuttle";
 System.out.println("Name = " + myName);
    }
}


Plik PascalTriangle.java

import java.io.*;

public class PascalTriangle {

    private int data[][];

    /** Create a Pascal's triangle to specified depth. */
    public PascalTriangle(int rows) {
        data = new int[rows][];
        for (int row = 0; row < rows; row++) {
   data[row] = new int[row + 1];
   if (row == 0)
       data[row][0] = 1;
   else
       for (int col = 0; col <= row; col++) {
  data[row][col] = 0;
  // if not on right edge, add node up and right
  if (col < row)
      data[row][col] += data[row - 1][col];
  // if not on left edge, add node up and left
  if (col > 0)
      data[row][col] += data[row - 1][col - 1];
       }
        }
    }

    /** Print this Pascal's triangle to given stream. */
    public void print(PrintStream ps) {
        for (int i = 0; i < data.length; i++) {
   int[] row = data[i];
   for (int j = 0; j < row.length; j++)
       ps.print(row[j] + " ");
   ps.println();
        }
    }

    /** Create a Pascal's triangle of depth 12 and print it. */
    public static void main(String[] args)
    {
        PascalTriangle pt = new PascalTriangle(12);
        pt.print(System.out);
    }
}


Plik EasyIn.java

// Simple input from the keyboard for all primitive types. ver 1.0
// Not thread safe, not high performance, and doesn't tell EOF.
// It's intended for low-volume easy keyboard input.
// An example of use is:
// EasyIn easy = new EasyIn();
// int i = easy.readInt();   // reads an int from System.in
// float f = easy.readFloat();   // reads a float from System.in

import java.io.*;
import java.util.*;

class EasyIn {
  static InputStreamReader is = new InputStreamReader( System.in );
  static BufferedReader br = new BufferedReader( is );
  StringTokenizer st;
  StringTokenizer getToken() throws IOException {
      String s = br.readLine();
      return new StringTokenizer(s);
    }

    boolean readBoolean() {
       try {
 st = getToken();
 return new Boolean(st.nextToken()).booleanValue();
       } catch (IOException ioe) {
 System.err.println("IO Exception in EasyIn.readBoolean");
 return false;
       }
    }

    byte readByte() {
       try {
         st = getToken();
         return Byte.parseByte(st.nextToken());
       } catch (IOException ioe) {
 System.err.println("IO Exception in EasyIn.readByte");
 return 0;
       }
    }

    short readShort() {
       try {
         st = getToken();
         return Short.parseShort(st.nextToken());
       } catch (IOException ioe) {
 System.err.println("IO Exception in EasyIn.readShort");
 return 0;
       }
    }

    int readInt() {
       try {
         st = getToken();
         return Integer.parseInt(st.nextToken());
       } catch (IOException ioe) {
 System.err.println("IO Exception in EasyIn.readInt");
 return 0;
       }
    }

    long readLong() {
       try {
         st = getToken();
         return Long.parseLong(st.nextToken());
       } catch (IOException ioe) {
 System.err.println("IO Exception in EasyIn.readLong");
 return 0L;
       }
    }

    float readFloat() {
       try {
         st = getToken();
         return new Float(st.nextToken()).floatValue();
       } catch (IOException ioe) {
 System.err.println("IO Exception in EasyIn.readFloat");
 return 0.0F;
       }
    }

    double readDouble() {
       try {
         st = getToken();
         return new Double(st.nextToken()).doubleValue();
       } catch (IOException ioe) {
 System.err.println("IO Exception in EasyIn.readDouble");
 return 0.0;
       }
    }

    char readChar() {
       try {
         String s = br.readLine();
         return s.charAt(0);
       } catch (IOException ioe) {
 System.err.println("IO Exception in EasyIn.readChar");
 return 0;
       }
    }

    String readString() {
       try {
         return br.readLine();
       } catch (IOException ioe) {
 System.err.println("IO Exception in EasyIn.readString");
 return "";
       }
    }

// This method is just here to test the class
   public static void main (String args[]){
       EasyIn easy = new EasyIn();

       System.out.print("enter char: "); System.out.flush();
       System.out.println("You entered: " + easy.readChar() );

       System.out.print("enter String: "); System.out.flush();
       System.out.println("You entered: " + easy.readString() );

       System.out.print("enter boolean: "); System.out.flush();
       System.out.println("You entered: " + easy.readBoolean() );

       System.out.print("enter byte: "); System.out.flush();
       System.out.println("You entered: " + easy.readByte() );

       System.out.print("enter short: "); System.out.flush();
       System.out.println("You entered: " + easy.readShort() );

       System.out.print("enter int: "); System.out.flush();
       System.out.println("You entered: " + easy.readInt() );

       System.out.print("enter long: "); System.out.flush();
       System.out.println("You entered: " + easy.readLong() );

       System.out.print("enter float: "); System.out.flush();
       System.out.println("You entered: " + easy.readFloat() );

       System.out.print("enter double: "); System.out.flush();
       System.out.println("You entered: " + easy.readDouble() );
   }

}


Plik Heritage.java

/**Program krotko demonstruje mechanizm korzystania z interfejsow*/
/**Glowna klasa programu, tworzy pozostale*/
public class Heritage
{
 public static void main (String[] args) {
  /*tworzymy obiekty i wywolujemy odpowiednie metody*/
  Client our_client = new Client();
  our_client.startingReport();
  Server our_server= new Server (our_client);
  our_server.execute(5);
 }
}

/**Klasa klienta implementuje interfejs Message*/
class Client implements Message {
    int counter=0;
    /**zeruje licznik i wyswietla komunikat poczatkowy*/
    public void startingReport()
    {
        counter=0;
        System.out.println ("To jest raport poczatkowy klienta");
        System.out.println ("Counter="+counter);
    }

/**Zwieksza licznik i wyswietla jego wartosc - podajac, ze klasa implementuje interfejs Message; zobowiazalismy sie, ze metoda o nazwie giveReport bedzie istniala*/
    public void giveReport()
    {
        counter++;
        System.out.println ("Counter="+counter);
    }
}

/**Klasa serwera korzysta z obiektu majacego zaimplementowany interfejs Message*/
class Server
{
    /*Zwrocmy uwage, ze typem obiektu jest nazwa interfejsu*/
    Message object;

/**Konstuktor. Jako parametr podajemy dowolny obiekt majacy zaimplementowany interfejs Message; w naszym przypadku bedzie to Client*/
    Server (Message object)
    {
        this.object=object;
    }

/** Wywolujemy metode giveReport obiektu z interfejsem Message times razy */
    public void execute (int times)
    {
        for (int k=0; k<times; k++)
   object.giveReport();
    }

}

/**Interfejs Message, kazda klasa ktora go zaimplementuje musi posiadac metode giveReport*/
interface Message
{
/**Tylko zobowiazanie, ze kazda klasa ktora implementuje ten interfejs bedzie miala metode giveReport - jej dzialanie bedzie zalezec od danej klasy*/
    void giveReport();
}


Plik Compare.java

/**Program krotko demonstruje mechanizm wyjatkow w Java*/
import java.io.*;

/**Klasa porownuje dwa pliki i zwraca rezultat porowanania na ekranie*/
public class Compare {
/**glowna i jedyna metoda aplikacji*/
 public static void main (String[] args) {
/*nazwy plikow*/
 String first_file = args[0];
 String second_file = args[1];
/*obiekty reprezentujace pliki*/
 RandomAccessFile first =null;
 RandomAccessFile second =null;
/*Zawartosc plikow bedzie umieszczona w tych buforach*/
 byte[] first_buffer;
 byte[] second_buffer;
/*Dlugosci plikow*/
 int first_size = -1;
 int second_size = -1;
 try {
 System.out.println ("Ten program porowna dwa pliki");
 System.out.println ("plik 1: "+first_file+" plik2: "+second_file);
 try {
 first = new RandomAccessFile(first_file, "r");
 second = new RandomAccessFile(second_file, "r");
/*blok, w ktorym porownujemy*/
 prawie_koniec:{ //etykieta
  first_size = (int)first.length();
  second_size = (int)second.length();
/*najpierw porownujemy dlugosci*/
 if (first_size!=second_size)
 {
  System.out.println ("Rozne pliki");
  break prawie_koniec;
 }
/*jesli dlugosci identyczne, wczytujemy pliki do pamieci*/
 first_buffer = new byte [first_size];
 second_buffer = new byte [second_size];
 first.readFully (first_buffer, 0, first_size);
 second.readFully (second_buffer, 0, second_size);
/*porownujemy zawartosc plikow*/
 for (int i=0; i<first_size; i++)
 {

  if (first_buffer[i]!=second_buffer[i])
  {
   System.out.println ("Rozne pliki");
   break prawie_koniec;
  }
 }
 System.out.println ("Pliki identyczne");
 }
/*tutaj przechodzi break prawie_koniec*/
 System.out.println ("---------------");
 }
/*przechwytujemy wyjatki zwiazane z operacjami I/O*/
  catch (IOException e)
  {
   System.out.println ("Blad I/O");
  }
/*to sie zawsze wykona*/
  finally
  {
   try
    {
     first.close();
     second.close();
    }
/*podczas zamykania plikow ignorujemy wyjatki*/
  catch (Exception ignored) { }
  System.out.println ("Koniec czesci wewnetrznej");
  }
 }
/*tu przechwytujemy wyjatki nie obsluzone w czesci wewnetrznej*/
  catch (Exception e)
  {
   System.out.println ("Wystapil nastepujacy wyjatek przechwycony w main");
   System.out.println (e);
   System.out.println ("Uzycie programu: Compare pierwszy_plik drugi_plik");
  }
/*na koniec zawsze wyswietlamy krotki komunikat*/
   finally
    {
     System.out.println ("Koniec dzialania programu");
    }

} //end main
}// end Compare

 


Bibliografia

[1] Cargill T. An Overview of Java for C++ Programmers. C++ Report, vo. 8, No. 2, pp. 46-49, 1996.
[2] Lorenz M. Java as an Object-Oriented Language. SIGS Books & Multimedia, New York 1996.
[3] Martin R. C++ and Java: A Critical Comparison. C++ Report, vo. 9, No. 1, pp. 42-49, 1997.
[4] Jain P. and Schmidt D.C. Experiences Converting a C++ Communication Software Framework to Java. C++ Report, vo. 9, No. 1, pp. 51-66, 1997.
[5] Gosling J., Joy B, Steele G. The Java Language Specification. Addison-Wesley, 1996, http://java.sun.com/docs/books/jls/.
[6] The Java Tutorial. http://java.sun.com/docs/books/tutorial/, 1998.
[7] JDK1.1.6 Documentation. http://java.sun.com/products/jdk/1.1/docs/, 1998.
[8] Servlet Tutorial. http://www.task.gda.pl/java/ServletTutorial.html, 1998.


D.F.



Copyright © by MiniMax 1997/2007. All rights reserverd!