Tik-76.115 Tekninen määrittely

Älykäs kalenteri

Viimeksi päivitetty $Date: 2001/04/21 11:56:01 $.

Sisällysluettelo

1. Johdanto
1.1 Tarkoitus ja kattavuus
1.2 Tuote ja ympäristö
1.3 Määritelmät, merkintätavat ja lyhenteet
1.4 Viitteet
1.5 Yleiskatsaus dokumenttiin
2. Järjestelmän yleiskatsaus
2.1 Sovellusalueen kuvaus
2.2 Järjestelmän liittyminen ympäristöön
2.3 Laitteisto- ja ohjelmistoympäristö
2.4 Toteutuksen keskeiset reunaehdot
2.5 Sopimukset ja standardit
3. Arkkitehtuurin kuvaus
3.1 Suunnitteluperiaatteet
3.2 Tietokanta-arkkitehtuuri
3.3 Ohjelmistoarkkitehtuuri, moduulit ja prosessit
4. Moduulikuvaukset
4.1 Kalenteriydin
4.2 Kyselyprosessori
4.3 Kalenterioperaatiot
4.4 Profiilioperaatiot
4.5 Käyttäjävarasto
4.6 Suodattimet ja suodatinprosessori
4.7 Hakemistopalvelu
4.8 Kalenterivarastot
4.9 Lokipalvelu
4.10 Jalostajamoduulit
4.11 Hälytysmoduuli
5. Muut erityiset tekniset ratkaisut
6. Hylätyt ratkaisuvaihtoehdot
6.1 Kalenteriydin
6.2 Protokolla
6.3 Kieliohjelmisto
7. Virhekäsittely

Versiohistoria

Versio

Pvm

Muutos

Muuttaja

1.0

3.12.2000

T2-vaiheen ensimmäinen versio

Juha, Kari, Teemu

1.1

12.2.2001

T3-vaiheen palautettava versio: profiilimääritykset lisätty kappaleisiin 3 ja 4. Kappale kuusi siirretty omaan dokumenttiin. Jalostajamoduulit lisätty kappaleeseen 4. Päivitetty 3.2, 4.1, 4.3, 4.4 ja 4.7

Juha, Teemu, Kari

1.2

19.3.2001

T4-vaiheen palautettava versio: Profiilimääritykset, hälytykset, tarkennettu käyttäjätietokanta ja todot lisätty kappaleeseen 3.2. Rajapintoja tarkennettu kappaleessa 4.8. Lokimäärityksiä tarkennettu kappaleesta 4.9. Jalostajamoduulien toiminta päivitetty kappaleessa 4.10. Hälytysmoduulit kappale 4.11 lisätty.

Teemu, Juha

Lopullinen

21.4.2001

LU-vaiheen palautettava versio: viimeiset tarkistukset asiakkaan toiveiden mukaisesti: esimerkkejä, viittauksia ja selityksiä lisätty.

Teemu

1. Johdanto

Dokumentti on Teknillisen korkeakoulun ohjelmistotyökurssilla (Tik-76.115) tehtävän Osprey-projektin keskeinen tekninen määrittely.

Projektin lopputuotteena syntyvän kalenteriarkkitehtuurin toteutus koostuu hajautetusta palvelinarkkitehtuurista. Lisäksi esimerkkiasiakasohjelmisto palvelinarkkitehtuurille toteutetaan. Projektin painopisteenä on ensin mainittu toisen mahdollistaessa kalenteriarkkitehtuurin toimivuuden demonstroinnin. Tämä dokumentti on palvelinarkkitehtuurin toteutuksen tekninen määrittely. Asiakasohjelmiston teknillinen määrittely on erillisessä dokumentissa [OSPREY-TA].

Toteutettava kalenteriarkkitehtuuri mahdollistaa perinteisistä kalenterisovellutuksista poiketen lisäkeinojen käytön kalenterikäyttäjien ajanhallinnan tehostamiseksi ja helpottamiseksi. Lisäkeinot muodostuvat kalenterin passiivisen roolin muuttamisesta aktiivisempaan, päätelmiä tekevään rooliin. Päätelmien teon pohjana toimivat paikannuspohjainen tieto sekä kalenterimerkintöjen tulkinta.

Ohjelmisto tehdään edelleen käytettäväksi akateemisiin tutkimustarkoituksiin Teknillisen korkeakoulun GO-PROD-hankkeen tutkijoille.

1.1 Tarkoitus ja kattavuus

Dokumentti määrittää kuinka toiminnallisen määrittelyn [OSPREY-TM] vaatimukset tullaan toteuttamaan.

Dokumentti ei sisällä kalenteriarkkitehtuurin toteutusta demonstroivan asiakasohjelmiston teknistä määrittelyä. Tämä on esitetty erillisessä omassa dokumentissaan [OSPREY-TA].

Projektin tutkimuksellisesta luonteesta johtuen tekninen määrittely tulee muuttumaan ja täydentymään projektin seuraavien vaiheiden aikana hyvinkin paljon.

1.2 Tuote ja ympäristö

Tuote on älykäs uudentyyppinen paikannus- ja kielellistä tietoa hyväkseen käyttävä kalenteriarkkitehtuuritoteutus. Järjestelmä sijoittuu paikannustietopalveluiden, tiedontuottajien ja loppukäyttäjien keskelle yhdistäen em. tahojen tietoja luoden uudentyyppistä lisäarvoa kalenterin käyttöön [OSPREY-VM].

1.3 Määritelmät, merkintätavat ja lyhenteet

Käytettävät termit, määritelmät ja lyhenteet on määritelty erillisessä omassa projektin termistödokumentissa [OSPREY-T].

Merkintätavat ovat alla olevat:

1.4 Viitteet

[CAP] S. Mansour, D. Rouer, G. Babics, Calendar Access Protocol (CAP), www.ietf.org/internet-drafts/draft-ietf-calsch-cap-03.txt, viitattu 30.11.2000

[DNS] P. Mockapetris, Domain Names - Implementations and Specification, ftp://ftp.funet.fi/pub/standards/RFC/rfc1035.txt, viitattu 6.12.2000

[LOG4J] Log4J, Apache-projektin lokimoduulin WWW-sivut, http://jakarta.apache.org/log4j, viitattu 15.3.2001

[OSPREY-PS] Osprey-ryhmä, Projekti Ospreyn projektisuunnitelma, projekti_suun_LU.pdf, viitattu 3.12.2000

[OSPREY-SP] Osprey-ryhmä, Projekti Ospreyn suunnittelupäätöksiä, suunnittelupaatokset.html, viitattu 30.1.2001

[OSPREY-T] Osprey-ryhmä, Projekti Ospreyn termistöä, termit.html, viitattu 30.11.2000

[OSPREY-TA] Osprey-ryhmä, Projekti Ospreyn kalenteriasiakasohjelmiston teknillinen määrittely, tekninenmaarittely-asiakas.html, viitattu 30.11.2000

[OSPREY-TM] Osprey-ryhmä, Projekti Ospreyn toiminnallinen määrittely, toiminnallinenmaarittely.html, viitattu 3.12.2000

[OSPREY-VM] Osprey-ryhmä, Projekti Ospreyn vaatimusmäärittely, vaatimusmaarittely.html, viitattu 3.12.2000

[RFC2445] Dawson, F. Stenerson, D. Internet Calendaring and Scheduling Core Object Specification (iCalendar), ftp://ftp.funet.fi/pub/standards/RFC/rfc2445.txt, viitattu 30.11.2000

[SYNCML] SyncML-järjestö, SyncML WWW-sivut, http://www.syncml.org viitattu 6.12.2000

[SYSLOG] Lonvick, C. Syslog Protocol. Internet Draft. 3.10.2000, http://www.ietf.org/internet-drafts/draft-ietf-syslog-syslog-02.txt viitattu 2.12.2000

1.5 Yleiskatsaus dokumenttiin

Ensimmäinen luku sisältää lyhyen johdannon projektiin, sen taustaan ja käytettäviin termeihin. Kappaleessa on myös listattu viitteet.

Toinen luku sisältää yleiskuvauksen toteutettavasta kalenteriarkkitehtuurista, sen ympäristöstä ja liittymisestä ympäristöön. Niin laitteisto kuin ohjelmistoympäristö kuvataan lyhyesti. Keskeiset rajoitteet ja käytettävät standardit määritellään myös kappaleessa kaksi.

Kolmas luku kuvaa kalenteriarkkitehtuurin keskeiset suunnitteluperiaatteet ja tietorakenteet. Kappaleessa esitetään myös toteutettavan ohjelmiston arkkitehtuuri ja sen moduulijako.

