You are on page 1of 39

Jacek Rumiski - Jzyk JAVA Rozdzia 8

Rozdzia 8 Integracja Javy z innymi jzykami - JNI.


Programowanie sieciowe
8.1 Integracja Javy z innymi jzykami - Java Native Interface
(JNI)
8.1.1 Obsuga metod rodzimych w kodzie Javy
8.1.2 Kompilacja i generacja plikw nagwkowych
8.1.3
Implementacja
metody
rodzimej
funkcja
a
biblioteka
8.1.4 Dostp do metod i pl zdefiniowanych w Javie
8.2 Programowanie sieciowe
8.2.1 Adresowanie komputerw w sieci (InetAddress i URL)
8.2.2 Komunikacja przez Internet (klient-serwer)
8.3 Serwlety
8.3.1 Model obsugi wiadomoci
8.3.2 rodowisko wykonywania serwletw
8.3.3 Kontrola rodowiska wymiany wiadomoci
8.3.4 Metody wywoywania serwletw
8.3.5 Obsuga protokou HTTP pakiet
javax.servlet.http.*
8.3.6 Bezpieczestwo serwletw
8.4 Zdalne wywoywanie metod - RMI
8.4.1 Typy obiektw i relacje pomidzy nimi w RMI
8.4.2 Komunikacja w procesie zdalnego wykonywania metod
8.4.3 Konstrukcja obiektu zdalnego oprogramowanie
serwera
8.4.4 Oprogramowanie klienta
8.4.5 Uruchamianie systemu.

8.1 Integracja Javy z innymi jzykami - Java Native Interface (JNI)


Tworzc programy w rodowisku jzyka programowania Java napotyka si
czasami na ograniczenia zwizane z dostpem do specyficznych dla danej platformy
cech. Konieczne jest wwczas zastosowanie narzdzi obsugujcych te cechy a
nastpnie zaimplementowanie tych narzdzi w kodzie programu tworzonego w Javie.
Operacja taka jest moliwa poprzez wykorzystanie swoistego interfejsu pomidzy
kodem w Javie a kodem programu stworzonego w innym rodowisku, np. C lub C++.
Co wicej wykorzystanie istniejcych ju funkcji (napisanych wczeniej w innych
jzykach programowania ni Java) moe znacznie uproci tworzenie nowej aplikacji
w Javie, szczeglnie wtedy gdy liczy si czas. Interfejs umoliwiajcy to specyficzne
poczenie kodw zosta nazwany Java Native Interface, lub w skrcie JNI. Kada
funkcja napisana w innym jzyku ni Java a implementowana bezporednio w kodzie
Javy nosi nazw metody rodzimej (native method) i wymaga jawnej,
sformalizowanej deklaracji. Metody rodzime mog wykorzystywa obiekty Javy tak,
jak to czyni metody tworzone w Javie, a wic tworzy obiekty, uywa je oraz
modyfikowa. Aby funkcjonalno metod rodzimych bya pena metody te mog
wywoywa metody tworzone w Javie, przekazywa im parametry i pobiera wartoci
lub referencje zwracane przez te metody. Moliwa jest rwnie obsuga wyjtkw
metod rodzimych.
Czym jest wic JNI? JNI to interfejs zawierajcy:
n plik nagwkowy rodowiska rodzimego (np. plik jni.h dla rodowiska C);
n generator pliku nagwkowego metody rodzimej (np. javah -jni);
n formalizacj deklaracji metody rodzimej,
n definicj i rzutowanie typw danych,

8-3

Jacek Rumiski - Jzyk JAVA Rozdzia 8

n zbir metod (funkcji) umoliwiajcych wymian danych i ustawianie stanw (np.


wyjtkw, monitora, itp.).
Implementacja JNI polega najprociej na wykonaniu nastpujcych dziaa:
1. stworzenie programu w Javie zawierajcego deklaracj metody rodzimej (native);
2. kompilacja programu;
3. generacja pliku nagwkowego rodowiska rodzimego dla klasy stworzonego
programu (javah -jni);
4. stworzenie implementacji metody rodzimej z wykorzystaniem plikw
nagwkowych interfejsu JNI i klasy stworzonego programu ;
5. kompilacja metody rodzimej i umieszczenie jej w bibliotece;
6. uruchomienie programu korzystajcego z metody rodzimej poprzez adowanie
biblioteki.

8.1.1 Obsuga metod rodzimych w kodzie Javy


Pierwszym krokiem w implementacji interfejsu JNI jest stworzenie kodu w
Javie obsugujcego metody rodzime. Najprostsza struktura obsugi moe wyglda
nastpujco:
Przykad 8.1:
//Informacje.java:
class Informacje{
//deklaracja metody rodzimej
public native int infoSystemu(String parametr);
//adowanie biblioteki zawierajcej implementacj metody rodzimej
static{
System.loadLibrary(sysinfo);
}
//wykorzystanie metody rodzimej
public static void main(String args[]){
Informacje i = new Informacje();
int status = i.infoSystemu(CZAS);
}
}// koniec class Informacje

Powyszy szkic stosowania metod rodzimych zawiera trzy bloki. Pierwszy z nich
deklaruje metod rodzim, ktra rni si od pozostaych metod tym, e uywany jest
specyfikator native w deklaracji. Drugi blok to kod statyczny adowany przy
interpretowaniu (kompilacji) kodu bajtw pobierajcy bibliotek przechowujcy
realizacj metody rodzimej. Ostatni blok to zastosowanie metody rodzimej.
Zadeklarowanie metody jako native oznacza, e kompilator ma uzna dan metod
jako rodzim zdefiniowan i zaimplementowan poza Jav. Podana w deklaracji
metody rodzimej nazwa jest odwzorowywana pniej na nazw funkcji w kodzie
rodzimym zgodnie z regu:
nazwa -> Java_NazwaPakietu_NazwaKlasy_nazwa, czyli np.

8-4

Jacek Rumiski - Jzyk JAVA Rozdzia 8

infoSystemu -> Java_Informacje_infoSystemu, (brak nazwy pakietu, gdy klasa


Informacje zawiera si w pakiecie domylnym, ktry nie posiada nazwy).
Wykorzystanie bibliotek, w ktrych znajduje si realizacja metod rodzimych wymaga,
aby biblioteki te byy dostpne dla uruchamianego programu, tzn. musi by
odpowiednio ustalona cieka dostpu.

8.1.2 Kompilacja i generacja plikw nagwkowych


Kompilacja kodu Javy wykorzystujcego metody rodzime odbywa si tak samo
jak dla czystego kodu Javy, np. javac -g Informacje.java.
Nowoci jest natomiast wygenerowanie pliku nagwkowego, jaki zawarty bdzie w
kodzie metody rodzimej. Generacja taka wymaga zastosowania narzdzia javah,
ktre generuje plik nagwkowy o nazwie takiej jak podana nazwa klasy z
rozszerzeniem .h (header - nagwek) tworzony w tym samym katalogu gdzie
znajduje si plik klasy programu. Przykadowo wywoanie polecenia:
jjaavvaahh --jjnnii IInnffoorrm
maaccjjee
spowoduje wygenerowanie nastpujcego pliku nagwkowego:
Przykad 8.2:
//Informacje.h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Informacje */
#ifndef _Included_Informacje
#define _Included_Informacje
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Informacje
* Method: infoSystemu
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_Informacje_infoSystemu
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif

Jak wida jest to nagwek dla kodu metody rodzimej tworzonego w C/C++.
Zasadniczo mona tworzy implementacje metod rodzimych w innych jzykach ale to
wymaga indywidualnego podejcia (konwersji typw i nazw), std zaleca si
korzystanie jedynie z C/C++ do obsugi metod rodzimych. W zasadniczej czci
nagwka (poza analiz skadni dla C czy C++) zawarto opis metody uywajc do

8-5

Jacek Rumiski - Jzyk JAVA Rozdzia 8

tego komentarza zawierajcego nazw klasy, w ciele ktrej zadeklarowano metod


