Tik-76.115 Käyttöohje

Älykäs kalenteri - Arkkitehtuurin kehittämisohje

Sisällysluettelo

1. Johdanto
2. Arkkitehtuurin yleiskuvaus
3. Dokumentit
4 Tiedostot
5. Rajapinnat
6. Toimintaympäristö
6. Jatkokehittäminen
6.1 JDK 1.3
6.2 Servlet API
6.3 PostgreSQL-tietokanta
6.4 XML-kirjasto
6.5 Log4J
7. Ohjelmiston asennus
7.1 Asiakasohjelmisto
7.2 Palvelin
8. Jatkokehittäminen
8.1 Esitietovaatimukset
8.2 Suunnitteluperiaatteet
8.3 Kääntäminen
8.4 Moduulien lisääminen ja vaihto ohjelmistoon
8.5 Virheiden etsintä
8.6 Konfigurointi
8.7 Jatkokehittämisohjeita
9. Tiedossa olevia virheitä ja vajeita
10. Viitteet

Versiohistoria

Versio

Pvm

Muutos

Muuttaja

0.1

18.1.2001

T3-vaiheen ensimmäinen versio

Niko

1.0

8.2.2001

T3-vaiheen toinen versio

Niko

1.1

15.3.2001

T4-vaiheen palautettava versio

Niko

1.5

9.4.2001

LU-vaiheen ensimmäinen versio, asiakkaalle ja eTLA:lle

Juha, Kari, Santeri ja Teemu

1.9

21.4.2001

LU-vaiheen toinen versio

Juha

1. Johdanto

Dokumentti on Teknillisen korkeakoulun ohjelmistotyökurssilla tehtävän Osprey-projektin käyttöohjeen liite. Se on tarkoitettu arkkitehtuurin jatkokehittämisen avuksi. Osprey-projektin käyttöohje keskittyi pelkästään asiakasohjelmiston kuvaamiseen. Siksi katsottiin järkeväksi tehdä erillinen käyttöohje arkkitehtuurille. Tämä oli myös asiakkaan toivomus.

Kehittämisohjeen tarkoitus on toimia oppaana Osprey-projektin arkkitehtuuria koskevaan materiaaliin, koota näistä dokumenteista järkevä yleiskuvaus sekä antaa viitekehys jatkokehittämiseen. Dokumentti sisältää kuvauksen Osprey-projektiin kuuluvista tiedostoista, käyttöympäristön vaatimukset sekä esimerkinomaisia jatkokehitysohjeita. Lisäksi dokumentti sisältää arkkitehtuurin asennusohjeet.

Tämä dokumentti on tarkoitettu projektin asiakasta varten. Tavalliselle asiakasohjelmiston kayttäjälle on erikseen oma käyttöohje [OSPREY-K].

2. Arkkitehtuurin yleiskuvaus

Arkkitehtuurin tekninen yleiskuva löytyy teknisestä määrittelystä [OSPREY-T].

3. Dokumentit

Osprey-projektin aikana on tehty useita dokumentteja, jotka liittyvät projektin tuotteena olevaan kalenteriin. Näihin dokumentteihin on hyvä perehtyä ennen jatkokehittämistä.

Käyttöohje
Tekninen määrittely
Tekninen määrittely, asiakasohjelmistoliite
Testaussuunnitelma
Termit
Toiminnallinen määrittely
Toiminnallinen määrittely, käyttöliittymä
Vaatimusmäärittely

Kaikki em. dokumentit löytyvät CD:ltä.

4. Tiedostot

Alla oleva hakemistolistaus käsittää ohjelmiston CD:n hakemistorakenteen.
README Lue minut ensiksi!
LICENSE GNU GPL lisenssi
src/ Lähdekoodit
doc/ Dokumentaatio
doc/javadoc Lähdekoodin Java-dokumentaatio
doc/kayttoohje Käyttöohjeet (tämä dokumentti ja asiakasohjelmiston)
doc/kehitysdokumentit Sekalaisia kehitysdokumenttejä
doc/muut Sekalaisia muistiinpanoja
doc/projektisuunnitelma Projektisuunnitelma
doc/skenaariot/ Projektin lähtökohtana toimineet skenaariot
doc/tekninenmaarittely Projektin tekninen määrittely
doc/testaus Testaukseen liittyvä dokumentaatio
doc/toiminnallinenmaarittely Projektin toiminnallinen määrittely
doc/vaatimusmaarittely Projektin vaatimusmäärittely
bin/ Valmis asiakasohjelmisto ja palvelin
conf/ Esimerkkikonfiguraatiotiedostot
lib/ Vaaditut kirjastot (JDBC, Xerces, Servlet, Log4J)
clientpics/ Asiakasohjelmiston vaatimat kuvat

Alla oleva listaus kuvaa lähdekoodin rakenteen ja samalla Java-pakettien hierarkian ja sisällön.

JLex/ JLex-lähdekoodit
java_cup/ JavaCUP-lähdekoodit
FI/hut/cs/osprey/ Osprey-projektin lähdekoodit
FI/hut/cs/osprey/client Asiakasohjelmisto
FI/hut/cs/osprey/common Palvelimen ja asiakasohjelmiston mahdollisesti yhteisiä osia
FI/hut/cs/osprey/common/cap CAP-asiakasohjelmisto
FI/hut/cs/osprey/common/core Ydin
FI/hut/cs/osprey/common/config Konfiguraatiotuki
FI/hut/cs/osprey/common/directory Hakemistopalvelu
FI/hut/cs/osprey/common/distiller Jalostajat
FI/hut/cs/osprey/common/filter Suodattimet
FI/hut/cs/osprey/common/icalendar iCalendar-esitysmuoto
FI/hut/cs/osprey/common/importer XML-sisääntuoja
FI/hut/cs/osprey/common/module Ytimen moduulituki
FI/hut/cs/osprey/common/location Etäisyyslaskuri
FI/hut/cs/osprey/common/repository Tietovarastot
FI/hut/cs/osprey/common/watcher Käyttäjän sijainnin tarkkailu
FI/hut/cs/osprey/common/watcher/sms SMS-hälytykset
FI/hut/cs/osprey/server Palvelin
FI/hut/cs/osprey/server/parser Palvelimen tuetut protokollat (CAP)

5. Rajapinnat

Rajapintojen kuvaukset löytyvät teknisen määrittelyn ([OSPREY-T]) luvusta neljä.

6. Toimintaympäristö

6.1 JDK 1.3

Osprey kalenteria kehitettäessä on palvelimessa käytetty Sunin Java Developer's Kit 1.3 -ympäristöä Debian GNU/Linux-ympäristössä. Osprey-palvelin toimii myös muissa käyttöjärjestelmissä, joille on saatavilla JDK 1.3. Osoitteesta http://java.sun.com/ on ilmaiseksi imuroitavissa versiot Windows-, Linux- ja Solaris-käyttöjärjestelmille. Todennäköisesti palvelin toimii myös JDK 1.2.x versiolla, koska mitään merkittäviä rajapintamuutoksia ei tiettävästi ole, mutta tätä ei ole testattu. JDK 1.1 ei toimi, koska Ospreyssä on käytetty Java 2:n (JDK 1.2) myötä tullutta Collections APIa, sekä JDBC 2.0 rajapintaa.

6.2 Servlet API

Asiakasohjelmisto on toteutettu Java2-servlettinä ja sen kääntämiseen vaaditaan Sun Microsystemsin Java Servlet API

Asiakasohjelmisto on toteutettu Java2-servlettinä ja sen ajamiseen vaaditaan Apachen Jakarta-Tomcat implementaatio

