Seminaariesitelmä käsittelee tietokantoja hyödyntäen rakennettavia dynaamisia World Wide Web-sivuja. Erityisesti kiinnitetään huomiota eri valmistajien tarjoamiin toteutustekniikoihin. Varsinaiset toteutusvälineet jätetään vähemmälle huomiolle.
Avainsanoja: WWW, tietokannat, JDBC, Active Server Pages, IntraBuilder, Java
Sisällysluettelo
Viime vuosien Internet-villiintymisen aikana on ollut muotia tehdä jokaiselle isolle ja pienellekin firmalle omat WWW-sivut. Jonkinlaisen sivuston kasaaminen ei tällä hetkellä maksa paljoakaan ja onnistuu periaatteessa keneltä vain. Sivujen suurena ongelmana on niiden pitäminen ajan tasalla. Liian usein näkee suurienkin yrityksien WWW-sivuja, joiden tietosisältö on ollut sivuja tehdessä ajan tasalla, mutta jotka sen jälkeen on täysin unohdettu. Yrityksen tiedot täytyy pitää ajantasalla WWW-sivuillakin, jotta niistä olisi jotain hyötyä. Sivujen manuaalinen päivittäminen on hidasta, vaivalloista ja kallista. Useimmiten suurin osa muuttuvasta informaatiosta on tallennettuna johonkin tietokantaan. Tällöin kannattaakin toteuttaa WWW-sivunsa tavalla, joka mahdollistaa niiden dynaamisen päivittymisen suoraan tietokannasta löytyvän informaation mukaan.
Ensimmäisessä luvussa pohditaan hieman sitä missä kaikkialla voidaan hyödyntää dynaamista sivun generointia ja mikä toteutustekniikka olisi paras mihinkin tilanteeseen. Luvussa kaksi tutkitaan tarkemmin eri valmistajien tarjoamia vaihtoehtoja tietokantaliittymän rakentamiseksi. Luvussa kolme mietitään mitä kaikkea tulee ottaa huomioon dynaamisten sivujen luomisessa.
1.1 Miksi tietokantaliittymiä WWW:hen?
Suuri osa maailman tietokoneiden sisältämästä informaatiosta on talletettuna tietokantoihin. Internetin kasvattaessa jatkuvasti suosiotaan erityisesti mainiona tiedonlähteenä on tullut ajankohtaiseksi kehittää menetelmiä jo valmiiden tietokantojen tietojen saattamiseksi helposti WWW:hen. [Borland 1, 1996]
Toisaalta tietokantoja kaivataan dynaamiseen sivujen ylläpitoon. Yritykset haluavat ottaa kaiken hyödyn irti WWW-sivuistaan ja tähän liittyy oleellisesti tietojen ylläpitäminen. Tämä onnistuu helpoiten rakentamalla WWW-sivut muotoutumaan dynaamisesti kulloinkin tietokannassa olevan tiedon mukaan.
Muokattavuus on päivän sana varsinkin uutisia tarjoavilla WWW-sivuilla. Kävijä voi itse määritellä minkätyyppisiä uutisia hän haluaa lukea ja uutissivut muodostetaan automaattisesti sen mukaan. Taustalla piilee jälleen kerran tietokanta.
Tietenkään ei saa unohtaa tiedon keräämistä. Monella WWW-sivulla kerätään rekisteröimistietoja tai tehdään jopa ihan galluppeja. On varmasti tehokkainta, että kyseiset asiat kerätään suoraan tietokantaan sen sijaan, että ne lähetettäisiin sähköpostitse jollekulle manuaalisesti käsiteltäväksi.
1.2 Mitä merkitystä toteutustekniikalla?
Lähes jokaisella valmistajalla, jolla on tarjolla työkaluja WWW-sivujen tuottamiseen, on oma ratkaisunsa tietokantapohjaisten sivujen rakentamiseen. Suurien tietokantaohjelmistojen tuottajat ovat myös tulleet mukaan WWW-villitykseen. He ovat kehittäneet omia ratkaisujaan, joilla heidän tietokantansa saadaan saumattomasti liitettyä World Wide Webiin.
Ensimmäiseksi on syytä miettiä, millaiseen käyttöön WWW-sivuja ollaan tekemässä. Samoin on mietittävä, millaisille käyttäjille sivut suunnataan. Voiko käyttäjäkunnan rajata pelkästään tietyn selaimen käyttäjiin, vai pitääkö sivuja pystyä katsomaan aivan millä tahansa selaimella? Entä täytyykö tietokannan tietoja pystyä päivittämään suoraan selaimelta?
Pelkästään dynaamisesti luotavien sivujen tuottaminen ei aiheuta erityisiä ongelmia. Palvelin hoitaa kaiken varsinaisen koodin suorittamisen ja yhteydet tietokantaan. Selaimille lähetetään pelkästään standardin mukaista HTML:ää sisältäviä dokumentteja (Kuva 1.). Tärkeintä on varmistaa, että palvelin on tarpeeksi tehokas tehtäväänsä. Dynaaminen sivujen generointi kuluttaa huomattavasti enemmän palvelimen resursseja kuin tavallisten staattisten HTML-dokumenttien jakaminen. Mitä suuremmalle yleisölle sivut on tarkoitettu, sitä enemmän palvelin joutuu työskentelemään. Monesti dynaamisten sivujen kohdalla huomaa, että sivut ovat hitaita palvelimen kuormituksen takia, eivätkä niinkään verkkoyhteyden takia, kuten useimmiten ensin ajatellaan.
Ongelmia nousee vastaan, kun halutaan mahdollisuus muokata tietokannan sisältöä selaimelta käsin. Perinteisesti tietokantapalvelimen ja asiakkaan välillä on ollut jatkuva yhteys, jonka ylitse tietojen lisääminen ja päivittäminen on voinut tapahtua. World Wide Web on kuitenkin luonteeltaan hyvin erilainen. Yhteys palvelimen ja asiakkaan välillä ei ole olemassa kuin aina tarvittaessa. Tämä aiheuttaa huomattavia ongelmia tietojen lisäämisessä, poistamisessa ja päivittämisessä. Toimitukset, joissa ei ole vaaraa, että useampi henkilö olisi yhtäaikaa käsittelemässä samaa tietoa onnistuvat vielä WWW:ssäkin. Tietojen poistaminen ja päivittäminen vaativat kuitenkin erityisiä lukituksia tietokannan puolelta, jotta ne saadaan toimimaan luotettavasti. Lukitseminen tarkoittaa samaan tietoon kohdistuvien yhtäaikaisten muutosten estämistä. Tietokannasta riippuen voidaan käyttää rivikohtaista lukitusta tai huonossa tapauksessa on tyydyttävä koko kannan lukitsemiseen. Ongelmaksi muodostuukin se, kuinka pitkäksi ajaksi lukitus täytyy muodostaa. Palvelin ei voi koskaan varmasti tietää, onko käyttäjä päättänytkin yhtäkkiä lähteä kesken tietojen päivittämisen kahvitauolle. Lukituksiin tulee siksi määritellä aikarajat, joiden jälkeen ne poistetaan automaattisesti, tällöin ei enää hyväksytä kyseisen käyttäjän päivitystä suoraan tietokantaan.
Helpommalla päästään jos pystytään luomaan suora tietokantayhteys selaimesta tietokantaan (Kuva 2.). Tätä ei ikävä kyllä ole mahdollista toteuttaa jokaisella selaimella toimivaksi. Java Database Connectivity (JDBC) mahdollistaa Javalla ohjelmoituihin sovelluksiin suoran tietokantayhteyden. Selaimen täytyy luonnollisesti tukea Javaa, jotta JDBC:n hyödyntäminen onnistuu. Toinen mahdollisuus on käyttää Microsoftin Remote Data Service (RDS) tekniikkaa. RDS vaatii toimiakseen Microsoftin Internet Explorer selaimen.
2. Erilaisia toteutustekniikoita
Tietokantapohjaisen dynaamisen liittymän luomiseen on olemassa monta eri tekniikkaa ja työkalua. Tässä luvussa käsitellään muutama toisistaan eroava tapa. Muitakin kuin allamainittuja tekniikoita on olemassa, mutta ne noudattavat hyvin läheisesti samoja ideoita kuin kyseiset tekniikat.
Active Server Pages (ASP) on Microsoftin kehittämä skriptiympäristö, jolla voidaan rakentaa dynaamisia, interaktiivisia ja tehokkaita WWW-palvelinsovelluksia. ASP-ympäristöön toteutetut sovellukset pyörivät kokonaisuudessaan palvelimella, eikä niitä käyttävän selaimen tarvitse välttämättä ymmärtää kuin tavanomaista HTML:ää. Active Server Pages on saatavilla vain Microsoftin omille WWW-palvelimille kuten Microsoft Internet Information Server 3.0, Microsoft Peer Web Services 3.0 ja Microsoft Personal Web Server. ASP:llä voidaan käsitellä tietokantoja tehokkaasti käyttämällä ActiveX Data Objects tekniikkaa ja OLE DB:tä. ([PC Magazine, 1997]).
ASP-tiedostot ovat tavallisia tekstitiedostoja, jotka sisältävät joko VBScriptillä tai Jscriptillä kirjoitettua ohjelmakoodia ja tavallista HTML:ää.
<table border="0">
<form action="syotto.asp"
method="post">
<%
For I = 0 To Rs.fields.Count - 1
%>
<tr>
<td><%=Rs(I).Name%></td>
<td>
<input type="text" name="<%=Rs(I).Name%>"
value="<%=Rs(I)%>">
</td>
</tr>
<%
Next
%>
VBScript on supistettu versio Microsoftin Visual Basic kielestä ja Jscript on Microsoftin versio Javascript-kielestä. Varsinainen koodi erotetaan HTML:stä merkinnöillä <%ja %>. ASP-koodia tuotetaan useimmiten Microsoftin Visual InterDev kehittimellä, mutta periaatteessa pelkkä tekstieditorikin riittää. HTML-koodin tuottamiseen ei ole mitään erityistä editoria, vaan se on kirjoitettava joko puhtaasti käsin tai tehtävä jonkinlainen pohja esim. Microsoft Frontpagella. ASP-koodin lisäämisen jälkeen sivun HTML-osaan ei uskalla enää koskea millään editorilla. Ainakin Frontpage sotkee erittäin varmasti HTML:n sekaan upotetun ASP-koodin.
Selain pyytää palvelimelta tiedostoa. Jos kyseessä on ASP-tiedosto, palvelin suorittaa tiedoston sisältämän VBScript tai Jscript-koodin ja lähettää muodostuneen HTML-koodin selaimelle (Kuva 3). ASP-koodi on siis täysin selainriippumatonta. Halutessa voidaan koodissa ottaa huomioon eri selaimet ja tuottaa HTML:ää sen mukaan, minkä tyyppinen selain on sivua palvelimelta pyytänyt.
OLE DB on Microsoftin tekniikka joka on rakennettu tekemään se mihin Open Database Connectivity (ODBC) ei ole pystynyt. ODBC tarjoaa yhteyden relaatiotietokantoihin mutta se asettaa sille pieniä rajoituksia. ODBC ei toimi yhteydettömissä ympäristöissä, kuten WWW, eikä ODBC:n ylitse pysty käsittelemään kuin SQL:ää tukevia relaatiotietokantoja. OLE DB:n pitäisi korjata nämä puutteet. OLE DB:n on tarkoitus mahdollistaa tiedon hakeminen ja käsittely mistä tahansa tietolähteestä ilman, että tietoa pitäisi ensin siirtää SQL-tietokantaan ("universaalitietokanta") (Kuva 4). ([Microsoft 1, 1997] [Microsoft 2, 1996]).
2.1.2 ActiveX Data Objects (ADO)
ASP:n vahvuudet tulevat esille erityisesti tietokantojen käsittelyssä. ASP käyttää tietokantayhteyksissä hyväkseen Microsoftin ActiveX Data Objects (ADO) -mallia. ADO mahdollistaa tietokantayhteyden luomisen OLE DB:n kautta mihin tahansa tietokantaan, jolle on olemassa Open Database Connectivity (ODBC) -ajuri.
ActiveX Data Objects (ADO) -malli määrittelee kolme yleiskäyttöistä luokkaa: Connection, Commandja Recordset, joista ohjelmoija voi luoda esiintymiä ja käyttää tiedon käsittelyyn . Näiden lisäksi ovat luokatField, Parameterja Property, joista ei voi suoraan luoda esiintymiä, mutta joita käytetään ensiksi mainittujen luokkien sisällä. Lisäksi on vielä erillinen Error-luokka. (Kuva 5). ([Microsoft 3, 1997]).
Connection-luokkaa käytetään ohjelman ja tietokannan välisen yhteyden muodostamiseen. Command-ja Recordset-luokat käyttävät Connection-luokkaa toiminnassaan.
Command-luokkaa käytetään tietokantakyselyn tekemisessä. Yleensä kyselyt tehdään käyttäen Standard Query Languagea (SQL), mutta ADO mahdollistaa minkä tahansa kyselykielen käyttämisen, kunhan kohteena oleva tietokanta ymmärtää, mistä on kyse. Tehdyn kyselyn tulokset talletetaan Recordset-olioon.
<%
Set Command =
Server.CreateObject("ADODB.Command")
Command.ActiveConnection =
ConnectionString
Command.CommandText = "DELETE FROM uusittu2"
RecordsAffected = 0
Command.Execute(RecordsAffected)
%>
Recordset-luokka on hyödyllisin
kaikista ADO:n sisältämistä luokista. Recordsetsisältää
tietokantahaun tuloksena tulleet tietueet. Recordset-oliolla voidaan
käsitellä jokaista tietuetta yksitellen. Esimerkiksi
haetaan tietokannasta lista opiskelijoista ja heidän
tenttituloksistaan. Käydään Recordsetläpi tietue kerrallaan ja
tulostetaan ne halutussa muodossa HTML-sivuksi. Recordsetin kautta voidaan myös
päivittää tietoja suoraan tietokantaan.
Connection, Commandja Recordsettoimivat kaikki kolme kiinteässä yhteistyössä. Connectionvoidaan luoda yksinäänkin. Pelkkä Connection-olio on hyödytön, jollei käytössä ole Command-oliota komentojen suorittamiseen. Recordsettaas vaatii toimiakseen Command-olion, jotta saadaan tehtyä kysely, jonka tuloksena saatavat tietueet talletetaan Recordsetiin. Kaikkia kolmea oliota ei kuitenkaan tarvitse aina erikseen luoda, jotta pystyttäisiin hyödyntämään Recordsetia. Sekä Recordsetettä Commandluokat sisältävät tarvittavat ominaisuudet, joiden avulla ne pystyvät luomaan lennosta tarvittavan Connectioninja/tai Commandin.
Esimerkissä luodaan uusi Recordset-olio, joka luo automaattisesti tarvitsemansa Connection- ja Command-luokkien esiintymät.
<%
Set Rs =
Server.CreateObject("ADODB.Recordset")
Rs.Open "SELECT * FROM uusittu2 ORDER BY
sukunimi", _
ConnectionString, 0, 1
%>
2.1.3 Remote Data Service (RDS)
Perinteinen tietokantapohjainen WWW-sivu on sekä dynaaminen että staattinen. Sivu luodaan palvelimella dynaamisesti tietokannasta saatavan tiedon perusteella, mutta selaimen esittämä sivu on kuitenkin mitä suurimmassa määrin staattinen. Sivulla näkyviä tietoja ei voi mitenkään helposti päästä muokkaamaan, koska WWW-palvelimelle ja sitä kautta tietokantapalvelimelle ei ole jatkuvaa yhteyttä, joka mahdollistaisi tiedon suoran muuttamisen tietokantaan.
Remote Data Service (RDS) on Microsoftin kehittämä tekniikka, joka mahdollistaa ODBC:n kautta tietokantayhteyden suoraan WWW-selaimesta. RDS toimii suoraan HTTP, HTTPS (HTTP over Secure Sockets layer) ja DCOM-protokollien ylitse. RDS käyttää datasidonnaisia ActiveX-komponentteja, joten myös selaimen on tuettava ActiveX:ää. RDS on aikaisemmalta nimeltään Microsoft Advanced Data Connector (ADC). ([Microsoft 4, 1997]).
RDS:n datasidonnaiset ActiveX-komponentit voidaan suoraan upottaa HTML-sivuun, josta ne sitten käsittelevät ODBC:n kautta saamaansa tietovirtaa. Näitä komponentteja käyttäen voi selaimen käyttäjä tarvittaessa suoraan muokata tietokannan sisältöä.
IntraBuilder on Borlandin vastaisku Microsoftin tekniikalle. IntraBuilder jakaantuu kahteen osaan: IntraBuilder Designeriin, joka on hyvin samankaltainen Rapid Application Development (RAD) ympäristö mikä löytyy monesta muustakin Borlandin tuotteesta, kuten Delphi ja C++-Builder, ja IntraBuilder Serveriin. Designerilla luodaan data-pohjaisia lomakkeita ja raportteja World Wide Webissä julkaistavaksi. IntraBuilder Server taasen toimii yhteistyössä jo olemassa olevien WWW-palvelimien kanssa ja tuottaa niille tarvittavan HTML-koodin. ([Borland 2, 1996]).
IntraBuilderin ja Microsoftin Active Server Pages -teknologian väliltä löytyy suuri eroavaisuus heti sivujen luomisvaiheesta. ASP-sivut ovat pohjimmiltaan HTML-koodia, jonka väliin on upotettu VBScriptiä tuottamaan lennosta halutut muutokset valmiiseen koodipohjaan. IntraBuilder taas käyttää hyväkseen Borlandin laajennettua versiota Javascriptistä. Borland on lisännyt Javascriptiin luokkamäärittelyt, perinnän ja poikkeusten käsittelyn tuoden näin Javascriptin huomattavasti lähemmäksi varsinaista Java-kieltä. IntraBuilder Designerilla luodaan lomake aivan samaan tyyliin kuin Delphissä rakennettaisiin omaa dialogia. Tuloksena muodostuu Javascript-koodia, jonka pohjalta IntraBuilder Server luo lennosta HTML-koodia aina, kun sivua pyydetään WWW-palvelimelta. IntraBuilderin käyttäjän ei siis tarvitse osata ollenkaan HTML:ää pystyäkseen tekemään tietokantapohjaisia WWW-sivuja.
IntraBuilderilla luodut sivut voivat sisältää myös selaimessa suoritettavaa Javascript-koodia, Java appletteja, ActiveX kontrolleja ja kuvatiedostoja.
IntraBuilder Server toimii yhteistyössä varsinaisen WWW-palvelimen kanssa. IntraBuilderin mukana tulee Borlandin oma Borland Web Server mutta IntraBuilder Server toimii kaikkien niiden WWW-palvelimien kanssa, jotka tukevat NSAPIa, ISAPIa tai Win-CGI:tä.
IntraBuilder Server jakautuu kolmeen osaan: IntraBuilder Brokeriin, IntraBuilder Agentteihin ja Borland Database Engineen (BDE). (Kuva 6)
IntraBuilder Broker hoitaa kommunikoinnin WWW-palvelimen ja IntraBuilder Agenttien kanssa. IntraBuilder Broker tukee tunnetuimpia WWW-palvelimien Application Programming Interfaceja (API), esim. NSAPIa (Netscape Server API), ISAPIa (Internet Server API) ja Win-CGI:itä (Windows Common Gateway Interface). ([Borland 2, 1996]).
IntraBuilder Broker osaa reitittää WWW-palvelimen pyynnöt älykkäästi aina juuri sille IntraBuilder Agentille, joka parhaiten pystyy pyynnön toteuttamaan. IntraBuilder Agentteja voi olla useammalla kuin yhdellä koneella, jolloin saavutetaan maksimaalinen suorituskyky.
IntraBuilder Brokereita on käynnissä aina vain yksi kerrallaan.
IntraBuilder Agentit tulkitsevat lomakkeet ja raportit sekä generoivat niiden pohjalta dynaamista HTML:ää. Agentit hoitavat myös eri käyttäjien istuntoihin liittyvät järjestelyt. Tavanomaisilla staattisilla WWW-sivuilla ei ole tarvetta tietää, kuka vaati mitäkin tietoa, mutta tietokantapohjaisessa toteutuksessa tämä on tiedettävä. IntraBuilder Agentit lisäävät jokaiseen luomaansa WWW-sivuun yksikäsitteisen ID-numeron, jonka perusteella pystytään lähettämään jokaiselle käyttäjälle oikea tulos. Esimerkiksi kaksi ihmistä katsoo samaa dynaamista WWW-sivua, jolla selaillaan tehtyjä tilauksia. Kummankin käyttäjän istunto on identifioitava jotta tiedetään tietue, joka on kullakin seuraavaksi vuorossa. Tämä säästää huomattavasti vaivaa sovelluksen ohjelmoijalta. WWW-palvelin ei näe millään tavalla, milloin käyttäjä lopettaa sovelluksen käyttämisen. Tälläistä tilannetta varten on IntraBuilder Agentteihin sisällytetty aikalaskuri, jonka määräämän ajanjakson kuluttua istunto lopetetaan ja siihen kuluneet resurssit palautetaan muuhun käyttöön. ([Borland 2, 1996]).
2.2.3 Borland Database Engine (BDE)
Borland Database Engine (BDE) pitää huolen tietokantayhteyksistä. BDE on käytössä myös monen muun Borlandin tuotteen yhteydessä (Delphi, Paradox jne). BDE pystyy käyttämään mitä tahansa ODBC-lähdettä. Tunnetuimpiin tietokantoihin BDE:stä löytyvät omat ajurit, jotka toimivat tehokkaammin kuin vastaavat ODBC-ajurit. ([Borland 2, 1996]).
2.3 Java Database Connectivity (JDBC) API
Java Database Connectivity (JDBC) on Javasoftin määrittelemä SQL-tietokantojen liittymärajapinta. JDBC on Javan vakio-osa ja on mukana JDK 1.1:ssä. Myös JDK 1.0.2:een voidaan lisätä JDBC-tuki. JDBC:n perusta on sama kuin ODBC:nkin, mutta JDBC on toteutettu puhtaasti Javalla, eikä C:llä niin kuin ODBC. Java-ohjelmat voivat hyödyntää jo olemassa olevia ODBC-ajureita käyttämällä Intersolvin julkaisemaa JDBC-ODBC-siltaa. Java-sovellukset voidaan ohjelmoida käyttäen JDBC-rajapintaa jolloin JDBC APIn kutsut ajetaan JDBC-ODBC-sillan läpi, joka muokkaa ne ODBC- kutsuiksi ja laittaa ne eteenpäin ODBC-ajurin käsiteltäväksi. (Kuva 7). ([Javasoft , 1997], [Hamann , 1997])
JDBC sallii minkä tahansa kyselyn suorittamisen tietokannalle. Kyselyn ei edes tarvitse olla SQL:ää, kunhan vastaanottava tietokanta ymmärtää kyselyn. Saadakseen Javasoftilta JDBC-yhteensopivuusmerkinnän täytyy ajurin tukea vähintään ANSI SQL92 -standardia.
Javasoft on päättänyt käyttää Uniform Resource Locator (URL) -standardia tietokantojen nimeämiseen JDBC:ssä. Käytetty syntaksi on seuraavanlainen: jdbc:<protokolla>:<nimi>.
Kyselyjen tekeminen tapahtuu java.sql.Statement-luokan avulla. Ensimmäiseksi luodaan yhteys, määritellään kysely ja suoritetaan kysely. Kyselyn tulokset saadaan Resultset-tyyppiseen olioon, jolta voidaan pyytää haluttujen kenttien sisältöä.
Esimerkissä suoritetaan kysely, joka hakee kolme saraketta Taulu-nimisestä taulusta. Saatujen sarakkeiden arvot sijoitetaan vastaavan tyyppisiin Java-kielen muuttujiin ja tulostetaan ruudulle sopivasti järjesteltyinä.
java.sql.Statement stmt =
conn.createStatement();
ResultSet r = stmt.executeQuery("SELECT a,b,c FROM
Taulu");
while (r.next()) {
int i = r.getInt("a");
String s = r.getString("b");
byte b[] = r.getBytes("c");
System.out.println("ROW = "+i+" "+s+" "+b[0]);
}
2.3.1 Yksitasoiset järjestelmät (One Tier Systems)
Tietokantayhteyttä asiakkaan ja palvelimen välillä JDBC:n kautta sanotaan yksitasoiseksi (One Tier), jos käytetty JDBC-ajuri on kirjoitettu kokonaan Javalla. Selain, Java-appletti, JDBC-ajurimanageri ja varsinainen ajuri ovat kaikki yhdellä koneella. WWW-palvelin ja tietokantapalvelin ovat molemmat samassa koneessa. Javan tietoturvaominaisuudet rajoittavat applettien mahdollisuuden verkkoyhteyden luomiseen vain siihen samaan koneeseen, josta se itse siirrettiin. ([Hamann , 1997]).
2.3.2 Kolmitasoiset järjestelmät (Three Tier Systems)
Aina käytetty JDBC-ajuri ei ole täysin kirjoitettu Javalla, vaan se tarvitsee avukseen jonkin tiettyyn käyttöjärjestelmään sidotun kirjaston. Tämä kirjasto sijoitetaan samalle koneelle WWW-palvelimen kanssa, jotta JDBC ajuri saa siihen yhteyden. Kirjastoa ei enää ole sidottu Java-applettien turvamääräyksillä vaan se voi edelleen ottaa yhteyden mihin tahansa tietokantapalvelimeen tai tietokantapalvelimiin riippumatta siitä, missäpäin verkkoa ne sijaitsevat. Kirjasto keskustelee tietokantapalvelimen kanssa ja välittää tiedot edelleen asiakkaan koneessa sijaitsevalle JDBC-ajurille. (Kuva 9). ([Hamann , 1997]).
Suurimmat tietokantapalvelimien valmistajat ovat jo pidemmän aikaa lisäilleet palvelimiinsa ominaisuuksia, jotka mahdollistavat niiden hyödyntämisen paremmin World Wide Webissä. Ajan- ja materiaalin puutteen takia näistä otetaan esille tässä esitelmässä vain joitakin mielenkiintoisia yksityiskohtia.
2.4.1 Sybase Adaptive Server Enterprise
Sybasen uusin tietokantapalvelin Adaptive Server tuo mukanaan myös PowerDynamo- nimisen WWW-palvelimen. PowerDynamo tuo mukanaan tarpeelliset työkalut dynaamisten tietokantapohjaisten WWW-sivujen luomiseksi. Mielenkiintoiseksi WWW-sivujen kehittäjän kannalta Adaptive Serverin tekee varsinainen tietokantapalvelin. Sybase kutsuu uusinta tietokantaansa olio-relaatiotietokannaksi. Adaptive Server tukee suoraan Java-kielen olioiden sijoittamisen tietokantaan. Seuraavaksi esitetään muutama esimerkki. ([Sybase 1, 1997], [Sybase 2, 1997])
Lisätään tyontekijat tauluun uusi työntekija, jonka osoitteena on Java-luokan Osoite esiintymä.
INSERT INTO tyontekijat(ID, nimi,
Osoite)
VALUES (1235, 'Kalle Kehveli',
new Osoite ('piilokuja 13', '11111
mörskäkylä')
Lisätään tyontekijat-tauluun uusi työntekijä, jonka osoitteena on Java-luokasta Osoite perityn SuomOsoite-luokan esiintymä.
INSERT INTO tyontekijat (ID, nimi,
osoite)
VALUES (1235, 'Ville Kehveli',
new SuomOsoite('Piilokuja 14', '11111
Mörskäkylä')
Etsitään työntekijät, joiden katuosoite on Piilokuja 14.
SELECT name
FROM tyontekijat
WHERE Osoite.katu = 'Piilokuja 14'
JBMS on Javalla ohjelmoitu relaatiotietokantapalvelin. JBMS on erittäin pieni ja kevyt, sillä se on pienimmillään alle 1 megatavun kokoinen. JBMS:ään voi helposti integroida minkä tahansa Java-luokkakirjaston. Kyselykielenä JBMS käyttää standardinmukaista SQL:ää ja tietokantayhteyksissä protokollana on luonnollisesti JDBC. Tietokannan sisäinen kieli on Java. ([Murphy, 1997]).
3. Huomioita tietokantapohjaisen WWW-liittymän toteuttamisesta
Tietokantapohjaisen WWW-sivun luominen tuo mukanaan heti aivan uusia huomioonotettavia asioita. Enää kaikki ei olekaan niin helppoa ja yksinkertaista kuin staattisten WWW-sivujen aikana.
Tietokannan käyttäminen WWW-sivujen pohjana tuo heti WWW-palvelimelle lisää vastuuta. Perinteisten sivujen kohdalla palvelimen ei tarvitse kuin vastaanottaa pyyntöjä halutuista sivuista ja lähettää niitä eteenpäin. Tietokantapohjaisissa dynaamisissa sivuissa tämä ei enää riitä. Palvelimen täytyy koko ajan olla selvillä siitä, missä "kohtaa" tietokantaa kukakin palvelun käyttäjä on. Perinteinen palvelin ei millään tavalla erottele sitä, käykö sama käyttäjä 100 kertaa minuutissa noutamassa samaa sivua vai onko kyseessä 100 eri käyttäjää minuutin aikana. ([Borland 3, 1996]).
Tietokantasovelluksessa on jotenkin pystyttävä tallentamaan jokaiselle käyttäjälle oma ns. istunto. Tämä tapahtuu yleisimmin luomalla jokaiselle käyttäjälle oma yksikäsitteinen ID-numero, joka lähetetään asiakaskoneelle HTML-sivun mukana. Seuraavan kerran, kun sama käyttäjä ottaa yhteyden palvelimeen, palvelin tarkistaa, löytyykö käyttäjän koneelta ID-numeroa. Jos se löytyy, niin palvelin määrittää jatkotoimensa sen mukaan. Yleensä ID-numerot talletetaan asiakaskoneelle cookiena. ID-numeron avulla pystytään luomaan esimerkiksi sovellus, jolla selaillaan tietokannasta saatavia tuotteita. Palvelin pitää muistissaan sitä, kuinka monennessa tuotteessa kukakin käyttäjä on menossa. Sekä Borlandin IntraBuilder Server että Microsoftin Active Server Pages -tekniikat osaavat erotella käyttäjät ID-numeroilla.
Tehtiinpä tietokantapohjaista sovellusta mihin ympäristöön tahansa, niin aina vastaan tulee sama ongelma. Kuinka käsitellä tilanne, jossa kaksi tai useampi käyttäjä yrittää muuttaa samaa tietoa? Tälläisten tilanteiden varalle tietokannoista löytyy erilaisia lukitusominaisuuksia. Eri tietokantapalvelimet tukevat erilaisia lukitustapoja. Toisissa on mahdollista lukita yksittäinen tietue, kun taas toisissa lukitus täytyy tapahtua kokonainen taulu kerrallaan. ([Borland 3, 1996], [Microsoft 5, 1997]).
Lukitusta vaativaan tilanteeseen voidaan suhtautua joko pessimistisesti tai optimistisesti. Pessimistiseksi lukitukseksi kutsutaan tilannetta, jossa oletetaan ilman muuta kahden tai useamman yrittävän muokata samaa tietuetta yhtäaikaa. Käytännössä tämä tapahtuu siten, että yritettäessä asettaa haluttu tietue muokkaustilaan tarkistetaan, onko kukaan muu jo muokkaamassa kyseistä tietuetta. Jos tietue on jo muokkauksen alla, ei päästetä ketään muuta tekemään muutoksia ennen kuin ensimmäinen muokkaaja on tietueen vapauttanut. Lukittua tietuetta voi kyllä katsoa, mutta ei muuttaa.
Optimistinen lukitus on yleisemmin käytössä kuin pessimistinen. Optimistisessa lukituksessa pidetään epätodennäköisenä tilannetta, että useampi sattuisi muokkaamaan samaa tietuetta samanaikaisesti. Tietokantojen tietueiden lukumäärä on yleensä suuri, jolloin todennäköisyys tietueen joutumisesta useamman muokattavaksi yhtäaikaa on pieni. Optimistisen lukituksen oletus vastaakin oikeaa käyttötilannetta paremmin kuin pessimistisen lukituksen oletus. Asiakkaan annetaan aivan rauhassa muokata sille annettua kopiota halutusta tietueesta. Mitään tarkistuksia ei tehdä ennen kuin asiakas yrittää päivittää tekemiään muutoksia tietokantaan. Tällöin tarkistetaan, onko tietueeseen tullut muutoksia sillä välin, kun asiakas on sitä muokannut. Jos muutoksia on ollut, niin asiakkaan haluama päivitys epäonnistuu ja siitä ilmoitetaan asiakkaalle. Asiakas voi nyt ottaa uuden jonkun muun muokkaaman tietueen nähtäväkseen ja päättää, haluaako yrittää muutoksiaan uudelleen. Näin jatketaan, kunnes asiakas onnistuu tekemään haluamansa muutokset tai luovuttaa. Erityisen suurissa tietokannoissa optimistinen lukitus toimii erittäin hyvin, koska todennäköisyys sille, että useampi yrittää muokata samaa yhtäaikaa, on hyvin pieni. Mitä enemmän tietueita, sitä todennäköisimmin optimistinen lukitus riittää, Mitä vähemmän, sitä todennäköisimmin tarvitaan pessimististä lukitusta.
Borland IntraBuilder Server tukee automaattisesti optimistista tai pessimististä lukitusta sen mukaan kumpaa tapaa käytössä oleva tietokantapalvelin tukee. Microsoftin ASP mahdollistaa myös lukituksien käytön, muttei niin tehokkaasti, eikä automaattisesti kuin IntraBuilder.
Transaktiot ovat erittäin tärkeä osa asiakas/palvelin-pohjaisissa tietokannoissa. Transaktio on useasta osatoimituksesta muodostuva kokonaisuus. Jokainen osanen pitää onnistua, jotta koko transaktio toteutuisi. Jos jokin osa pettää voidaan vielä peruuttaa kaikki siihen mennessä toteutetut osatapahtumat. ASP:ssä ja IntraBuilderissa on kummassakin mahdollista käyttää transaktioita. ([Borland 3, 1996]).
IntraBuilderissa on lisäksi transaktioon verrattavissa oleva lisäominaisuus. IntraBuilder voidaan määrätä tallettamaan kaikki tapahtumat lokaaliin välimuistiin, kunnes kaikki vaiheet on käyty läpi. Tämän jälkeen määrätään sitten koko tapahtumasarja suoritettavaksi kerralla tietokantapalvelimelle. Perinteisessä transaktiossa jokainen vaihe toteutetaan suoraan tietokantaan josta ne kuitenkin ovat vielä peruttavissa. IntraBuilderin käyttämässä välimuistitalletuksessa säästetään tietokantapalvelinta mahdollisesti turhalta rasitukselta. ASP:lla voidaan myös rakentaa vastaavantyyppinen toiminto kuin IntraBuilderissa.
Tieto on valtaa. Siksipä tieto pitää osata tarvittaessa pitää poissa epätoivotuista käsistä. World Wide Webin tietoturva on ollut parin viime vuoden aikana jatkuvasti otsikoissa, eikä dynaamisten WWW-sivujen ilmaantuminen markkinoille ole yhtään vähentänyt otsikointia. Päinvastoin, suojattavaahan on nyt entistä enemmän, kun yrityksien yksityiset tietokannat siirretään WWW-aikaan.([Borland 3, 1996]).
3.4.1 WWW-palvelimien turvallisuus
ASP:llä ja IntraBuilderilla toteutetut sovellukset pyörivät suurimmaksi osaksi WWW-palvelimen taustalla, joten niiden tietoturvaan vaikuttaa suoraan käytetyn WWW-palvelimen turvallisuus. Tietovirta WWW-palvelimen ja selaimen välillä voidaan tarvittaessa salata esim Secure Socket Layer (SSL) -tekniikalla.
3.4.2 Tietokantapalvelimien turvallisuus
Käytännössä kaikista tietokantapalvelimista löytyy sisäänrakennettuna valmiit käyttäjäoikeusmäärittelyt. Tietokantaan pääsemiseksi voidaan vaatia jokin määrätty käyttäjätunnus ja salasana. Eri tunnuksille voi olla määritelty eritasoisia oikeuksia, jolloin toiset pääsevät vain lukemaan tietoja ja jotkut taas päivittämään. Käyttäjätunnus- ja salasanatiedot voivat olla suoraan koodattuna palvelinpäähän tai ne voidaan kysyä jokaiselta käyttäjältä vaikkapa WWW-sivukohtaisesti.
3.4.3 Sovelluskohtainen turvallisuus
Tietokantapohjaisiin sovelluksiin on tietenkin vielä helppo lisätä tarpeen mukaan eritasoisia käyttäjiä, salasanoja ja oikeustasoja luomalla oma tietokanta näitä varten.
Kaikkien näiden dynaamisesti luotujen tietokantapohjaisten WWW-sivujen keskellä kannattaa pitää pää kylmänä. Yhdessäkään artikkelissa ei suoraan neuvottu milloin oikeastaan kannattaa tehdä dynaamisesti luotava WWW-sivu ja milloin ei. Kaikki vaan tuntuu olevan itsestään selvästi aina dynaamista. Dynaaminen sivun luominen on kuitenkin hyvin paljon resursseja kuluttavaa puuhaa ja tehokaskin palvelin on nopeasti polvillaan. Ajatellaan tilannetta, jossa WWW-sivu sisältää listauksen opiskelijoiden hyväksytyistä harjoitustöistä. Lista luodaan tietokannasta löytyvien tietojen perusteella aina, kun joku selain pyytää sivua. Tietoja ei kuitenkaan päivitetä kuin ehkä kerran tai pari päivässä, mutta sitä saatetaan selailla kymmeniä kertoja päivässä. Sama sivu siis luodaan monta kertaa turhaan, koska luontikertojen välillä siihen ei ole tullut muutoksia. Tällöin kannattaisikin siirtää sivun luominen tapahtumaan uuden harjoitustyön syöttämisen yhteyteen. Miten tämä sitten toteutetaan, riippuu taas siitä, kuinka uuden syöttäminen tapahtuu. Tällä muutoksella säästettäisiin kuitenkin huomattavasti koneresursseja, koska nyt sivu käyttäytyisi useimmiten kuin mikä tahansa tavallinen pelkkää tekstiä sisältävä WWW-sivu, eikä aiheuttaisi turhaa dynaamista sivun luomista. Tämä kannattaa muistaa, kun seuraavan kerran selailee esimerkiksi Microsoftin kotisivuja ja ihmettelee miksi sivut ovat niin hitaat.
Alunperin niin siisti ja yksinkertainen World Wide Web on muutamassa vuodessa paisunut pelkästä jokapojan kotisivuhiekkalaatikosta todelliseksi sovellusten työmaaksi. Enää ei riitä, että osaa ulkoa muutaman yleisimmän HTML-muotoilukomennon, jotta pääsee rakentamaan suuryrityksien Intranet/Extranet/Internet-kokonaisuuksia. WWW:hen on alkanut ilmestyä aivan oikeita sovelluksia, jotka vaativat ammattitaitoisia tekijöitä. Työkalut ovat myös onneksi kehittyneet huimasti. Enää ei tarvitse kaikkea vääntää hiki hatussa CGI-ohjelmointina vaan valmiin sovelluksen voi saada tehtyä parilla hiiren näpäytyksellä. Laadukkaan ja käyttökelpoisen sovelluksen tekeminen vaatii kuitenkin vielä hieman enemmän.
Kaikki tässä esitelmässä läpikäydyt tekniikat ovat käyttökelpoisia kuitenkin hieman käyttötarkoituksesta riippuen. Jos välttämättä on toteutettava kiinteäyhteyksinen tietokantaliittymä, niin vaihtoehdoiksi ei jää kuin Microsoftin ASP ja RDS tai Java ja JDBC. Kummankin ongelmana on tietynlaiset vaatimukset käytettävälle selaimelle. Microsoftin tekniikka ei tällä hetkellä toimi kuin Microsoftin omalla selaimella. Java taas vaatii selaimelta Java-tuen, joka ei tunnu Microsoftin selaimelle olevan kovin tärkeä ominaisuus. Kummassakin tapauksessa ulkopuolelle jäävät tekstipohjaisten selainten käyttäjät. Tietyn yrityksen sisäisessä intranetissä, jossa kaikilta voidaan olettaa löytyvän tietty selain voi esim. ASP ja RDS olla hyvinkin onnistunut valinta. Molemmat vaihtoehdot vaativat myös, että verkkoyhteyden on oltava suhteellisen stabiili. Valittiin kumpi tahansa tekniikka, niin tietokantasovelluksen rakentaminen ei ole kuitenkaan aivan helppoa. Java-toteutus vaatii selkeästi eniten ohjelmointitaitoa, eikä ASP ja RDS versiokaan aivan tumpelolta onnistu. Active Server Pages ratkaisun ulkonäön muokkaamiseen ei edes ole vielä kunnollista työkalua.
Jos unohdetaan kiinteä yhteys tietokantaan, niin Borlandin IntraBuilder nostaa heti selkeästi osakkeitaan. IntraBuilderin tapa on kaikista esitellyistä tekniikoista kätevin. IntraBuilder on helpoin käyttää ja se on alusta alkaen suunniteltu juuri tietokantojen käyttämiseen. Vahvuuksiin voidaan lukea myös tuki useammalle WWW-palvelimelle kuin Microsoftin ASP:llä. IntraBuilderilla rakennetut sovellukset toimivat haluttaessa kaikilla selaimilla. Tällä hetkellä valitsisin työkalukseni Borlandin IntraBuilderin.
[PC Magazine, 1997] Lam John, "Database Connectivity and the Internet", <URL:http://www.zdnet.com/pcmag/pctech/content/16/22/it1622.001.html>, 1997
[Microsoft 1, 1997] Microsoft, "OLE DB Overview", <URL: http://www.microsoft.com/data/oledb/prodinfo.htm>, 1997
[Microsoft 2, 1996] Cameron David ja Pizzo Michael, "OLE DB, Data Access for the masses", <URL:http://www.microsoft.com/data/oledb/resource/presentations/PDCNov96a/sld001.htm>, 1996
[Microsoft 3, 1997] Microsoft, "ADO Product Information", <URL: http://www.microsoft.com/data/ado/prodinfo.htm>, 1997
[Microsoft 4, 1997] Microsoft, "RDS Product Information",<URL:http://www.microsoft.com/data/rds/prodinfo.htm>, 1997
[Microsoft 5, 1997] Microsoft, "Microsoft Visual InterDev Documentation", 1997
[Borland 1, 1996] Borland, "Enabling Data-Driven Intranets", <URL:http://www.borland.com/intrabuilder/papers/enablewp/>, 1997
[Borland 2, 1996] Krull Klaus, "IntraBuilder Architecture Overview", <URL: http://www.borland.com/intrabuilder/papers/intraarch/>, 1996
[Borland 3, 1996] Kaufman Dana S., "IntraBuilder Client / Server Development", <URL: http://www.borland.com/intrabuilder/papers/csdevwp/>, 1997
[Murphy, 1997] Murphy Kieron, "Cloudscape readies light, Java-powered database manager", <URL:http://www.developer.com/news/tmp-112597_jbms.html>, 1997
[Javasoft , 1997] Javasoft, "THE JDBC DATABASE ACCESS API", <URL: http://java.sun.com/products/jdbc/>, 1997
[Hamann, 1997] Hamann Jerrid, "Analysis of Java Database Connectivity and its Application in a Multi-Platform, Multi-DBMS Environment", <URL: http://www.cs.tamu.edu/people/jhamann/jdbc/report/>, 1996
[Sybase 1, 1997] Sybase, "Sybase Adaptive Server 11.5 Datasheet ", <URL:http://www.sybase.com/adaptiveserver/whitepapers/datasheet.html>, 1997
[Sybase 2, 1997] Sybase, "Sybase Adaptive Server: Java in the Database", <URL: http://www.sybase.com/adaptiveserver/whitepapers/java_wps.html>, 1997
Microsoft, "Universal Data Access", <URL: http://www.microsoft.com/data/>, 1997
Microsoft, "Visual InterDev Start Page", <URL:http://www.microsoft.com/vinterdev/>, 1997
Microsoft, "SiteBuilder Network Server" , <URL:http://www.microsoft.com/workshop/server/default.asp>, 1997
LanTimes Online, "Borland International IntraBuilder 1.5", <URL: http://www.lantimes.com/lantimes/97/97nov/711a088b.html>, 1997
Borland, "Borland DataGateway for Java", <URL: http://www.borland.com/datagateway/papers/datagateway/>, 1997
Karjalainen Marko, Koivula Heidi ja Korva Jari, "OLE ja ActiveX tietokantaohjelmoinnissa", <URL:http://www.student.oulu.fi/~jpkorva/thj/thj.html>, 1997
Oracle, "Oracle Web Application Server 3.0", <URL: http://www.oracle.com/products/asd/was/collateral/was30_twp.html>, 1997
The Yankee Group, "What's So Hot About Domino?", <URL: http://www.lotus.com/core/content.nsf/61a518eb6fbc296d8525630f004e7ac0/3352ddd034a24b48852565150050468e?OpenDocument>, 1997
Mahon Andrew, "Lotus Domino and the Intranet Strategy", <URL: http://www.lotus.com/core/content.nsf/61a518eb6fbc296d8525630f004e7ac0/2758da4e06e845e3852564f7005c5789?OpenDocument>, 1997
Lotus, "Lotus Domino 4.5, Powered by Notes: Part I - Technical Overview", <URL: http://www.lotus.com/core/content.nsf/61a518eb6fbc296d8525630f004e7ac0/761b47361da8780d852564f20073b9e1?OpenDocument>, 1997
Javasoft, "JDBC - Answers to Frequently Asked Questions", <URL:http://java.sun.com/products/jdbc/jdbc-frequent.html>, 1997
Hazarika Deva, "Developing and Deploying Interactive Applications on the Internet", <URL:http://www.microsoft.com/workshop/prog/prog-gen/mspaper.htm>, 1996
Rauch Stephen, "Manage Data from Myriad Sources with the Universal Data Access Interface", <URL:http://www.microsoft.com/msj/0997/universaldata.htm>, 1997
6.1 ASP:llä toteutettu opiskelijoiden demoaktiivisuuslista
<%@ LANGUAGE="VBSCRIPT" %>
<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual
InterDev 1.0">
<META HTTP-EQUIV="Content-Type"
content="text/html; charset=iso-8859-1">
<TITLE>Tietokone ja
perusohjelmistot</TITLE>
</HEAD>
<BODY bgcolor="#FFFFFF" text="#333333"
leftmargin="0" topmargin="0">
<h1><strong>TIETOKONE JA
PERUSOHJELMISTOT</strong></h1>
<%
if (Request("htyot") <> "") then
call Listaahtyot
else
call listaa
end if
%>
</BODY>
</HTML>
<%
sub listaa
%>
0 tarkoittaa mitä tahansa
demoryhmää<br>
1-8 ovat demoryhmien numerot<br>
tyhjä tarkoittaa puuttuvaa
demosuoritusta<br>
<br>
<a
href="lista.asp?htyot=kukkuu"><strong>Hyväksytyt
harjoitustyöt</strong></a>
<br>
Jos listauksen tiedoissa on puutteita tai vikoja
niin lähetä sähköpostia<a
href="mailto:hazor@iki.fi">
hazor@iki.fi</a>
<%
ConnectionString =
Session("opiskelijat_ConnectionString")
Set Rs =
Server.CreateObject("ADODB.Recordset")
Rs.Open "SELECT * FROM uusittu2 ORDER BY sukunimi",
_
ConnectionString, 0, 1
if (Rs.BOF AND Rs.EOF) then
Response.Write "Ei yhtään
opiskelijaa<br>"
exit sub
end if
%>
<table border="1" cellpadding="2"
cellspacing="0">
<tr>
<td> </td>
<td><strong>Sukunimi</strong></td>
<td><strong>Etunimi</strong></td>
<td><strong>E-mail</strong></td>
<td><strong>KO</strong></td>
<td><strong>Demo1</strong></td>
<td><strong>Demo2</strong></td>
<td><strong>Demo3</strong></td>
<td><strong>Demo4</strong></td>
<td><strong>Demo5</strong></td>
<td><strong>Demo6</strong></td>
<td><strong>Demo7</strong></td>
<td><strong>Demo8</strong></td>
</tr>
<%
counter = 1
Do While Rs.EOF = false
%>
<tr>
<td><%=counter%></td>
<td><%=Rs("sukunimi")%> </td>
<td><%=Rs("etunimi")%> </td>
<td><a href="mailto:<%=Rs("sähköpostiosoite")%>"><%=Rs("sähköpostiosoite")%> </a></td>
<td><%=Rs("koulutusohjelma")%> </td>
<td><%=Rs("demo1")%> </td>
<td><%=Rs("demo2")%> </td>
<td><%=Rs("demo3")%> </td>
<td><%=Rs("demo4")%> </td>
<td><%=Rs("demo5")%> </td>
<td><%=Rs("demo6")%> </td>
<td><%=Rs("demo7")%> </td>
<td><%=Rs("demo8")%> </td>
</tr>
<%
counter = counter + 1
Rs.MoveNext
Loop
%>
</table>
<%
end sub
'-------------------------------------
sub listaahtyot
%>
<strong>Hyväksytyt
harjoitustyöt</strong>
<%
ConnectionString =
Session("opiskelijat_ConnectionString")
Set Rs =
Server.CreateObject("ADODB.Recordset")
Rs.Open "SELECT * FROM uusittu2 WHERE
htyo_palautettu IS NOT NULL ORDER BY sukunimi", _
ConnectionString, 0, 1
if (Rs.BOF AND Rs.EOF) then
Response.Write "Ei yhtään
opiskelijaa<br>"
exit sub
end if
%>
<table border="1" cellpadding="2"
cellspacing="0">
<tr>
<td> </td>
<td><strong>Sukunimi</strong></td>
<td><strong>Etunimi</strong></td>
<td><strong>E-mail</strong></td>
<td><strong>KO</strong></td>
<td><strong>Harjoitustyön
tyyppi</strong></td>
<td><strong>Nimi</strong></td>
<td><strong>Pvm</strong></td>
<td><strong>Bonus</strong></td>
</tr>
<%
counter = 1
Do While Rs.EOF = false
%>
<tr>
<td><%=counter%></td>
<td><%=Rs("sukunimi")%> </td>
<td><%=Rs("etunimi")%> </td>
<td><a href="mailto:<%=Rs("sähköpostiosoite")%>"><%=Rs("sähköpostiosoite")%> </a></td>
<td><%=Rs("koulutusohjelma")%> </td>
<td><%=Rs("htyontyyppi")%> </td>
<td><%=Rs("nimi")%> </td>
<td><%=Rs("htyo_palautettu")%> </td>
<td><%=Rs("extrabonus")%> </td>
</tr>
<%
counter = counter + 1
Rs.MoveNext
Loop
%>
</table>
<%
end sub
%>
6.2
ASP-koodin tuottama HTML-koodi
<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft
Visual InterDev 1.0">
<META HTTP-EQUIV="Content-Type"
content="text/html; charset=iso-8859-1">
<TITLE>Tietokone ja
perusohjelmistot</TITLE>
</HEAD>
<BODY bgcolor="#FFFFFF" text="#333333"
leftmargin="0" topmargin="0">
<h1><strong>TIETOKONE JA
PERUSOHJELMISTOT</strong></h1>
0 tarkoittaa mitä tahansa
demoryhmää<br>
1-8 ovat demoryhmien
numerot<br>
tyhjä tarkoittaa puuttuvaa
demosuoritusta<br>
<br>
<a
href="lista.asp?htyot=kukkuu"><strong>Hyväksytyt
harjoitustyöt</strong></a>
<br>
Jos listauksen tiedoissa on puutteita tai vikoja
niin lähetä sähköpostia<a
href="mailto:hazor@iki.fi">
tlahtone@cc.hut.fi</a>
<table border="1" cellpadding="2"
cellspacing="0">
<tr>
<td> </td>
<td><strong>Sukunimi</strong></td>
<td><strong>Etunimi</strong></td>
<td><strong>E-mail</strong></td>
<td><strong>KO</strong></td>
<td><strong>Demo1</strong></td>
<td><strong>Demo2</strong></td>
<td><strong>Demo3</strong></td>
<td><strong>Demo4</strong></td>
<td><strong>Demo5</strong></td>
<td><strong>Demo6</strong></td>
<td><strong>Demo7</strong></td>
<td><strong>Demo8</strong></td>
</tr>
<tr>
<td>1</td>
<td>Aittola </td>
<td>Jussi </td>
<td><a
href="mailto:"> </a></td>
<td> </td>
<td> </td>
<td>2 </td>
<td>2 </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td>2</td>
<td>Arhosalo </td>
<td>Touko </td>
<td><a
href="mailto:tparhosa@itu">tparhosa@itu </a></td>
<td>Fys </td>
<td>0 </td>
<td>7 </td>
<td>7 </td>
<td> </td>
<td>7 </td>
<td>7 </td>
<td>3 </td>
<td>7 </td>
</tr>
<tr>
<td>3</td>
<td>Forsblom </td>
<td>Hannu </td>
<td><a
href="mailto:hmforsbl@itu">hmforsbl@itu </a></td>
<td>Kemko </td>
<td>0 </td>
<td>3 </td>
<td>3 </td>
<td> </td>
<td>3 </td>
<td>7 </td>
<td>3 </td>
<td>3 </td>
</tr>
<tr>
<td>4</td>
<td>Haapala </td>
<td>Elina </td>
<td><a
href="mailto:elhaapal@itu">elhaapal@itu </a></td>
<td>Kem </td>
<td>0 </td>
<td>3 </td>
<td>3 </td>
<td>2 </td>
<td>3 </td>
<td>3 </td>
<td>1 </td>
<td>3 </td>
</tr>
<tr>
<td>5</td>
<td>Hakanen </td>
<td>Leila </td>
<td><a
href="mailto:"> </a></td>
<td>Matko </td>
<td>0 </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td>6</td>
<td>Halonen </td>
<td>Tomi </td>
<td><a
href="mailto:tohalone@silmu">tohalone@silmu </a></td>
<td>Tie </td>
<td>0 </td>
<td>8 </td>
<td>8 </td>
<td>8 </td>
<td>8 </td>
<td>8 </td>
<td>8 </td>
<td>8 </td>
</tr>
<tr>
<td>7</td>
<td>Halttunen </td>
<td>Helena </td>
<td><a
href="mailto:halttunen@jykem.jyu.fi">halttunen@jykem.jyu.fi </a></td>
<td>Kem </td>
<td>0 </td>
<td>7 </td>
<td>6 </td>
<td>6 </td>
<td>4 </td>
<td>4 </td>
<td>4 </td>
<td>4 </td>
</tr>
{ POISTETTU YLI 40 SIVUA TURHAA LISTAUSTA
}
<tr>
<td>168</td>
<td>Äijänen </td>
<td>Jussi </td>
<td><a
href="mailto:jpaijane@itu">jpaijane@itu </a></td>
<td>Fys </td>
<td>0 </td>
<td> </td>
<td>5 </td>
<td>5 </td>
<td>5 </td>
<td>5 </td>
<td>5 </td>
<td>5 </td>
</tr>
<tr>
<td>169</td>
<td>Äyrämö </td>
<td>Sami </td>
<td><a
href="mailto:samiayr@silmu">samiayr@silmu </a></td>
<td>Fys </td>
<td>0 </td>
<td>4 </td>
<td>4 </td>
<td>4 </td>
<td>4 </td>
<td>4 </td>
<td> </td>
<td> </td>
</tr>
</table>
</BODY>
</HTML>
6.3
IntraBuilderilla toteutettu opiskelijoiden
demoaktiivisuuslista
//
// Generated on 11.12.1997
//
var r = new BARReport();
if (BAR.arguments.length == 2) {
r.startPage = BAR.arguments[0];
r.endPage = BAR.arguments[1];
}
r.render();
class BARReport extends Report {
with (this) {
title = "Uusittu2";
linkText = "Next Page";
}
with (this.opiskelijat1 = new
Database()){
left = 0;
top = 0;
databaseName = "OPISKELIJAT";
active = true;
}
with (this.uusittu21 = new Query()){
left = 0;
top = 0;
database = parent.opiskelijat1;
sql = "SELECT * FROM uusittu2";
active = true;
}
with (this.uusittu21.rowset) {
indexName = "PrimaryKey";
}
with (this.StreamSource1 = new
StreamSource(this)){
}
with (this.StreamSource1.detailBand) {
height = 2890;
}
with (this.StreamSource1.detailBand.html1 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
width = 1700;
color = "black";
fontBold = true;
text = "Sukunimi";
}
with (this.StreamSource1.detailBand.html2 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["Sukunimi"].value};
}
with (this.StreamSource1.detailBand.html3 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
top = 240;
width = 1700;
color = "black";
fontBold = true;
text = "Etunimi";
}
with (this.StreamSource1.detailBand.html4 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
top = 240;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["Etunimi"].value};
}
with (this.StreamSource1.detailBand.html5 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
top = 480;
width = 1700;
color = "black";
fontBold = true;
text = "Sähk÷postiosoite";
}
with (this.StreamSource1.detailBand.html6 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
top = 480;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["Sähk÷postiosoite"].value};
}
with (this.StreamSource1.detailBand.html7 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
top = 720;
width = 1700;
color = "black";
fontBold = true;
text = "Koulutusohjelma";
}
with (this.StreamSource1.detailBand.html8 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
top = 720;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["Koulutusohjelma"].value};
}
with (this.StreamSource1.detailBand.html9 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
top = 960;
width = 1700;
color = "black";
fontBold = true;
text = "demo1";
}
with (this.StreamSource1.detailBand.html10 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
top = 960;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["demo1"].value};
}
with (this.StreamSource1.detailBand.html11 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
top = 1200;
width = 1700;
color = "black";
fontBold = true;
text = "demo2";
}
with (this.StreamSource1.detailBand.html12 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
top = 1200;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["demo2"].value};
}
with (this.StreamSource1.detailBand.html13 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
top = 1440;
width = 1700;
color = "black";
fontBold = true;
text = "demo3";
}
with (this.StreamSource1.detailBand.html14 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
top = 1440;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["demo3"].value};
}
with (this.StreamSource1.detailBand.html15 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
top = 1680;
width = 1700;
color = "black";
fontBold = true;
text = "demo4";
}
with (this.StreamSource1.detailBand.html16 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
top = 1680;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["demo4"].value};
}
with (this.StreamSource1.detailBand.html17 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
top = 1920;
width = 1700;
color = "black";
fontBold = true;
text = "demo5";
}
with (this.StreamSource1.detailBand.html18 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
top = 1920;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["demo5"].value};
}
with (this.StreamSource1.detailBand.html19 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
top = 2160;
width = 1700;
color = "black";
fontBold = true;
text = "demo6";
}
with (this.StreamSource1.detailBand.html20 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
top = 2160;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["demo6"].value};
}
with (this.StreamSource1.detailBand.html21 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
top = 2400;
width = 1700;
color = "black";
fontBold = true;
text = "demo7";
}
with (this.StreamSource1.detailBand.html22 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
top = 2400;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["demo7"].value};
}
with (this.StreamSource1.detailBand.html23 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
top = 2640;
width = 1700;
color = "black";
fontBold = true;
text = "demo8";
}
with (this.StreamSource1.detailBand.html24 = new
HTML(this.StreamSource1.detailBand)){
height = 240;
left = 1750;
top = 2640;
width = 7610;
color = "black";
text =
{||this.form.uusittu21.rowset.fields["demo8"].value};
}
with (this.PageTemplate1 = new
PageTemplate(this)){
height = 16837;
width = 11905;
marginTop = 1080;
marginLeft = 1080;
marginBottom = 1080;
marginRight = 1080;
gridLineWidth = 1;
}
with (this.PageTemplate1.StreamFrame1 = new
StreamFrame(this.PageTemplate1)){
height = 11376;
left = 360;
top = 1584;
width = 9360;
}
with (this.PageTemplate1.html1 = new
HTML(this.PageTemplate1)){
height = 414;
left = 360;
top = 360;
width = 1640;
color = "black";
fontBold = true;
text = "<H2>Uusittu2</H2>";
}
with (this.PageTemplate1.html2 = new
HTML(this.PageTemplate1)){
height = 296;
left = 360;
top = 784;
width = 2320;
color = "black";
fontBold = true;
text = {||new Date()};
}
with (this.PageTemplate1.html3 = new
HTML(this.PageTemplate1)){
height = 296;
left = 360;
top = 13140;
width = 1285;
color = "black";
fontBold = true;
text =
{||this.parent.parent.reportPage};
}
with (this.printer) {
duplex = 1;
orientation = 1;
paperSource = 7;
paperSize = 9;
resolution = 4;
color = 1;
trueTypeFonts = 3;
}
with (this.reportGroup) {
groupBy = "";
}
with (this.reportGroup.headerBand) {
height = 0;
}
with (this.reportGroup.footerBand) {
height = 0;
}
this.firstPageTemplate =
this.form.PageTemplate1
this.form.PageTemplate1.nextPageTemplate =
this.form.PageTemplate1
this.form.PageTemplate1.StreamFrame1.streamSource =
this.form.StreamSource1
this.form.StreamSource1.rowset =
this.form.uusittu21.rowset
}
6.4
IntraBuilderin Javascript-koodista tuotettu
HTML-koodi
<html>
<head>
<title>Uusittu2</title>
</head>
<body bgcolor="ffffff">
<form method="post"
action="http:intrasrv.isv?bar.jrp"><input type="hidden"
name="sessionID" value=881840734><input type="hidden"
name="session.sequenceNumber" value=0>
<input type="hidden" name="session.FormHandle"
value="13179512"><!-- Non table objects -->
<!-- Table objects -->
<table cellspacing=0 cellpadding=0 border=1
width=719>
<tr>
<td width=96><img
src="/ibserver/trans.gif" width=96 height=1
border=0></td>
<td width=85><img
src="/ibserver/trans.gif" width=85 height=1
border=0></td>
<td width=31><img
src="/ibserver/trans.gif" width=31 height=1
border=0></td>
<td width=507><img
src="/ibserver/trans.gif" width=507 height=1
border=0></td>
</tr>
<tr><td colspan=4 height=96>
</td>
<tr>
<td> </td>
<td align=left valign=top width=109 height=27
colspan=2><b><H2>Uusittu2</H2></b></td>
<tr><td colspan=4 height=1>
</td>
<tr>
<td> </td>
<td align=left valign=top width=154 height=19
colspan=3><b>11.12.1997
13:44:39</b></td>
<tr><td colspan=4 height=34>
</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>Sukunimi</b></td>
<td align=left valign=top width=507
height=16>Arhosalo</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>Etunimi</b></td>
<td align=left valign=top width=507
height=16>Touko</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>Sähk÷postiosoite</b></td>
<td align=left valign=top width=507
height=16>tparhosa@itu</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>Koulutusohjelma</b></td>
<td align=left valign=top width=507
height=16>Fys</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo1</b></td>
<td align=left valign=top width=507
height=16>0</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo2</b></td>
<td align=left valign=top width=507
height=16>7</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo3</b></td>
<td align=left valign=top width=507
height=16>7</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo4</b></td>
<td align=left valign=top width=507
height=16></td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo5</b></td>
<td align=left valign=top width=507
height=16>7</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo6</b></td>
<td align=left valign=top width=507
height=16>7</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo7</b></td>
<td align=left valign=top width=507
height=16>3</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo8</b></td>
<td align=left valign=top width=507
height=16>7</td>
<tr><td colspan=4 height=1>
</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>Sukunimi</b></td>
<td align=left valign=top width=507
height=16>Forsblom</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>Etunimi</b></td>
<td align=left valign=top width=507
height=16>Hannu</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>Sähk÷postiosoite</b></td>
<td align=left valign=top width=507
height=16>hmforsbl@itu</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>Koulutusohjelma</b></td>
<td align=left valign=top width=507
height=16>Kemko</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo1</b></td>
<td align=left valign=top width=507
height=16>0</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo2</b></td>
<td align=left valign=top width=507
height=16>3</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo3</b></td>
<td align=left valign=top width=507
height=16>3</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo4</b></td>
<td align=left valign=top width=507
height=16></td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo5</b></td>
<td align=left valign=top width=507
height=16>3</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo6</b></td>
<td align=left valign=top width=507
height=16>7</td>
<tr>
<td> </td>
<td align=left valign=top width=113 height=16
colspan=2><b>demo7</b></td>
<td align=left valign=top width=507
height=16>3</td>