rodzim, nazw metody rodzimej w kodzie Javy oraz podpis (sygnatura) metody.
Sygnatura metody ma format (typy-argumentw)typy-zwracane; gdzie poszczeglne
typy s reprezentowane przez swoje sygnatury, i tak:
sygnatura
Z
B
C
S
I
J
F
D
Lpena-nazwa-klasy
[typ

znaczenie typu w Javie


boolean
byte
char
short
int
long
float
double
pena nazwa klasy
typ[]

W powyszym przykadzie pliku nagwkowego widnieje informacja, e metoda


zawiera argument o sygnaturze Ljava/lang/String czyli obiekt klasy String oraz
zwraca warto typu o sygnaturze I czyli typu int. Mona okreli sygnatury typw
argumentw i wartoci zwracanych metod poprzez uycie narzdzia de-asemblacji
kodu a mianowicie javap:
jjaavvaapp --ss --pp IInnffoorrm
maaccjjee
co wygeneruje:
Compiled from Informacje.java
class Informacje extends java.lang.Object {
static {};
/* ()V */
Informacje();
/* ()V */
public native int infoSystemu(java.lang.String);
/* (Ljava/lang/String;)I */
public static void main(java.lang.String[]);
/* ([Ljava/lang/String;)V */
}
W powyszym wydruku w opcji komentarza zawarto sygnatury typw.
Po opisie metody rodzimej nastpuje deklaracja metody dla rodowiska rodzimego
czyli C/C++. Deklaracja ta oprcz omwionej ju nazwy zawiera szereg nowych
elementw i tak:
JNIEXPORT i JNICALL - oznaczenie funkcji eksportowanych z bibliotek (jest to
odniesienie si do specyfikacji deklaracji funkcji eksportowanych, JNIEXPORT oraz
JNICALL s zdefiniowane w jni_md.h);
jint lub inny typ - oznaczenie typu elementu zwracanego przez funkcj, np.

8-6

Jacek Rumiski - Jzyk JAVA Rozdzia 8

typ w Javie, typ rodzimy, rozmiar,


boolean
jboolean
8
byte
jbyte
8
char
jchar
16
short
jshort
16
int
jint
32
long
jlong
64
float
jfloat
32
double
jdouble
64
void
void

typ dla C/C++ (Win32)


unsigned unsigned char
signed char
unsigned unsigned short
short
long
__int64
float
double
void

JNIEnv* wskanik interfejsu JNI zorganizowany jako tablica funkcji JNI o konkretnej
lokalizacji. Metoda rodzima wykorzystuje funkcje poprzez odwoanie si do
wskanika JNIEnv*. Przykadowo mona pobra rozmiar macierzy wykorzystujc
funkcj GetArrayLength() poprzez wskanik JNIEnv*:
(...) JNIEnv *env (...) jintArray macierz (...)
jsize rozmiar = (*env)->GetArrayLength(env, macierz);
jobject to kolejny element deklaracji funkcji w JNI. Argument tego typu stanowi
referencj do biecego obiektu; jest odpowiednikiem this w Javie.
Warto tu zauway, e odpowiednikiem metody Javy zadeklarowanej jako native
jest funkcja zawierajca co najmniej dwa argumenty, nawet wwczas gdy metoda nie
zawiera adnego.
jstring lub inne typy argumentw - kolejne argumenty funkcji (argumenty metody
rodzimej).

8.1.3 Implementacja metody rodzimej - funkcja a biblioteka


Kolejny krok stosowania funkcji w kodzie Javy to stworzenie tych funkcji lub
ich adaptacja do formy wymaganej przez JNI. Deklaracja realizowanej funkcji musi
by taka sama jak zaoona (wygenerowana) w pliku nagwkowym. Nastpujcy
przykad ukazuj przykadow realizacj metody rodzimej deklarowanej we
wczeniejszych przykadach:
Przykad 8.3:
//informacje.cpp
#include "jni.h"
#include <stdio.h>
#include <dos.h>
#include "Informacje.h"
JNIEXPORT jint JNICALL Java_Informacje_infoSystemu(JNIEnv *env, jobject o, jstring str){
struct time t;
const char *s=(env)->GetStringUTFChars(str,0);

8-7

Jacek Rumiski - Jzyk JAVA Rozdzia 8

printf("Obsugiwana aktualnie opcja to: %s\n",s);


if ((((*s=='C')&&(*(s+1)=='Z'))&&(*(s+2)=='A'))&&(*(s+3)=='S')){
gettime(&t);
printf("Biecy czas to: %2d:%02d:%02d.%02d\n",t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund);
return 1;
} else {
printf("Nie obsugiwana opcja");
return 0;
}

W powyszym kodzie funkcji w C++ wczono szereg plikw nagwkowych. Plik


stdio.h oraz dos.h to standardowe pliki nagwkowe biblioteki C. Pierwszy jest
wymagany ze wzgldu na stosowanie funkcji printf, drugi ze wzgldu na dostp do
czasu systemowego poprzez funkcj gettime() oraz struktur time. Ponadto zawarto
dwa pliki nagwkowe wymagane ze wzgldu na implementacj interfejsu JNI, czyli
jni.h (definicja typw i metod) oraz Informacje.h (deklaracja funkcji odpowiadajcej
metodzie rodzimej). Pierwsze linia kodu funkcji zawiera deklaracj zmiennej typu
struktury time przechowujcej informacje zwizane z czasem systemowym po
wykorzystaniu funkcji gettime() w dalszej czci kodu. Kolejna linia kodu jest bardzo
wana ze wzgldu na zobrazowanie dziaania konwersji danych. Wykorzystano tam
funkcj GetStringUTFChars() do konwersji zmiennej (argumentu funkcji) typu jstring
do const char *. Konwersja ta jest wymagana gdy nie wystpuje wprost
odwzorowanie typw String na const char *. Jest to rwnie spowodowane tym, e
Java przechowuje znaki w Unicodzie i dlatego konieczna jest dodatkowa konwersja
znakw z typu String(Unicode -UTF) na char *. Warto zwrci uwag na wywoanie
funkcji konwertujcej. Odbywa si ono poprzez wykorzystanie wskanika (env) do
struktury przechowujcej szereg rnych funkcji (okrelonych w jni.h). Ze wzgldu na
sposb zapisu funkcji w jni.h moliwe s dwa sposoby wywoania funkcji albo:
(env*)->GetStringUTFChars(env*, str ,0) dla C albo:
(env)->GetStringUTFChars(str,0) dla C++.
Obie funkcje s zapisane w jni.h, druga z nich jest realizowana poprzez
zastosowanie pierwszej z pierwszym argumentem typu this.
Dalsza cz kodu przykadu to wywietlenie komunikatu zawierajcego warto
argumentu tekstowego po konwersji, pobranie informacji o czasie systemowym i
wywietlenie go.
Tak przygotowany kod funkcji naley nastpnie skompilowa i wygenerowa
bibliotek (w prezentowanym przykadzie bdzie to biblioteka typu Dynamic Link
Library - DLL).
Naley pamita o lokalizacji plikw jni.h oraz innych plikw nagwkowych woanych
przez jni.h. Pliki te s zapisane w podkatalogu include oraz include/win32 gwnego
katalogu JDK.
Tak przygotowana funkcja i biblioteka umoliwiaj uruchomienie programu w Javie
wykorzystujcego metod rodzim. W wyniku wywoania prezentowanego na
pocztku kodu :
java Informacje
uzyskamy rezultat typu:
Obsugiwana aktualnie opcja to: CZAS
Biecy czas to: 16:11:06.50

8-8

Jacek Rumiski - Jzyk JAVA Rozdzia 8

gdzie podawany czas zaley oczywicie od ustawie systemowych.

8.1.4 Dostp do metod i pl zdefiniowanych w Javie


W celu wykorzystania w funkcji metod i metod statycznych zdefiniowanych w Javie
naley wykona trzy podstawowe kroki:
1. pobra obiekt klasy (Class) w ciele ktrej znajdowa ma si dana metoda:
jclass c = (env)->GetObjectClass(o); gdzie o jest zmienn typu jobject
2. pobra identyfikator metody dla danej klasy poprzez podanie nazwy metody oraz
sygnatur:
jmethodID id = (env)->GetMethodID(c, suma, (II)I); id przyjmuje warto 0 jeeli
nie ma szukanej metody w klasie reprezentowanej przez obiekt c,
3. wywoa metod poprzez podanie identyfikatora id oraz obiektu o, np.:
(env)->CallIntMethod(o,id,a1,a2); gdzie a1 i a2 to argumenty. W zalenoci od
zwracanego typu mona wykorzysta rne funkcje np. CallVoidMethod(),
CallBooleanMethod(), itp.
Wykorzystanie metod statycznych jest analogiczne do powyszego schematu z t
rnic, e w kroku 2 i 3 naley wywoa odpowiednie funkcje GetStaticMethodID() i
CallStaticIntMethod() (lub podobne innych typw), przy czym funkcje CallStatic* jako
argument wykorzystuj zmienn typu jclass zamiast jobject (odwoanie si do obiektu
klasy Class reprezentujcego klas zamiast do obiektu bdcego wystpieniem
klasy).
Przykadowe fragmenty kodw w Javie i w C obrazujce stosowanie metod mog by
nastpujce:
//Liczenie.java:
(...)
public native void oblicz(int a, int b);
public int suma(int a, int b){
return (a+b);
}
(...)
//policz.cpp:
(...) JNIEXPORT void JNICALL Java_Liczenie_oblicz(JNIEnv *env, jobject o, jint a, jint b){
jclass c = (env)->GetObjectClass(o);
jmethodID id = (env)->GetMethodID(c, suma, (II)I);
if (id==0)
return;
printf(Oto warto sumy argumentw: %d, (env)->CallIntMethod(o,id,a,b));
}

Dostp do pl obiektw i zmiennych statycznych klas Javy z poziomu funkcji jest


wykonywany w podobny sposb jak dla metod. Wyrnia si trzy kroki postpowania:
1. pobra obiekt klasy (Class) w ciele ktrej znajdowa ma si dana zmienna:
8-9

Jacek Rumiski - Jzyk JAVA Rozdzia 8

jclass c = (env)->GetObjectClass(o); gdzie o jest zmienn typu jobject


2. pobra identyfikator zmiennej dla danej klasy poprzez podanie nazwy zmiennej
oraz sygnatury:
jfielddID id = (env)->GetFieldID(c, a, I); id przyjmuje warto 0 jeeli nie ma
szukanej zmiennej w klasie reprezentowanej przez obiekt c,
3. pobra lub ustawi warto zmiennej poprzez podanie identyfikatora id oraz
obiektu o, np.:
jint a = (env)->GetIntField(o,id);
lub
(env)->SetIntField(o,id,a);
W zalenoci od typu zmiennej mona wykorzysta rne funkcje np.
SetObjectField(), GetObjectField(), GetLongField(), SetDoubleField(), itp.
Wykorzystanie pl statycznych jest analogiczne do powyszego schematu z t
rnic, e w kroku 2 i 3 naley wywoa odpowiednie funkcje GetStaticFieldID() i
SetStaticIntField() (lub podobne innych typw), przy czym funkcje {Set,Get}Static*
jako argument wykorzystuj zmienn typu jclass zamiast jobject (odwoanie si do
obiektu klasy Class reprezentujcego klas zamiast do obiektu bdcego
wystpieniem klasy).
Przykadowe fragmenty kodw w Javie i w C ukazujce dostp do pl mog by
nastpujce:
//Liczenie.java:
class Liczenie{
static String str=Operacja zakonczona;
int suma = 10;
(...)
public native void oblicz(int a, int b);
public int suma(int a, int b){
return (a+b);
}
(...)
}
//policz.cpp:
(...) JNIEXPORT void JNICALL Java_Liczenie_oblicz(JNIEnv *env, jobject o, jint a, jint b){
jclass c = (env)->GetObjectClass(o);
jfieldID id = (env)->GetFieldID(c, suma, I);
if (id==0)
return;
jint s = (env)->GetIntField(o,id);
printf(Oto warto sumy argumentw: %d,s);
(env)->SetIntField(o,id, (env)->CallIntMethod(o,id,a,b));
id = (env)->GetStaticFieldID(c, str, Ljava/lang/String;);
if (id==0)
return;
jstring tekst = (env)->GetStaticObjectField(c,id);
printf(tekst);
}

8-10

Jacek Rumiski - Jzyk JAVA Rozdzia 8

Na zakoczenie tej sekcji warto przedstawi w skrcie zagadnienia zwizane z


wyjtkami. Wyjtki mog pojawi si w rnych okolicznociach w pracy z metodami
rodzimymi np. przy braku wzywanej metody, przy braku wzywanego pola, przy zym
argumencie, itp. JNI dostarcza klika funkcji do obsugi zdarze w kodzie funkcji.
Podstawowe funkcje to ExceptionOccurred(), ExceptionDescribe() i ExceptionClear().
Pierwsza funkcja bada czy wystpi wyjtek; jeli tak to zwraca warto logiczn
odpowiadajc prawdzie. Wwczas mona w bloku instrukcji warunkowej zawrze
pozostae dwie funkcje (wysanie informacji o wyjtku na ekran, oraz wyczyszczenie
wyjtku). Dodatkowo mona wywoa wyjtek, ktry zostanie zwrcony do kody Javy,
gdzie naley go obsuy. Mona to zrobi za pomoc funkcji Throw(jthrowable o) lub
ThrowNew(jclass, const char *).
Naley pamita rwnie o tym, e JNI umoliwia korzystanie z Maszyny Wirtualnej
w ramach aplikacji rodzimej. W tworzeniu takiej aplikacji zanim wywoywane bd
metody i pola (tak jak to ukazano do tej pory) konieczne jest wywoanie Maszyny
Wirtualnej Javy oraz uzyskanie obiektu klasy, np.:
JDK1_1InitArgs vm;
JavaVM *jvm;
JNIEnv *env;
jclass c;
vm.version=0x00010001;
//okrelenie wersji Maszyny Wirtualnej jako 1.1.2 i wyszych
JNI_GetDefaultJavaVMInitArgs(&vm);
jint test = JNI_CreateJavaVM(&jvm,&env,&vm);
c=(env)->FindClass(NazwaKlasy);
// np. GetStatic{Method,Field}Int(c,...) i tak dalej

8.2 Programowanie sieciowe


Tworzenie programw dziaajcych w sieciach komputerowych byo jednym z
celw stworzenia jzyka Java. Moliwoci aplikacji sieciowych tworzonych za
pomoc Javy s rne. Podstawowe, proste rozwizania wykorzystujce
mechanizmy wysokiego poziomu pracy w sieci dostarczane s przez podstawowe
klasy pocze (adresowania) jak InetAddress i URL.

8.2.1 Adresowanie komputerw w sieci (InetAddress i URL)


Klasa InetAddress opisuje adres komputera w sieci poprzez nazw/domen,
np. www-med.eti.pg.gda.pl oraz poprzez numer IP, np. 153.19.51.66. Istnieje szereg
metod statycznych klasy InetAddress wykorzystywanych do tworzenia obiektu klasy,
brak jest bowiem konstruktorw. Podstawowe metody wykorzystywane do tworzenia
obiektw to:
IInneettA
Addddrreessss..ggeettB
ByyN
Naam
mee((S
Sttrriinngg nnaazzw
waa)),,

8-11

Jacek Rumiski - Jzyk JAVA Rozdzia 8

IInneettA
Addddrreessss..ggeettA
AlllB
ByyN
Naam
mee((S
Sttrriinngg nnaazzw
waa)),,
IInneettA
Addddrreessss..ggeettLLooccaallH
Hoosstt(());;
Pierwsza metoda tworzy obiekt klasy bazujc na podanej nazwie komputera lub
adresie. Druga metoda jest wykorzystywana wwczas kiedy komputer o danej
nazwie ma wiele adresw IP. Zwracana jest wwczas tablica obiektw typu
InetAddress. Ostania metoda jest wykorzystywana do uzyskania obiektu
reprezentujcego adres komputera lokalnego. Wszystkie metody musz zawiera
deklaracje lub obsug wyjtku UnknownHostException powstajcego w przypadku
braku identyfikacji komputera o podanej nazwie lub adresie. Poniej zaprezentowano
przykadowy program wykorzystujcy prezentowane metody klasy InetAddress.
Przykad 8.4:
//Adresy.java
//Adresy.java
import java.net.*;
public class Adresy{
public static void main(String args[]){
try{
InetAddress a0 = InetAddress.getLocalHost();
System.out.println("Adres komputera "+a0.getHostName()+" to: " +a0);
InetAddress a1 = InetAddress.getByName("biomed.eti.pg.gda.pl");
System.out.println("Adres komputera biomed to: "+a1);
InetAddress a2[] = InetAddress.getAllByName("www.eti.pg.gda.pl");
System.out.println("Adres komputera www.eti.pg.gda.pl to:");
for(int i=0; i<a2.length; i++){
System.out.println(a2[i]);
}
} catch (UnknownHostException he) {
he.printStackTrace();
}
}
}// koniec public class Adresy

W wyniku dziaania powyszego programu wywietlone zostan informacje na temat


adresw sieciowych wybranych komputerw. W programie zastosowano rwnie
jedn z metod klasy InetAddress umoliwiajc operacje na adresie a mianowicie
getHostName(). Metoda ta zwraca nazw komputera jako obiekt klasy String. Istniej
rwnie metody umoliwiajce filtracj adresu komputera w celu uzyskania jedynie
numeru IP: byte[] getAddress(), String getHostAddress().
Inn klas wykorzystywan w Javie do adresowania komputerw jest klasa
URL oraz jej pochodne (URL, URLClassLoader, URLConnection, URLDecoder,
URLEncoder, URLStreamHandler). URL czyli Uniform Resource Locator jest
specjaln form adresu zasobw w sieci. URL posiada dwa podstawowe elementy:
8-12

Jacek Rumiski - Jzyk JAVA Rozdzia 8

identyfikator protokou oraz nazw zasobw. Identyfikator protokou to np. http, ftp,
gopher, rmi czy jdbc. Nazw zasobw stanowi takie elementy jak: nazwa hosta,
nazwa pliku, numer portu, nazwa odwoania (w danym pliku). Tworzc wic obiekt
klasy URL otrzymujemy gotowy wskanik, ktry jest wykorzystywany przez liczne
metody Javy (np. otwieranie obrazka getImage(), tworzenie poczenia w JDBC Connection). W odrnieniu od klasy InetAddress tworzenie obiektw klasy URL
odbywa si poprzez wykorzystanie jednego z licznych konstruktorw. Kady z nich
zwizany jest z koniecznoci obsugi wyjtku MalformedURLException powstajcym
w wypadku problemw z identyfikacj wskazanego w wywoaniu konstruktora
protokou. Liczne konstruktory umoliwiaj podania parametrw adres URL albo
poprzez odpowiednik adresu bdcy tekstem (String) albo poprzez tworzenie tego
adresu z takich elementw jak nazwa protokou, nazwa komputera, port, nazwa pliku,
itp. Przykadowe konstruktory maj posta:
U
RLL((S
Sttrriinngg aaddrreess)) ,,
UR
R
L
(
S
U
Sttrriinngg pplliikk))
Sttrriinngg hhoosstt,, iinntt ppoorrtt,, S
URL(Sttrriinngg pprroottookk,, S
Klasa URL zawiera szereg metod umoliwiajcych filtracj adresu, a wic pobranie
nazwy protokou (getProtocol()), nazwy komputera (getHost()), pliku (getFile()) czy
numeru portu (getPort()). Dodatkowo klasa URL zawiera metody umoliwiajce
wykonywanie poczenia z hostem (tworzone jest gniazdo o czym dalej) i
przesyanie danych. Przykadowy program ukazuje moliwo wykorzystania
funkcjonalnoci klasy URL:
Przykad 8.5:
//Pobiez.java
import java.net.*;
import java.io.*;
public class Pobiez{
public static void main(String args[]){
URL url;
String tekst;
if (args.length !=1) {
System.out.println("Wywoanie: Pobiez URL; gdzie URL to adres zasobw");
System.exit(1);
}
try{
url = new URL(args[0]);
BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
while( (tekst=br.readLine()) !=null){
System.out.println(tekst);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}// koniec public class Pobiez
8-13

Jacek Rumiski - Jzyk JAVA Rozdzia 8

Powyszy program umoliwia pobranie rda wskazanego pliku (html) i wywietlenie


go na ekranie. Mona oczywicie tak skonstruowa strumie aby pobierany plik by
nagrywany do lokalnego pliku i w ten sposb stworzy narzdzie do kopiowania stron
z Internetu. W przykadzie zastosowano konstrukcj obiektu klasy URL poprzez
podanie argumentu do konstruktora jako tekstu (String) bdcego argumentem
wywoania aplikacji. Przykadowe wywoanie aplikacji moe by nastpujce:
jjaavvaa P
Poobbiieezz hhttttpp :://// bbiioonntt..eettii..ppgg..ggddaa..ppll//jjaavvaa..hhttm
m
w wyniku czego uzyskamy wydruk:
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2">
<meta name="Author" content="Jacek Ruminski">
<meta name="GENERATOR" content="Mozilla/4.6 [en-gb] (WinNT; I) [Netscape]">
<title>Jezyk JAVA - wyklad</title>
</head>
<body text="#FFFFFF" bgcolor="#330033" link="#0000EE" vlink="#551A8B" alink="#FF0000">
<center><b><i><font
size=+3>Jzyk&nbsp;<img
SRC="javalogo.gif"
height=88
align=ABSCENTER>
wykad</font></i></b>
<br>&nbsp;
<p><img SRC="jav_logo.jpg" height=125 width=260>
<p><b><font color="#CC0000"><font size=+1>Plan wykadu:</font></font></b></center>

width=52

(...)

8.2.2 Komunikacja przez Internet (klient-serwer)


Do komunikacji poprzez Internet programy Javy wykorzystuj protokoy TCP i
UDP. Klasy URL* oraz Socket i ServerSocket wykorzystuj Transfer Control Protocol
klasy takie jak DatagramPacket, DatagramSocket, oraz MulticastSocket korzystaj z
User Datagram Protocol. W pakiecie java.net zdefiniowane s jeszcze inne klasy, z
ktrych warto przytoczy te zwizane z autoryzacj pocze i nadawaniem
uprawnie:
Authenticator,
NetPermission,
PasswordAuthentication,
SocketPermission.
W aplikacjach klient-serwer, serwer dostarcza okrelonej usugi np. przetwarza
zapytanie skierowane do bazy danych, zapisuje seri obrazw diagnostycznych.
Klient wykorzystuje usugi wiadczone przez serwer i jest odpowiedzialny za danie
usugi oraz obsug wynikw. Funkcje penione przez kad ze stron mona uj
nastpujco:
- poczenie z urzdzeniem zdalnym (przygotowanie wysyania i odbioru danych),
- wysyanie danych,
- odbir danych,
- zamknicie poczenia,
- przywizanie portu (dla danej aplikacji na danym hocie),
8-14

Jacek Rumiski - Jzyk JAVA Rozdzia 8

- nasuch,
- akceptacja pocze na danych portach.
Pierwsze cztery funkcje s waciwe dla klienta, serwer rozszerza je o dodatkowe
trzy. W Javie obsug klienta, a wic realizacj pierwszych czterech funkcji dostarcza
klasa Socket; dla serwera przeznaczono klas ServerSocket. Socket (gniazdo) to
dobrze znane pojcie wynikajce z planw stworzenia dostpu do sieci jako do
strumienia danych (strumie wejcia, strumie wyjcia). Koncepcja strumieni miaa
by uniwersalna dla kadego moliwego przepywu danych (z urzdzenia, z pliku, z
sieci). Socket jest wic pewn abstrakcj umoliwiajc przejcie na wyszy poziom i
nie zajmowaniem si takimi zagadnieniami jak rozmiar pakietu, retransmisja pakietu,
typ mediw, itp. Rozwamy teraz zagadnienia zwizane ze stron klienta procesu
komunikacji sieciowej, a wic zapoznajmy si z klas Socket pakietu java.net.
Klasa Socket posiada szereg rnych konstruktorw, z ktrych najbardziej popularne
s:
S
Addddrreessss
Addddrreessss aaddddrreessss,, iinntt ppoorrtt)) -- ggddzziiee aaddddrreessss ttoo oobbiieekktt kkllaassyy IInneettA
Soocckkeett((IInneettA
5
)
,
3
6
5
5
(
0
t
u
o
r
e
r
p
m
n
u
t
p
o
r
,
o
s
t
a
h
z
w

n
a
u
b
l
I
P
bbddccyy aaddrreesseem
m IP lub nazw hosta, port - numer portu (0-65535),
S
w hhoossttaa,, ppoorrtt -Sttrriinngg hhoosstt,, iinntt ppoorrtt)) -- ggddzziiee hhoosstt ttoo tteekksstt oozznnaacczzaajjccyy nnaazzw
Soocckkeett((S
)
.
5
5
3
5
6
(
0
t
u
r
o
p
r
e
nnuum
mer portu (0-65535).
Poniewa poczenie wykonywane przez obiekt klasy Socket moe nie powie si z
rnych przyczyn (np. nie znany host) konieczna jest obsuga wyjtkw.
Klasyczny fragment kodu obsugi klasy Socket pokazano poniej:
ttrryy {{

S
mgg..ggddaa..ppll"",, 8800));;
w..aam
ww
ww
Soocckkeett((""w
wS
Soocckkeett ggnniiaazzddoo== nneew

}}
ccaattcchh ((U
Unnkknnoow
wnnH
HoossttE
Exxcceeppttiioonn ee)) {{
S
Syysstteem
m..eerrrr..pprriinnttllnn((ee));;
}}
ccaattcchh ((IIO
OE
Exxcceeppttiioonn ee)) {{
S
Syysstteem
m..eerrrr..pprriinnttllnn((ee));;
}}

W powyszym przykadzie podjta jest prba (try) poczenia z serwerem


www.amg.gda.pl na porcie 80. Jeeli nazwa hosta jest nieznana lub serwer nazw nie
dziaa zostanie zwrcony wyjtek UnknownHostException (wyjtek nieznanego
hosta). Jeli z innych przyczyn nie uda si uzyska poczenia zostanie zwrcony
wyjtek IOException (wyjtek wejcia-wyjcia). Najprostszym przykadem programu
implementujcego klas Socket moe by prosty skaner portw serwera:
Przykad 8.6:
//SkanerPortow.java:
import java.net.*;
import java.io.*;
public class SkanerPortow {

8-15

Jacek Rumiski - Jzyk JAVA Rozdzia 8

public static void main(String[] args) {


Socket gniazdo;
String host = "localhost";
if (args.length > 0) {
host = args[0]; //jeli nie podano argumentu programu hostem bedzie komputer lokalny
}
for (int n = 0; n < 1024; n++) { //skanuj wszystkie porty "roota"
try {
gniazdo = new Socket(host, n);
System.out.println("Znalazem serwer na porcie " + n + " komputera: " + host);
}
catch (UnknownHostException e) {
System.err.println(e);
break; //koniec ptli for w razie nieznanego hosta
}
catch (IOException e) {
// System.err.println(e); - nie drukuj informacji o braku serwera
}
}
}
} // koniec public class SkanerPortow

Program powyszy jest skanerem portw na ktrych dziaaj aplikacje (serwery).


Skanowane porty 0-1023 nale do zakresu portw, ktre na maszynach UNIXowych przynale do administratora, to znaczy tylko root moe uruchamia serwery
na tych portach. Odwzorowanie portw na aplikacj mona znale w pliku ustawie
/etc/services. Klasa Socket posiada wiele metod umoliwiajcych midzy innymi
uzyskanie informacji zwizanych z obiektem tej klasy takich jak:
- getLocalAddress() - zwraca lokalny adres, do ktrego dowizane jest gniazdo,
- getLocalPort() - zwraca lokalny port, do ktrego dowizane jest gniazdo,
- getInetAddress() - zwraca zdalny adres, do ktrego gniazdo jest podczone,
- getPort() - zwraca zdalny numer portu, do ktrego gniazdo jest podczone.
Kolejny przykad obrazuje wykorzystanie metody getLocalPort().
Przykad 8.7:
// SkanerPortow2.java:
import java.net.*;
import java.io.*;
public class SkanerPortow2 {
public static void main(String[] args) {
Socket gniazdo;
String host = "localhost";

8-16

Jacek Rumiski - Jzyk JAVA Rozdzia 8

if (args.length > 0) {
host = args[0];
}
for (int n = 0; n < 1024; n++) {
try {
gniazdo = new Socket(host, n);
int lokalPort = gniazdo.getLocalPort();
System.out.println("Numer lokalnego portu to:" + lokalPort);
System.out.println("Znalazem serwer na porcie " + n + " komputera: " + host);
}
catch (UnknownHostException e) {
System.err.println(e);
break;
}
catch (IOException e) {
//System.err.println(e);
}
}
}
}// koniec public class SkanerPortow2

Powiedziano wczeniej, e idea gniazd zwizana bya ze stworzeniem strumienia, do


ktrego mona pisa, i z ktrego mona czyta. Podstawow, uniwersaln a
zarazem abstrakcyjn klas obsugujc strumie wejciowy jest klasa InputStream
dla strumienia wyjciowego jest to OutputStream. Obydwie klasy s rozszerzane i
stanowi podstaw przepywu danych (np. z i do pliku, z i do urzdzenia, z i do sieci).
W celu obsugi sieci w klasie Socket zdefiniowano metody zwracajce obiekty klas
InputStream oraz OutputStream, co umoliwia stworzenie strumieni do przesyania
danych przez sie. Najczciej wykorzystywane klasy nie abstrakcyjne to
BufferedReader obsugujce czytanie danych przez bufor oraz PrintStream dla
obsugi zapisu nie zwracajca wyjtku IOException. W celu zobrazowania pracy ze
strumieniami posumy si przykadami. Pierwszy przykad prezentuje dziaanie
typowe dla klienta, a wic czytanie ze strumienia.
Przykadowy program czy si z serwerem czasu a nastpnie wywietla ten czas na
ekranie.
Przykad 8.8:
//Zegar.java:
import java.net.*;
import java.io.*;
public class Zegar {
public static void main(String[] args) {
Socket gniazdo;
String host = "localhost";
BufferedReader strumienCzasu;
if (args.length > 0) {

8-17

Jacek Rumiski - Jzyk JAVA Rozdzia 8

host = args[0];
try {
gniazdo = new Socket(host, 13);
strumienCzasu = new BufferedReader(new InputStreamReader(gniazdo.getInputStream()));
String czas = strumienCzasu.readLine(); //wprowad lini znakw z bufora strumienia
System.out.println("Na "+host+" jest: "+czas);
}
catch (UnknownHostException e) {
System.err.println(e);
}
catch (IOException e) {
System.err.println(e);
}

}
}//koniec public class Zegar

Kolejny przykad umoliwi pokazanie zarwno stworzenie programu klienta jak i


programu serwera.
Przykad 8.9:
//KlientEcho.java:
import java.net.*;
import java.io.*;
public class KlientEcho {
public static void main(String[] args) {
Socket gniazdo;
String host = "localhost";
BufferedReader strumienEcha, strumienWe;
PrintStream strumienWy;
String echo;
if (args.length > 0) {
host = args[0];
}
try {
gniazdo = new Socket(host, 7); //port 7 jest standardowym portem obslugi echa
strumienWe = new BufferedReader(new InputStreamReader(gniazdo.getInputStream()));
//czytaj z serwera
strumienWy = new PrintStream(gniazdo.getOutputStream());
strumienEcha = new BufferedReader(new InputStreamReader(System.in));
//czytaj z klawiatury
while(true){
echo=strumienEcha.readLine();
if (echo.equals(".")) break; //znak . oznacza koniec pracy

8-18

Jacek Rumiski - Jzyk JAVA Rozdzia 8

strumienWy.println(echo); //wyslij do serwera


System.out.println(strumienWe.readLine()); //wyslij na monitor

}
}
catch (UnknownHostException e) {
System.err.println(e);
}
catch (IOException e) {
System.err.println(e);
}
}
}//koniec public class KlientEcho

Program serwera
Przykad 8.10:
//SerwerEcho.java:
import java.net.*;
import java.io.*;
public class SerwerEcho {
public static void main(String[] args) {
ServerSocket serwer;
Socket gniazdo;
String host = "localhost";
BufferedReader strumienEcha, strumienWe;
PrintStream strumienWy;
String echo;
if (args.length > 0) {
host = args[0];
}
try {
serwer = new ServerSocket(7); //stworz serwer pracujacy na porcie 7 biezacego komputera
while(true){ //gwna ptla serwera
try{
while(true){ //gwna ptla poczenia
gniazdo = serwer.accept(); //przyjmuj poczenia i stworz gniazdo
System.out.println("Jest polaczenie");
while(true){
strumienWe = new BufferedReader(new InputStreamReader(gniazdo.getInputStream()));
strumienWy = new PrintStream(gniazdo.getOutputStream());
echo=strumienWe.readLine();
strumienWy.println(echo); //wyslij to co przyszlo
}//od while
}//od while

8-19

Jacek Rumiski - Jzyk JAVA Rozdzia 8

}//od try
catch (SocketException e){
System.out.println("Zerwano polaczenie"); //klient zerwa poczenie
}
catch (IOException e) {
System.err.println(e);
}
}//od while
}// od try
catch (IOException e) {
System.err.println(e);
}

}
}//koniec public class SerwerEcho

Przykad SerwerEcho.java demonstruje zastosowanie klasy ServerSocket do


tworzenia serwerw w architekturze klient-serwer. Klasa ServerSocket dostarcza
kilka konstruktorw umoliwiajcych stworzenie serwera na danym porcie, z
okrelon maksymaln liczb pocze (kolejka), na danym porcie danego
komputera o konkretnym IP (wane w przypadku wielu interfejsw) z okrelon
maksymaln liczb pocze (kolejka). Kolejnym istotnym elementem implementacji
klasy ServerSocket jest oczekiwanie i zamykanie pocze. W tym celu wykorzystuje
si metody ServerSocket.accept() oraz Socket.close(). Metoda accept() blokuje
przepyw instrukcji programu i czeka na poczenie z klientem. Jeli klient podczy
si do serwera metoda accept() zwraca gniazdo, na ktrym jest poczenie.
Zamknicie poczenia odbywa si poprzez wywoanie metody close() dla
stworzonego gniazda. Wwczas poczenie jest zakoczone i aktywny jest nasuch
accept() oczekujcy na nastpne podczenie. Jeeli jest potrzeba zwolnienia portu
serwera to wwczas naley wywoa metod ServerSocket.close(). Inne przydatne
metody klasy ServerSocket to getLocalPort() umoliwiajca uzyskanie numeru portu
na jakim pracuje serwer oraz metoda setSoTimeout() umoliwiajca danemu
serwerowi ustawienie czasu nasuchu metod accept(). Metoda setSoTimeout() musi
by wywoana przed accept(). Czas podaje si w milisekundach. Jeeli w
zdefiniowanym okresie czasu accept() nie zwraca gniazda (brak poczenia)
zwracany jest wyjtek InterruptedException.

8.3 Serwlety
Serwlet jest definiowan przez programist klas implementujc interfejs
javax.servlet.Servlet. Zadaniem serwletu jest wykonywanie dziaa w rodowisku
serwera. Oznacza to, e serwlet nie stanowi oddzielnej aplikacji, lecz jego
wykonywanie jest zalene od serwera. Serwlet stanowi zatem odmian apletu, z tym,
e dziaa nie po stronie klienta (w otoczeniu np. przegldarki WWW) lecz po stronie
serwera. Taka forma dziaanie serwleta wymaga od serwera zdolnoci do
interpretacji kodu poredniego Javy oraz moliwoci wykorzystania produktu
wykonanego kodu Javy w obrbie funkcjonalnoci serwera. Interpretacja kodu
poredniego odbywa si najczciej za porednictwem zewntrznej wzgldem
serwera maszyny wirtualnej co wymaga zaledwie prostej konfiguracji serwera.
Zdolno do wykorzystania serwletw przez serwer deklaruj producenci danego

8-20

Jacek Rumiski - Jzyk JAVA Rozdzia 8

serwera. Naley podkreli, e biblioteki kodw konieczne do tworzenia servletw


(javax.servlet.*) nie stanowi czci standardowej dystrybucji i musz by pobrane
od producenta (SUN) oddzielnie jako standardowe rozszerzenie JDK. Istniej rne
wersje bibliotek kodw servletw (JSDK - Java Servlet Development Kit), ktre s
obecnie wykorzystywane w rnych serwerach: 2.0 (np. jserv - dodatek do serwera
WWW Apache 1.3.x), 2.1, 2.2 (np. tomcat). Przed przystpieniem do tworzenia
serwletw konieczne jest zatem ustalenie wersji biblioteki jakiej naley uy, aby by
zgodnym z obsugiwanym serwerem.

8.3.1 Model obsugi wiadomoci.


Serwlety wykorzystuj model obsugi wiadomoci typu danie odpowied
(request response). W modelu tym klient wysya wiadomo zawierajc danie
usugi, natomiast serwer wykonuje usug i przesya do klienta dane informacje.
Model taki jest zwizany z wikszoci popularnych protokow komunikacyjnych jak
FTP czy HTTP, std serwlety mona teoretycznie stworzy dla rnych typw usug.
Dziaajcy serwer komunikuje si z serwletem (stanowicym cz procesu serwera)
w oparciu o trzy podstawowe metody zadeklarowane w interfejsie
javax.servlet.Server:
-

init(),
service()
destroy()

Rol i moment wywoania tych metod ukazuje nastpujca sekwencja zada


wykonywana w czasie uruchamiania serwleta:
a.) serwer aduje kod poredni serwletu,
b.) serwer wywouje obiekt zaadowanego kodu,
c.) serwer woa metod init() serwletu, ktra umoliwia wszelkie wymagane przez
serwlet ustawienia. Metoda ta stanowi odpowiednik metody init() apletu, oraz z
funkcjonalnego punktu widzenia odpowiada rwnie konstruktorowi klasy obiektu.
d.) serwer na podstawie danych dostarczonych przez klienta usugi tworzy obiekt
dania (request object), implementujcy interfejs ServletRequest,
e.) serwer tworzy obiekt odpowiedzi (response object) implementujcy interfejs
ServletResponse,
f.) serwer woa metod serwletu service(), ktra realizuje zadania (usugi) stworzone
przez programist,
g.) metoda service() przetwarza obiekt dania i korzystajc z metod obiektu
odpowiedzi wysya okrelon informacj do klienta,
h.) jeeli serwer nie potrzebuje serwletu woa jego metod destroy(), ktrej obsuga
umoliwia zwolnienie zasobw (jak np. zamknicie plikw, zamknicie dostpu do
bazy danych, itp.).
Model obsugi serwletu jest wic bardzo prosty. Interfejs javax.servlet.Servlet
wymaga oczywicie penej definicji wszystkich metod std tworzc kody klas
serwletw nie korzysta si bezporednio z implementacji tego interfejsu lecz
dziedziczy si po klasach interfejs ten implementujcych. Do klas tych naley
zaliczy klasy:

