14.12.2000
Tekijä: Teemu Katajisto
Yhteystiedot: Sähköposti teekata@st.jyu.fi
Työn nimi: Java-servletit
Title in English: Java
Servlet
Työ: LuK-tutkielma
Linja: Ohjelmistotekniikka
Teettäjä: Jyväskylän yliopisto, tietotekniikan laitos
Tiivistelmä: LuK-tutkielma kuvaa Java Servlet -tekniikan perusteita. Tutkielmassa käsitellään pääasiassa HTTP-servlettejä sekä niihin liittyen istunnonhallintaa, avusteita ja säikeitä.
Avainsanat: Java, servletti, HTTP-servletti, istunnon hallinta, JSDK
Keywords: Java, servlet, HTTP-servlet, session management, JSDK
Sisällysluettelo
3.2. Servletit vai CGI-tekniikka
4. Servlet API -rajapinnan perusteet
4.3. HTTP-servletin liittymäluokat
4.4. Esimerkki proxy-palvelin -servletistä
4.5. Säikeiden käytöstä servleteissä
5.3. Avusteiden asettaminen Servlet APIn avulla
6.3. Java-servlettejä tukevat WWW-palvelimet
Alun perin WWW-sivut olivat staattisia HTML-dokumentteja, jotka tallennettiin tiedostoihin WWW-palvelimille. Näiden sivujen palauttamaa dataa ei voinut muuttaa tilanteen mukaan. Tämän takia kehitettiin CGI-rajapinta, joka HTML:n lomakkeiden (engl. form) avulla mahdollisti dynaamisten WWW-sivujen luonnin. Tämä mahdollisti interaktiivisten WWW-sovellusten rakentamisen suoraan WWW-palvelinten laajennuksina, jolloin sovelluksia voitiin käyttää suoraan Internet-yhteyden kautta WWW-selaimella.
Verkossa tarjottavien palveluiden, kuten sähköisen kaupankäynnin, kasvaessa myös tekniikoiden on kehityttävä entistä turvallisemmiksi ja luotettavimmiksi. Lisäksi palveluiden tuottajien kannalta olennaisia asioita ovat siirrettävyys ja tehokkuus. Myöhemmin CGI:n rinnalle on kehitetty uusia tekniikoita, joilla pyritään välttämään CGI:n ongelmat, kuten esimerkiksi siirrettävyys. Näistä varsinkin Javan servletit ovat tehokas ja käyttöjärjestelmästä riippumaton tekniikka dynaamisten WWW-sivujen luomiseen.
Tässä tutkielmassa selvitetään servlettien perusteet, tavallisten servlettien ja HTTP-servlettien tekeminen ja asennus sekä mitä servleteillä voi yleensäkin tehdä. Lisäksi kerrotaan lyhyesti servlettien ohjelmoinnin turvallisuusnäkökulmista, säikeistä ja servletin tilan seurannasta.
Luvussa 2 esitellään tutkielmassa käytetyt termit ja lyhenteet. Luku 3 käsittelee servlettien perusteita, ja luvussa 4 perehdytään tarkemmin Java Servlet -rajapinnan luokkiin ja metodeihin. Luvussa 5 kuvataan servlettien istunnon hallinnan menetelmiä. Luvussa 6 tarkastellaan servlettien asennusta ja käyttöönottoa sekä luetellaan servlettejä tukevia palvelimia.
Luvussa esitellään lyhyesti tutkielmassa kätetyt termit ja lyhenteet.
Appletti eli sovelma on pieni Javalla tehty ohjelma, jota voidaan ajaa Javaa tukevilla WWW-selaimilla.
CGI eli Common Gateway Interface on WWW-palvelimen rajapinta, jonka avulla voidaan luoda interaktiivisia WWW-sovelluksia.
HTML eli Hyper Text Markup Language on kieli, jossa HTML-tiedostojen perusteella selaimet muodostavat WWW-sivun.
Java on siirrettävä ja turvallinen olio-ohjelmointikieli.
JDK eli Java Development Kit on kehitysympäristö, joka sisältää välineet Java-ohjelmien tekemiseen, kääntämiseen ja ajamiseen.
JSDK eli Java Servlet Development Kit on kehitysympäristö, jota tarvitaan servlettien tekemiseen ja ajamiseen.
JVM eli Java Virtual Machine on virtuaalikone, joka ajaa Java-ohjelmia.
Servletti eli palvelma on pieni ohjelma, joka on
tehty Javalla laajentamaan palvelimen toiminnallisuutta. Servletit ajetaan
palvelimella.
Servlet API on rajapinta servlettien toteuttamiseen
palvelimilla.
WWW eli World Wide Web on Internetin
graafinen käyttöliittymä.
Luvussa esitellään servlettien toteuttamiseen tarvittavat perusteet sekä kerrotaan hieman servlettien arkkitehtuurista ja elämänkaaresta. Luku perustuu pääasiallisesti lähteisiin [Callaway] ja [Campione].
Servletti on Javalla ohjelmoitu ohjelmakomponentti, jolla dynaamisesti laajennetaan palvelimen toiminnallisuutta [Callaway]. Servletit toimivat Javaa tukevilla WWW-palvelimilla, kuten appletit Javaa tukevilla WWW-selaimilla. Servletit eivät kuitenkaan toimi graafisen käyttöliittymän avulla applettien tapaan, vaan ne toimivat palvelimen taustalla ja vasta niiden prosessoimat tulosteet näytetään käyttäjälle (katso kuva 1).
Servletit ovat Java-luokkia. Niille on ennalta määritelty Servlet API -ohjelmointi-rajapinta, jonka avulla palvelin voi kutsua servlettiä. Servlettien käyttöä ei ole rajoitettu WWW-palvelimiin, vaan minkä tahansa Servlet APIa tukevan palvelimen toiminnallisuutta voidaan laajentaa servlettien avulla. Nämä voivat olla esimerkiksi
ftp-, telnet- tai uutisryhmäpalvelimia.
Kuva
1. Selaimen ja servletin välinen liikenne.
Servletit määräävät raamit, jonka avulla toteutetaan pyyntö/vastaus -tyyppisiä (engl. request/response) sovelluksia. Tällaisia ovat esimerkiksi HTML-sivujen muodostaminen ja tulostaminen käyttäjäkohtaisesti, käyttäjien tunnistus ja muut tietoturvasovellukset, pyyntöjen hajauttaminen eri palvelimille resurssien säästämiseksi sekä monen asiakassovelluksen lähettämän tiedon julkaiseminen (esim. online-ilmoitustaulu).
3.2. Servletit vai CGI-tekniikka
Servlettien edut CGI:hin nähden tulevat esiin suorituskyvyssä, siirrettävyydessä ja turvallisuudessa [Callaway]. Näistä suorituskyky on ehkä kaikkein näkyvin parannus, sillä useimmat servletit ajetaan samassa prosessiavaruudessa kuin palvelin ja ne ladataan vain kerran palvelimen käynnistyessä. Tällöin ne pystyvät vastaamaan asiakassovellusten pyyntöihin mahdollisimman tehokkaasti ja nopeasti. CGI joutuu luomaan uuden prosessin jokaista pyyntöä kohti, josta aiheutuu huomattava kustannus verrattuna servlettien tapaan. Tämä näkyy selvimmin tietokantasovelluksissa, joissa servletti voi jakaa saman tietokantayhteyden useamman pyynnön kanssa, joka taas CGI:llä on mahdotonta.
Toinen selvä etu on siirrettävyys. Servlettejä voidaan ajaa erilaisilla palvelimilla ja erilaisissa ympäristöissä ilman muutoksia. Tämä on erityisen tärkeää tehtäessä hajautettuja sovelluksia.
Myös turvallisuusnäkökohdasta katsoen servletit tarjoavat etuja verrattuna CGI:hin. Epäluotettavat servletit (joita ei ole esim. digitaalisesti allekirjoitettu) ajetaan omassa ”hiekkalaatikossa” (engl. sandbox) eli suojatussa muistiavaruudessa, jolloin ne eivät voi käsitellä ohjelman ulkopuolisia resursseja. Näitä asetuksia voi tarvittaessa muuttaa Javan turvallisuusmanagerin (engl. security manager) avulla.
Servlettien perusrakenne on melko yksinkertainen. Ne toteuttavat joko GenericServlet- tai HttpServlet-luokkien rajapinnan ja ylikirjoittavat ainakin yhden metodin, jossa servletin toiminnallisuus toteutetaan.
Tämä metodi voi olla service, jota automaattisesti kutsutaan
jokaisen asiakassovelluksen pyynnön saapuessa. HTTP-servlettien ollessa
kyseessä tätä metodia ei kuitenkaan yleensä ylikirjoiteta, vaan ylikirjoitetaan
muita metodeja riippuen HTTP-pyynnön tyypistä (GET, POST, HEAD, PUT tai DELETE). Yleensä servleteissä
ylikirjoitetaan myös metodit init ja destroy.
Tavallisen servletin perusrakenne on lyhyesti esitettynä seuraavanlainen:
public class MyServlet extends GenericServlet
{
public void init()
{
//
alustus
}
public void service()
{
// toiminnallisuus
}
public void destroy()
{
// resurssien vapautus
}
}
Servletin metodeista init-metodia kutsutaan, kun servletti ladataan ensimmäisen kerran. Tämä metodi vastaa luokan rakentajafunktiota eli konstruktoria, jossa suoritetaan servletin alustustoimenpiteet. Varatut resurssit, kuten esimerkiksi tietokantayhteydet, vapautetaan destroy-metodissa. Se vastaa siis toiminnaltaan luokan tuhoajafunktiota eli destruktoria. Näitä metodeja ei ole pakko ylikirjoittaa.
Servletin oma toiminnallisuus toteutetaan service-metodissa tai HTTP-servletin ollessa kyseessä ylikirjoitetaan esim. doGet-metodi, joka vastaa HTTP-pyynnön tyyppiä GET. Tavalliset servletit eroavat HTTP-servleteistä myös hieman perusmetodien välittämien parametrien ja poikkeusten tyypeissä. Edellä esitetyssä perusrakenteessa niitä ei kuitenkaan ole yksinkertaisuuden säilyttämisen takia käytetty.
Servletin elämänkaari voidaan jakaa yhdeksään osaan [Callaway]:
Nämä yhdeksän askelta (katso kuva 2) kuvaavat koko servletin elämänkaaren, vaikka ne saattavatkin hieman vaihdella riippuen palvelimen servlettituen toteutuksesta.
Kuva
2. Servletin elämänkaari.
Servlettien rakentamiseen ja ajamiseen tarvittavat luokat ja rajapinnat sisältyvät kahteen pakettiin: javax.servlet ja javax.servlet.http. Nämä paketit tunnetaan yhteisnimellä Java Servlet API. Kuvassa 3 on esitelty näiden pakettien luokkahierarkia ja suhteet muihin Javan luokkiin.
Kuva
3. Servlet APIn luokkahierarkia.
Paketissa javax.servlet ovat ne luokat ja liittymäluokat, joita tarvitaan yleisten servlettien rakentamiseen. Paketti sisältää myös poikkeusluokat, joita servlettien metodit voivat aiheuttaa. Paketissa javax.servlet.http on näistä perittyjä luokkia ja liittymäluokkia, joihin on lisätty HTTP-protokollan käsittelyyn liittyviä ominaisuuksia.
Servlet APIn yleisimmin käytetyt luokat ovat GenericServlet ja HttpServlet, joita laajentamalla servletit yleensä toteutetaan. Lisäksi servlettien välittämää dataa käsitellään yleisimmin liittymäluokkien ServletRequest ja HttpServletRequest sekä ServletResponse ja HttpServletResponse avulla. Seuraavassa luvussa on kuvattu tarkemmin näiden luokkien käyttöä.
4. Servlet API -rajapinnan perusteet
Luvussa käydään läpi esimerkin avulla tavallisen servletin toteutuksessa tarvittavat metodit ja periaatteet. Tämän jälkeen kerrotaan metodit, jotka HTTP-servletin pitää toteuttaa, jotta se voisi vastata asiakassovelluksen pyyntöihin. Lopuksi puhutaan lyhyesti säikeistä ja niiden turvallisesta käytöstä servleteissä. Luku perustuu pääasiallisesti lähteisiin [Callaway], [Campione] ja [Cornell].
Seuraavassa on yksinkertainen esimerkki GenericServlet-luokan perivästä servletistä, joka tulostaa tekstin ”Hei maailma!” sisältävän HTML-koodin.
import java.io.*;
import javax.servlet.*;
public class MyServlet extends
GenericServlet {
public void init() throws ServletException {}
public void destroy() {}
public void service(ServletRequest req,
ServletResponse res
) throws ServletException, IOException {
res.setContentType( "text/html" );
PrintWriter out = res.getWriter();
out.println( "<html>" );
out.println( "<head> );
out.println( "<title>Esimerkkiservletti</title>"
);
out.println(
"</head>" );
out.println( "<body>" );
out.println( "<h1>Hei maailma!</h1>" );
out.println(
"</body>" );
out.println( "</html>" );
out.close();
}
}
Esimerkin kahdella ensimmäisellä rivillä otetaan käyttöön tarvittavat Java-paketit io ja servlet.
Seuraavalla rivillä määritellään MyServlet-luokka. Jokainen servletti joko toteuttaa Servlet-rajapinnan tai periytyy GenericServlet- tai HttpServlet-luokista. Vaikka servlettejä voidaan tehdä toteuttamalla Servlet-rajapinta, ei sitä kuitenkaan yleensä käytetä.
Tämän jälkeen ylikirjoitetaan init-metodi. Metodi suoritetaan kerran jokaiselle instanssille. Tämän jälkeen servletti pysyy palvelimen muistissa, kunnes se ajetaan alas. Jos palvelin muodostaa servletistä vain yhden instanssin, niin silloin palvelin luo uuden säikeen jokaista service-metodin kutsua varten. Tämä voidaan estää toteuttamalla SingleThreadModel-rajapinta (ks. luku 4.5). init-metodia voidaan käyttää servlettien välisten jaettujen resurssien (esim. tietokantayhteyksien) muodostamiseen staattisten muuttujien avulla.
service-metodin ensimmäinen parametri ServletRequest sisältää asiakaspyynnön datan, kuten käytetyn protokollan otsikot. Näitä voidaan lukea käyttämällä ServletRequest-luokan metodeja. Vastaavasti voidaan toisena parametrina välitetyn ServletResponse-olion sisältämää vastausta asiakaspyyntöön muuttaa ServletResponse-luokan metodeilla. Servletti ei saa käsitellä IOExeption-poikkeusta, vaan se on aina välitettävä eteenpäin palvelimen käsiteltäväksi.
Ensimmäisenä service-metodissa asetetaan HTTP-otsikon content-type-kentän arvoksi text/html. Kenttä content-type on asetettava ennenkuin varsinaista dataa lähetetään takaisin selaimelle. Tämän jälkeen avataan kirjoitusvirta getWriter-metodilla. Jos vastaukseen haluaa liittää binääristä dataa, niin silloin on käytettävä getOutputStream-metodia, joka palauttaa viittauksen ServletOutputStream-olioon.
Seuraavaksi kirjoitetaan kirjoitusvirtaan println-metodilla haluttu HTML-koodi. Lopuksi pitää aina muistaa sulkea avattu kirjoitusvirta. Jos servletissä käytetään poikkeusten käsittelyä, niin silloin luonnollinen paikka virran sulkemiseen olisi finally-lohko, jolloin se tulisi aina suoritettua. Kuvassa 4 on esimerkin tulostama HTML-sivu.
Kuva
4. Hei maailma! -servletin tulostus.
Paketista javax.servlet.http löytyvä HttpServlet-luokka on laajennettu GenericServlet-luokasta. HttpServlet-luokkaan on lisätty metodeita, joilla pystytään käsittelemään HTTP-protokollan pyyntöja. Lisäksi paketista javax.servlet.http löytyy liittymäluokkia ja luokkia avusteiden sekä HTTP-istuntojen ja -otsikoiden käsittelyyn.
Tavallisessa servletissä oli ylikirjoitettava ainoastaan metodi service, jota palvelin kutsui servlettiä pyydettäessä. HTTP-servletissäkin voidaan käyttää tätä metodia, mutta suositeltavampaa on käyttää suoraan HTTP-pyyntöä vastaavia metodeita. Nämä ovat doPost, doGet, doHead, doPut ja doDelete. Jos palvelin saa sellaisen pyynnön, jota ei ole tuettu servletissä, niin silloin palvelin generoi selaimelle näytettävän HTTP 400 ”Bad Request” –viestin.
Taulukossa 1 on kuvattu ylikirjoitettavat metodit ja luvussa 4.4 on esimerkki proxy-palvelin -servletistä, joka toteuttaa doGet-metodin. Lisäksi on olemassa metodit HTTP TRACE ja HTTP ALLOWS -pyyntöjen käsittelyyn. Näitä ei kuitenkaan yleensä ole tarvetta ylikirjoittaa.
Metodi |
Kuvaus |
service |
Metodia kutsutaan palvelimen toimesta, kun servlettiä pyydetään. Jos service-metodia ei ylikirjoiteta, sen oletustehtävänä on kutsua yhtä alla olevista do-metodeista riippuen HTTP-pyynnön tyypistä. |
doGet |
Metodia kutsutaan vastaamaan HTTP GET -pyyntöön. Metodin toteuttaminen antaa automaattisesti tuen myös HTTP HEAD -pyynnöille. |
doHead |
Metodia kutsutaan vastaamaan HTTP HEAD -pyyntöön. Jos metodia ei ole ylikirjoitettu ja saadaan HEAD-pyyntö, niin silloin oletuksena kutsutaan doGet-metodia luomaan tarvittavat HTTP-otsikkokentät, jotka palautetaan pyytäjälle. |
doPost |
Metodia kutsutaan vastaamaan HTTP POST -pyyntöön. |
doPut |
Metodia kutsutaan vastaamaan HTTP PUT -pyyntöön. |
doDelete |
Metodia kutsutaan vastaamaan HTTP DELETE -pyyntöön. |
Taulukko
1. Servlettien ylikirjoitettavia metodeita.
HTTP-servletit toteutetaan siis laajentamalla HttpServlet-luokkaa, joka taas perii perustoimintonsa GenericServlet-luokalta. Tämän luokan metodeista käyttökelpoisimpia ovat
public String getInitParameter(String name)
public Enumeration getInitParameterNames()
public void log(String msg).
Näistä kahdella ensimmäisellä voidaan lukea palvelimen servletille välittämiä alustustietoja ja viimeisellä voidaan kirjoittaa servletin viestejä lokitiedostoon. Tiedoston nimi ja paikka riippuvat käytetystä palvelimesta.
4.3. HTTP-servletin liittymäluokat
Luokat HttpServletRequest ja HttpServletResponse laajentavat vastaavien ServletRequest- ja ServletResponse-luokkien toiminnallisuutta.
HttpServletRequest-olio välitetään parametrina service- ja do-metodeille. Lisäksi se määrittelee metodit, jotka kuvaavat tehdyn HTTP-pyynnön. Olion kapseloima data sisältää HTTP-otsikon tiedot, kuten HTTP-pyynnön tyypin, avusteet, autentikointitiedot sekä HTML-lomakkeella välitetyt parametrit. Käytetyimpiä metodeita ovat
public
Cookie[] getCookies(),
jota käytetään avusteiden yhteydessä (ks. luku 5.2), sekä
public
String getQueryString(),
jolla saadaan HTTP POST -metodin välittämät parametrit selville otsikosta. Tämä voidaan parsia Hashtableksi HttpUtils-luokan staattisella metodilla
public static Hashtable parseQueryString( String
queryString ).
HttpServletResponse-olio välitetään myös parametrina service- ja do-metodeille. Servletti voi käyttää tätä oliota vastauksessaan HTTP-pyyntöön. Sen metodien avulla voidaan asettaa avusteita, muuttaa vastauksen otsikkokenttiä ja välittää uudelleensuuntausohjeita. Käytetyimpiä metodeita ovat
public
void addCookie( Cookie cookie ),
jolla voidaan asettaa avuste vastaukseen (ks. luku 5.2) sekä
public void sendError( int status, String message)
throws IOException,
jota käytetään virhetilanteissa palauttaamaan oikea statuskoodi selaimelle. Statuskoodit on määritelty julkisiksi staattisiksi vakioiksi luokan sisälle. Esimerkkejä näiden käytöstä on luvussa 4.4.
4.4. Esimerkki proxy-palvelin -servletistä
Seuraavassa on hieman monipuolisempi esimerkki proxy-palvelin -servletistä. Sitä voidaan käyttää esimerkiksi HTTP-palvelimilla kiertämään applettien rajoitusta ottaa yhteyttä ainoastaan siihen palvelimeen, josta se on ladattu. Tässä esimerkissä servletti lataa pyydetyn URL-osoitteen ja palauttaa sen sisällön selaimelle.
import java.io.* ;
import java.net.* ;
import javax.servlet.* ;
import javax.servlet.http.* ;
public class ProxyServer extends HttpServlet {
public void doGet( HttpServletRequest req,
HttpServletResponse
res )
throws ServletException,
IOException
{
String query = null;
res.setContentType(“text/html”);
PrintWriter out =
response.getWriter();
// Selvitetään pyynnöstä haettava URL
query = req.getParameter(“URL”);
if ( query == null ){
res.sendError(HttpServletResponse.SC_BAD_REQUEST,
“Missing URL parameter”);
return;
}
try {
query =
URLDecoder.decode(query);
}
catch( Exception exception) {
res.sendError(HttpServletResponse.SC_BAD_REQUEST,
“URL decode error “ + exception);
return;
}
//
Luetaan data URL:stä ja tulostetaan sivu
try {
URL url = new URL(query);
BufferedReader in = new
BufferedReader(
new
InputStreamReader(url.openStream()));
String line;
while ( (line = in.readLine()) !=
null ) {
out.println(line);
}
out.flush();
}
catch( IOException exception ) {
res.sendError(HttpServletResponse.SC_NOT_FOUND,
“Exception:
“ + exception);
}
}
}
4.5. Säikeiden käytöstä servleteissä
Java-ohjelmien yksi ydinhuolenaihe on säieturvallisuus (engl. thread safety). Tällä tarkoitetaan sitä, että useampi säie ei yhtäaikaa pysty muuttamaan tai lukemaan samaa dataa. Servletin rajapinta ei toteuta säieturvallisuutta, vaan siihen on käytettävä Javan tarjoamia keinoja. Näitä ovat säikeiden synkronointi, lokaalien muuttujien sekä SingleThreadModel-rajapinnan käyttö.
Synkronoinnilla voidaan luokan sisäinen muuttuja lukita niin, etteivät muut säikeet pysty sitä muuttamaan. Tämä voidaan toteuttaa siten, että määritellään synkronointilohko koodiin seuraavasti:
synchronized (this) { ... },
jolloin vain yksi säie kerrallaan voi suorittaa kyseisen lohkon. Myös koko metodi voidaan synkronoida määrittelyllä
public synchronized void service() {
... },
jolloin vain yksi säie kerrallaan voi suorittaa service-metodin. Tämä ei tietenkään ole kovin kannattavaa tehokkuussyistä monen käyttäjän järjestelmissä.
Paikallisia muuttujia voidaan käyttää service-, doGet- ja doPost-metodien sisällä luokan sisäisen muuttujan sijaan. Tällöin jokaisella säikeellä on yksi oma kopio kyseisestä muuttujasta, eivätkä muut säikeet pysty muuttamaan sen arvoa.
Yksinkertaisin tapa toteuttaa säieturvallisuus on käyttää SingleThreadModel-rajapintaa. Rajapinta ei määrittele metodeja, vaan toimii lippuna palvelimelle aiheuttaen sen, että ainoastaan yksi säie kerrallaan pystyy ajamaan servletin service-, doPost- tai doGet-metodin.
Myös tästä saattaa aiheutua tehokkuusongelmia, vaikka palvelin muodostaakin SingleThreadModel-rajapintaa käyttävästä servletistä useita instansseja valmiiksi, jonka jälkeen niistä valitaan yksi vuorollaan palvelemaan samanaikaisia pyyntöjä. Koska valmiiden instanssien määrä on rajattu (määriteltävissä palvelinkohtaisesti), joudutaan vapautuvaa instanssia odottamaan, kun kaikki instanssit ovat jo käytössä. Rajapinta saadaan käyttöön kirjoittamalla servletin luokan määrittelyssä
public class MyServlet extends GenericServlet
implements
SingleThreadModel { ... }.
SingleThreadModel-rajapinnan käyttö on suositeltavaa, kun pyyntöjen määrän tiedetään pysyvän alhaisena.
HTTP on tilaton protokolla. Tällä tarkoitetaan sitä, että palvelin ei muista edellisiä asiakassovelluksen yhteydenottoja, vaan jokainen palvelupyyntö on edellisistä pyynnöistä riippumaton istunto.
Tämä aiheuttaa ongelmia esimerkiksi sellaisissa tilanteissa, joissa asiakas pitää tunnistaa ennenkuin palvelupyyntö voidaan toteuttaa. Tällöin palvelimen on pyydettävä asiakkaalta tunnistustiedot joka pyynnön yhteydessä. Tällainen tilanne voidaan ratkaista joko tallentamalla tieto asiakkaasta URL-polkuun käyttämällä piilotettuja muuttujia (engl. hidden variables) tai käyttämällä avusteita ja servlettien yhteydessä myös suoraan Servlet APIn metodeita. Tämä luku perustuu lähteeseen [Callaway].
Servlet API tukee suoraan istunnon hallintaa HttpSession-liittymäluokan avulla. HttpSession-olio kapseloi HTTP-istunnon tiedot, kuten istunnon ID:n ja muut asiakkaaseen littyvät tiedot. Olio saadaan käyttöön kutsumalla HttpServletRequest-olion metodia getSession seuraavalla tavalla:
HttpSession mySession = request.getSession(true);
Kutsussa boolean arvo true kertoo, että jos istuntoa ei ole, niin luodaan uusi. Tämän jälkeen HttpSession-olion metodeilla voidaan käsitellä istunnon dataa. Servlet API käyttää istunnon hallintaan oletuksena avusteita. Jos selain ei tue avusteita, niin silloin käytetään URL-polkuun tallentamista.
Avusteet ovat yksinkertainen mekanismi käyttäjäkohtaisen datan tallentamiseen ja lukemiseen WWW-sovelluksissa. HTTP-palvelimen palauttaessa pyyntöä selaimelle se voi liittää mukaan informaatiota. Informaatio tallennetaan selaimelle, jos selain sallii tämän. Informaation sisältävän URL-osoitteen perusteella selain tietää, mille palvelimelle avuste pitää palauttaa. Selain tarkistaa jokaisen HTTP-yhteyden muodostuksen yhteydessä, onko sille tallennettu kyseisen palvelimen toimesta avuste. Jos avuste löytyy, se liitetään selaimen pyyntöön.
HTTP-otsikon syntaksi avusteen asettamiselle on
Set-Cookie:
<NIMI>=<ARVO>; expires=<PÄIVÄMÄÄRÄ>;
domain=<TOIMIALUE>; path=<POLKU>; secure
HTTP-otsikon syntaksi avusteen palauttamiselle on
Cookie:
<NIMI1>=<ARVO1>; <NIMI2>=<ARVO2>; ...
Otsikon Set-Cookie attribuutit on selitetty taulukossa 2.
Attribuutti |
Selitys |
<NIMI>=<ARVO> |
Attribuuttipari vastaa WWW-muuttujia, jotka lähetetään HTTP POST -operaatiossa. NIMI on avusteen nimi ja ARVO vastaavasti avusteeseen tallennettu arvo. |
expires=<PVM> |
Attribuutti ilmaisee milloin avuste vanhenee. Kun avuste vanhenee, se
poistetaan selaimelta eikä sitä enää käytetä. Jos attribuuttia ei anneta,
niin avuste vanhenee selain suljettaessa. Attribuutin formaatti on Weekday,
DD-Mon-YY HH:MM:SS GMT |
domain=<TOIMIALUE> |
Attribuuti ilmoittaa palvelimen toimialueen mihin avuste palautetaan. Esimerkiksi domain=jyu.fi palauttaisi avusteen mm. osoitteisiin tukki.jyu.fi ja www.jyu.fi. Toimialueen on oltava ainakin kaksiosainen. |
path=<POLKU> |
Attribuuti asettaa avusteen polun selaimella. Polun on myös sisällyttävä ja täsmättävä domain-attribuuttiin. Yleisimmin käytetty arvo on ”/”. |
secure |
Attribuutti ilmaisee, että avuste voidaan lähettää ainoastaan salatun yhteyden kautta, kuten esimerkiksi HTTPS (Secure HTTP). Muussa tapauksessa avustetta ei lähetetä. |
Taulukko
2. Set-Cookie -otsikon attribuutit.
5.3. Avusteiden asettaminen Servlet APIn avulla
HttpServletResponse-liittymäluokka määrittelee metodin setHeader, jonka avulla voidaan asettaa HTTP-otsikon kenttien arvoja. Yksinkertaisempaa on kuitenkin käyttää avusteiden lähettämiseen luokan javax.servlet.http.Cookie metodeja. Se sisältää metodit avusteen sisältämän tiedon muokkaamiseen sekä attribuuttien asettamiseen.
Avusteita käytettäessä on huomioitava se, että asetettaessa kaksi avustetta, joilla on sama nimi ja polku, niin viimeisenä asetettu korvaa ensin asetetun. Avusteet voivat olla olemassa yhtäaikaa, jos polut eroavat toisistaan. Lisäksi on hyvä muistaa, että selain voi tallentaa maksimissaan kolmesataa avustetta, joista samalta palvelimelta voi olla maksimissaan kaksikymmentä.
Avuste luodaan yksinkertaisesti kutsulla
Cookie myCookie = new Cookie(”testi”, ”testiarvo”)
joka asettaa avusteen nimeksi “testi” ja arvoksi “testiarvo”. Tämän jälkeen avusteelle voidaan asettaa muita attribuutteja kutsuilla
myCookie.setDomain(“jyu.fi”);
myCookie.setPath(“/”);
myCookie.setSecure(“true”);
Avuste lisätään HTTP-otsikkoon service-, doPost- ja doGet-metodien välittämän HttpServletResponse-olion avulla. Tästä luokasta löytyy metodi addCookie, jolla lisäys hoidetaan seuraavasti:
response.addCookie(myCookie);
Vastaavasti saadaan selville selaimen palauttamat avusteet käyttämällä HttpServletRequest-olion metodia getCookies, joka palauttaa taulukon selaimen palauttamista avusteista seuraavasti:
Cookies[] myCookies = request.getCookies();
Tässä esiteltyjen metodien lisäksi Cookie-luokasta löytyy monia muitakin käyttökelpoisia metodeja avusteiden käsittelyyn.
Kirjoitettujen servlettien testaaminen ja ajaminen vaatii ensin servletin asentamisen palvelinkoneelle, jonka jälkeen voidaan selaimella pyytää palvelimelta servletin ajamista. Jos käytössä ei ole servlettejä tukevaa WWW-palvelinta, voi servlettejä testata myös esimerkiksi JSDK:n (Java Servlet Development Kit) mukana tulevan Servlet Runnerin avulla. Seuraavassa on lyhyesti esitelty näitä menetelmiä tarkemmin. Luku perustuu pääasiassa lähteisiin [Callaway] ja [Magelan Institute].
Servlettien kääntämiseen vaaditaan JDK:n mukana tulevan Java-ympäristön lisäksi myös Java-servlettien laajennuspaketti, JSDK. Tämä sisältää servlettiluokat ja joitakin hyödyllisiä apuohjelmia.
JSDK:n asentamisen jälkeen pitää Java-kääntäjälle kertoa, missä servlettiluokat sijaitsevat. Tämä tehdään asettamalla CLASSPATH-ympäristömuuttuja osoittamaan oikeaan paikkaan. Unixin C-shellissä tämä tapahtuu komennolla
setenv
CLASSPATH .:servlet_hakemisto/servlet.jar:$CLASSPATH
ja Windowsissa komennolla
set CLASSPATH=.;servlet_hakemisto\servlet.jar;%CLASSPATH%
Tämän jälkeen ympäristö on valmis servlettien kääntämiseen. Servletti asennetaan palvelimelle siten, että ensin kopioidaan Java-tiedosto palvelimen servlet-hakemistoon, asetetaan CLASSPATH osoittamaan tähän hakemistoon ja käännetään tiedosto tavukoodiksi javac-komennolla.
Servlet Runner -ohjelma sijaitsee JSDK:n /bin-hakemistossa. JSDK:n versiosta riippuen ajettava ohjelma on joko servletrunner (v. 2.1) tai runner (v.2.2) ja se voidaan käynnistää komentoriviltä. Itse asiassa Servlet Runner käyttää JSDK:n mukana tulevaa luokkaa sun.servlet.http.HttpServer, jolle se välittää annetut komentoriviparametrit. Taulukossa 3 on esitelty Servlet Runnerin komentorivioptiot.
Optio |
Selitys |
Oletusarvo |
-p |
Portti, jota Servlet Runner kuuntelee. |
8080 |
-b |
Odottavien pyyntöjen maksimimäärä. |
50 |
-m |
Yhtäaikaisten yhteyksien maksimimäärä. |
100 |
-t |
Yhteyden muodostamiseen kuluvan ajan maksimiarvo, jonka jälkeen yhteys katkaistaan (millisekunteina). |
5000 |
-d |
Servlettihakemisto. |
<tämän hetkinen hakemisto>/examples |
-r |
Dokumenttien juurihakemisto. |
<tämän hetkinen hakemisto>/examples |
-s |
Hakemisto, jossa tiedosto servlet.properties sijaitsee. |
<tämän hetkinen hakemisto>/examples |
-v |
Tulostaa informaatiota ohjelman toiminnan aikana. |
Pois päältä. |
Taulukko
3. Servlet Runnerin komentorioptiot.
Servletin aliakset ja alustusparametrit määritellään tiedostossa servlet.properties. Parametrit määritellään seuraavassa muodossa:
<parametrin_nimi>=<parametrin_arvo>
Esimerkiksi servletin alias määritellään seuraavasti:
servlet.esimservlet.code=EsimerkkiServlet,
jossa esimservlet on alias servletille EsimerkkiServlet.class. Samoin määritellään arvot Servlet Runnerin servletille välittämille alustusparametreille rivillä
servlet.esimservlet.initArgs=arvo1=10,\
arvo2=100.
Käyttämällä takakauttamerkkiä ’\’ voidaan parametrien luettavuutta parantaa huomattavasti kirjoittamalla seuraava parametri seuraavalle riville.
Servlettejä kutsutaan kirjoittamalla selaimen URL:ksi
http://localhost:8080/servlet/<servletin_nimi>/[/polku_informaatio][?<query_string>],
jossa servletin_nimi on joko servletin alias tai sen varsinainen nimi, esimerkiksi esimservlet tai EsimerkkiServlet. Servletille välitetty polkuinformaatio voidaan selvittää servletissä HttpServletRequest-olion metodilla getPathInfo. query_stringiin voidaan sisällyttää nimi/arvo-pareja, jotka saadaan selville HttpServletRequest-luokan getParameterNames- ja getParameterValues-metodeilla. query_string on muotoa nimi1=arvo1&nimi2=arvo2.
Servlet Runner pitää käynnistää joka kerta uudelleen, kun servlettiä muutetaan.
6.3. Java-servlettejä tukevat WWW-palvelimet
Sunin Java Web Server (JWS) oli ensimmäinen kaupallinen tuote, jossa oli tuki servleteille. JWS:stä on saatavilla ilmainen kokeiluversio Sunin kotisivuilta. Yksinkertaisin tapa asentaa servletit JWS:ään on kopioida servletit palvelimen juurihakemistossa sijaitsevaan hakemistoon /servlet.
JWS:ssä servletti voidaan myös rekisteröidä, jolloin se on mahdollista ladata heti JWS:n käynnistyessä tai assosioida servletti johonkin URL:ään, esimerkiksi http://localhost:8080/index.html. Näitä asetuksia voidaan muuttaa käyttämällä hallintasovelmaa, jota käytetään URL:n http://localhost:9090 kautta. Tämä tosin vaatii Java 1.1 -yhteensopivan selaimen.
Muita suoraan servlettejä tukevia palvelimia ovat muun muassa Netscapen Enterprise Server sekä Apache Jserv, joka on täysin ilmainen tuote.
WWW-palvelin voi tukea servlettejä myös servlettikoneen kautta. Tällaisia ovat esimerkiksi Netscapen Fast Track, Apache Web Server ja Microsoftin Internet Information Server.
Yleisimmin käytetty servlettikone on Live Softwaren Jrun. Se tukee edellä mainittuja palvelimia ja se voidaan asentaa myös erilaisiin käyttöjärjestelmiin, kuten Windows, Unix ja Macintosh. Toinen vastaava tuote on New Atlanta Communicationsin ServletExec, joka myös tukee tunnetuimpia palvelimia ja käyttöjärjestelmiä.
Java-servletti on tehokas, turvallinen ja käyttöjärjestelmästä riippumaton ohjelmointi-rajapinta. Java-servletti -rajapinnan lisäksi on käytettävissä Javan luokkakirjastot, jotka antavat monipuoliset työkalut kaikenlaiseen ohjelmointiin.
Java-servleteissä on myös mahdollisuus asiakaspyyntöjen uudelleensuuntaukseen muilla palvelimilla sijaitseville servleteille. Tämän lisäksi hajautettujen sovelluksien toteutuksessa on käytettävissä Javan oma RMI-tekniikka ja CORBA-luokat.
Siten Java-servletti tarjoaa varteenotettavan vaihtoehdon muille menetelmille luoda dynaamisia WWW-sivuja sekä interaktiivisia ja hajautettuja WWW-palveluja.
Callaway Dustin R,
“Inside Servlets: Server-Side Programming for the Java Platform”, Addison
Wesley Longman, Massachusetts, 1999.
Campione Mary, Walrath
Kathy, Huml Allison and Tutorial Team, “The Java Tutorial Continued: The Rest
of the JDK: The Java Series”, Addison Wesley Longman, Massachusetts, 1998.
Cornell Gary and
Horstmann Cay S., “Core Java 2 Volume 2: Advanced Features”, Prentice Hall,
1999.
Magelan Institute,
“Fundamentals of Java Servlets”, saatavilla WWW-muodossa <URL: http://developer.java.sun.com/developer/onlineTraining/Servlets/Fundamentals/index.html >, Java Developer Connection, luettu
30.8.2000.