Luvussa neljä esitellään yksittäiset moduulit. Niin rajapinnat, virheidenkäsittely kuin moduulien toteutuskin käsitellään.

Viidennessä luvussa esitellään muut erityiset tekniset ratkaisut ja kuudennessa luvussa hylätyt ratkaisut. Seitsemäs luku keskittyy ohjelmiston virheidenkäsittelyyn.

2. JÄRJESTELMÄN YLEISKUVAUS

2.1 Sovellusalueen kuvaus

Kalenteriarkkitehtuuri sijoittuu henkilökohtaisten monen käyttäjän kalenterijärjestelmien sovellusalueelle. Perinteiset kalenterijärjestelmät ovat toiminnoissaan käyttäjän aktiivista osallistumista vaativia - oli kyseessä yhden tai monen käyttäjän kalentereita. Käyttäjän toimia perinteisesti vaativat mm. eri kalenterien välillä olevien tapahtumien yhteyksien havaitseminen, kuin myös tapahtumien luokittelu. Em. esimerkit ovat kalenteriarkkitehtuurin keskeisiä käyttäjän toimia helpottavia ominaisuuksia.

Edellä mainitulle sovellusalueelle on syntymässä joukko uusia standardeja [CAP], jotka mahdollistavat kalenteripalvelimien keskinäisen kommunikoinnin jopa eri valmistajien palvelimien välillä.

Edelleen tietoliikenneohjelmistojen käyttöön on tulossa lähitulevaisuudessa tarkka paikannustieto. Projektin keskeisiä tavoitteita on tutkia juuri paikannustiedon käyttömahdollisuuksia kalenterijärjestelmissä toteuttamalla sitä hyväkseen käyttävä kalenteriohjelmisto [OSPREY-PS].

Projektin tuloksena syntyvä kalenteriarkkitehtuuri poikkeaa perinteisistä kalenterijärjestelmistä siinä, että se tekee käyttäjää avustavia päätelmiä käyttäen hyväkseen sekä kielellistä älykkyyttä, että paikannustietoa. Edelleen kalenteriarkkitehtuurin toteutuksen käyttämät standardiehdotukset mahdollistavat sen liittämisen muihin kalenterijärjestelmiin tulevaisuudessa (mm. SUN Microsystemsin iPlanet kalenteripalvelimet). Edellinen olettaa luonnollisesti, että arkkitehtuurin toteutuksessa käytetyistä standardiehdotuksista tulee yleisesti käytetyt.

2.2 Järjestelmän liittyminen ympäristöönsä

Kalenteriarkkitehtuurin toteutus sijoittuu kalenteripalveluiden käyttäjien, niihin kalenterimerkintöjä tuottavien sisällöntuottajien ja hakemistopalveluiden keskelle. Tarjottavat Kalenteripalvelut syntyvät em. osapuolien tietoja yhdistäen ja jalostaen.

Hakemistopalvelut sisältävät paikannustietoa kalentereista ja niiden käyttäjistä. Hakemistopalvelujen keskeisin tehtävä on ylläpitää käyttäjien fyysistä sijaintitietoa.

Järjestelmän liittyminen tunnistus- ja oikeuspalveluihin tapahtuu omaa erillistä sovitinta käyttäen [OSPREY-TM]. Järjestelmään ei toteuteta ko. sovitinta, kuin yksinkertaisena tunnus- ja salasanatarkistimena.

Sisällöntuottajille ja kalenterin käyttäjille tarjotaan julkinen CAP-rajapinta [CAP]. Rajapinta perustuu kyselyihin, joita asiakasohjelmisto lähettää palvelimille. CAP-protokollan perusidea on hyvin samanlainen kuin HTTP-protokollassa.

2.3 Laitteisto- ja ohjelmistoympäristö

Kalenteriarkkitehtuuri toteutetaan Java 2 Standard Edition -ajoympäristön päälle.

Suoria liityntöjä laitteistoon ei ole, vaan kaikki kommunikointi laitteiston kanssa tapahtuu Java-ajoympäristön rajapintoja käyttäen. Toteutus on siis alustariippumaton.

2.4 Toteutuksen keskeiset reunaehdot

Kalenteriarkkitehtuurin toteutusta ei haluta sidottavan mihinkään tiettyyn laitteistoalustaan. Myös tästä syystä on toteutuskieleksi valittu Java 2.

Kalenteriarkkitehtuuri ei myöskään saa olla sidottu mihinkään sovelluskerroksen verkkoprotokollaan sillä tavalla, ettei sitä voitaisi vaihtaa. Arkkitehtuurin on sovelluttava Dynamics HUT Mobile IP -verkkoon.

Edellä mainitut reunaehdot ovat aiemmin määritelty projektin vaatimusmäärittelyssä [OSPREY-VM].

Kalenteriarkkitehtuurin toteutuksen ei tarvitse toimia ilman verkkoyhteyttä.

2.5 Sopimukset ja standardit

Kalenteripalvelimien kommunikointi toteutetaan CAP-protokollaa käyttäen [CAP] ja kalenteritapahtumat määrittämään edelleen iCalendar-formaattia noudattaen [RFC2445].

3. Arkkitehtuurin kuvaus

Alla on listattu järjestelmän keskeiset osat.

Kalenteripalvelimet hallinnoivat käyttäjien ja paikkojen kalenteritietoja. Kalenteripalvelimet muodostavat toteutettavan kalenteriarkkitehtuurin.
Kalenteriasiakasohjelmistot antavat loppukäyttäjälle liittymän kalenteripalvelimien palveluihin. Asiakasohjelmistot ovat tyypillisesti keveitä, ne toimivat lähinnä palvelimien antamien tietojen visualisoijina.
Hakemistopalvelut toimivat kalenteripalvelimissa hajautetun tiedon indeksoijina ja mahdollistavat näin palveluiden nopean löytämisen muista kalenteripalvelimista. Olennaisin hakemistopalvelu on kalenterin yhdistäminen fyysiseen sijaintipaikkaan, mutta hakemistopalveluita voidaan käyttää muihinkin tarkoituksiin.

Kuva 1. Järjestelmän keskeiset osat.

Sekä kalenteriasiakasohjelmistot ja kalenteripalvelimet että kalenteripalvelimet keskenään kommunikoivat CAP-protokollalla. Kalenteriarkkitehtuuria ei kuitenkaan ole mitenkään erityisesti sidottu näihin protokolliin.

Kuva 2. Esimerkkitapahtumasekvenssejä järjestelmässä.

Yllä olevassa kuvassa 2 on kuvattu tapahtumat, joita on myös hahmotettu kuvassa 1. Kuvan 1 nuolien yllä olevat järjestysnumerot viittaavat kuvan 2 sekvenssijärjestykseen. Käyttäjä yhden ja kahden asiakasohjelmistot keskustelevat kalenteripalvelimiin. Kullakin käyttäjällä on oma primäärinen kalenteripalvelin.

Käyttäjä yhden toimesta on tehty haku omaan kalenteripalvelimeen 1, mikä edellyttää edelleen merkintöjen hakua palvelimesta 2. Kaksi ylintä getEvents nuolta kuvassa 2 kuvaavat näitä tapahtumia. Hakuehtona voi olla esimerkiksi: anna kaikki kalenterin X tapahtumat aikaväliltä Y - Z joiden kuvauksessa on sana W.

Käyttäjä kahden toimesta on edelleen tehty operaatio, joka edellyttää lähialueen kalenteripalvelimien selvittämistä. Tämän johdosta haku etenee hakemistopalveluun, minkä jälkeen tarvittavat tiedot haetaan löytyneeltä palvelimelta 3. Tätä hakuprosessin alkua kuvaa kolmas getEvents nuoli, jonka taakse voi kätkeytyä esimerkiksi seuraavanlainen hakuehto: anna kaikki tapahtumat suhteessa sijaintiini säteellä X.

3.1 Suunnitteluperiaatteet

Tärkeimpänä suunnittelulähtökohtana ovat toimineet yhdessä asiakkaan kanssa koottu vaatimusmäärittely [OSPREY-VM] ja erityisesti siitä johdettu toiminnallinen määrittely [OSPREY-TM].

Asiakkaan ja projektiryhmän kannalta ei hakemistopalveluiden ja paikallisten kalenterivarastojen, eikä asiakasohjelmiston, toteutus ole kiinnostavaa. Sen sijaan rajapinnat edellämainittuihin palveluihin ovat mielenkiintoisia ja suunnitellaan.