8-21

Jacek Rumiski - Jzyk JAVA Rozdzia 8

GenericServlet
HttpServlet
definiowane kolejno w dwch dostpnych pakietach JSDK API:
javax.servlet
javax.servlet.http.
Korzystajc z przedstawionego modelu mona skonstruowa pierwszy przykad
serwletu:
Przykad 8.11:
//WitajcieServlet.java:
import javax.servlet.*;
import java.io.*;
public class WitajcieServlet extends GenericServlet{
static String witajcie= "Witajcie ! Jestem serwletem!\n";
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
response.setContentLength(witajcie.length());
response.setContentType("text/plain");
PrintWriter pw=response.getWriter());
pw.print(witajcie);
pw.close();
}
}// koniec public class WitajcieServlet

Powyszy przykad definiuje now klas WitajcieServlet, ktra dziedziczy po


GenericServlet, czyli automatycznie implementuje interfejs javax.servlet.Servlet. W
ciele klasy serwletu zdefiniowana jedn metod (przepisano metod service() klasy
GenericServlet) service(), ktra na podstawie pobranych argumentw bdcych
obiektami dania i odpowiedzi, wykonuje okrelon usug i przesya informacje do
klienta. W przypadku omawianej metody usuga polega na przesaniu wiadomoci o
okrelonym rozmiarze (setContentLength()), typie (setContentType()) i treci
(print(witajcie)) do klienta. Zdefiniowana klasa serwletu korzysta z domylnych
definicji metod init() oraz destroy() wystpujcych w klasie rodzica (GenericServlet).