6.3 PostgreSQL-tietokanta

Ospreyn kehityksessä on käytetty vapaata tietokantaohjelmistoa, PostgreSQL 7.0.2. Sen kotisivut löytyvät osoitteesta http://www.postgresql.org/. Siitä on olemassa versio lähes jokaiselle Unix (tai Linux) -alustalle, sekä Cygwin-kirjastoa käyttävä versio Windows NT / 2000 käyttöjärjestelmälle. Tietokanta ei siis rajoita käytettävää palvelintyyppiä. Harjoitustyössä käytettiin Linux-versiota tietokannasta Debian levityksessä. Myös muille Linux-levityksille on olemassa valmiit asennuspaketit.

Kun PostgreSQL on asennettu, on hyvä tapa luoda Osprey-palvelimelle oma looginen tietokantansa, vaikka periaatteessa voitaisiin käyttää myös PostgreSQL vakiokantaa template1 tms. Kannan luominen tapahtuu komentorivityökalulla "createdb osprey". Kyseisellä Unix-käyttäjällä täytyy olla oikeus luoda tietokantoja. Helpointa on käyttää Unix-käyttäjätunnusta postgres, joka on PostgreSQL-tietokannan oletusylläpitäjä. Mikäli halutaan käyttää muuta käyttäjätunnusta, siihen löytyy ohjeet PostgreSQL-manuaalista. Täysin Unix-käyttäjätunnuksista erillinen asia on PostgreSQL-käyttäjä, joka luodaan komennolla "createuser -P ospreyuser". Kun kanta on luotu, tarvitsee se kantamäärityksen. Tarvittava schema löytyy CD:ltä tiedostosta src/FI/hut/cs/osprey/common/icalendar/schema.sql. Se ajetaan kantaan osprey komennolla "psql -U ospreyuser -f schema.sql osprey". Tiedostosta src/FI/hut/cs/osprey/common/icalendar/testdata.sql löytyy esimerkkikäyttäjien lisäys kantaan.

Tietokanta on syytä suojata luvattomalta käytöltä rajoittamalla osoitteita, joista tietokantaan saa ottaa yhteyden. Tämä tapahtuu editoimalla PostgreSQL PGDATA -hakemistosta tiedostoa pg_hba.conf. Rivi "host all 1.2.3.4 255.255.255.255 password" sallii yhteydet osoitteesta 1.2.3.4 vaatien selväkielisen salasanan. Tarkemmat tiedot kannan turvaamisesta löytyvät PostgreSQL-manuaalista kappaleesta "28. Security".

PostgreSQL ei myöskään ole ainoa mahdollinen tietokanta, kunhan kantaan löytyy JDBC 2.0-yhteensopivat ajurit Javalle. Muita kantoja ei kuitenkaan ole testattu, joten niiden käyttäminen aiheuttaa ylimääräistä työtä. PostgreSQL tuotantoajuritkaan eivät toteuta, tai ainakaan kokeiluhetkellä toteuttaneet JDBC 2.0 -rajapintaa, joten osprey-käyttöä varten niitä täytyy patchata. Korjatut PostgreSQL-JDBC-ajurit (version 7.0.2 pohjalta) löytyvät ohjelmiston CD:ltä hakemistosta lib. PostgreSQL JDBC-ajurien kotisivu löytyy osoitteesta http://jdbc.postgresql.org/. PostgreSQL:n JDBC-ajurit ovat tyyppiä 4, eli ne ovat puhdasta Javaa.

Tietokantayhteyden parametrit määritellään ospreyn asetustiedostossa conf/osprey.conf. Siellä tarvitaan seuraavat asetukset:

Tietokannan ei tietenkään tarvitse sijaita samalla palvelimella kuin varsinaisen kalenteripalvelimen. Tällöin localhost vaihdetaan tietokantapalvelimen osoitteeseen. Porttinumero riippuu luonnollisesti tietokannan asetuksista. Käyttäjätunnus ja salasana on määritelty postgres-käyttäjää luotaessa.

6.4 XML-kirjasto

Kumpikaan, kalenteripalvelin eikä asiakasohjelmisto, ei käytä XML:ää mihinkään. Kalenterimerkintöjä voi kuitenkin tuoda kalenteripalvelimeen XML-tiedostosta. Mikäli käytetään tätä erillistä työkalua, tarvitaan Apachen Xerces XML-kirjasto xerces.jar Javan CLASSPATH:iin. Ks. kappale 8.7.13.

6.5 Log4J

Kalenteripalvelin sekä asiakasohjelmistona toimiva servlet käyttävät Apache- projektin Log4J monipuolista lokimoduulia. Java CLASSPATH:iin pitää siis sisältää Log4J:n kirjasto log4j.jar.

7. Ohjelmiston asennus

7.1 Asiakasohjelmisto

Asiakasohjelmiston tarvitsemat Java-luokat pitää kopioida paikkaan, josta Jakarta-Tomcat ne löytää, esim. hakemistoon /usr/local/jakarta-tomcat/lib/, josta Tomcat löytää luokat automaattisesti. (Tässä oletetaan, että Jakarta-Tomcat on asennettu hakemistoon /usr/local/jakarta-tomcat/).

Asiakasohjelmisto vaatii seuraavat paketit toimiakseen:

Kaikki yllämainitut paketit tulisi kopioida hakemistoon /usr/local/jakarta-tomcat/lib/. Tiedostojen kopioinnin jälkeen Tomcat on käynnistettävä uudelleen, jotta se havaitsee uudet paketit.

Luokkatiedostojen lisäksi asiakasohjelmisto tarvitsee grafiikan tuottamiseen kuvat, jotka löytyvät CD:lta hakemistosta clientpics. Kuvat tulee kopioida Tomcatin webapps/test/ hakemistoon, mista servlet niita yrittaa hakea.

Ks. kappale 8.6.1 miten asiakasohjelmisto konfiguroidaan.

Konfiguraatiotiedoston muokkauksen jälkeen asiakasohjelmisto voidaan käynnistää avaamalla WWW-selaimella sivu: http://<Apache-palvelin>:8080/servlet/FI.hut.cs.osprey.client.Client. (Tässä oletetaan, että Jakarta-Tomcat vastaanottaa kutsuja portista 8080.)

7.2 Palvelin