Kalenteriarkkitehtuurin eri elementit irtaantuvat helposti ja luontevasti olioiksi, joten oliopohjainen lähestymistapa vaikutti suunnittelussa luonnollisimmalta. Toteutuskieleksi valittiin Java sen käytön helppouden ja alustariippumattomuuden vuoksi.

Moduuleihin jako on suoritettu itsenäisten toiminnallisuuksien mukaan. Näin pyritään uudelleenkäytettäviin, geneerisiin moduuleihin.

Kalenteripalvelu perustuu ajatukseen kalenteriytimeen rekisteröityneistä palvelumoduuleista. Perusajatuksena on, että ohjelmistoarkkitehtuuri olisi mahdollisimman joustava ja hajautettava. Palvelut rekisteröityvät ytimeen, minkä jälkeen muut palvelut pystyvät pyytämään viitteitä rekisteröityneisiin palveluihin ytimen kautta. Kalenteriydin toimii siis vain moduulien hakupalveluna. Tällä rakenteella mahdollistetaan hajauttaminen kohtuullisella työpanoksella ja hyvinkin erilaisten palvelumoduulien lisääminen ytimen toteutusta muuttamatta.

Arkkitehtuurissa pyritään välttämätään tarpeettomia skaalautumista ja hajauttamista vaikeuttavia osia. Toisin sanoen pitkäikäisiä tilallisia operaatioita pyritään välttämään ja lyhyt kestoisia tilattomia suosimaan. Perusrakenne on asiakas-palvelin-arkkitehtuuri.

Arkkitehtuuria suunnitellessa pyritään käyttämään mahdollisimman paljon valmiiksi suunniteltuja ja jopa valmiiksi toteutettuja osia.

3.2 Tietokanta-arkkitehtuuri

3.2.1 Kalenterioliot

Kalenterin ja sen tapahtumien kuvaamiseen käytetään dokumentissa iCalendar [RFC2445] määriteltyjä olioita. Niiden attribuuttien perusteella rakennetaan kuvan 3 mukainen luokkahierarkia yhdistämällä yhteiset attribuutit yhteiseksi isäluokaksi. Kukin olio viittaa lisäksi muihin olioihin, jotka kuvaavat olion ominaisuuksia. Ne taas edelleen mallinnetaan iCalendar-määrityksen mukaisesti. Esimerkkinä attribuutti "organizer", jolla on määreet: nimi, hakemisto, lähettäjä, kieli ja osoite. Kalenteriolioiden tarkempi kuvaus löytyy iCalendar-määrityksestä [RFC2445].

Kalenteriluokkien perimä

Kuva 3. Kalenterioliot.

VFreeBusy määrittelee aikoja, jolloin kalenterissa on varauksia tai tyhjää. VJournal on päiväkirjamerkintä, eli vapaasti aikaan sidottuja kommentteja. VTodo on tehtävä, jolle ei vielä ole määritelty tarkkaa aikaa. VEvent on normaali kalenterimerkintä. VCommand määrittelee kalenterille tehtävät operaatiot, kuten merkinnän lisäyksen ja poiston. VQuery on kysely kalenterille SQL-sukuisella kielellä. VProfile on käyttäjän profiilitietue (ks. kappale 3.2.2). Kuvassa kolme on esitetty em. olioiden perimät.

Olioiden persistenttiys saadaan aikaan tallentamalla ne tietokantaan täysin vastaavaan rakenteeseen. Koska sekä olio- että tietokantamalli on mallinnettu suoraan iCalendar-määrityksestä [RFC2445], on konversio yksinkertaista myös ensisijaisesti käytettävään CAP-protokollaan [CAP] päin.

Kalenteriolio

Kuva 4. Kalenteriolio.

Kaikki oliot siirretään eteenpäin käärittynä VCalendar-olioon, kuten kuvassa 4 esitetään. Operaatiosta riippuen VCalendar sisältää viittauksia muihin kalenteriolioihin. Esimerkiksi kyselyn paluuarvona voitaisiin palauttaa VCalendar, jonka sisällä 10 VEvent-oliota.

3.2.2 Profiililaajennus

CAP-protokolla [CAP] ei mahdollista käyttäjätietojen välittämistä protokollaa käyttäen. Tätä varten CAP-protokollaa laajennetaan mahdollistamaan ns. profiilitiedon siirtämisen. Laajennus tehtiin lisäämällä uusi tietue VCalendar-objektin sisään tyypiltään VProfile VEventin tapaan (ks. kappale 3.2.1).

Profiilit toteutetaan käyttämällä avain- ja arvopareja. CAP:iin lisätty VProfile-tietue pitää sisällään käyttäjän matkapuhelimen puhelinnumeron, säteen jonka sisällä käyttäjän lähikalentereita haetaan sekä viittaukset käyttäjän kannalta mielenkiintoisiin kalentereihin (paikkojen tai ihmisten).

3.2.3 Kalenteritietokanta

Alla on määritelty kalenteritietokannan taulurakenne. Taulurakenne on karsittu versio CAP-protokollan spesifikaatiossa [CAP] esitetystä esimerkkitaulurakenteesta. CAP-spesifikaatiossa esitetystä taulurakenteesta on karsittu pois kaikki lokaalisaatioihin viittaava.

CREATE TABLE VEVENT (
-- Owner of this even
       TARGET         TEXT,

-- VEvent object columns follow
       TRANSP         TEXT,              

-- VEventTodoParent object columns follow
       GEO            INTEGER,            -- VALUE_KEY 
       LOCATION       INTEGER,            -- VALUE_KEY 
       RESOURCES      INTEGER,            -- VALUE_KEY 
       PRIORITY       INTEGER,            
       VALARM         INTEGER,            -- VALUE_KEY

-- VJournal object columns follow
       CLASS          INTEGER,            
       CREATED        INTEGER,            -- VALUE_KEY 
       DESCRIPTION    TEXT,            
       LAST_MODIFIED  INTEGER,            -- VALUE_KEY 
       RECURRENCE_ID  INTEGER,            -- VALUE_KEY 
       SUMMARY        TEXT,            
       STATUS         TEXT,            
       SEQUENCE       INTEGER,            
       ATTACH         INTEGER,            -- VALUE_KEY 
       CATEGORIES     INTEGER,            -- VALUE_KEY 
       EXDATE         INTEGER,            -- VALUE_KEY 
       EXRULE         INTEGER,            -- VALUE_KEY 
       RDATE          INTEGER,            -- VALUE_KEY 
       RELATED_TO     INTEGER,            -- VALUE_KEY 
       RRULE          INTEGER,            -- VALUE_KEY 

-- VBase
       DTSTAMP        INTEGER,            -- VALUE_KEY 
       ORGANIZER      INTEGER,            -- VALUE_KEY 
       UID            TEXT,            
       URL            TEXT,            
       ATTENDEE       INTEGER,            -- VALUE_KEY 
       COMMENT        INTEGER,            -- VALUE_KEY 
       CONTACT        INTEGER,            -- VALUE_KEY 
       DTEND          TIMESTAMP,            
       DTSTART        TIMESTAMP            
);

CREATE TABLE VTODO (
-- Owner of this todo entry
       TARGET         TEXT,
-- VTodo object columns follow
       PERCENT_COMPLETE INTEGER,
 
-- VEventTodoParent object columns follow
       GEO            INTEGER,            -- VALUE_KEY
       LOCATION       INTEGER,            -- VALUE_KEY
       RESOURCES      INTEGER,            -- VALUE_KEY
       PRIORITY       INTEGER,
       VALARM         INTEGER,            -- VALUE_KEY
 
-- VJournal object columns follow
       CLASS          INTEGER,
       CREATED        INTEGER,            -- VALUE_KEY
       DESCRIPTION    TEXT,
       LAST_MODIFIED  INTEGER,            -- VALUE_KEY
       RECURRENCE_ID  INTEGER,            -- VALUE_KEY
       SUMMARY        TEXT,
       STATUS         TEXT,
       SEQUENCE       INTEGER,
       ATTACH         INTEGER,            -- VALUE_KEY
       CATEGORIES     INTEGER,            -- VALUE_KEY
       EXDATE         INTEGER,            -- VALUE_KEY
       EXRULE         INTEGER,            -- VALUE_KEY
       RDATE          INTEGER,            -- VALUE_KEY
       RELATED_TO     INTEGER,            -- VALUE_KEY
       RRULE          INTEGER,            -- VALUE_KEY
 
-- VBase object columns follow
       DTSTAMP        INTEGER,            -- VALUE_KEY
       ORGANIZER      INTEGER,            -- VALUE_KEY
       UID            TEXT,
       URL            TEXT,
       ATTENDEE       INTEGER,            -- VALUE_KEY
       COMMENT        INTEGER,            -- VALUE_KEY
       CONTACT        INTEGER,            -- VALUE_KEY
       DTEND          TIMESTAMP,
       DTSTART        TIMESTAMP
);