8.3.2 rodowisko wykonywania serwletw:


W celu uruchomienia serwletu naley go najpierw skompilowa do czego
wymagana jest oczywicie platforma Javy oraz dodatkowo pakiety kodw serwletw
(JSDK). Biblioteki JSDK naley zainstalowa, tak aby byy widoczne dla kompilatora
Javy (np. zawrze pakiety kodw serwletw w ustawieniach CLASSPATH lub
przegra archiwum *.jar servletw do katalogu ext stanowicego cz biblioteki
(lib) maszyny wirtualnej (jre). Udana kompilacja kodu umoliwia jego wywoanie.
Uruchomienie serwletu wymaga jednak odpowiedniego serwera zdolnego do
8-22

Jacek Rumiski - Jzyk JAVA Rozdzia 8

prowadzenia dialogu z serwletem. Moliwe tutaj s rne rozwizania. Najprostszym


z nich jest zastosowaniem dostarczanego w ramach JSDK prostego programu
servletrunner (odpowiednik funkcjonalny programu appletviewer dla apletw). Ten
prosty serwer umoliwia okrelenie podstawowych parametrw przy jego wywoaniu
jak numer portu, katalog serwletw itp. Standardowa konfiguracja serwera wyglda
nastpujco:
./servletrunner -v
servletrunner starting with settings:
port = 8080
backlog = 50
max handlers = 100
timeout = 5000
servlet dir = ./examples
document dir = ./examples
servlet propfile = ./examples/servlet.properties
Bardzo wanym elementem konfiguracji programu servletrunner jest pliku
waciwoci serwletw: servlet.properties. Wymagane jest aby w pliku tym podana
zostaa nazwa servletu reprezentujc plik jego klasy, np.:
//servlet.properties:
# Servlets Properties
#
# servlet.<name>.code=class name (foo or foo.class)
# servlet.<name>.initArgs=comma-delimited list of {name, value} pairs
#
that can be accessed by the servlet using the
#
servlet API calls
#
# Witajcie servlet
servlet.witajcie.code=WitajcieServlet
Tak przygotowany plik ustawie wasnoci serwletu oraz uruchomienie programu
servletrunner umoliwia wywoanie servletu, np.:
lynx medvis.eti.pg.gda.pl:8080/servlet/witajcie
albo
http://medvis.eti.pg.gda.pl:8080/servlet/witajcie
W konsoli serwera (servletrunner) pojawi si wwczas komunikat:
WitajcieServlet: init
oznaczajcy wywoanie metody init() serwletu przez serwer.
Warto zwrci uwag, e przy wywoaniu serwletu pojawi si w ciece dostpu
katalog o nazwie servlet. Jest to katalog logiczny, definiowany w ustawieniach
serwera (w powyszym przykadzie katalog logiczny servlet to katalog fizyczny

8-23

Jacek Rumiski - Jzyk JAVA Rozdzia 8

examples). W wyniku poprawnego dziaania serwletu klient uzyska wywietlon


nastpujc informacj:
Witajcie ! Jestem serwletem!
Wad wykorzystania programu servletrunner jest konieczno jego powtrnego
wywoywania w przypadku zmiany kodu serwletu. Na rynku dostpne s obecnie
rne wersje serwerw, gwnie WWW, obsugujcych serwlety. Do najbardziej
jednak popularnych naley zaliczy rozszerzenie serwerw WWW opracowanych w
ramach projektu Apache ApacheJServ oraz nowy serwer obsugujcy servlety oraz
Java Server Pages (dynamiczna konstrukcja stron WWW). Podstawowa rnica
pomidzy tymi produktami jest taka, e pierwszy z nich jest dodatkiem do serwera
WWW obsugujcym kody serwletw zgodne ze specyfikacj 2.0, natomiast drugi
jest referencyjn implementacj specyfikacji serwletw 2.2 pracujc jako
samodzielny serwer WWW.
Odwoanie do rodowiska wywoania serwletu moe nastpowa poprzez wykonanie
metod zdefiniowanych dla klasy ServletContext. W czasie inicjowania serwletu (init())
informacje rodowiska podawane s w ramach obiektu ServletConfig. Odwoanie si
do tego obiektu poprzez metod getServletContext() w czasie wykonywania serwletu
(service()) zwraca obiekt klasy ServletContext. W ten sposb mona wywoa na nim
szereg metod uzyskujc cenne czsto informacje o rodowisku pracy. Poniszy
przykad demonstruje wykorzystanie metody getServerInfo() obiektu klasy
ServletContext w celu uzyskania informacji o nazwie serwera servletw i jego wersji.
Przykad 8.12:
//SerwerServlet.java:
import javax.servlet.*;
import java.io.*;
public class SerwerServlet extends GenericServlet{
static String witajcie= "Jestem serwletem! Dzia\u0142am na:\n";
private ServletConfig ustawienia;
public void init(ServletConfig cfg){
ustawienia=cfg;
}
public void service(ServletRequest request, ServletResponse response) throws ServletException,
IOException {
String wiad=witajcie+"";
ServletContext sc = ustawienia.getServletContext();
wiad+=sc.getServerInfo();
response.setContentLength(wiad.length());
response.setContentType("text/plain; charset=iso-8859-2");
PrintWriter pw=response.getWriter();
pw.print(wiad);
pw.close();
}
}// koniec public class SerwerServlet

8-24

Jacek Rumiski - Jzyk JAVA Rozdzia 8

Efektem dziaania powyszego serwletu moe by komunikat:


Jestem serwletem! Dziaam na:
servletrunner/2.0
lub np.:
Jestem serwletem! Dziaam na:
Tomcat Web Server/3.1 (JSP 1.1; Servlet 2.2; Java 1.2; SunOS 5.5.1 sparc;
java.vendor=Sun Microsystems Inc.)

8.3.3 Kontrola rodowiska wymiany wiadomoci


W modelu wymiany wiadomoci typu danie-odpowied wan rol peni
dostp do informacji konfiguracyjnych wystpujcych w daniu oraz moliwo
ustawie podobnych informacji dla odpowiedzi. W przypadku serwletw funkcje te
moliwe s poprzez obsug obiektw podawanych jako argumenty w gwnych
metodach usug serwletu. W przypadku pakietu javax.servlet.* obiekty te posiadaj
interfejs odpowiednio o nazwach: ServletRequest (dane dania) i ServletResponse
(dane odpowiedzi). Dla pakietu javax.servlet.http.*, w ktrym zdefiniowano klasy i
metody obsugi protokou HTTP przez servlety, wystpujc interfejsy dziedziczce po
powyszych: HttpServletRequest i HttpServletResponse. Obiekty obu typw
posiadaj do dyspozycji szereg metod umoliwiajcych dostp do parametrw
wywoania, ustawie konfiguracyjnych i innych. Przykadowe metody obiektw typu
*Request to:
getCharacterEncoding() pobranie informacji o stronie kodowej
getContentLength() pobranie informacji o rozmiarze wiadomoci
getContentType() pobranie informacji o typie (MIME) wiadomoci
getParameter(java.lang.String name) pobranie wartoci parametru o danej nazwie
getProtocol() pobranie informacji o protokole komunikacji
getRemoteAddr() pobranie informacji o adresie komputera zdalnego,
getReader() utworzenie obiektu strumienia do odczytu (znakw)
getInputStream() utworzenie obiektu strumienia do odczytu (bajtw)
Przykadowe metody obiektw typu *Response to:
getCharacterEncoding() pobranie informacji o aktualnej stronie kodowej,
getOutputStream()-utworzenie obiektu strumienia do zapisu (bajtw)
getWriter() utworzenie obiektu strumienia do zapisu (znakw)
setContentLength(int len) ustawienie rozmiaru wiadomoci
setContentType(java.lang.String type) ustawienie typu (MIME) wiadomoci.
Niektre z powyszych metod stosowane byy we wczeniejszych przykadach. Inn
ilustracj metod obiektw typu *Request i *Response moe by nastpujcy
program:
Przykad 8.13:

8-25

Jacek Rumiski - Jzyk JAVA Rozdzia 8

//KlientServlet.java:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class KlientServlet extends HttpServlet {
static String wiad = "Oto nag\u0142\u00F3wki: \n";;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException{
String nazwa, wartosc, nag="";
response.setContentType("text/plain; charset=iso-8859-2");
// dla wersji nowszej od JSDK 2.0 mona ustali lokalizacje:
//response.setLocale(new Locale("pl","PL"));
PrintWriter pw = response.getWriter();
Enumeration e = request.getHeaderNames();
while (e.hasMoreElements()) {
nazwa = (String)e.nextElement();
wartosc = request.getHeader(nazwa);
nag+=(nazwa + " = " + wartosc+"\n");
}
pw.print(wiad+nag);
pw.close();
}
}// koniec public class KlientServlet