Asennus koostuu seuraavista vaiheista:

  1. Tarvittavien ajonaikaiskirjastojen ja Java 1.3 ympäristön asennus. Tarvittavat lisäohjelmistot ja -kirjastot on käsitelty kappaleessa 6.
  2. Kalenteripalvelimen ajonaikaistiedostojen ja konfigurointitiedostojen kopiointi palvelimelle. Valmiiksi käännetyt binäärit löytyvät CD:ltä hakemistosta bin ja esimerkkikonfiguraatiotiedostot hakemistosta conf. Palvelinohjelmisto löytyy tiedostosta osprey.jar.
  3. Palvelimen ohjelmiston ajoympäristön valmistelu Java CLASSPATH:n osalta. Sen tulee pitää sisällään niin tarvittavat lisäkirjastot kuin itse kalenteripalvelimen ajonaikaistiedosto, osprey.jar. Alla esimerkki CLASSPATH tilanteesta jossa lisäkirjastot on sijoitettu /usr/share/java:aa ja itse palvelin hakemistoon /usr/local/osprey.
    /usr/local/osprey/osprey.jar:/usr/share/java/log4j.jar:/usr/share/java/jdbc7.0-1.2.jar:\
    /usr/share/java/xerces.jar
    
  4. Seuraavaksi voidaan muuttaa palvelimen konfiguraatiotiedostoa, mikäli oletuskonfiguraatio ei ole toivottava. Oletuskonfiguraatio on useimpiin tarkoituksiin sopiva. Ks. kappale 8.6.2.
  5. Mikäli halutaan konfiguroida palvelimen lokikäyttäytymistä, tässä vaiheessa voidaan muokata lokikonfiguraatiota. Ks. kappale 8.6.2, mikäli haluat tarkempia tietoja.
  6. Lopuksi tietokantaan on syötettävä palvelimen tietokanta schema ja lisättävä halutut käyttäjät. Schema löytyy lähdekoodin joukosta Java-paketista FI.hut.cs.osprey.common.icalendar. Ks. kappale 8.7.11 miten käyttäjätiedot lisätään kantaan ja kappale 6.3 miten schema asennetaan PostgreSQL-tietokantaan.
  7. Nyt palvelin on valmis käynnistettäväksi konsolilta. Tämä tapahtuu käytännössä seuraavanlaisella komentorivillä:
    java FI.hut.cs.osprey.server.CalendarServer
    
    Parametreiksi voidaan antaa konfiguraatiotiedoston sijainti optiolla -f <tiedoston_sijainti> ja Log4J:n konfiguraation sijainti optiolla -l <tiedoston_sijainti>. Konfiguraatiotiedostoa haetaan oletusarvoisesti sijainnista /etc/osprey.conf ja mikäli lokikonfiguraatiota ei löydy parametreistä, käytetään Log4J:n peruskonfiguraatiota, joka tulostaa lokiviestit konsolille.
  8. Palvelin on pystyssä ja voidaan tappaa CTRL-C näppäinyhdistelmällä tarvittaessa.

8. Jatkokehittäminen

8.1 Esitietovaatimukset

Kehittäjältä oletetaan tuntemusta ainakin seuraavista asioista:

Käytettyjen työkalujen tarkemmat kuvaukset löytyvät luvusta kuusi.

8.2 Suunnitteluperiaatteet

Suunnitteluperiaatteiden tarkka kuvaus löytyy teknisen määrittelyn ([OSPREY-T]) luvusta 3.1. Tärkein suunnitteluperuste oli modularisointi hyvin määriteltyjen rajapintojen avulla.

8.3 Kääntäminen

Sekä asiakasohjelmiston että palvelimen kääntäminen lähdekoodeista tapahtuu käyttämällä Apache-projektin Ant make-työkalua. Tarvittava XML-pohjainen make-tiedosto löytyy CD:n juurihakemistosta nimellä build.xml.

Kääntäminen vaatii kappaleessa 6 mainitut kirjastot Javan CLASSPATHiin. Projektin makefile tunnistaa seuraavat käännöskokonaisuudet:

On huomattava, että Ant ei build.xml-tiedoston määrityksien perusteella tunne käännettävien luokkien riippuvaisuuksia. Suuria muutoksia tehdessä kannattaa siis vanhat käännökset siivota pois ennen uutta käännöstä.

8.4 Moduulien lisääminen ja vaihto ohjelmistoon

Eri moduulien korvaaminen toisilla saman rajapinnan toteuttavilla moduuleilla on helppoa: muutat vain kalenteriserveriluokasta FI.hut.cs.osprey.server.CalendarServer ladattavat moduulit. Muihin tiedostoihin ei tarvitse koskea, pelkkä kalenteriserveriluokan uudelleenkääntäminen riittää. Ladattavat moduulit olisi lisäksi melko helppo muuttaa haettavaksi konfiguraatiotiedostosta, jollain mitään ei tarvisi uudelleenkääntää moduulien vaihtuessa.

Modulirakenne

8.5 Virheiden etsintä

Sekä palvelimen että asiakasohjelmiston vikojen etsintä kannattaa suorittaa hyväksikäyttäen Log4J:n monipuolisia mahdollisuuksia rajata lokimerkintöjä. Projektin tuotoksissa on käytetty luokkakohtaista erottelua lokiviesteille ts. lokiviestit on mahdollista suodattaa hyvinkin tarkasti käyttäen Log4J:n lokimäärityksiä.

Oletetaan esimerkiksi, että kehittäjä haluaa tutkia miksi suodattimet tekevät outouksiaan. Mahdollisuuksia on kaksi:

Lisäapuna lokiviesteihin talletaan käyttäjän nimi, joka aiheutti operaatiot. Lokiviesteistä saadaan siis helposti selville esim. grep:aamalla yksittäiseen käyttäjään liittyvät lokimerkinnät.

Lisätietoja Log4J:n tarjoamista mahdollisuuksista muokata, suodattaa ja uudelleenohjata lokimerkintöjä löytyy ohjelmiston kotisivulta runsaasti.

8.6 Konfigurointi

8.6.1 Asiakasohjelmisto

Asiakasohjelmisto lukee käynnistyessään konfiguraatiotiedoston /etc/osprey-client.conf (esimerkkitiedosto osprey/src/conf/osprey.conf). Tässä tiedostossa määritellään asiakasohjelmiston käyttäjien kalenteripalvelimen IP-osoite ja portti, jota kalenteripalvelin kuuntelee, sekä hakemistopalvelimen IP-osoite ja portti. Esimerkkitiedoston sisältö:

###########################################################################
# IP-address of the calendar server
#
SERVER_ADDRESS=ohjtyo-13.cs.hut.fi

##########################################################################
# Port of the calendar server
#
SERVER_PORT=8889

###########################################################################
# IP-address of the directory server
#
DIRECTORY_ADDRESS=ohjtyo-13.cs.hut.fi

##########################################################################
# Port of the directory server
#
DIRECTORY_PORT=9999

Servlet käsittelee em. konfiguraatiotiedostoa standardina ns. Java property -tiedostona.

8.6.2 Palvelin

Alla on esimerkki palvelimen konfiguraatiotiedostosta. Konfiguraatiotiedostoa haetaan oletusarvoisesti sijainnista /etc/osprey.conf.

###########################################################################
# Osprey JDBC local database storage connection URL
# 
DATABASE_URL=jdbc:postgresql://localhost:5432/osprey
 
###########################################################################
# Osprey JDBC database user name
# 
DATABASE_USERNAME=osprey 
 
###########################################################################
# Osprey JDBC database user password 
# 
DATABASE_PASSWORD=osprey 
 
###########################################################################
# Osprey CAP listener port number
#
CAP_LISTENER=8889 
 
###########################################################################
# Osprey Simple Directory Service listener port number
# 
DIRECTORY_LISTENER=9999 
 
###########################################################################
# Watcher on/off. Watcher triggers alarms (sends SMS message).
#
WATCHER=YES
 
###########################################################################
# Watcher on/off. Predict generates alarms, if user is not near
# the location next event / todo is happening at.
#
PREDICT=YES

Alla on kuvattuna yo. konfiguraatio-optiot tarkemmin.

Konfiguraatiotiedoston luku on toteutettu Java-paketissa FI.hut.cs.osprey.common.config. Konfiguraatio-optioita ei ole paketissa määritelty, vaan staattiselta konfiguraatioluokalta voidaan pyytää millä tahansa parametrin nimellä option arvoa. Mikäli arvoa ei ole määritelty luetussa tiedostossa, heitetään poikkeus. Alla on listattu konfiguraatio-optioiden lukuun tarkoitetut metodit.

/**
 * Returns a value of the configuration item.
 * @param key The configuration item key searched.
 * @throws IllegalArgumentException if no item searched is found.
 * @return A value string defined by the item key.
 */