-- The physical location of events/todos
CREATE TABLE GEO (
     VALUE_KEY      INTEGER NOT NULL PRIMARY KEY,
     LATITUDE       TEXT,
     LONGITUDE      TEXT
);

-- The location description of events/todos
CREATE TABLE LOCATION (
     VALUE_KEY      INTEGER NOT NULL PRIMARY KEY,
     VALUE          TEXT
);

-- Resources allocated to events/todos
CREATE TABLE RESOURCES (
     VALUE_KEY     INTEGER NOT NULL PRIMARY KEY,
     VALUE         TEXT NOT NULL
);

-- Combined DATE/TIMEs of events/todos
CREATE TABLE DATETIME (
     VALUE_KEY     INTEGER NOT NULL,
     VALUE         TIMESTAMP NOT NULL
);

-- Attachments to events/todos
CREATE TABLE ATTACHMENT (
     VALUE_KEY    INTEGER NOT NULL,
     VALUE        VARCHAR(255)   NOT NULL
);

-- The category of events/todos
CREATE TABLE CATEGORY (
     VALUE_KEY    INTEGER NOT NULL,
     VALUE        TEXT
);

-- The attendees of events/todos
CREATE TABLE ATTENDEE (
     VALUE_KEY     INTEGER NOT NULL,
     VALUE         TEXT
);

-- Contact information of events/todos
CREATE TABLE CONTACT   (
    VALUE_KEY      INTEGER NOT NULL,
    VALUE          TEXT NOT NULL
);

-- Free comments of events/todos
CREATE TABLE COMMENT   (
    VALUE_KEY      INTEGER NOT NULL,
    VALUE          TEXT    NOT NULL
);

-- Alarms for events/todos
CREATE TABLE VALARM ( 
    VALUE_KEY      INTEGER NOT NULL PRIMARY KEY, 
    ACTION         TEXT,          -- VALUE_KEY
    DESCRIPTION    TEXT,          -- VALUE_KEY
    SUMMARY        TEXT,          -- VALUE_KEY 
    TRIGGER        INTEGER        -- VALUE_KEY 
); 

3.2.4 Käyttäjätietokanta

Alla on määritelty käyttäjätietokannan taulurakenne. Taulurakenne on määritelty sillä perusteella, että käyttäjäautentikointi suoritetaan tunnus ja salasana -parilla.

CREATE TABLE TARGET(
    NAME           VARCHAR2(128) UNIQUE NOT NULL,
    AUTH           VARCHAR2(32)  NOT NULL,
);

3.2.5 Profiilitietokanta

Alla on määritelty kalenterin käyttäjien profiilien taulurakenne.

CREATE TABLE VPROFILE (
    TARGET         TEXT,
    CONTACTENTRY   INTEGER,            -- VALUE_KEY
    PHONE          TEXT, 
    RADIUS         INTEGER
); 

CREATE TABLE CONTACTENTRY ( 
    VALUE_KEY      INTEGER NOT NULL,
    VALUE          TEXT NOT NULL
); 

3.3 Ohjelmistoarkkitehtuuri, moduulit ja prosessit

Kuva 5. Ohjelmistoarkkitehtuurin moduulien rekisteröityminen kalenteriytimeen.

Kalenteripalvelin on kyselyihin perustuva ohjelmisto. Herätteen palvelimen toimintoihin aiheuttaa aina julkisesta rajapinnasta tuleva kysely. Projektin puitteissa implementoidaan CAP-rajapinta esimerkiksi julkisesta rajapinnasta, mutta kuten kuvasta 5 käy ilmi voidaan muitakin mahdollisesti tällä hetkellä tuntemattomia rajapintoja jatkossa implementoida. Kyselyillä voidaan sekä hakea tietoa kalenteripalvelimesta, että muokata sitä. Analogia WWW-palvelimeen on osuva.

Kalenteripalvelimen perusrakenne on yksinkertainen. Protokollakohtaiset kyselyprosessorit lukevat sisään kyselyitä avoinna olevista yhteyksistä julkisilta rajapinnoilta ja muuntavat ne kalenteripalvelimen protokollariippumattomaan sisäiseen esitysmuotoon olioiksi. Oliot siirretään ytimeltä saadun tiedon mukaiselle moduuleille huolehdittavaksi.

Itse kalenteriydin sisältää siis minimäärän toiminnallisuutta, sen tehtävänä on huolehtia moduulien löytämisestä. Moduulit hoitavat varsinaisen työn. Moduulin löytämisen jälkeen ydin ei osallistu moduulin käyttäjän ja moduulin kommunikointiin.

Kalenterivarastot tarjoavat muille moduuleille pääsyn sekä paikalliseen että ulkoisiin kalenterijärjestelmiin. Paikallinen kalenterijärjestelmä pitää sisällään kyseistä palvelinta kotipalvelimenaan pitävät kalenterit. Ulkoiset kalenterijärjestelmät pitävät sisällään niin arkkitehtuuriin kuuluvat ei-paikalliset järjestelmät kuin mahdolliset muut arkkitehtuuriin kuulumattomat kalenterijärjestelmät.

Paikallisen ja ulkoisen kalenterivaraston ero on pyritty hämärtämään kalentereiden käsittelyssä. Kaikki kalenteritoiminnot saadaan aikaan yhtä rajapintaa käyttämällä. Moduulit eivät tiedä onko käytössä paikallinen vai ulkoinen kalenteri - elleivät sitä tietoa erikseen tarvitse. Ulkoisia kalenterivarastoja edustava moduuli huolehtii tarvittavista teknisistä yksityiskohdista kalenteriyhteyttä luotaessa.

Profiilivarastot tarjoavat muille moduuleille pääsyn sekä paikallisen että ulkoisten kalenterijärjestelmien profiilitietoihin. Profiilitiedot kuvaavat niin käyttäjän ominaisuuksia, kuin myös kalenteripalvelimen tai fyysisen paikan ominaisuuksia.

Kuten kalenterivarastojenkin kohdalla, myös profiilivarastojen sijainti on pyritty hämärtämään niiden käsittelyssä. Kaikki profiilitoiminnot saadaan aikaan yhtä rajapintaa käyttämällä, eivätkä moduulit tiedä onko käytössä paikallinen vai ulkoinen profiilivarasto - elleivät sitä tietoa erikseen tarvitse. Ulkoisia profiilivarastoja edustava moduuli huolehtii tarvittavista teknisistä yksityiskohdista yhteyttä luotaessa.

Muut moduulit voivat käyttää suodatinprosessorimoduulin palveluita, mikäli ne haluavat suodattaa suurta listaa kalenterimerkintöjä ja/tai kalenterijärjestelmiä suppeammaksi listaksi eri kriteerien perusteella. Lista on saatu edelleen esim. hakemistopalvelulta. Suodattimien rakenteesta kertoo enemmän luku 4.

Hakemistomoduuli toimii rajapintana edelleen kohti hakemistopalvelua, jonka avulla pidetään yllä hajautettuna tietoa kalentereista ja käyttäjistä - ei kalenterien sisällöstä. Kuten aiemmin mainittiin, toteutettavassa arkkitehtuurissa hakemistopalvelun tärkein tehtävä on kalenterien ja käyttäjien paikannustiedon indeksointi.

4. Moduulikuvaukset

Moduulien tärkeysjärjestys on seuraava: kalenteriydin, CAP-rajapinta ja kyselyprosessori, kalenterioperaatiot, kalenterivarastot, suodatinprosessori ja suodattimet, käyttäjävarasto, hakemisto ja loki. Järjestys on johdettu vaatimusmäärittelyn [OSPREY-VM] toiminnallisuuksien priorisoinnista.

4.1 Kalenteriydin

4.1.1 Yleiskuvaus

Kalenteriydin koordinoi moduulien toimintaa. Moduulit rekisteröityvät ytimeen, joka sitten tarjoaa viitteitä moduuleihin niitä tarvitseville. Kalenteriydin ei siis ota kantaa käytettäviin palveluihin, se vain toimii tiedon keskuspaikkana.

Kalenteriytimen toiminta

Kuva 6. Kalenterimoduulien rekisteröityminen kalenteriytimeen.

Yllä olevassa kuvassa 6 on kuvattu moduulien rekisteröityminen ytimeen. Jokainen moduuli kutsuu kalenteriytimen register-metodia omalla nimellään ja viittauksella instanssiinsa.

4.1.2 Rajapinta