Powyszy serwlet jest zdefiniowany dla klasy typu HttpServlet definiujcej szereg
metod obsugujcych protok HTTP. Jedn z usug tego protokou jest pobranie
nagwka i danych GET. Obsuga tej usugi jest moliwa poprzez zastosowanie
metody doGet(), do ktrej s przekazywane obiekty typu HttpServletRequest i
HttpServletResponse. Poniewa wraz z przesyaniem wiadomoci w HTTP przesya
si rwnie nagwek zawierajcy informacje sterujce mona te informacje pobra i
wywietli. Omawiany program pobiera zestaw informacji konfiguracyjnych
pochodzcych
z
nagwkw
wygenerowanych
przez
klienta
usugi
(request.getHeaderNames()). Pobrane informacje s formatowane w postaci
tekstowej zgodnie ze stron kodow iso-8859-2 i s przesyane jako tre informacji
do klienta (respone). W wyniku dziaania tego serwletu klient moe obserwowa w
swojej przegldarce nastpujcy efekt:
Oto nagwki:
Connection = Keep-Alive
User-Agent = Mozilla/4.6 [en-gb] (WinNT; I)
Host = med16:8080
Accept = image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding = gzip
Accept-Language = en-GB,en,en-*
Accept-Charset = iso-8859-1,*,utf-8

8-26

Jacek Rumiski - Jzyk JAVA Rozdzia 8

8.3.4 Metody wywoywania serwletw.