static String getString(String key) throws IllegalArgumentException;

/** 
  * Returns a value of the configuration item.
  * @param key The configuration item key searched. 
  * @throws IllegalArgumentException if no item searched is found.
  * @return A value int defined by the item key.
  */ 
static int getInt(String key) throws IllegalArgumentException;

Lisätietoja miten Log4J konfiguroidaan löytyy ohjelmiston kotisivuilta.

8.7 Jatkokehittämisohjeita

Seuraavaan on koottu keskeisiä ohjeita arkkitehtuurin jatkokehityksen kannalta. Ohjeet on kirjoitettu tyylillä, joka vaatii käytännössä lähdekoodin lukua samalla kun ohjeita luetaan. Ohjeita lukiessa pitää siis varautua käyttämään runsaasti aikaa.

8.7.1 Jalostajat

Jalostajien tekninen kuvaus ja toteutetut jalostajat löytyvät teknisen määrittelyn ([OSPREY-T]) luvusta 4.10.

Jalostajat muokkaavat kalenterikomentoja (lisäys, poisto, muokkaus, luku) ja tuottavat siten lisäarvoa peruskalenteritoimintoihin. Jalostajien tarkoituksena on mahdollistaa monipuolisten älyominaisuuksien luominen itse kalenterirunkoon koskematta. Projektin puitteissa on toteutettu muutama jalostajamoduuli (pakkauksessa FI.hut.cs.osprey.common.distiller), joista voi ottaa mallia.

Jalostajamoduuleilla ei ole varsinaisesti mitään rajoituksia niiden monimutkaisuudelle: ne voivat tehdä mitä tahansa Java sallii. Kannattaa kuitenkin huomioida, että jalostajamoduuleita kutsutaan useasti, joten monimutkaiset käsittelyt voivat kuormittaa serveriä. Jokainen kalenterikomento suoritetaan omassa säikeessään, joten kuormitus tarkoittaa vain serverin hidastumista.

Alla on esimerkki yksinkertaisesta jalostajasta. Se tutkii tapahtuman otsikkotietoa ja määrittelee sen kategoriaan kiireinen (urgent), jos otsikossa esiintyy sana urgent.

01: public class TestDistillerModule implements DistillerModule, ModuleFactory {
02:   private Core core;
03: 
04:   public static org.apache.log4j.Category cat =
05:     org.apache.log4j.Category.getInstance(LunchCheckerModule.class.getName());
06: 
07:   public void setCore(Core core) {
08:     this.core = core;
09:     try {
10:       ((CalendarModule)core.getModule("calendar")).register(VCommand.MODIFY, this);
12:     } catch(NotRegisteredException e) {
13:       cat.warn("Couldn't register TestDistillerModule to calendar");
14:     }
15:   }
16:   public void distill(VProfile p, VCommand c) throws VCalendarError {
17:     for(int j=0; j< c.numElements(); ++j) {
18:       VEventTodoParent e = (VEventTodoParent)c.getElement(j);
19:       if(e == null)
20:         continue;
21: 
22:       StringTokenizer st = new StringTokenizer(e.getSummary());
23:       while(st.hasMoreTokens()) {
24:         String s = st.nextToken();
25:         if("urgent".equals(s.toLowerCase()))
26:           e.addCategory("urgent", "1");
27:       }
28:     }
29:     return;
30:   }
31:   public Module getInstance() { return this; }
32: }

Rivillä 1 kerrotaan, moduuli on jalostajamoduuli ja sen lisäksi osaa itse toimia moduulitehtaana. Rivillä 10 rekisteröidytään kalenterimoduuliin ja kerrotaan että käsittelemme MODIFY-tyyppisiä käskyjä. Rivillä 16 on varsinainen jalostusmetodi. Kalenterioperaatiomoduuli kutsuu tätä kun sopivan tyyppinen komento tulee sisään.

Rivillä 17 aloitetaan käskyn kaikkien tapahtumien läpikäynti. Rivillä 19 tarkistetaan onko tapahtuma käsiteltävää tyyppiä, tällä hetkellä kaikki tapahtumat ovat. Rivillä 22 hajoitetaan tapahtuman otsikko sanoiksi ja rivillä 25 tarkistetaan näitä sanoja. Jos sana kuuluu etsittyihin sanoihin tehdään merkintä kategorioihin rivillä 26. Kategorioihin merkittyjä tietoja voidaan myöhemmin käyttää hyväksi muissa moduuleissa.

8.7.2 Suodattimet

Suodattimia käytetään valitsemaan joukosta kalenteriolioita (VEvent, VTodo jne.) mielenkiintoisimmat. Niitä voidaan pinota useampia peräkkäin ajettaviksi. Se, mitä suodattimia ajetaan, on sidottu "named queryihin". Jokaista named queryä kohti on mahdollista sitoa tietty setti suodattimia. Sitominen tapahtuu luokassa FI.hut.cs.osprey.common.module.NamedQuery. Sen konstruktorissa täytetään hajautusrakenne, avaimena kyselyn nimi ja arvona suodatinsetti merkkijonona.

Suodatinsetin määrityksen muoto on pakkaus.EnsimmäinenSuodatin(sana=vakioarvo,toinensana=toinenarvo); pakkaus.ToinenSuodatin(sana=arvo,jokumuu=?profiilista?); Arvot, jotka tulee antaa kaikille suodattimille, ovat lowdrop, highpass ja weight. Muut arvot riippuvat suodattimesta.
lowdrop pistemäärä, jota pienemmät pisteet kyseisestä suodattimesta saaneet eivät pääse läpi seuraavalle suodattimelle, eivätkä myöskään koko suodatinsetistä kokonaisluku 0..100, < highpass
highpass pistemäärä, jota suuremmat pisteet saaneet pääsevät automaattisesti läpi suodatinsetistä, riippumatta seuraavien suodatinten antamista pisteistä kokonaisluku 0..100 > lowdrop
weight painoarvo, jolla kyseinen suodatin vaikuttaa kokonaispisteisiin. Eri suodatinten antamista pisteistä lasketaan siis painotettu keskiarvo. kokonaisluku > 0

Esimerkki: "FI.hut.cs.osprey.common.filter.WordFilter(lowdrop=20,highpass=100,weight=1,words=computer:10/programming:20/cooking:-20); FI.hut.cs.osprey.common.filter.ProximityFilter(lowdrop=30,highpass=100,weight=2,minutes=20,zerominutes=30,limitpoints=80,latitude=62.12345,longitude=32.12345);"

Määrityksessä voidaan antaa myös käyttäjäkohtaisia arvoja, jotka merkitään kysymysmerkein ympäröidyllä sanalla. Asiakasohjelmistossa voidaan profiilinmuokkaussivulla antaa filttereihin liittyville avainsanoille arvoja: profiilista=yy/kaa/koo/nee,. Tämä saa jälkimmäisestä suodatinmäärittelystä aikaan seuraavanlaisen: pakkaus.ToinenSuodatin(sana=arvo,jokumuu=yy/kaa/koo/nee);

Suodattimet instantioidaan luokassa FI.hut.cs.osprey.common.filter.FilterEngine. Se ottaa vastaan suodattimia, jotka perivät abstraktin luokan FI.hut.cs.osprey.common.filter.Filter. Kun määritellään uusi suodatin, on toteutettava abstrakti metodi int filter(VObject object). Sen tulee palauttaa suodatettavalle oliolle pistemäärä 0..100. Se, miten pisteytys varsinaisesti tapahtuu on täysin sovelluskohtaista. Mikäli kyseinen suodatin ei osaa suodattaa sille annetun tyyppisiä olioita, sen kuuluu heittää FI.hut.cs.osprey.common.filter.FilterTypeException. Mikäli suodatin tarvitsee muita parametreja kuin yllä luetellut pakolliset, on ne alustettava init-metodissa. Kun määritellään korvaava init-metodi, on suositeltavaa, että se kutsuu isäluokkansa init-metodia, joka alustaa vakioparametrit.