Rajapinnan metodit ovat synkronisia eli metodikutsut palaavat vasta kun operaatio on suoritettu.

public interface Core {
    // Register Module to Core by TypeId
    public boolean register(String typeId, ModuleFactory factory);  

    // get Module by TypeId
    public Module getModule(String typeId) throws NotRegisteredException; 

    // de-Register Module from Core
    public void deregister(ModuleFactory factory); 
}

public interface ModuleFactory {
  // Give reference of Core to module
  void setCore(Core core); 

  // Construct new servant
  public Module getInstance(); 

public interface Module {
    ; // Empty, just to get a super interface for modules
}

4.1.3 Toteutus

Alla on pseudokooditoteutukset Core- ja ModuleFactory-rajapinnoille.

public class CalendarCore implements Core {
  /**
   * Create new Core instance
   */
  public CalendarCore() {
    module = new HashMap();
  }

  /**
   * Register module of given type to the core.
   */
  public boolean register(String typeId, ModuleFactory h) {
    h.setCore(this);
    module.put(typeId, h);
    return true;
  }

  /**
   * Get a reference to a module with the specified TypeId.
   */											
  public Module getModule(String typeId) throws NotRegisteredException {
    ModuleFactory m = (ModuleFactory) module.get(typeId);
    if(m == null)
      throw new NotRegisteredException();

    return m.getInstance();
  }

  /**
   * Remove the module from Core.
   */										
  public void deregister(ModuleFactory factory) {
    module.remove(factory);
  }

  // Mappings from type to module
  private Map module;
}


public class CalendarOperationModuleFactory implements ModuleFactory {

    /** Get new servant for core requesting a servant */
    public CalendarOperationModule getInstance() {
	return new CalendarOperationModule();
    }
}

4.1.4 Virhekäsittely

register palauttaa arvon false, mikäli rekisteröinti ei onnistunut. getModule heittää poikkeuksen NotRegisteredException, mikäli kyseiselle tyypille ei ole rekisteröitynä moduleita.

4.2 Kyselyprosessori

4.2.1 Yleiskuvaus

Kyselyprosessori muodostaa sisääntulevasta protokollasta tarvittavat palvelimen sisäiset oliorakenteet ja välittää ne edelleen ytimelle. Kalenteriydin välittää olion edelleen Kalenterioperaatiot-moduulille tai antaa virheilmoituksen jos sellaista ei ole.

Oliorakenne on kuvattu luvussa 3.2.1.

Kyselyprosessorin tehtäviin kuuluu CAP-protokollan tapauksessa myös kyselyn tekijän autentikointi. Tämän toteuttamiseksi se käyttää käyttäjävaraston palveluita hyväkseen.

4.2.2 Rajapinta

Alla CAP-protokollan tulkkaavan prosessorin laajentaman luokan rajapinta. Sisään moduulille tulee siis kysely CAP-muodossa ja moduulilta ulos vastaus em. kyselyyn CAP:lla. Kyselyn prosessointi tapahtuu omassa säikeessään. Säie käynnistetään rajapinnan Input- ja OutputStreamien asetuksen jälkeen.

public abstract class RequestParser extends Thread {
    public abstract void setInputStream(InputStream in);
    public abstract void setOutputStream(OutputStream out);
}

4.2.3 Toteutus

Moduuli toimii muuntimena yksinkertaisen tekstipohjaisen CAP-protokollan ja sisäisen oliomallin välillä. Koska arkkitehtuurin sisäinen esitysmuoto on olioiksi muutettu CAP-protokollan käyttämä VCalendar-muoto, voidaan käännös tehdä yksinkertaisesti suorittamalla ainoastaan leksikaalinen analyysi ja parsiminen tuottaen sisäistä esitysmuotoa olevia VCalendar-olioita. Sama pätee toiseen suuntaan ts. muutettaessa sisäistä esitysmuotoa takaisin vastaukseksi kyselyntekijälle tekstimuotoon. Alla esimerkki CAP-muotoisesta kyselystä, joka lisää tapahtuman kalenteriin.

BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VCOMMAND
METHOD:CREATE
TARGET:cap://ospreyn-kalenteri
BEGIN:VEVENT
DESCRIPTION:T2-palautus
SUMMARY:Muista palauttaa
DTSTART:20001210T150000Z
DTEND:20001210T150001Z
END:VEVENT
END:VCOMMAND
END:VCALENDAR
.

Autentikoinnin tulos talletetaan myös sisäiseen oliomuotoon, jolloin kyselyn käsittelijä (Kalenterioperaatiot-moduuli) tietää käyttäjän identiteetin ja täten edelleen mm. käyttäjän henkilökohtaisen kalenterin sijainnin tietokannassa.

4.2.4 Virhekäsittely

Mikäli sisääntulevassa protokollassa havaitaan virheitä, palautetaan CAP-protokollan mukaisia virhekoodeja [CAP]. Samoin mikäli kyselyprosessorin edelleen kutsumat moduulit aiheuttavat virhetilanteina, palautetaan CAP-protokollan virhekoodeja.

4.3 Kalenterioperaatiot

4.3.1 Yleiskuvaus

Moduuli sisältää kalenteriasiakasohjelmiston kalenterin käyttöön tarvitseman keskeisen toiminnallisuuden eli toiminnallisessa määrittelyssä [OSPREY-TM] mainittujen kalenterioperaatioiden logiikan.

Moduuli suorittaa eri kalenterioperaatioiden perustoiminnot. Lisäksi kalenterimoduuliin voi liittyä jalostajamoduuleita (Distiller), jotka voivat vaikuttaa tapahtumaketjun eri vaiheiden tapahtumiin.

4.3.2 Rajapinta

Moduuli toteuttaa CalendarModule-rajapinnan. Rajapinnan metodit ovat synkronisia eli ne palaa vasta kun operaatio on suoritettu.

public interface CalendarModule extends Module {

    /** 
     * Send a calendar query in and retrieve the answer to it, blocking method */
     */
    public VCalendar send(VCalendar cal);    

    /**
     * Register a protocol (e.g. CAP) specific Distiller to the CalendarModule
     * to be used in Calendar Operations.
     */
    public void register(String protocol, DistillerModule m);
}

4.3.3 Toteutus

Alla on esitetty ensivaiheessa toteutettavien peruskalenteritoimintojen toteutus pääpiirteittäin. Projektin päätavoitteena olevat kehittyneet kalenteritoiminnot liittyvät perusrakenteeseen erillisinä jalostajamoduuleina.

Seuraavassa puhuttaessa kalenteriasiakasohjelmistosta voidaan tarkoittaa myös kalenteripalvelinta, joka tekee kyselyitä toiseen kalenteripalvelimeen.

4.3.3.1 Kalenterimerkintöjen selaus

Käyttäjän selatessa omia merkintöjään kalenteriasiakasohjelmisto tekee tarvittavat kyselyt palvelimen CAP-rajapinnalle. Tämä autentikoi käyttäjän asiakasohjelmiston kanssa, prosessoi ne olioiksi ja antaa Kalenterioperaatiot-moduulin käsiteltäväksi.

Sisääntuleva kysely sisältää eksplisiittisen SQL-sukuisen kyselyn, joka tehdään kohteena olevalle kyselyn määräämälle kalenterivarastolle. Operaatio tapahtuu pyytämällä ytimeltä kalenterivarastoja edustava moduuli. Tämän jälkeen merkinnät palautetaan kohti CAP-rajapintaa kyselyprosessorille.

Edellä kuvattua tapahtumaketjua on kuvattu kuvassa 7.

Useiden, mahdollisesti ennaltamääräämättömien, kalenteripalvelimien tapahtumien selaus suodatusta käyttäen määritellään seuraavassa vaiheessa.

Perustoiminta

Kuva 7. Peruskalenterioperaatio: haku

4.3.3.2 Kalenterimerkintöjen teko, poisto ja muuttaminen

Kalenterimerkintöjä muutettaessa kalenteriasiakasohjelmisto tekee tarvittavan kyselyn, joka ohjautuu edellisessä luvussa mainitulla tavalla Kalenterioperaatiot-moduulille.

Moduuli käyttää samaan tapaan kuin edellä kalenterivarastojen palveluita toteuttaakseen päivityksen. Uutta merkintää luodessaan palautetaan kyselyprosessorille myös merkinnälle allokoitu uniikki globaali tunniste.

4.3.4 Virhekäsittely

Virhetilanteissa tieto virheestä kapsuloidaan palautettavaan VCalendar-olioon. Tarkempi virhetilannekuvaus talletetaan lokeihin Loki-moduulia käyttäen.

4.4 Profiilioperaatiot

4.4.1 Yleiskuvaus

Moduuli sisältää käyttäjätietoja täydentävien profiilitietojen käsittelyyn tarvittavan logiikan. Profiilitietoja tallennetaan niin kalenterin käyttäjille kuin paikoille. Profiilitietoja voidaan luoda dynaamisesti ts. kaikki profiilit eivät ole talletettu persistentisti.

4.4.2 Rajapinta

Moduuli toteuttaa ProfileModule-rajapinnan. Rajapinnan metodi on synkroninen eli se palaa vasta kun operaatio on suoritettu.

public interface ProfileModule extends Module {