Serwlety mog by rwnie (o ile umoliwia to serwer np. Java Web
ServerTM) wywoywane z kodu HTML poprzez zastosowanie mechanizmu SSI
(Serwer-Side Include). Technika opisu serwletu w kodzie HTML jest podobna do
opisu apletu. W najprostszej formie opis ten moe wyglda nastpujco:
<servlet name=witajcie code=WitajcieServlet NAZWA_1=WARTOSC_1 ...
NAZWA_n=WARTOSC_n>
<PARAM NAME=nazwa_1 value=wartosc_1>
.
.
.
<PARAM NAME=nazwa_n value=wartosc_n>
</servlet>
W przedstawionym opisie wykorzystano znacznik <servlet> do oznaczenia
zawartego w kodzie HTML wywoania serwletu. W obrbie znacznika zastosowano
szereg atrybutw jak:
name nazwa servletu
code nazwa pliku kodu serwletu
NAZWA_1, WARTOSC_1 pary parametrw wywoania serwletu.
Parametry wywoania serwletu mog by pobrane przez serwlet poprzez uycie
metod klas GenericServlet i HttpServlet jak np. getInitParameter(java.lang.String
name) dostarczajc warto parametru o podanej nazwie. W obrbie znacznika
<servlet> mona zastosowa inne znaczniki takie jak <PARAM NAME>
umoliwiajce zdefiniowanie parametrw dostpnych przez serwlet za pomoc
metod obiektw dania jak np. getParameter(java.lang.String name).
Przykad 8.14:
//LicznikServlet.java:
import javax.servlet.*;
import java.io.*;
import java.util.*;
public class LicznikServlet extends GenericServlet{
static Date pocz = new Date();
static int licznik=0;
public void service(ServletRequest request, ServletResponse response) throws ServletException,
IOException {
int licz_tmp;
response.setContentType("text/plain; charset=iso-8859-2");
PrintWriter pw=response.getWriter();
synchronized(this){
licz_tmp=licznik++;
}
8-27

Jacek Rumiski - Jzyk JAVA Rozdzia 8

pw.print("Liczba odwiedzin strony od "+pocz+" wynosi: "+licz_tmp);


pw.close();

}// koniec public class LicznikServlet


//serwlety.shtml:
<html>
<head>
<title> Serwlety: wywoanie serwletu za pomoc znacznikw w kodzie HTML</title>
</head>
<body>
<H1>Strona demonstracyjna</H1>
<H2>Pokaz wywoania serwletu za pomoc znacznikw z kodu HTML</H2>
<servlet name="LicznikServlet" code="LicznikServlet">
</servlet>
</body>
</html>

Niestety zastosowanie tego typu jest ograniczone poniewa tylko niektre serwery je
umoliwiaj (Java Web ServerTM). Stosowanie dynamicznej kompozycji stron w
obrbie kodu HTML jest obecnie realizowane poprzez technologi Java Server
Pages (JSP).

8.3.5 Obsuga protokou HTTP pakiet javax.servlet.http.*


Protok HTTP jest jednym z najbardziej popularnych ze wzgldu na obsug
WWW. Dlatego trudno si dziwi, e opracowano pakiet klas (javax.servlet.http.*)
umoliwiajcy obsug usug tego protokou w ramach serwletw. Wyrnia si
nastpujce usugi (metody) protokou HTTP:
-

HEAD danie informacji od serwera w formie danych nagwka


GET- danie informacji od serwera w formie danych nagwka i treci (np. pliku),
wystpuje ograniczenie rozmiaru danych do przesania (kilkaset bajtw)
POST danie umoliwiajce przesanie danych od klienta do serwera
PUT danie umoliwiajce przesanie przez klienta pliku do serwera (analogia
do ftp)
DELETE danie usunicia dokumentu z serwera
TRACE danie zwrotnego przesania nagwkw wiadomoci do klienta
(testowanie)
OPTIONS danie od serwera identyfikacji obsugiwanych metod, informacja o
ktrych jest przesyana zwrotnie w nagwku
Inne.

W celu obsugi powyszych usug stworzono zestaw metod dostpnych poprzez


klas javax.servlet.http.HttpServlet dziedziczc po javax.servlet.Servlet, a
mianowicie:
doGet() dla da HEAD i GET
doPost() dla dania POST
8-28

Jacek Rumiski - Jzyk JAVA Rozdzia 8

doPut() dla dania PUT


doDelete() dla dania DELETE
doTrace() dla dania TRACE
doOptions() dla dania OPTIONS.
Kada z wymienionych metoda jest zadeklarowana jako chroniona (protected).
Jedyn metod dostpn (public) jest metoda service() poprzez ktr przechodz
wysyane przez klienta dania i s kierowane do obsugi w ramach wyej
pokazanych metod doXXX(). Najprostsz realizacj usugi na danie ze strony
klienta jest dynamiczne stworzenie strony HTML, ktr odczytuje klient.
Przykad 8.15:
//StronaServlet.java:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class StronaServlet extends HttpServlet {
static String tytul = "Strona g\u0142\u00F3wna serwisu nauki JAVY \n";
String dane="";
public void init(ServletConfig config){
dane=config.getServletContext().getServerInfo();
}
public String naglowek(String tytul){
String nag="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//PL\">"
+ "<HTML>"
+ "<HEAD>"
+ " <TITLE>" + tytul + "</TITLE>"
+" <META NAME=\"Autor\" CONTENT=\"Jacek Rumi\u0144ski\">"
+ " <META NAME=\"Serwer\" CONTENT=\"" + dane + "\">"
+ "</HEAD>";
return nag;
}
public String stopka(){
String stop ="</BODY>"+ "</HTML>";
return stop;
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException{
Date data = new Date();
response.setContentType("text/html; charset=iso-8859-2");
PrintWriter pw = response.getWriter();
String wiad=naglowek(tytul);
wiad=wiad + "<BODY BGCOLOR=\"#C0C0FF\">"
+ " <CENTER>"
+ " <H1>" + tytul + "</H1>"
+ " <H2>Witamy na stronie kursu Javy!</H2>"
8-29

Jacek Rumiski - Jzyk JAVA Rozdzia 8

+ " <H3>[ Czas: <font color='#FFFFC0'>" + data + "</font> ]</H3>"


+ " <FONT SIZE=\"-2\">Zapraszam na:"
+ " <A HREF=\"http://biont.eti.pg.gda.pl/java.htm\">J\u0119zyk JAVA</a><br>"
+ " </FONT>"
+ " </CENTER>";
wiad+=stopka();

pw.print(wiad);
pw.close();

}// koniec public class StronaServlet

W wyniku dziaania
(sformatowany) tekst:

powyszego

programu

mona

uzyska

nastpujcy

Strona gwna serwisu nauki JAVY


Witamy na stronie kursu Javy!
[ Czas: Tue May 09 16:35:13 GMT+02:00 2000 ]
Zapraszam na: Jzyk JAVA
Rozwaajc konstruowanie dynamicznych stron HTML w oparciu o serwlety
konieczne jest przedstawienie czenia ich z formularzami.
Przykad 8.16:
//OgloszenieServlet.java
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class OgloszenieServlet extends HttpServlet {
static String tytul = "Strona testowa serwisu nauki JAVY \n";
String dane="";
public void init(ServletConfig config){
dane=config.getServletContext().getServerInfo();
}
public String naglowek(String tytul){
String nag="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 //PL\">"
+ "<HTML>"
+ "<HEAD>"
+ " <TITLE>" + tytul + "</TITLE>"
+ " <META NAME=\"Autor\" CONTENT=\"Jacek Rumi\u0144ski\">"
+ " <META NAME=\"Serwer\" CONTENT=\"" + dane + "\">"
+ "</HEAD>";
return nag;
}
public String stopka(){
8-30

Jacek Rumiski - Jzyk JAVA Rozdzia 8

String stop ="</BODY>"+ "</HTML>";


return stop;

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException,


ServletException{
Date data = new Date();
response.setContentType("text/html; charset=iso-8859-2");
PrintWriter pw = response.getWriter();
String wiad=naglowek(tytul);
wiad=wiad + "<BODY BGCOLOR=\"#C0C0FF\">"
+ " <CENTER>"
+ " <H1>" + tytul + "</H1>"
+ " <H2>[ Lokalny czas to: <font color='#FFFFC0'>" + data + "</font> ]</H2>"
+ " <H3>Mi\u0142o jest mi zakomunikowa\u0107, \u017Ce:</H3>"
+ " <BR><FONT SIZE=\"+2\">" + (String)request.getParameter("nazwisko")
+ " to "+ (String)request.getParameter("opinia")
+ " </FONT><BR>"
+ " <FONT SIZE=\"-2\">Zapraszam na:"
+ " <A HREF=\"http://biont.eti.pg.gda.pl/java.htm\">J\u0119zyk JAVA</a><br>"
+ " </FONT>"
+ " </CENTER>";
wiad+=stopka();

pw.print(wiad);
pw.close();

}// koniec public class OgloszenieServlet


//formularz.html:
<html>
<head>
<title> Serwlety: wywoanie serwletu dla formularza w kodzie HTML</title>
</head>
<body>
<H1>Strona demonstracyjna</H1>
<H2>Pokaz wywoania serwletu dla formularza w kodzie HTML</H2>
<form action="/servlet/OgloszenieServlet" method="get">
<p> Wykadowaca
<select name="nazwisko">
<option value="Kowalski" selected>Kowalski</option>
<option value="Nowak" selected>Nowak</option>
<option value="Misiak" selected>Misiak</option>
</select>
to:
<input type="text" name="opinia">
</p>
<p>
<input type="submit" name="publikuj" value="Publikuj">
</p>
</form>
</body>

8-31

Jacek Rumiski - Jzyk JAVA Rozdzia 8

</html>

W wyniku podania parametrw w formularzu moliwe jest wygenerowanie


nastpujcej strony:
Strona testowa serwisu nauki JAVY
[ Lokalny czas to: Wed May 10 11:38:08 CEST 2000 ]
Mio jest mi zakomunikowa, e:
Nowak to dobry nauczyciel
Zapraszam na: Jzyk JAVA
W prezentowanym przykadzie zastosowano formularz w kodzie HTML zawierajcy:
- pole wyboru o nazwie nazwisko umoliwiajce wybr jednego z trzech nazwisk
- pole tekstowe o nazwie opinia umoliwiajce wpisanie dowolnego tekstu opinii o
wykadowcy
- pole wykonania operacji o nazwie publikuj wywoujce zadan akcj, w tym
przypadku danie GET obsugiwane przez /servlet/OgloszenieServlet.
W obsudze dania GET realizowanego przez serwlet pobierane s informacje o
wartociach kolejnych dwch parametrw:
(String)request.getParameter("nazwisko")
(String)request.getParameter("opinia")
ktre s wywietlane w ramach tworzonej strony HTML.
Oczywicie wywoanie serwletu jako programu obsugujcego okreon operacj
moe pochodzi z innych rde, np. z apletu. atwo mona rwnie stworzy serwlet
obsugujcy baz danych dla potrzeb serwisu WWW (inicjowanie poczenia w
metodzie init() serwletu; polecenia SQL w ramach formularza lub apletu; zamknicie
poczenia w ramach metody destroy()) czc go dodatkowo ze zdalnym
wykonywaniem metod (na serwerze aplikacji obsugujcej baz danych) poprzez
RMI.

8.3.6 Bezpieczestwo serwletw


Serwlety maj dostp do informacji o kliencie i protokole, natomiast informacje
i dostp do sieci oraz plikw maj takie na ile umoliwia im do system
bezpieczestwa (Security Manager). Dziaalno systemu bezpieczestwa w
stosunku do servletw jest analogiczna jak dla apletw, co jest omwione w ostatnim
rozdziale tego podrcznika. Warto jednak wspomnie, e wprawdzie uprawnione
serwlety nie spowoduj bdw dostpu do pamici (co jest cech programw w
Javie) lecz mog wywoa polecenie System.exit(), co moe prowadzi do
zakoczenia pracy serwera. Innym elementem zabezpieczania serwera przez
niewaciwym dziaaniem niektrych serwletw jest stosowanie list dostpu (ACL
access code lists) wskazujcych kto i co moe na danym serwerze wywoa
(uruchomi). Mona w ten sposb ograniczy wykonywanie niektrych serwletw.

8-32

Jacek Rumiski - Jzyk JAVA Rozdzia 8

8.4 Zdalne wywoywanie metod - RMI


Programowanie sieciowe skupia si zazwyczaj na tworzeniu aplikacji w dwch
zasadniczych grupach:
- aplikacji wymiany plikw (np. obsuga protokow FTP, HTTP, NFS, SMTP)
- aplikacji wywoywanych i wykonywanych zdalnie (np. obsuga baz danych, telnet,
RPC, CGI).
Zdalne wykonywanie zada jest istotnym elementem w rozwizywaniu zada
poprzez programy dziaajce rwnolegle (oddzielne procesy na oddzielnych
procesorach) w rodowisku rozproszonym (oddzielne procesory s elementami
rnych maszyn wsppracujcych ze sob poprzez sie komputerow). Oczywicie
przetwarzanie zada z wykorzystaniem zdalnych procedur nie musi mie charakteru
przetwarzania rwnolegego, lecz moe wystpowa jedynie w formie rozproszonej
(rne zadania s kolejno wykonywane przez rne jednostki). Oglnie zdalne
wykonywanie zada polega:
- wysaniu przez klienta dania wykonania procedury (wraz z podaniem
odpowiednich argumentw) do serwera aplikacji,
- wykonaniu procedury przez serwer,
- przesanie przez serwer wyniku dziaania procedury do klienta
- wykorzystanie przez klienta otrzymanego wyniku dziaania zdalnej procedury do
dalszych zada.
Jednym z pierwszych rozwiza tego typu bya opracowana przez Suna technologia
zwana RPC Remote Procedure Call (zdalne wywoywanie procedur). W RPC
zastosowano podejcie strukturalne (niezalene procedury) z jednoczesn realizacj
da niezalen od jzyka programowania i od typu platformy. Uniwersalno RPC
wymaga jednak realizacji wielu dodatkowych zada jak np. konwersja typw danych
(rne rozmiary liczb cakowitych) argumentw; konwersja reprezentacji typw
danych (rny zapis liczb cakowitych little endian, big endian). Poniewa RPC
stosuje podejcie strukturalne nie mona przesa jako argumentw zoonych typw
danych takich jak dla klas obiektw. Ze wzgldu na wymienione wady oraz ze
wzgldu na powstanie nowej platformy Javy, Sun stworzy kolejn technologi
zdalnego wywoywania procedur o nazwie RMI Remote Method Invocation (zdalne
wywoywanie metod). Poniewa RMI stosuje podejcie obiektowe zmieniono w
nazwie technologii sowo procedura (procedure) na metoda (method) wskazujc w
ten sposb na moliwo zdalnego wykonywania zada przypisanych dla obiektu.
RMI stanowi wic dobre rozwizanie do zdalnego wykonywania zada realizowanych
w Javie pomidzy platformami rnego typu. RMI ogranicza si zatem jedynie do
metod tworzonych w Javie.

8.4.1 Typy obiektw i relacje pomidzy nimi w RMI


W zdalnych wykonywaniu zada wyrnia si dwa typy obiektw: obiekty
lokalne (klient) i obiekty zdalne (serwer). Kady obiekt zdalny musi implementowa
specjalny interfejs, okrelajcy wszystkie metody moliwe do wykonywania przez
klienta. Interfejs te musi dziedziczy po zdefiniowanym w API interfejsie Remote.
Interfejs Remote ma charakter znacznika zbioru metod zdalnych (podobnie jak
interfejs Serializable okrela obiekty, ktre mog podlega utrwalaniu np. poprzez
zapis lub wymian przez sie). Oprogramowanie lokalne (klienta) moe wywoywa
8-33

Jacek Rumiski - Jzyk JAVA Rozdzia 8

metody obiektu zdalnego tak, jakby byy to metody lokalne. Mechanizm ten jest wic
bardzo wygodny dla programisty. Pojawia si jednak pewien problem. Ot jeli
obiekt jest przekazywany (argument) lub zwracany przez metod zwracana jest w
rzeczywistoci referencja realizowana jako wskanik do pamici organizowanej przez
dan maszyn wirtualn. Wymiana obiektw, a wic referencji pomidzy dwoma
maszynami wirtualnymi przysparza pewien problem: referencja obiektu A, np. 12345
w danej maszynie wirtualnej nie wskazuje tego samego obiektu na innej maszynie
wirtualnej. Rozwizanie tego problemu moe by wykonane na dwa sposoby. Po
pierwsze mona przekaza zdaln referencj obiektu wskazujc na pami zdalnej
maszyny wirtualnej. Oznacza to, e jeeli klient przekazuje jako argument obiekt
zdalny (realizowany na maszynie zdalnej) to w rzeczywistoci przekazuje jego zdaln
referencj czyli zdalny obiekt nigdy nie opuszcza swojej maszyny wirtualnej. Jeeli,
co stanowi drugie rozwizanie, natomiast klient przekazuje swj obiekt w wywoaniu
metody zdalnej tworzy jego kopi, ktra jest przesyana. W celu przesania kopii
obiektu lokalnego konieczna jest jego konwersja do takiej formy zbioru bajtw, aby
bya odtwarzalna po stronie serwera aplikacji. Konieczne jest zatem, dostpne w
Javie, zastosowanie mechanizmu serializacji (klasy obiektw musz implementowa
interfejs Serializable). Prawie wszystkie obiekty mog by w ten sposb podlega
konwersji, z wyjtkiem tych, ktre maj charakter lokalny (np. odnosz si do plikw
lokalnych). Przesyanie obiektw poprzez ich kopie wykonywane jest rwnie dla tych
obiektw po stronie serwera aplikacji (zdalnej), ktre nie implementuj interfejsu
Remote, czyli s obiektami lokalnymi serwera lecz nie stanowi w wietle RMI
obiektw zdalnych. Podsumowujc, moliwe s nastpujce formy przekazywania
argumentw i wynikw dziaania metod:
- przez warto: w komunikacji dwustronnej poprzez warto przekazywane s
proste typy danych jak: int, boolean, iitp),
- przez referencj zdaln: w komunikacji klient -> serwer przekazywana jest zdalna
referencja zdalnego obiektu,
- przez kopi: - czyli rwnie przez warto w komunikacji dwustronnej poprzez
kopie przekazywane s obiekty inne ni zdalne (tzn. te dziedziczce po interfejsie
Remote).

8.4.2 Komunikacja w procesie zdalnego wykonywania metod.


W celu analizy procesu komunikacji pomidzy klientem a serwerem aplikacji
posumy si modelem zaprezentowanym na rysunku:

Rysunek 8.1. Model warstwowy procesu komunikacji w RMI


Z prezentowanego modelu wida, e logicznie oprogramowanie klienta pracuje tak,
jakby byo bezporednio powizane z programami serwera. W rzeczywistoci

8-34

Jacek Rumiski - Jzyk JAVA Rozdzia 8

komunikacja jest bardziej zoona. Klient wywoujc metody zdalne uywa


specjalnego obiektu stub bdcego odpowiednikiem, lokalnym reprezentantem
obiektu zdalnego. Stub implementuje interfejs obiektu zdalnego dziki czemu
posiada peen opis (sygnatury) metod tego obiektu. Obiekt stub stanowi wic
namiastk (stub jest czsto tumaczony przez sowo namiastka) obiektu zdalnego po
stronie lokalnej. Wywoywane przez klienta metody zdalne s bezporednio
odnoszone do obiektu stub, a nie do obiektu zdalnego. Stub przekazuje dalej
wywoanie do warstwy zdalnych referencji. Gwnym zadaniem tej warstwy jest
odniesienie lokalnych referencji obiektu stub do referencji obiektu zdalnego po
stronie serwera. Kolejnym krokiem jest przesanie danych wywoania metody do
warstwy transportowej. Warstwa ta jest odpowiedzialna za przesyanie danych przez
sie i realizuje: ustalanie pocze, ledzenie obiektw zdalnych, zarzdzanie
poczeniem, itp. Po stronie serwera warstwa transportowa realizuje nasuch danych
przenoszcych danie wykonania metody zdalnej. Po uzyskaniu referencji obiektu
zdalnego, bdcego teraz obiektem lokalnym serwera dane przekazywane s do
kolejnej warstwy o nazwie skeleton. Skeleton (namiastka) jest odpowiednikiem stub
a po stronie klienta. Warstwa ta odpowiada za przypisanie do wywoywanych metod
przez stub ich implementacji realizowanych w oprogramowaniu serwera. Po
wykonaniu zadania przez serwer ewentualne wyniki mog by zwrotnie
transportowane do klienta (jako: wartoci, kopie obiektw lub obiekty zdalne).
Zgodnie z zaprezentowanym modelem wan rol w procesie wymiany parametrw
odgrywaj warstwy stub oraz skeleton. Nazwy stub oraz skeleton s tu przyjte z
technologii RPC. Warstwy porednicz i steruj procesem wykonywania zdalnych
procedur. Jakkolwiek w wersjach Javy od JDK1.2 nie jest ju wymagana oddzielna
realizacja (poza oprogramowaniem serwera) warstwy skeleton. Fizyczna realizacja
oprogramowania warstw stuba i skeletonu powstaje w wyniku generacji dla nich
kodu poredniego Javy na podstawie klasy obiektu zdalnego. Generacja ta
wykonywana jest za pomoc dodatkowego kompilatora o nazwie rmic (RMI
compiler).
Powysze rozwaania nie uwzgldniaj problemu adresowania zdalnego serwera
aplikacji. Moliwe jest przecie, e w sieci istnie bd tysice komputerw
serwujcych setki obiektw zdalnych (ich metod) kady. Jak zatem zaadresowa po
stronie klienta konkretny obiekt zdalny na konkretnym serwerze? Ot w tym celu
tworzony jest mechanizm rejestracji obiektw zdalnych. RMI wykorzystuje w tym celu
interfejs java.rmi.registry.Registry oraz klas java.rmi.registry.LocateRegistry do
obsugi (rejestracja obiektw i przeszukiwanie rejestru) rejestru obiektw zdalnych
poprzez przypisane im nazwy. Rejestr peni zatem rol prostej bazy danych wicej
ze sob nazwy obiektw z ich realizacj. Przykadow realizacj rejestru
(implementujca interfejs Registry) jest program dostarczany przez Suna
rmiregistry, ktry po wywoaniu pracuje na danym komputerze na domylnym porcie
dla RMI zdefiniowanym w interfejsie Registry:
public static final int REGISTRY_PORT = 1099.
Oczywicie mona poda jako argument do programu rmiregistry inny numer portu,
naley jednak pamita o konsekwencjach tego posunicia, czyli o waciwym
adresowaniu rejestru z poziomu programw go uytkujcych. Lokalizacja rejestru jest
obsugiwana przez metody klasy LocateRegistry. Uytkowanie rejestru odbywa si
poprzez zastosowanie metod klasy java.rmi.Naming. Metody tej klasy wykonujc

8-35

Jacek Rumiski - Jzyk JAVA Rozdzia 8

operacje na rejestrze odwoujc si porednio przy pobieraniu referencji do rejestru


do metody getRegistry() klasy LocateRegistry. Wystpujce w klasie Naming metody
s realizacj deklarowanych w interfejsie Registry metod, przeznaczon do obsugi
adresw podawanych w formie URL:
-

lookup() zwraca obiekt zdalny zwizany z podan nazw,


bind() wie obiekt zdalny z podan nazw jeli podana nazwa ju wystpuje
zwracany jest wyjtek klasy, AlreadyBoundExcepton,
rebind() wie obiekt zdalny z podan nazw jeli podana nazwa ju
wystpuje przypisany do niej obiekt jest zastpowany nowym,
unbind() usuwa powizanie nazwy z obiektem zdalnym w rejestrze,
list() zwraca list nazw wystpujcych w rejestrze (lista obiektw typu String).

Podawana nazwa przyjmuje format URL:


//host:port/nazwa
gdzie:
host nazwa lub adres komputera gdzie uruchomiony jest rejestr,
port numer portu (domylnie 1099),
nazwa nazwa przyjta dla obiektu zdalnego w rejestrze,
i jest reprezentowana jako obiekt acucha znakw String.
Podsumowujc przeprowadzone rozwaania mona przedstawi uproszczony model
przepywu danych:
1. Serwer rejestruje obiekt zdalny w rejestrze,
2. Klient przeszukuje rejestr w celu uzyskania obiektu zdalnego (lookup()),
3. Klient da przesania klasy stubu obiektu zdalnego (dynamiczne adowanie
klasy RMIClassLoader),
4. Klient poprzez stub zapisuje i transmituje parametry z daniem wykonania
metody obiektu zdalnego
5. Serwer poprzez skeleton realizuje wykonanie metod podawanych przez stub
6. Serwer przesya wynik dziaania metody zdalnej do klienta.

8.4.3 Konstrukcja obiektu zdalnego oprogramowanie serwera.


Tworzc obiekt zdalny naley najpierw zdefiniowa interfejs dziedziczcy po
interfejsie Remote zawierajcy deklaracj wszystkich metod zdalnych. Przykadowo
interfejs taki moe wyglda nastpujco:
Przykad 8.17:
//Srednia.java:
import java.rmi.*;
public interface Srednia extends Remote{
public Double policzSrednia(int i) throws RemoteException;
}
8-36

Jacek Rumiski - Jzyk JAVA Rozdzia 8

Kada metoda zdalna interfejsu musi mie deklaracj wyjtku RemoteException.


Majc zdefiniowany interfejs mona stworzy klas obiektu zdalnego:
Przykad 8.18:
//ObliczeniaSrednia.java:
import java.rmi.*;
import java.rmi.server.*;
import java.net.*;
public class ObliczeniaSrednia extends UnicastRemoteObject implements Srednia{
public ObliczeniaSrednia() throws RemoteException{
super();
}
public Double policzSrednia(int i) throws RemoteException{
double s=0.0;
for (int j=0;j<i;j++){
s=s+(int)j;
}
return (new Double(s/i));
}
public static void main(String args[]){
try{
ObliczeniaSrednia ob = new ObliczeniaSrednia();
Naming.rebind("srednia", ob);
System.out.println("Serwer gotowy");
}catch (RemoteException re){
System.out.println("Wyjtek: "+re);
}catch (MalformedURLException ue){
System.out.println("Wyjtek adresowania: "+ue);
}
}
}// koniec public class ObliczeniaSrednia

W powyszym kodzie zdefiniowano klas ObliczeniaSrednia dla obiektw zdalnych o


definicji metody policzSrednia podanej w interfejsie Srednia. Definiowana klasa
dziedziczy dodatkowo po klasie UnicastRemoteObject. Klasa ta pochodzi z pakietu
java.rmi.server w ktrym zdefiniowano m.in. klasy takie jak:
-

RemoteObject klasa abstrakcyjna dziedziczca po java.lang.Object definiujca


zachowanie obiektw zdalnych na podobiestwo obiektw zwykych
dziedziczcych po java.lang.Object. Wykorzystanie tej klasy jest konieczne
poniewa obiekt zdalny jest definiowany tylko przez te metody podawane w
interfejsie dziedziczcym po Remote. Niezbdne jest wic zdefiniowanie dla
niego metod takich jak np. equals(),
RemoteServer klasa abstrakcyjna dziedziczca po RemoteObject,
umoliwiajca obsug zdalnych referencji, np. eksport obiektw zdalnych,

8-37

Jacek Rumiski - Jzyk JAVA Rozdzia 8

UnicastRemoteObject klasa dziedziczca po RemoteServer, realizujca


zadania klas abstrakcyjnych, z ktrych dziedziczy.

Stosowanie UnicastRemoteObject nie jest konieczne, lecz wwczas trzeba stworzy


wasn implementacj usug przez ni dostarczanych.
W ciele metody gwnej omawianej aplikacji przykadowej zawarto w bloku obsugi
wyjtkw trzy polecenia:
- stworzenie obiektu danej klasy:
ObliczeniaSrednia ob = new ObliczeniaSrednia();
- stworzenie nazwy dla obiektu i jego rejestracja w rejestrze
Naming.rebind(srednia, ob);
- wydruk o gotowoci serwera do pracy
System.out.println(Serwer gotowy);
Tak przygotowany kod mona nastpnie skompilowa:
javac g Srenia.java
javac g ObliczneniaSrednia.java
Po kompilacji kodu konieczne jest stworzenie klasy stubu i ewentualnie skeletonu.
Do tego konieczne jest zastosowanie kompilatora rmic z podaniem jako argumentu
penej nazwy (caej cieki jeli dana lokalizacja nie wystpuje w ustawieniach
zmiennej rodowiska - CLASSPATH) pliku kodu poredniego serwera, np.:
rmic classpath www/classes ObliczeniaSrednia
gdzie:
www/classes to odpowiednie podkatalogi z kodem wykorzystywanych klas i
interfejsw.
W ten sposb wygenerowany zostanie kod klas dla stuba i skeletona:
ObliczeniaSrednia_Stub.class i ObliczeniaSrednia_Skel.class.
Oczywicie ze wzgldu na funkcj oprogramowania klienta kody te musz by
umieszczone w dostpnym sieciowo katalogu.

8.4.4 Oprogramowanie klienta.


Zanim klient bdzie mg wywoa zdaln metod musi pobra obiekt zdalny,
dla ktrego t metod zdefiniowano. Wykonywane jest to poprzez zastosowanie
implementacji metody lookup(), np. w klasie java.rmi.Naming:
Object o = Naming.lookup(rmi://medvis.eti.pg.gda.pl/srednia),
gdzie:
rmi to nazwa protokou komunikacji,
medvis.eti.pg.gda.pl - adres serwera na ktrym pracuje rejestr,
srednia - nazwa przywizana do obiektu zdalnego przez serwer.

8-38

Jacek Rumiski - Jzyk JAVA Rozdzia 8

Uzyskiwana w ten sposb zdalna referencja (stub) wskazuje na obiekt klasy Object,
ktrego typ trzeba rzutowa na typ danego interfejsu obiektu zdalnego:
Srednia s = (Srednia) o;
lub razem:
Srednia s = (Srednia) Naming.lookup(rmi://medvis.eti.pg.gda.pl/srednia).
Uzyskujc w ten sposb referencj obiektu zdalnego mona wywoa zdefiniowan
metod zdaln. Przykadowy program klienta przedstawiono poniej:
Przykad 8.19:
//SredniaKlient.java:
import java.rmi.*;
import java.util.*;
public class SredniaKlient{
public static void main(String args[]){
if (System.getSecurityManager()==null)
System.setSecurityManager(new RMISecurityManager());
try{
Random r = new Random();
int n = r.nextInt(50);
Srednia s = (Srednia) Naming.lookup("rmi://medvis.eti.pg.gda.pl/srednia");
Double d = s.policzSrednia(n);
System.out.println("Srednia z kolejnych"+ n+" wartoci wynosi: "+d);
}catch (Exception e){
System.out.println("Wystpi wyjtek: "+ e);
}

}
}// koniec public class SredniaKlient

Na pocztku metody gwnej aplikacji klienta zawarto test wykrywajcy dziaanie


systemu zarzdzania bezpieczestwem platformy Javy. Dziaanie systemu
bezpieczestwa jest tu konieczne ze wzgldu na okrelenie moliwoci dziaania
adowanego przez klienta kodu. Wszystkie programy uywajce RMI musz uywa
systemu zarzdzania bezpieczestwem inaczej protok RMI nie przekopiuje
wymaganych klas z serwera. Dla RMI stworzono oddzieln klas systemu
zarzdzania bezpieczestwem, ktra prawie w caoci jest identyczna z klas
SecurityManager zmieniajc definicj tylko jednej z metod checkPackageAccess().
Tak przygotowany kod naley skompilowa:
javac g SredniaKlient.java

8-39

Jacek Rumiski - Jzyk JAVA Rozdzia 8

8.4.5 Uruchamianie systemu.


Zanim bdzie mona skorzysta z klienta naley uruchomi rejestr. W tym celu
naley wywoa program rmiregistry bez numeru portu, poniewa w rozpatrywanych
przykadach przyjty zosta port domylny (1099). Dla waciwego dziaania systemu
przed uruchomieniem rejestru naley wyeliminowa z ustawie rodowiska terminala,
w ktrym bdzie wywoywany program rmiregistry, ciek dostpu (CLASSPATH)
do stworzonych wanie klas serwera. Dziki temu moliwe bdzie podanie przy
wywoaniu programu serwera katalogu bazowego wykorzystywanych klas
(CODEBASE). W przeciwnym przypadku widziane przez program rmiregistry klasy
uniemoliwiyby adowanie klas z katalogu podanego w opcji CODEBASE wywoania
programu serwera. Z tego powodu przed mona przed wywoaniem programu
rmiregistry poda polecenie w danym shellu terminala Unixa:
unsetenv CLASSPATH (lub dla Win32 unset CLASSPATH).
Nastpnie mona wywoa program rmiregistry poprzez podane jego nazwy:
rmiregistry
Po uruchomieniu rejestru czas na rozpoczcie pracy przez serwer. Uruchomienie
aplikacji serwera powinno zawiera dodatkowe opcje oznaczajce wasnoci:
CODEBASE - podanie katalogu klas serwera
HOSTNAME podanie nazwy serwera.
Wywoanie programu serwera ma wic posta:
java Djava.rmi.server.codebase=http://medvis.eti.pg.gda.pl/classes/
-Djava.rmi.server.hostname=medvis.eti.pg.gda.pl
ObliczeniaSrednia
co oznacza, e wymagane klasy znajduj si na serwerze medvis.eti.pg.gda.pl w
katalogu classes. W przypadku braku dostpu programisty do gwnego katalogu
serwisu WWW mona klasy umieci w swoim katalogu WWW, np. zalenie od
ustawie serwera WWW: www lub public_html; i wwczas katalog bdzie dostpny
pod adresem: ~username/classes/, gdzie: username to nazwa uytkownika w danym
systemie.
Po uruchomieniu serwera mona oczywicie wywoa klienta, zakadajc e dla
maszyny wirtualnej klienta widziane s klasy interfejsu obiektu zdalnego oraz klasa
klienta:
java SredniaKlient
Przy standardowych ustawieniach rodowiska bezpieczestwa dla maszyny
wirtualnej klienta jako efekt dziaania uruchamianej aplikacji otrzymamy komunikat:
Wystpi wyjtek: java.security.AccessControlException:
(java.net.SocketPermission medvis.eti.pg.gda.pl resolve)

8-40

access

denied

Jacek Rumiski - Jzyk JAVA Rozdzia 8

Jest to zwizane z tym, e dla klienta uruchomiany jest system zarzdzania


bezpieczestwem, ktry sprawdza pliki zasad bezpieczestwa. Standardowo
skonfigurowany plik java.policy nie zawiera waciwych uprawnie dla ustalania
pocze sieciowych (potrzebnych w RMI do wywoania metod i skopiowania stuba).
Informacje na temat ustawie plikw zasad bezpieczestwa podano w ostatnim
rozdziale tego podrcznika. W celu przyzwolenia na wykonywanie pocze na
okrelonych portach konieczne jest nadanie nastpujcych uprawnie:
//moje_policy:
grant {
permission java.net.SocketPermission "*:1024-65535", "connect, accept";
permission java.net.SocketPermission "*:80", "connect";
};
-

ustawienia dla portw 1024-65535 s potrzebne ze wzgldu na port rmi 1099


ustawienia dla portu 80 s potrzebne ze wzgldu na poczenie z miejscem
lokalizacji klas stuba czyli z serwerem WWW dziaajcym na porcie 80, w
rozpatrywanym przypadku jest to medvis.eti.pg.gda.pl.

Uprawnienia te mog by zapisane w pliku np. moje_policy i wwczas wywoanie


programu klienta bdzie nastpujce:
java -Djava.security.policy=moje_policy SredniaKlient
Efektem czego bdzie komunikat o przykadowej nastpujcej treci:
Srednia z kolejnych 34 wartoci wynosi: 16.5

8-41

You might also like