Alla on esimerkki yksinkertaisesta suodattimesta. Se arpoo luvun 0..100, ja mikäli se on pienempi kuin parametrissa limit annettu arvo, annetaan 0 pistettä, muuten annetaan juuri arvottu pistemäärä.

01: public class RandomFilter extends Filter {
02: 
03:   private int limit = 0;
04: 
05:   public int filter(VObject object) throws FilterTypeException {
06:     java.util.Random rand = new java.util.Random(); 
07:     int rndNum =  rand.nextInt(100);
08:     if (!object instanceof VEvent)
09:       throw new FilterTypeException();
10:     if (rndNum < limit)
11:       return 0;
12:     else
13:       return rndNum;
14:   }
15:
16:   public void init(Map properties, Core core) throws FilterTypeException {
17:     super.init(properties, core);
18:     try {
19:       String lim = (String)properties.get("limit");
20:       if (lim != null)
21:         limit = String.parseInt(lim);
22:     } catch (Exception e) {
23:       throw new FilterTypeException();
24:     }
25:   }
26: } 

Rivillä 1 kerrotaan suodattimen perivän abstraktion luokan Filter, kuten kaikkien suodatinten täytyy.

Rivillä 8-9 tarkastetaan, että suodatettava olio on tyyppiä, jota suodattimemme ymmärtää. Mikäli näin ei ole, heitetään poikkeus FilterTypeException

Riveillä 10-13 lasketaan oliolle annettavat pisteet. Mikäli laskentakaava mahdollistaa pisteitä alle nollan ja yli sadan, on ne muunnettava ko. välille.

Rivillä 16 init-metodi kutsuu isäluokkansa init-metodia. Se alustaa kaikille suodattimille yhteiset parametrit

Riveillä 19-21 pyydetään suodattimen tarvitsemat parametrit taulukosta. Mikäli tarvittavaa parametria ei löydy, voidaan turvautua vakioarvoihin tai vaihtoehtoeisesti heittää poikkeus, mikäli suodatin ei voi toimia ilman ko. parametria.

Harjoitustyössä toteutettiin kaksi suodatinta, joista toinen on FI.hut.cs.osprey.common.filter.ProximityFilter. Se suodattaa tapahtumia sen perusteella, kuinka kauan niihin siirtyminen kestäisi nykyisestä sijainnista.

ProximityFilter

Tarvittavat parametrit kaikille yhteisten lisäksi:

latitude Vertailusijainnin (esim. käyttäjän nykyisen sijainnin) leveyspiiri Asteita desimaalilukuna
longitude Vertailusijainnin pituuspiiri Asteita desimaalilukuna
minutes Jos siirtymiseen kuluu tasan minutes minuuttia, annetaan limitpoints pistettä. Yo. kuvassa pisteen A x-koordinaatti. Kokonaisluku > 0
limitpoints Pistemäärä, joka annetaan kun siirtymiseen kuluu tasan minutes minuuttia. Pisteen A y-koordinaatti. Kokonaisluku 0..100
zerominutes Siirtymiseen kuluva aika, jolloin annetaan nolla pistettä. Pisteen B x-koordinaatti. Kokonaisluku > minutes

Yllä lueteltujen pisteiden välillä pistemäärä interpoloidaan siten, että hetkellä 0 annetaan 100 pistettä. Jälkimmäinen suodatin, WordFilter, suodattaa tapahtumia siinä esiintyvien sanojen perusteella. Asiakasohjelmistossa voidaan määritellään esim. parametri words=computer:10/programming:20/car:-20 jolloin aina kun tapahtuman summary tai description -kentistä löytyy joku kyseisistä sanoista, sen pistemäärään lisätään määrityksessä sanan perässä sille annettu pistemäärä. Esim. yllä olevalla määrityksellä tapahtuma: "Summary: Lecture in computer programming, Description: Topics car and cdr." saisi 10+20-20=10 pistettä.

8.7.3 CAP-tuen laajentaminen

Sekä kalenteripalvelin, että asiakasohjelmisto käyttävät samaa toteutusta CAP-protokollasta. CAP-protokolla tuki ei ole täydellinen, joten jatkokehityksessä saattaa tulla tarve täydentää tuettuja ominaisuuksia. CAP:sta puuttuu mm. tuki käyttäjätietojen välityksiin, koska protokolla keskittyy vain itse kalenterimerkintöjen siirtoon. CAP-protokolla on myös hyvin monimutkainen, mikä varmasti hidastaa sen käyttöönottoa (tai jopa estää sen).

CAP-protokollajäsennin on toteutettu käyttäen JavaCUP:lla. Selaimena toimii JLex. Kielioppi löytyy Java-paketin Fi.hut.cs.osprey.common.cap alta tiedostosta parser.cup. Lekserin määritys löytyy vastaavasta paketista tiedostosta lexer.lex.

CAP-parseri luo suoraan Java-paketissa FI.hut.cs.osprey.common.icalendar olevia iCalendar-olioita. Vastaavasti iCalendar-oliot pystyvät tuottamaan CAP:n mukaisen esityksen itsestään toString-metodilla.

Sekä asiakasohjelmisto että palvelin käyttävät edelleen samasta paketista löytyvää CAPParser-luokkaa, joka edelleen käyttää JavaCUP:n luomaa parseriluokkaa. Palvelimen CAP-tuki löytyy luokasta FI.hut.cs.osprey.server.parser.CAPRequestParser. Vastaavasti CAP-yhteyden asiakaspää löytyy luokasta FI.hut.cs.osprey.common.cap.CAPClient.

CAP-yhteydet voivat olla luonteeltaan persistenttejä ts. sama yhteys palvelee useampaa saman käyttäjän palvelupyyntöä. Palvelin implementaatio ei kuitenkaan tue tällaisia persistenttejä yhteyksiä, vaan CAP-yhteydet on rajoitettu yhteen palvelupyyntöön. Rajoitus juontuu sekä CAPClient- että CAPParser -toteutuksesta. Yhteyden persistentiksi muuttaminen vaatii siis molempien muuttamista ts. serveripäähän palvelusilmukan muodostamista ja asiakasohjelmistoon yhteyden sulkematta jättämisen. Servlet-käytössä TCP-yhteyksien aukipitäminen ei kuitenkaan ole välttämättä paras mahdollinen idea, johtuen servlettien transientista luonteesta.

CAP mahdollistaa useita eri autentikointimahdollisuuksia käyttäjälle mm. Kerberoksen. Lisäksi on mahdollista käyttää esim. salattuja TCP-yhteyksiä ns. SSL:ää käyttäen. Kaikki nämä seikat liittyvät kuitenkin vain CAP-yhteyden alussa suoritettavaan kättelyyn asiakasohjelmiston ja palvelimen välillä. Joten vain edellä mainitut asiakasohjelmiston ja palvelinpuolen toteuttavat luokat vaativat muutoksia.

Nykyinen autentikointimenetelmä on Osprey-projektin oma ja perustuu yksinkertaisesti käyttäjän tunnuksen ja salasanan selväkielisenä lähetykseen palvelimelle.