    /**
     * Send a Profile query in to the module and retrieve an answer for it, blocking.
     */
    public VCalendar send(VCalendar cal);    
}

4.4.3 Toteutus

Seuraavassa on esitetty profiilioperaatioiden toteutus pääpiirteittäin.

4.4.3.1 Profiilitietojen selaus

Käyttäjän selatessa omia profiilitietojaan kalenteriasiakasohjelmisto tekee tarvittavat kyselyt palvelimen CAP-rajapinnalle. Tämä autentikoi käyttäjän asiakasohjelmiston kanssa, prosessoi ne olioiksi ja antaa Profiilioperaatiot-moduulin käsiteltäväksi.

Hakuoperaatio tapahtuu pyytämällä ytimeltä käyttäjävarastoja edustava moduuli ja hakemalla tarvittavat profiilitiedot sieltä. Vastauksista muodostetaan VCalendar-olioiden avulla profiiliolio. Tämän jälkeen profiiliolio palautetaan kohti CAP-rajapintaa kyselyprosessorille.

4.4.3.2 Profiilitietojen muokkaaminen

Profiilitietoja muutettaessa kalenteriasiakasohjelmisto tekee tarvittavan kyselyn, joka ohjautuu edellisessä luvussa mainitulla tavalla Profiilioperaatiot-moduulille.

Moduuli käyttää samaan tapaan kuin edellä käyttäjävarastojen palveluita toteuttaakseen päivityksen.

4.4.4 Virhekäsittely

Virhetilanteissa tieto virheestä kapsuloidaan palautettavaan VCalendar-olioon. Tarkempi virhetilannekuvaus talletetaan lokeihin Loki-moduulia käyttäen.

4.5 Käyttäjävarasto

4.5.1 Yleiskuvaus

Käyttäjävarasto tarjoaa keinot tallettaa pysyvästi käyttäjätietoa ts. tunnistamiseen tarvittavia tietoja.

4.5.2 Rajapinta

Alla määritelty käyttäjävaraston rajapinta. Rajapinnan metodit ovat synkronisia eli palaavat vasta kun operaatio on suoritettu.

public class TargetModule {

    /** 
     * Get the authentication string (password) of the user (i.e. a target) 
     */
    public String getAuthentication(Target target); 

    /** 
     * Get list of all users in this user repository.
     */
    public List getList();
}

4.5.3 Toteutus

Käyttäjätiedot talletetaan kalenteritietojen tapaan JDBC-ajurien takana olevaan relaatiokantaan. Moduulin operaatiot muodostuvat yksinkertaisista kantahakuoperaatioista käyttäjätunnisteen perusteella ja siellä olevien tietojen muuttamisesta.

Taulurakenne on määritelty luvussa 3.

4.5.4 Virhekäsittely

Virhetilanteissa metodit palauttavat null:n. Virheen tarkempi selitys talletetaan Loki-moduulin palveluita käyttäen.

4.6 Suodattimet ja suodatinprosessori

4.6.1 Yleiskuvaus

Suodatinarkkitehtuuri

Kuva 9. Suodatinarkkitehtuuri

Suodattimet valikoivat ja mahdollisesti myös jalostavat pääasiassa kalenterimerkintöjä, mutta niitä voidaan käyttää myös muiden elementtien kohdalla, kunhan niille toteutetaan omat toteutusluokkansa.

Suodatinprosessori ottaa vastaan suodattimien parametrit, sekä instantioi tarvittavat suodatinoliot näiden tietojen perusteella. Suodattimia asetetaan monta peräkkäin kaskadiin, ja suodatettavat elementit ajetaan peräkkäin suodattimien läpi, kuten kuvassa 9 nähdään. Suodatinprosessori siis syöttää elementit suodattimille siten, että edellisen suodattimen paluuarvo annetaan seuraavan syötteeksi. Kukin suodatin antaa kullekin suodatettavalle elementille pistemäärän, joka kulkee elementin mukana.

Kullekin suodattimelle voi määritellä painoarvon, jolla se vaikuttaa lopulliseen tulokseen. Kun kaikki suodattimet on käyty läpi, kalenteriprosessori laskee pistemääristä painotetun keskiarvon, jossa painotuskertoimina käytetään kyseisiä painoarvoja. Parametrina annetun pistemäärän ylittävät elementit palautetaan kyselijälle.

Suodattimille voidaan määritellä pisteraja, jonka alittavat elementit eivät pääse enää läpi seuraavalle suotimelle. Vastaavasti voidaan antaa myös pisteraja, jonka ylittävät elementit eivät joudu enää käsiteltäviksi seuraaville suodattimille, vaan pääsevät automaattisesti läpi, vaikka joku niistä olisikin saattanut antaa huonot pisteet, tai jopa tiputtaa elementin kokonaan pois.

Em. ominaisuuden vuoksi suodattimien järjestys on suunniteltava tarkkaan kyseisen tilanteen mukaan. Samalle elementille voidaan toisessa suodattimessa antaa pudottamiseen, ja toisessa suoraan läpipääsyyn oikeuttavat pisteet. Näistä tärkeämpi on siis asetettava ensimmäiseksi.

Suodattimet

Kuva 10. Suodatusprosessi

Kuva kymmenen esimerkissä halutaan viedä joltain kalenterilta saadut tapahtumat suodattimien läpi. Käyttäjämodulilta on saatu tekstimuodossa tiedot siitä, millaisia suodattimia käytetään, sekä niiden parametrit. Suodatinmoottori ottaa nämä tiedot vastaan, instantioi suodattimet, ja initialisoi ne oikeilla parametreilla.

Esimerkin ensimmäinen suodatin, TimeSpanFilter antaa 100 pistettä tapahtumille, jotka osuvat tarkasti annetun aikavälin sisälle, muille 0 pistettä. Alle 100 pistettä saavia tapahtumia ei päästetä eteen päin seuraaville suodattimille. Toinen suodatin, ProximityFilter pisteyttää tapahtumia tapahtumapaikan läheisyyden perusteella. Yli 80 pistettä saavat tapahtumat pääsevät suoraan läpi, ja alle 20 pistettä saavat pudotetaan. Kolmas suodatin, HeuristicsFilter pisteyttää tapahtumia sen mukaan, kuinka paljon ne kielellisesti muistuttavat annettuja sanoja, lauseita tai tapahtumia.

Kun kaikki suodattimet on käyty läpi, lasketaan lopulliset pisteet painotettuna keskiarvona. Ensimmäiselle suodattimelle on annettu painoarvo 0, joten se ei vaikuta millään tavalla pistemäärään. Toinen suodatin saa painoarvon 20, joten se vaikuttaa pisteisiin kaksi kertaa niin paljon kuin kolmas, jonka paino on 10. Niille tapahtumille, jotka on merkitty automaattisesti läpi pääseviksi tai pudotetuiksi, ei tarvitse laskea yhteispistemäärää. Muilta lasketaan pistemäärä, ja ne, jotka saavat pisteitä enemmän kuin koko kaskadin pisterajan, FilterModule palauttaa kysyjälle.

4.6.2 Rajapinta

Rajapinnan metodit ovat synkronisia eli metodit palaavat vasta kun operaatiot on suoritettu.

public interface Filter {

    /** Events getting lower than this score get dropped automatically */
    public int lowDrop = 0;

    /** Events getting higher than this pass */
    public int highPass = 100;

    /** The weight value of this filter */
    public int weight = 1;
    
    /** 
     * Filter the object 
     */
    public int filter(VObject object) throws FilterTypeException;
    
    /** 
     * Initialise the filter 
     */
    public void init(String[][] properties);
}

public class FilterEngine {

    /**
     * Filter the given objects according to the specifications and lowest 
     * possible score.
     */
    public VObject[] filter(String filterSpecs, int lowScore,
                        VObject[] objects) 
    throws FilterTypeException;
}

4.6.3 Toteutus

Alla esimerkkitoteutukset suodattimesta ja suodatinprosessorin toteuttavasta suodatinmoottorista.

public class HalfFilter implements Filter {

