Viimeksi päivitetty $Date: 2001/04/21 11:56:01 $.
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
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 |
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.
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.
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].
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:
Lähdekoodi on kirjoitettu Courier-kirjaisimella.
[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
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.
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.
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.
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.
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ä.
Kalenteripalvelimien kommunikointi toteutetaan CAP-protokollaa käyttäen [CAP] ja kalenteritapahtumat määrittämään edelleen iCalendar-formaattia noudattaen [RFC2445].
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.
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.
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].
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.
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.
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).
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 );
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, );
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 );
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.
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.
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.
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.
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 }
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(); } }
register palauttaa arvon false, mikäli rekisteröinti ei onnistunut. getModule heittää poikkeuksen NotRegisteredException, mikäli kyseiselle tyypille ei ole rekisteröitynä moduleita.
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.
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); }
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.
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.
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.
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); }
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.
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.
Kuva 7. Peruskalenterioperaatio: haku
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.
Virhetilanteissa tieto virheestä kapsuloidaan palautettavaan VCalendar-olioon. Tarkempi virhetilannekuvaus talletetaan lokeihin Loki-moduulia käyttäen.
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); }
Seuraavassa on esitetty profiilioperaatioiden toteutus pääpiirteittäin.
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.
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.
Virhetilanteissa tieto virheestä kapsuloidaan palautettavaan VCalendar-olioon. Tarkempi virhetilannekuvaus talletetaan lokeihin Loki-moduulia käyttäen.
Käyttäjävarasto tarjoaa keinot tallettaa pysyvästi käyttäjätietoa ts. tunnistamiseen tarvittavia tietoja.
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(); }
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.
Virhetilanteissa metodit palauttavat null:n. Virheen tarkempi selitys talletetaan Loki-moduulin palveluita käyttäen.
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.
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.
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; }
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); } }
Mikäli suodattimille annetaan väärän tyyppisiä olioita, heitetään FilterTypeException. Muut ajonaikaiset virheet annetaan kutsujan hoidettaviksi.
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ä.
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); }
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.
Mikäli kalenteria ei ole rekisteröity,
getCalendars
palauttaa tyhjän listan,
getPosition
palauttaa
null
in. 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.
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.
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.
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; }
Taulurakenne on määritelty luvussa 3.
Virhetilanteissa metodit heittävät AbstractCalendarException-poikkeukset. Tarkempi tieto virheestä talletetaan Loki-moduulin palveluita käyttäen.
Ulkopuolisella kalenterivarastolla tarkoitetaan muista kuin kyseisessä kalenteripalvelimessa sijaitsevia kalentereita. Ulkopuolisiin varastoihin voidaan ottaa yhteyksiä useilla eri protokollilla.
Rajapinta on sama kuin paikallisella kalenterivarastolla.
Yhteys ulkopuoliseen kalenterivarastoon toteutetaan CAP-protokollalla [CAP] ulkopuolisen kalenteripalvelimen CAP-rajapintaan. Esimerkkikalenteriasiakasohjelmisto käyttää samoja yhteysluokkia.
Virhetilanteissa metodit heittävät AbstractCalendarException-poikkeukset. Tarkempi tieto virheestä talletetaan Loki-moduulin palveluita käyttäen.
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.
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.
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; }
Taulurakenne on määritelty luvussa 3.
Virhetilanteissa metodit heittävät AbstractProfileException-poikkeukset. Tarkempi tieto virheestä talletetaan Loki-moduulin palveluita käyttäen.
Ulkopuolisella profiilivarastolla tarkoitetaan muista kuin kyseisessä kalenteripalvelimessa sijaitsevia profiileja. Ulkopuolisiin varastoihin voidaan ottaa yhteyksiä useilla eri protokollilla.
Rajapinta on sama kuin paikallisella kalenterivarastolla.
Yhteys ulkopuoliseen profiilivarastoon toteutetaan CAP-protokollalla [CAP] ulkopuolisen kalenteripalvelimen CAP-rajapintaan. Esimerkkikalenteriasiakasohjelmisto käyttää samoja yhteysluokkia.
Virhetilanteissa metodit heittävät AbstractProfileException-poikkeukset. Tarkempi tieto virheestä talletetaan Loki-moduulin palveluita käyttäen.
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>
Rajapinta on määritelty Log4J:n dokumentaatiossa.
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.
Moduuli ei heitä poikkeuksia, koska sen oletetaan olevan taho joka toimii aina. Moduuli yrittää selvitä mahdollisista sisäistä virhetilanteista omatoimisesti raportoimatta niistä ulospäin.
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.
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; }
Toteutus vaihtelee moduulikohtaisesti. Tällä hetkellä on toteutettu seuraavat jalostajat:
Moduulit ilmoittavat virheistään VCalendarException-poikkeuksella.
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.
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.
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.
Virheet talletetaan lokiin. Koska moduulia ei käytetään suoraan muiden moduulien toimesta, virheidenkäsittelyä vaativaa rajapintaa ei ole.
Projektin tässä vaiheessa muita erityisiä teknisiä ratkaisuja ei ole tehty.
Hylättyjä ratkaisuvaihtoehtoja ja suunnittelupäätöksiä on käsitelty erillisessä suunnitteluperusteet-dokumentissa [OSPREY-SP].
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öä:
WARN | varoitus, saattaa aiheuttaa ongelmia myöhemmin. Ko. operaatio ei keskeydy. |
ERROR | virhe, käyttäjän operaatiota ei voida suorittaa loppuun |
FATAL | mahdollisesti kaikkien käyttäjien operaatiot vaarassa |