8.7.4 Kantakoodin tehokkaammaksi teko

Tietokantaoperaatiot suoritetaan keskitetysti Java-paketin FI.hut.cs.osprey.common.repository alta. Paketissa on kaksi tietokantaa käsittelevää luokkaa, sillä käyttäjien profiilitietueet ja itse kalenterimerkinnät käsitellään kukin omissa luokissaan.

Kummastakin Java-luokasta löytyy metodi getConnection:

private Connection getConnection(String url, String user,
                                 String password) throws SQLException;
Metodia kutsutaan luokissa aina, kun halutaan saada käyttöön JDBC-pohjainen tietokantayhteysolio java.sql.Connection. Metodin parametrit noudattelevat standardia JDBC-formaattia. Lisätietoja JDBC:stä löytyy täältä.

getConnection-metodin yhteydenhakutapaa muuttamalla voidaan implementoida tietokantayhteyksien pooli ja siten huomattavasti tehostaa tietokantaoperatioita. Oletusarvoinen implementaatio avaa aina uuden yhteyden JDBC-tietokantaan, mikä on verrattain hidas operaatio. Poolin avulla yhteyksien avausta ei tarvitse suorittaa joka kantaoperaation yhteydessä.

8.7.5 Mediapoli WLAN

Asiakasohjelmiston ja kalenteripalvelin lisäksi ohjelmistosta löytyy pieni komentorivityökalu, jolla voidaan päivittää käyttäjän sijainti kalenteripalvelimella. Tämä soveltuu käytettäväksi esimerkiksi juuri Mediapolin WLAN-verkossa.

Toimintaperiaate on seuraavanlainen:

  1. Käyttäjä liikkuu WLAN-solusta toiseen
  2. Käyttäjän terminaali suorittaa ajoittain ko. komentorivityökalun, jolle annetaan parametreiksi käyttäjän nimi, ja käyttäjän sen hetkinen solutieto (esim. reitittimen IP).
  3. Kalenteripalvelimella on tieto, jolla voidaan yksittäinen solutieto muuttaa fyysisiksi koordinaateiksi.
  4. Kalenteripalvelin päivittää käyttäjän sijainnin hakemistopalveluunsa.

Käyttäjän päätelaite tarvitsee siis säännöllisin väliajoin suoritettavan oman pienen Java-ohjelman, joka ottaa TCP-yhteyden käyttäjän kalenteripalvelimeen. Käyttäjän sijaintia ei voida siis päivittää automaattisesti ellei ko. työkalu ole säännöllisesti kertomassa uudesta sijainnista (location update). Käyttäjä voi kuitenkin päivittää sijaintinsa tällöinkin manuaalisesti.

Samoin asiakasohjelmiston on itse päivitettävä käyttäjän päätelaitteen paikka palvelimelta, jos käytössä ei ole jonkinlaista push-tekniikkaa. Osprey-projektin puitteissa toteutettu asiakasohjelmisto ei automaattisesti päivitä käyttäjän paikkaa, vaan käyttäjän on itse ladattava karttasivu uudelleen hakeakseen paikkatietonsa palvelimelta.

Sekä ko. työkalu, että vastaava osa palvelimesta löytyvät Java-paketista FI.hut.cs.osprey.common.directory.

8.7.6 Hälytykset

Kalenteri lähettää käyttäjälle hälytyksiä tapahtumista ja todo-merkinnöistä. Käyttäjä voi määrittää itse ennakon, jolloin hälytys tapahtuu. Mikäli käyttäjä ei ole määrittänyt hälytysennakkoa, palvelin päättelee käyttäjän sijainnista koska on aika suorittaa hälytys.

Palvelimen hälytyskäyttäytyminen on toteutettu Java-paketissa FI.hut.cs.osprey.watcher. Moduuli WatcherModule suorittaa hälytyksen tapahtumiin ja todoihin merkittyjen hälytysennakoiden mukaan käyttäen saatavilla olevia hälytysmekanismeja. Moduuli PredictModule luo merkintöihin hälytyksiä ennakoiden käyttäjän sijaintia suhteessa tulevaan tapahtumaan, mikäli käyttäjä ei ole hälytysennakkoa merkintään tehnyt.

Palvelimessa on toteutettuna lyhytsanomia (SMS) lähettävä hälytin. Hälyttimiä voi tehdä tarpeen mukaan helposti lisää esim. email-hälyttimen. Hälyttimien pitää toteuttaa vain alla oleva rajapinta, jonka kautta sisään tulee niin tieto hälytyksen kohteesta kuin aiheuttajasta.

public interface Alerter { 
    /** 
     * Send an alarm to the target user about the event
     * or the todo.
     */ 
    public void alert(Target t, VEventTodoParent v);
} 

Java-paketista FI.hut.cs.osprey.common.watcher.sms löytyy HTTP-asiakasohjelmisto, joka lähettää hälytyksen HTTP-palvelimelle. Useat kaupalliset SMS-viestintäalustat mahdollistavat viestien lähetyksen HTTP:llä. Ko. paketin luokkia modifoimalla voidaan nykyinen hälytintoteutus muuntaa lähes mille tahansa em. rajapinnan tarjoavalle SMS-palvelulle.

Esimerkin vuoksi kuvataan yksinkertaisen sähköpostilla hälytyksen lähettävän hälyttimen teko.

Käyttäjän sähköpostiosoitetta ei talleta profiilitietoihin. Tämän muuttaminen vaatii seuraavia toimenpiteitä:

  1. VProfile-luokkaan on lisättävä attribuutti osoitteelle vrt. String phonenumber.
  2. VProfile-luokasta löytyvät kantaoperaatioiden kyselyiden muodostusmetodeja read, write ja delete on muutettava käsittelemään ko. uutta attribuuttia.
  3. Sähköpostiosoitetta on luonnollisesti hyvä päästä muuttamaan myös asiakasohjelmiston kautta, joten uuden attribuutin on siirryttävä myös CAP-protokollaan tehdyn profiililaajennuksen ylitse. Tämä vaatii protokollan laajentamista. Muutokset kohdistuvat siis parser.cup- tiedostoon ja lexer.lex-tiedostoon. VProfile-osuuksia katsomalla ko. tiedostoista selviää nopeasti kääntäjiä ennen tehneelle henkilölle, miten laajennus voidaan tehdä, joten yksityiskohtia ei tässä näytetä.
  4. Asiakasohjelmistoon on vielä tehtävä muutos, joka mahdollistaa käyttäjän sähköpostiosoitteen muuttamisen. Ks. luokka ProfilePage.
  5. Lopuksi tarvitaan vielä itse hälytintoteutus. Tämä tapahtuu toteuttamalla em. rajapinta. Toteutuksen rakenne noudattelee seuraavia vaiheita: käyttäjän (kohteen ts. targetin) profiilin haku ytimen avustuksella, SMTP-yhteyden muodostamista ja profiiliin konfiguroidulle osoitteelle postin lähettämisestä vapaavalintaisella sisällöllä tai esim. hälytyksen aiheuttaman koosteen (summary) sisällöllä.

8.7.7 Kalenteriälyominaisuuksien lisäys

Kalenterin perustoiminnallisuus on kapsuloitu CalendarModule-rajapintaan, tällä hetkellä toiminnallisuuden toteuttaa CalendarOperationModule-luokka. Se hoitaa aivan perustoiminnallsuuden: halutun kalenterin haun, jalostajien kutsumisen, muokatun käskyn välittämisen kalenterille ja suodatuksen tulosjoukolle. Se on siis pelkästään työnjakaja, joka kutsuu muita moduuleja. Tarkka toiminnallisuus on kuvattu alla.