    /** 
     * Initialise the filter 
     */
    public void init(String[][] properties) [
        // Go through the properties if necessary
	lowDrop = 50;
    }

    /** 
     * Initialise the filter 
     */
    public int filter(VObject object) {
        return random(100); 
    }
}

public class FilterEngine {
    /**
     * Filter the given objects according to the specifications and lowest 
     * possible score.
     */
    public VObject[] filter(String filterSpecs, int lowScore,
                        VObject[] objects) 
    throws FilterTypeException {

        Filter[] filters = getFiltersBySpecs(filterSpecs);
        for (int i = 0; i < objects.length; i++) {
	   object = objects[i];
	   for (int j = 0; j < filters.length; j++) {
               if (!object.passed && !object.dropped) {
                   score =  filters[j].filter(object);
                   if (score >= filters[i].lowDrop) {
                        object.score += filters[i].weight * score;
                        object.weight += filters[i].weight; 
                   } else {
                        object.dropped = true;
                   }
                   if (score >= filters[i].highPass) {
                        objects[i].passed = true;
                   }
               }
           }

           object.score = object.score / object.weight;
	   object.weight = 1;
       }
       return (objects over lowScore);
    }
}

4.6.4 Virhekäsittely

Mikäli suodattimille annetaan väärän tyyppisiä olioita, heitetään FilterTypeException. Muut ajonaikaiset virheet annetaan kutsujan hoidettaviksi.

4.7 Hakemisto

4.7.1 Yleiskuvaus

Hakemistomoduulin tehtävä on tarjota liityntä hakemistopalveluun, jonka tehtävä on pitää indeksiä hajautetun kalenteriavaruuden tiedoista. Tärkein tällainen tieto on kalenterien löytäminen sijaintipaikan perusteella.

Hakemistopalvelu on hajautettu rakenne, jonka kautta on mahdollista suorittaa kyselyjä haluttujen kalenterien löytämiseksi. Esimerkkinä "anna sijainnin x kalenterit". Järjestelmän hierarkialle ei aseteta muita vaatimuksia kuin että se pystyy toimittamaan edellämainitun kaltaisia toimenpiteitä. Mallina järjestelmälle voi käyttää esimerkiksi DNS:iä [DNS].

Eri kalenterien sijainnit tulee tallettaa fyysisinä koordinaatteina, mutta palveluun pitää varata mahdollisuus antaa arvoja muunkin tyyppisinä. Esimerkiksi ip-osoitteen muuntaminen fyysiseksi koordinaatiksi on käyttäjän sijainnin selvittämisessä oleellista. Käyttäjän sijainnin selvittämiseen on olemassa ja tulossa kaupallisia palveluja. Myös DNS:ssä on mahdollisuus koordinaattien tallentamiseen.

Ohjelmatyöprojektin puitteissa hakemistopalveluille määritellään rajapinta ja toteutetaan yksinkertainen yhden palvelimen hakemistopalvelu, joka voitaisiin tarvittaessa korvata hajautetulla järjestelmällä.

4.7.2 Rajapinta

public interface Directory {

    /**
     * Get calendar servers near given position inside the specified 
     * radius.
     */
    public CalendarDescription[] getCalendars(GeoPosition position, 
					      int radius);

    /**
     * Get an exact position of specified calendar.
     */
    public GeoPosition getPosition(CalendarDescription calendar);

    /**
     * Register the calendar server to the specified position.
     * (servers usually have a fixed position).
     */
    public void registerCalendar(CalendarDescription calendar,
				 GeoPosition position);

    /**
     * Unregister the specified calendar i.e. remove its location,
     * if the location is the one specified.
     */
    public void unregisterCalendar(CalendarDescription calendar,
				   GeoPosition position);

    /**
     * Unregister the specified calendar without caring its
     * location.
     */
    public void unregisterCalendar(CalendarDescription calendar);
}

4.7.3 Toteutus

Esimerkkisovelluksen hakemistopalveluna toteutetaan Javalla yksinkertainen palvelin, joka varastoi tietoa hajautustauluun koordinaatti ja kalenteri -pareina. Tämä ei riitä mihinkään todelliseen käyttöön, mutta on demonstraatiota varten sangen riittävä.

getCalendars käy läpi kaikki hakemistoon tallennetut tietueet, laskee kunkin etäisyyden annetusta pisteestä, ja palauttaa ne, jotka ovat annetun säteen sisällä.

getPosition hakee hajautustaulusta kalenterin URLin perusteella kalenterille rekisteröidyn sijainnin.

registerCalendar lisää kalenterin kuvauksen hajautustauluun.

unregisterCalendar poistaa kalenterin hajautustaulusta.

4.7.4 Virhekäsittely

Mikäli kalenteria ei ole rekisteröity, getCalendars palauttaa tyhjän listan, getPosition palauttaa nullin. unregisterCalendar ei palauta mitään, eikä heitä poikkeusta riippumatta siitä, onko kalenteria rekisteröity. Kaksi täsmälleen samaan paikkaan rekisteröityä kalenteria jättää tallelle vain toisen tässä yksinkertaistetussa toteutuksessa.

4.8 Kalenterivarastot

Kalenterivarastoja edustaa yksi moduuli, jonka taakse piilotetaan sekä paikalliset että ulkoiset kalenterivarastot. Kalenterivarastoja käytettäessä käytettävä kalenterivarasto määritellään URL:lla - muuta eroa ulkoisen ja palvelimen sisäisen kalenterivaraston välillä ei varastojen käyttäjälle näy.

4.8.1 Paikalliset kalenterivarastot

4.8.1.1 Yleiskuvaus

Paikallisella kalenterivarastolla tarkoitetaan palvelimelle paikallisesti talletettuja kalentereita. Kalentereiden talletusmuotoa ei ole rajoitettu, yhtenä vaihtoehtona voi olla vaikka tietokanta. Esimerkkiarkkitehtuuriin paikallinen kalenterivarasto toteutetaan tietokantaan. Yhteys tietokantaan hoidetaan JDBC-ajureilla, joten kantasidonnaisuus vältetään.

4.8.1.2 Rajapinta

Alla on määritelty rajapinta kalenterivarastolle.

public interface AbstractCalendar {
    /**
     * Add VEvent or VTodo to calendar
     */
    public boolean add(VEventTodoParent e) throws AbstractCalendarException;

    /**
     * Get events/todos happening at given criteria.
     */
    public List read(VQuery query) throws AbstractCalendarException;

    /**
     * Delete the specified event/todo.
     */
    public boolean delete(VEventTodoParent e) throws AbstractCalendarException;
    
    /**
     * Updates the content of the given event/todo.
     */
    public boolean update(VEventTodoParent e) throws AbstractCalendarException;
}

4.8.1.3 Toteutus

Taulurakenne on määritelty luvussa 3.

4.8.1.4 Virhekäsittely

Virhetilanteissa metodit heittävät AbstractCalendarException-poikkeukset. Tarkempi tieto virheestä talletetaan Loki-moduulin palveluita käyttäen.

4.8.2 Ulkopuoliset kalenterivarastot

4.8.2.1 Yleiskuvaus

Ulkopuolisella kalenterivarastolla tarkoitetaan muista kuin kyseisessä kalenteripalvelimessa sijaitsevia kalentereita. Ulkopuolisiin varastoihin voidaan ottaa yhteyksiä useilla eri protokollilla.

4.8.2.2 Rajapinta

Rajapinta on sama kuin paikallisella kalenterivarastolla.

4.8.2.3 Toteutus

Yhteys ulkopuoliseen kalenterivarastoon toteutetaan CAP-protokollalla [CAP] ulkopuolisen kalenteripalvelimen CAP-rajapintaan. Esimerkkikalenteriasiakasohjelmisto käyttää samoja yhteysluokkia.

4.8.2.4 Virhekäsittely

Virhetilanteissa metodit heittävät AbstractCalendarException-poikkeukset. Tarkempi tieto virheestä talletetaan Loki-moduulin palveluita käyttäen.

4.9 Profiilivarastot

Profiilivarastoja edustaa yksi moduuli, jonka taakse piilotetaan sekä paikallinen että ulkoinen profiilivarasto. Profiilivarastoja käytettäessä käytettävä profiilivarasto määritellään URL:lla - muuta eroa ulkoisen ja palvelimen sisäisen varaston välillä ei varastojen käyttäjälle näy.

Varastoihin talletettujen profiilitietojen lisäksi profiilivarasto voi olla myös dynaaminen ts. profiilitietueet luodaan lennossa hakemistopalvelun tietoja hyväksi käyttäen. Näin voidaan luoda esim. paikalle profiili, joka pitää viittauksen lähialueen kalentereihin sisällään.

4.9.1 Paikalliset kalenterivarastot

4.9.1.1 Yleiskuvaus

Paikallisella profiilivarastolla tarkoitetaan palvelimelle paikallisesti talletettuja profiileja. Profiileja talletusmuotoa ei ole rajoitettu, yhtenä vaihtoehtona voi olla vaikka tietokanta. Esimerkkiarkkitehtuuriin paikallinen profiilivarasto toteutetaan tietokantaan. Yhteys tietokantaan hoidetaan JDBC-ajureilla, joten kantasidonnaisuus vältetään.

4.9.1.2 Rajapinta

Alla on määritelty rajapinta profiilivarastolle.

public interface AbstractProfile {
    /**
     * Get the profile
     * @return VProfile of matching id.
     */
    public VProfile readProfile(String name) throws AbstractProfileException;