Työnkulku CalendarOperationModule:ssa
1. Tarkistetaan komennon oikeellisuus
2. Hankitaan käskyn lähettäjän profiili
3. Suoritetaan jalostajat rekisteröintijärjestyksessä
4. Toimitaan käskyn tyypin mukaisesti
 READ.   Lähetetään pyynnöt kohdekalentereille ja filtteröidään tulosjoukko
 CREATE. Lähetetään minimiversio pyynnöstä (aika) kohdekalentereille uid:n 
         selvittämiseksi.
         Tehdään UPDATE koko tiedoilla.
 UPDATE. Lähetetään pyyntö kohdekalenterille.
 DELETE. Lähetetään pyynnöt kohdekalentereille.

Itse älyominaisuudet on toteutettu jalostajamoduuleissa. Uuden ominaisuuden lisääminen tapahtuu luomalla uusi jalostajamoduuli, johon haluttu älykkyys ohjelmoidaan. Sen jälkeen moduuli lisätään vain ladattavaksi serverille (FI.hut.cs.osprey.server.CalendarServer) ja ominaisuus on kytkeytynyt päälle. Kalenteriarkkitehtuurin muihin luokkiin ei tarvitse koskea.

Esimerkki uuden jalostajamoduulin luomisesta löytyy kohdasta 8.7.1.

8.7.8 Hakemistopalvelun vaihto

Harjoitustyössä toteutettiin vain hyvin yksinkertainen hakemistopalvelu, josta voidaan kysellä tietyllä alueella sijaitsevia kalentereja. Tavoitteena oli kuitenkin tehdä rajapinta, joka voitaisiin toteuttaa myös monimutkaisemmalla toteutuksella, esimerkiksi hajautetulla hierarkisella rakenteella DNS:n tyyliin. Toteutetttava rajapinta on FI.hut.cs.osprey.common.directory.Directory. Siinä rekisteröitävien olioiden on toteutettava FI.hut.cs.osprey.common.directory.Description rajapinta, eli tällä hetkellä ne ovat joko luokkaa ClientDescription, joka tarkoittaa jonkun asiakasohjelmiston kuvausta, tai CalendarDescription, joka tarkoittaa jonkin kiinteämmän paikan kalenteria.

Kun kysellään vaikkapa Innopolin sijainnilla kilometrin säteellä olevia kalentereita, metodi Description[] get(GeoPosition position, int radius, int type) voisi siis aloittaa kyselyn maailman juurisijaintipalvelimelta. Tämä osaisi palauttaa palvelimen, joka vastaa esim. Euroopan sijanneista, tämä taas Suomen, tämä taas Espoon. Espoon palvelin saattaisi palauttaa sekä Otaniemen, että Tapiolan lokaatiopalvelimet, joilta sitten saadaankin varsinainen vastaus. Kullakin lokaatiopalvelimella olisi keskussijainti sekä ympyrän säde, josta kyseinen palvelin vastaa.

Koska usein tarvitaan myös vastakkaissuuntaista kyselyä, eli "missä tämä kalenteri sijaitsee", GeoPosition getPosition(Description obj), täytyy myös sellainen toteuttaa. Koska kalentereja kuvataan niiden URLeilla, on kyseisen palvelimen osoite siis tiedossa. Silloin voitaisiin sijaintikysely sisällyttää itse kalenteripalvelimeen. Myös erillinen lokaatiopalvelu voidaan toteuttaa samalla tyylillä kuin reverse DNS. Tämäkin toiminnallisuus piilotetaan Directory-rajapinnan taakse, joten kysyjän ei tarvitse tietää, miten hakemisto on toteutettu. Register ja unregister metodit toteutetaan samalla hierarkialla kuin hakukin.

8.7.9 Palvelimen hajauttaminen

Palvelimen moduulit kommunikoivat keskenään ytimen välityksellä. Toisin sanoen palvelimesta löytyy keskeinen kohta, joka on vastuussa kaikesta kommunikaatiosta palvelimen sisällä. Tätä hyväksi käyttäen palvelin prosessi on mahdollista hajauttaa useampaan prosessiin. Muutaman käyttäjän järjestelmässä tähän tuskin tulee tarvetta, mutta koska älykkäät kalenterioperaatiot vaativat kohtuullisesti laskentatehoa, käyttäjämäärän lisääntyessä tähän tulee varmasti tarvetta.

Moduulit pyytävät ytimeltä, joka toteuttaa rajapinnan FI.hut.cs.osprey.common.core.Core. Rajapinnasta löytyy metodit niin moduulien rekisteröintiin ytimeen, kuin moduulien hakuun. Hajautus voitaisiin toteuttaa seuraavien vaiheiden mukaisesti:

  1. Muodostetaan keskitetty nimipalvelin, jonne moduulit rekisteröityessään tallettevat tyyppinsä ja sijaintinsa palvelinklusterissa.
  2. Jokaiselle moduulille tehtäisiin ns. proxy, joka palautetaan ytimeltä minkä tahansa moduulin pyytäessä palvelimen paikalliselta ytimeltä ko. moduulia. Proxyn tehtävänä olisi tietää missä moduuli sijaitsee oikeasti (nimipalvelimen avustuksella) ja toteuttaa sama rajapinta, jonka oikeakin moduulikin toteuttaa, mutta välittää moduulin metodikutsut verkon ylitse aidolle moduulille.
  3. Vastaavasti aidolle moduulille pitäisi luoda palvelinosa, joka vastaanottaa proxyn kutsuja verkon ylitse ja vastaa niihin.

Yllämainitulla tavalla itse moduulien toteuksiin ei tarvitse koskea, mutta palvelin prosessi voidaan hajauttaa usealle koneelle. Mikäli halutaan kehittyneempiä hajautusmenetelmiä vrt. kuormanjakoa (load-balancing) klusterin sisällä, voidaan proxyjen toteutusta muuttaa siten, että proxyt tajuavat useamman saman moduulin palveluja tarjoavan palvelimen läsnäolon ja käyttävät esim. vähiten kuormitettuna olevaa.

8.7.10 Lokipohjaisten analyysien teko

Mikäli halutaan esimerkiksi analysoida käyttäjien tapoja käyttää kalenteria, on luontevin tapa lähestyä ongelmaa toteuttaa erillinen palvelin ohjelmiston lokitiedosto(j)a analysoiva työkalu.

Työkalun tehtävää voidaan helpottaa lisäämällä vakio lokitiedoston rinnalle toinen, erityisesti analyysejä varten ulkoasultaan optimoitu lokitiedosto. Log4J mahdollistaa useampien lokitiedostojen rinnakkaisuuden, ja jokaisella lokitiedostolla voi olla oma konfiguraatio mm. erilainen ulkoasu. Lisää tietoja lokitiedostojen lisäämisestä ja ulkoasujen konfiguroinnista löytyy Log4J:n kotisivuilta.

Analyysejä varten todennäköisesti kiinnostavimmat lokimerkinnät syntyvät CalendarOperationModule:ssa, joten saattaa edelleen olla hyödyllistä rajoittaa analyysilokiin tulostettavaksi ainoastaan merkinnät ko. luokasta. Luokkahan pitää sisällään kalenterioperaatioiden älyn ts. logiikan ja kaikki kalenterimerkinnöille tehtävät operaatiot matkaavat ko. luokan lävitse.

8.7.11 Käyttäjätietojen hallinta

Kalenteripalvelin ei tarjoa erillistä käyttäjähallintarajapintaa lukuunottamatta käyttäjien profiilien muuttamista. Tästä johtuen käyttäjien ts. kalenterien lisäys palvelimeen on tehtävä suoraan kantaan SQL-operaatioina.

Kalenterin nimeä ei voida muuttaa ts. kalenteri on tuhottava ja luotava uudestaan uudella nimellä mikäli nimi halutaan vaihtaa.

Kun kalenteri ts. käyttäjä on lisätty tietokantaan, kalenteri on käyttäjälle valmis käytettäväksi. Palvelin luo muut tarvittavat tietueet lennossa käyttäjän sisäänkirjoittautuessa ensimmäisen kerran.

8.7.12 Käyttöliittyman muokkaus PDA:lle

Koska toteutettu käyttöliittymä on tehty WWW-selaimella käytettäväksi, se on suhteellisen helppo muokata mille tahansa laitteelle, joka osaa hakea ja näyttää WWW-sivuja.

Käyttöliittymä on optimoitu täysikokoisilla monitoreilla katsottavaksi. Käyttöliittymä on kuitenkin toteutettu käyttäen koko näyttöä pienempiä kehyksiä (frames), jotka yhdessä tai erikseen näyttävät eri toimintoja. Alla olevassa esimerkkikuvassa on neljä kehystä:

Kuva selainikkunasta

Toteutus voidaan muokata PDA:lle sopivaksi. Tässä oletetaan, että PDA:n näyttö on pienempi ja suhteellisesti kapeampi kuin normaali monitori. Tällölin kehyksistä voidaan poistaa oikeanpuoleinen, ja vasemmanpuoleinen voidaan siirtää ylävalikkopalkin alle. Kehykset on määritelty luokissa FrontFrame, CalendarFrame, TodoFrame, MapFrame ja SettingsFrame.

Tämän jälkeen kaikki HTML-ohjaukset oikeanpuoleiseen kehykseen kannattaa ohjata keskimmäiseen kehykseen. Esim. linkki <A HREF="..." TARGET="right"> muuttuisi muotoon <A HREF="..." TARGET="center">. Jotkin linkit on syytä poistaa kokonaan. Esim. CalendarFrame näyttää keskimmäisessä kehyksessä käyttäjän tapahtumat ja oikeanpuoleisessa kehyksessä lähialueen tapahtumat. Jos jälkimmäinen määrittely ohjataan center-kehykseen, sisältö kirjoittautuisi käyttäjän tapahtumien päälle, joten linkki pitää poistaa PDA:lle konvertoitaessa. Tällaiset poistettavat linkit eivät kuitenkaan aiheuta toiminnallisuuden menetystä, sillä saman sisällön voi saada näkyviin toistakin kautta. (Tässä tapauksessa esim. karttasivun kautta.)

Näiden muutosten jälkeen selainikkunan korkeus on suurempi kuin leveys, jolloin se sopii paremmin PDA:lla näytettäväksi. Myös fonttikoon ja kehysten suhteellisten kokojen muutoksilla voidaan helposti vaikuttaa selainikkunan sopivuuteen PDA:n näytölle.

8.7.13 XML-pohjaisten merkintöjen sisääntuonti

Java-paketista FI.hut.cs.osprey.common.importer löytyvä komentorivipohjainen kalenterimerkintöjen sisääntuoja on periaatteeltaan yksinkertainen:

  1. Ohjelma avaa sille komentorivillä annetun XML-tiedoston ja parsii sen event.dtd:n rajoituksien mukaan. DTD:ssä on nimestä huolimatta määritelty rakenne sekä Todo- että tapahtumamerkinnöille.
  2. Kun tiedosto on parsittu onnistuneesti muodostaen iCalendar-olioita, avataan yhteys komentorivillä annettuun palvelimeen.
  3. CAP-yhteyden avauksen onnistuttua, salasanan ja tunnuksen ollessa siis oikein, lähetetään merkinnät uusina lisäyksinä kohdekalenteriin. Palvelin käyttäytyy aivan kuten käyttäjä tekisi merkinnät käsin.

Alla ohjelmiston ajon, ilman parametrejä, tulostamat käyttöohjeet:

Usage: <XML-file> <default target calendar>
       <default target password> <IP of calendar server> <port of calendar server>
Yllä target tarkoittaa jälleen käytännössä käyttäjää tai paikannimeä ts. kalenterin nimeä.

Komentorivityökalun on tarkoitus toimia pohjana monipuolisemmalle liitynnälle jo olemassa olevaan kalenteriratkaisuun. Mikään ei rajoita toteuttamasta myös muita kalenterioperaatioita kuin merkintöjen lisäystä em. tapaan.

9. Tiedossa olevia virheitä ja vajeita

Alla olevat toiminnallisuus- ja vaatimusmäärittelyissä mainitut ominaisuudet ovat jääneet toteuttamatta johtuen projektin aikana suoritetusta priorisoinnista - jo määrittelyjä tehdessä asiakkaan kanssa tiedettiin että kaikkia ei pystytä millään toteuttamaan. On huomattava, että puuttuvat ominaisuudet ovat verrattain pieniä osia koko arkkitehtuurista.

Asiakasohjelmisto:

Kalenteripalvelin:

Olemassaolevat moduulit eivät tällä hetkellä käsittele saamiaan internet-osoitteita mitenkään, eivätkä siten osaa yhdistää vaikka esimerkiksi foo.bar.com:n ja calendar.zak.net:n olisi sama kone. Nimien käyttö ristiin voi aiheuttaa kalenterien/profiilien löytymättömyyksiä. Tämä pitäisi varmaankin korjata siirtymällä numeeristen osotteiden käyttöön.

Toteutetun käyttöliittymän suurin ongelma on Java-grafiikkametodien riippuvuus todellisesta grafiikkaympäristöstä. Toteutus siis vaatii käynnissä olevat X-ympäristön, jotta esim. java.awt.Graphics-luokan kuvamanipulaatiometodeja voisi käyttää, vaikka käyttöliittymä itsessään ei X-ympäristöllä mitään teekään. Sun Microsystemsin Java-versiot ennen versiota 1.4 eivät tue ns. headless-grafiikkaa, jolloin kuvia voi muokata myös ilman käynnissä olevaa X-ympäristöä.

Toteutettu käyttöliittymä vaatii siis toimiakseen X-palvelimen, johon käyttöliittymäservletti voi ottaa yhteyden. Servletin ajoympäristölle (esim. Apache Jakarta-Tomcat) on kerrottava DISPLAY-ympäristömuuttujan avulla, mistä X-palvelin löytyy. Jos X-palvelinta ajetaan samassa koneessa kuin käyttöliittymäservlettiä, tämä voidaan tehdä esim. lisäämällä servlet-ajoympäristön käynnistysskriptiin rivi: export DISPLAY=:0

Tietokantaoperaatiot eivät käytä PostgreSQL:n mahdollistamia sekvenssejä uniikkien tunnisteiden allokointiin, koska PostgreSQL:n JDBC-ajurit eivät tue ko. ominaisuutta. Tarvittava koodi on kommentoitu pois luokasta FI.hut.cs.osprey.common.icalendar.Sequence ja korvattu random-funktiolla 64-bittisestä lukuavaruudesta.

10. Viitteet

[OSPREY-K] Osprey-ryhmä, Projekti Ospreyn käyttöohje, kayttoohje.html, viitattu 24.1.2001

[OSPREY-T] Osprey-ryhmä, Projekti Ospreyn tekninen määrittely, tekninenmaarittely.html, viitattu 21.4.2001