    /**
     * Updates the content of the given profile. Creates new one if no old exists.
     * @return true if the operation was successful.
     */
    public boolean updateProfile(String name, VProfile prof) throws AbstractProfileException;
}

4.9.1.3 Toteutus

Taulurakenne on määritelty luvussa 3.

4.9.1.4 Virheiden käsittely

Virhetilanteissa metodit heittävät AbstractProfileException-poikkeukset. Tarkempi tieto virheestä talletetaan Loki-moduulin palveluita käyttäen.

4.9.2 Ulkopuoliset profiilivarastot

4.8.2.1 Yleiskuvaus

Ulkopuolisella profiilivarastolla tarkoitetaan muista kuin kyseisessä kalenteripalvelimessa sijaitsevia profiileja. Ulkopuolisiin varastoihin voidaan ottaa yhteyksiä useilla eri protokollilla.

4.8.2.2 Rajapinta

Rajapinta on sama kuin paikallisella kalenterivarastolla.

4.8.2.3 Toteutus

Yhteys ulkopuoliseen profiilivarastoon toteutetaan CAP-protokollalla [CAP] ulkopuolisen kalenteripalvelimen CAP-rajapintaan. Esimerkkikalenteriasiakasohjelmisto käyttää samoja yhteysluokkia.

4.8.2.4 Virhekäsittely

Virhetilanteissa metodit heittävät AbstractProfileException-poikkeukset. Tarkempi tieto virheestä talletetaan Loki-moduulin palveluita käyttäen.

4.9 Loki

4.9.1 Yleiskuvaus

Lokimoduulina käytetään Apache-projektin Log4J:tä [LOG4J]. Log4j mahdollistaa mahdollistaa esim. lokien kerääminen keskitetysti yhteen paikkaan tai ohjaamiseen järjestelmän logeihin (SYSLOG).

Lokiin pyritään tallettamaan mahdollisimman paljon tietoa käytettäväksi myöhemmin esim. käyttäjien tapojen analysointiin. Lokit talletetaan ohjataan seuraavan formaatin mukaisesti konsolille. Lokit voidaan ohjata tiedostoon muuttamalla Log4j:n konfigurointitiedostoa. Myös alla olevaa lokien ulkoasua voidaan muuttaa muuttamalla ko. konfigurointitiedostoa.

<Päivämäärä> <aika> <kalenteripalvelimen nimi> <moduulin nimi> <vakavuusaste> <vapaamuotoinen teksti>

4.9.2 Rajapinta

Rajapinta on määritelty Log4J:n dokumentaatiossa.

4.9.3 Toteutus

Log4J:n toteutus on kuvattu ohjelmiston manuaaleissa. Poiketen muista järjestelmän moduuleista, lokimoduuli ei rekisteröidy ytimeen. Moduuli tarjoaa palvelujaan suoraan staattisten metodien kautta, noudattaen Log4J:n tapaa toteuttaa lokipalvelu.

4.9.4 Virhekäsittely

Moduuli ei heitä poikkeuksia, koska sen oletetaan olevan taho joka toimii aina. Moduuli yrittää selvitä mahdollisista sisäistä virhetilanteista omatoimisesti raportoimatta niistä ulospäin.

4.10 Jalostajamoduulit

4.10.1 Yleiskuvaus

Jalostajamoduulit lisäävät varsinaisen älykkyyden kalenteriin. Ne liittyvät peruskalenteritoimintoihin ja voivat muuttaa niitä rajatta, samoin esimerkiksi hylätä kalenterimerkinnän. Tähän tarkoitukseen jalostajat voivat käyttää vapaasti kaikkia ytimestä löytyviä moduuleita.

4.10.2 Rajapinta

Alla on määritelty rajapinta jalostajamoduuleille.

public interface DistillerModule extends Module {
   /**
    * Distill the given command (includes an event or a todo) according to the
    * specified user profile.
    */
   public void distill(VProfile p, VCommand e) throws VCalendarError;
}
    

4.10.3 Toteutus

Toteutus vaihtelee moduulikohtaisesti. Tällä hetkellä on toteutettu seuraavat jalostajat:

4.10.4 Virhekäsittely

Moduulit ilmoittavat virheistään VCalendarException-poikkeuksella.

4.11 Hälytysmoduuli

4.11.1 Yleiskuvaus

Kalenterioperaatiomoduuli toimii kyselypohjaisesti ja ei siten pidä sisällään käyttäjien kalentereita taustalla valvovia ominaisuuksia. Tätä varten arkkitehtuurista löytyy tarkoitukseen varattu moduuli, jonka tehtävänä on pitää huolta kalenterimerkintöihin asennettujen hälytysten laukaisemisesta.

Edellisen lisäksi hälytysmoduuli luo kalenteritapahtumiin hälytyksen, mikäli käyttäjän havaitaan olevan liian kaukana fyysisesti seuraavasta tapahtumasta. Näin tehdään, mikäli käyttäjän nykyinen sijainti ja seuraavan tapahtuman sijainti tiedetään. Matka-ajan arviointi perustuu hyvin karkeisiin arvioihin matkan pituuden linnuntietä mukaan.

4.11.2 Rajapinta

Moduulin palvelut eivät ole tarjolla ulkopuolelle, vaan moduuli huolehtii itsenäisesti toiminnastaan käynnistyksen jälkeen. Moduuli rekisteröidään kuten muutkin moduulit ytimeen, jotta moduulin alustus ei aiheuta erikoistapauksia muualle arkkitehtuuriin.

4.11.3 Toteutus

Moduuli tarkkailee kantaa itsenäisesti etsien tapahtumia, joiden hälytyksen olisi lauettava ko. ajanhetkellä. Tarkkailu suoritetaan 60 sekunnin jaksoissa. Kantahaut tapahtuvat käyttäen kalenterivaraston palveluja ytimen kautta. Käyttäjän sijaintia suhteessa käyttäjän seuraavaan kalenterimerkintään tarkkaillaan samalla 60 sekunnin jaksolla.

Hälytysmoduuli on kytkettävissä pois päältä väliaikaisesti.

4.11.4 Virhekäsittely

Virheet talletetaan lokiin. Koska moduulia ei käytetään suoraan muiden moduulien toimesta, virheidenkäsittelyä vaativaa rajapintaa ei ole.

5. Muut erityiset tekniset ratkaisut

Projektin tässä vaiheessa muita erityisiä teknisiä ratkaisuja ei ole tehty.

6. Hylätyt ratkaisuvaihtoehdot

Hylättyjä ratkaisuvaihtoehtoja ja suunnittelupäätöksiä on käsitelty erillisessä suunnitteluperusteet-dokumentissa [OSPREY-SP].

7. Virhekäsittely

Palvelimesta ulos päin annettavat virheilmoitukset on kunkin operaation kohdalla määritelty dokumentissa [CAP]. Virheellä on A.B -muotoinen numerokoodi, sekä tekstimuotoinen selitys.

Palvelimen sisällä virheilmoitukset siirretään poikkeuksilla. Jokaiseen poikkeukseen laitetaan vapaamuotoisesti selvitys poikkeuksen syystä, mutta varsinainen tieto poikkeuksen syystä saadaan poikkeuksen tyypistä.

Kun poikkeus otetaan kiinni, siitä kirjoitetaan rivi lokiin. Poikkeuksen vakavuuksien mukaan virheilmoitukset luokitellaan seuraavasti, noudattaen Log4j:n käytäntöä:

WARNvaroitus, saattaa aiheuttaa ongelmia myöhemmin. Ko. operaatio ei keskeydy.
ERRORvirhe, käyttäjän operaatiota ei voida suorittaa loppuun
FATALmahdollisesti kaikkien käyttäjien operaatiot vaarassa