hyväksymispäivä arvosana arvostelija JDO Java Data Objects Kasper J. Nora Helsinki 17. maaliskuuta 2003 Seminaari Relaatiotietokannat nyt HELSINGIN YLIOPISTO Tietojenkäsittelytieteen laitos
ii JDO - Java Data Objects Kasper J. Nora Seminaari: Relaatiotietokannat nyt Tietojenkäsittelytieteen laitos Helsingin yliopisto 17. maaliskuuta 2003, 14 sivua Java Data Objects (JDO) -standardi tarjoaa ohjelmointirajapinnan Java-olioiden persistenssille. JDO:ta käyttämällä sovelluskehittäjät voivat kirjoittaa Java-kielellä sovelluksia, jotka suorittavat latauksia, talletuksia ja kyselyitä objekteille, joiden persistenssi on toteutettu sovelluskehittäjälle huomaamattomasti.
iii Sisältö 1 Johdanto... 1 2 JDO rakenne... 1 2.1 JDO ohjelmointirajapinta... 1 2.2 JDO Arkkitehtuuri... 3 2.3 JDO ja JDBC vertailua... 5 2.4 JDO käyttö... 6 2.5 JDO ilmentymän elinkaari... 7 3 JDO esimerkki... 10 4 Yhteenveto... 12 Lähteet... 14
1 1 Johdanto Java Data Objects (JDO) määrittely mahdollistaa läpinäkyvän persistenssin Javaolioille. JDO määrittelyn versio 1.0 on Javan kehitysprosessia ohjaavan Javayhteisöprosessin (Java Community Process JCP) huhtikuussa 2002 julkaisema. [Sun02] JDO:ta käyttämällä sovelluskehittäjät voivat keskittyä oliomallinnukseen, luokkien persistenssiominaisuudet kuvataan erilliseen xml-muotoiseen dokumenttiin. Erilaisia tietovarastoja (data store) käyttäviä JDO toteutuksia on olemassa, ne käyttävät pääosin relaatiotietokantoja, mutta myös oliotietokantoja ja tiedostorajapintaa hyödyntäviä on tarjolla. JDO toteutusta ja sen käyttämää tietovarastoa voidaan vaihtaa muuttamatta JDO rajapintaa hyödyntävän sovelluksen lähdekoodia tai uudelleen kääntämättä sovellusta. JDO:ssa käytettävän kyselykielen, Java Data Object Query Language (JDOQL), syntaksi on Java tyylinen erotuksena JDBC:n käyttämään SQLkyselykieleen. JDO:ta voidaan käyttää asiakas-palvelin mallin (client server) sekä Java Remote Method Invokations (RMI) arkkitehtuurien mukaisissa hallinnoimattomissa (non-managed) ympäristössä, missä sovelluspalvelinta ei ole käytössä. Toisaalta JDO voidaan integroida EJB-palvelualustan kanssa, joka tarjoaa hajautettuja objekteja ja transaktioita [Sun02]. 2 JDO rakenne 2.1 JDO ohjelmointirajapinta JDO ohjelmointirajapinta muodostuu kuudesta rajapinnasta, kahdesta luokasta sekä yhdeksästä poikkeuksesta, joista esitellään tässä keskeisimmät. javax.jdo.persistentmanagerfactory luo PersistenceManager ilmentymiä ja sallii myös sovelluskehittäjän muokata persistenssi-tason toimintaa, kuten
2 hallita yhteysaltaita ja muokata transaktioasetuksia ja vaikuttaa siten transaktioiden toimintaan. javax.jdo.persistencemanager on tärkein rajapinta JDO:ta käyttäville sovelluskomponenteille, se hoitaa persistenttien olioiden ilmentymien elinkaarta ja hallinnoi transaktioiden kulkua sekä välimuistia, jonne on talletettu persistenttien olioiden alustettuja ilmentymiä. PersistentManager toimii myös Query ilmentymien luojana. javax.jdo.persistencecapable rajapinnan on toteutettava jokaisen luokan, jonka ilmentymiä talletetaan JDO:n avulla. JDO muokkaajan (enhancer) ja XML kuvauksen avulla luokka saadaan toteuttamaan tämä rajapinta. javax.jdo.instancecallbacks rajapinta määrittää takaisinkutsumetodit persistoitaville olioille. Mikäli luokalla on esimerkiksi kenttiä, joita ei persistoida, mutta niiden arvot ovat riippuvaisia muista, persistoitavista kentistä, tarvitaan takaisinkutsumetodeita, jotka asettavat kyseisten kenttien arvot persistoitavan olion elinkaaren eri vaiheissa. Rajapintaan kuuluu metodit jdopostload(), jdopreclear(), jdopredelete(), jdoprestore().[sun02] javax.jdo.transaction rajapinnan toteuttavia ilmentymiä palauttaa PersistenceManager rajapinnan metodi currenttransaction(). Transaktoita voidaan ajaa joko paikallisena (non-managed environment) tai hajautettuna (managed environment). Transaktion päättyessä se joko sitoutuu tai peruuntuu. javax.jdo.extent luokan oliot edustavat tietyn luokan kaikkia tietovarastossa olevia persistoituja ilmentymiä, haluttaessa sisältäen myös kyseisen luokan aliluokat. PersistenceManager rajapinnalla on metodi getextent, joka palauttaa Extent olioita. [Kru02]
3 public Extent getextent(class persitentcapable, boolean subclasses) javax.jdo.query rajapintaa käytetään ilmentymien hakemiseen tietovastastosta annettujen kriteerien mukaan. PersistenceManager rajapinnalla on erilaisia kuormitettuja newquery() metodeita, jotka palauttavat Query objekteja [Bro02]. 2.2 JDO Arkkitehtuuri JDO on suunniteltu toimimaan kahdessa erilaisessa arkkitehtuuriympäristössä. Yksinkertaisimmillaan kaksitasorakenteen (two-tier) mukaisesti sovelluskomponentit kutsuvat suoraan JDO toteutuksen palveluita (Kuva 1). Käytettävissä voi olla useita toteutuksia, jotka on liitetty eri tietovarastoihin. Eri toteutuksien PersistenceManager rajapinnan toteuttavat luokat hallitsevat kyselyitä ja transaktiota sekä persistoitavien olioiden elinkaarta. (kts. 2.5) JDO toteutus piilottaa sovellukselta Java-olioiden ja tiedon talletustavan tietotyyppien ja suhteiden liittämiseen keskenään tietovarastoon. Näin sovelluskomponentit pääsevät käsiksi yhtenäisellä tavalla talletettuun tietoon. Hallinnoidussa ympäristössä (managed environment) JDO integroidaan J2EE sovelluspalvelimen kanssa ja sovellukset kutsuvat PersistentManager:ia edelleen samaan tapaan kuin edellä. Sovelluksilta piilotetaan sovelluspalvelimen ja JDO toteutuksen väliset sopimukset hajautetuista transaktiosta ja yhteyksien hallinnasta (Kuva 2). JDO käyttää J2EE Connector Architecture:n määrittelemiä resurssisovittimia, jotka toimivat J2EE-ympäristössä ulkoisten järjestelmien ja sovelluspalvelimen välisenä standardina yhdistämiskeinona. JDO:n PersistentManager voi käyttää joko toimittajan omia natiiveja tai kolmannen osapuolen toimittamia resurssisovittimia. Hajautetussa järjestelmässä javax.jdo.transaction luokan on toteuttava
4 rajapinta javax.transaction.synchronization, joka sallii välimuistin sisällön kirjoittamisen tietovarastoon loppuun saatettaessa transaktiota. [Sun02]. Lisäksi Sekä kaksitasorakenteessa, että hajautetussa ympäristössä sovelluskehittäjä keskittyy sovelluskomponenttien liiketoimita- ja esityslogiikan suunnitteluun joutumatta puuttumaan esimerkiksi tiettyyn tietovarastoon liittymiseen. Kuva 1 JDO hallinnoimattomassa ympäristössä [Kru02]
5 Kuva 2 Hajautettu järjestelmä [Ros02] 2.3 JDO ja JDBC vertailua JDBC ja JDO ovat kummatkin sovellusliittymiä (API), joiden kautta päästään Javasta käsiksi tietoon. Molemmat ovat erään tason abstraktioita häivyttäen tiedon tallennuksen yksityiskohtia pois. JDBC sovellusliittymää voidaan käyttää esimerkiksi tietämättä tietokannan fyysistä sijaintia tai esimerkiksi toimittajaa. JDO toteutuksen taustalla voi olla tiedon talletukseen käytössä relaatiotietokanta, oliotietokanta, tiedostojärjestelmä, xml-dokumentti tai joku muu. Jos kohteena on relaatiotietokanta, voidaan käyttää esimerkiksi JDBC yhteyttä taustalla. Se miten yhteys on toteutettu, piilotetaan sovelluskehittäjältä ja jätetään JDO toteutuksen tehtäväksi (kuva 3). [Bro02] JDBC:n näkymä tietokantaan on keskittynyt tietokannan relaatiomalliin, joka on hyvin kaukana oliokeskeistä näkymästä. Tämän johdosta joudutaan usein kirjoittamaan ylimääräinen sovelluskerros tietokannan ja sovelluksen välille huolehtimaan Java olioiden pilkkomisesta (decompose). Pilkkomisen yhteydessä olion ominaisuudet
6 paloitellaan pienemmiksi osiksi, siten että olio voidaan tallettaa relaatiotietokantaan. Vastaavasti on toteutettava pilkkomisen käänteinen operaatio, joka lukee tietokannan sarakkeita ja rivejä ja muodostaa niistä olioita. JDO:n näkymä tietokantaan on oliokeskeinen. [Bro02] Transientteja objekteja JVM Sovellus Persistenttejä objekteja Kirjoita muutokset huomaamatta takaisin tietokantaan Hae objektit tietokannasta virtuaalikoneeseen JDO toteutus Objekti/Relaatio sidonta JDBC:n kautta tai suora objektien persistointi Tietokanta Navigoiva / Kyselypohjainen Kuva 3 Läpinäkyvä persistenssi [McC02] 2.4 JDO käyttö JDO kehitysprosessi on hyvin yksinkertainen, persistoitavat luokat kirjoitetaan aivan normaalisti, ilman että niihin tarvitsee lisätä mitään erityistä toiminnallisuutta tai metodeja JDO:n takia. Tieto persistoitavista luokista kirjoitetaan XML kuvaukseen, joka sisältää meta-tietoa näistä luokista, kuten persistoitavien kenttien nimiä ja suhteita muihin luokkiin. Persistoitavalle luokalle ja sen kentille voidaan asettaa eri attribuutteja, jotka ohjaavat JDO:n toimintaa, kuten automaattisten tunnisteiden luomista tai kenttien viittaamien joukkojen hakemista. Valmis lähdekoodi annetaan kääntäjälle (kuva 4), joka tuottaa välikielisiä (bytecode) luokkia. Aiemmin tehty XML kuvaus persistoitavista luokista sekä käännetyt luokat
7 annetaan syötteeksi JDO muokkaajalle (JDO Enhancer), jonka toimintaa XML kuvaus ohjaa. Muokkaaja käsittelee välikielisiä (bytecode) käännettyjä luokkia ja tekee niihin tarpeellisia muutoksia, jonka jälkeen kaikki persistoitavat luokat toteuttavat rajapinnan PersistentCapable. Jotkin muokkaajat tekevät samalla tietokannan taulujen luontilauseet ja jotkin saattavat jopa luoda kantakaavan (database schema) suoraan tietokantaan. Jotkut toteutukset tarjoavat erillisen työkalun kantakaavan rakentamiseksi, joilla olioiden ja relaation välisen nimien sidonnan voi tehdä haluamallaan tavalla. Jotkut toteutuksen tekevät tarvittavat muutokset suoraan lähdekoodiin ennen kääntämistä. [TeL02] Luokka.java Java kääntäjä Luokka.class Luokka.class JDO muokkaaja XML kuvaus Java virtuaalikone Kuva 4 JDO muokkaaja [Bro02] 2.5 JDO ilmentymän elinkaari JDO ilmentymän eli PersistentCapable rajapinnan toteuttavan luokan ilmentymän elinkaarta hallitaan joukolla tiloja ja niiden välisiä tilasiirtymiä. Ilmentymä siirtyy olemassaolonsa aikana eri tilojen välillä kunnes se tulee poistonsa jälkeen Javan virtuaalikoneen (JVM) roskienkerääjän syömäksi. Näihin tilasiirtymiin vaikuttaa ilmentymään suoraan sekä JDO:n PersistentManager luokan kautta tehdyt operaatiot. Toisinaan ilmentymä saattaa olla ristiriidassa persistentin versionsa kanssa jo
8 transaktion alusta lähtien, tällöin ilmentymä on merkittävä likaiseksi (dirty). Esimerkiksi transaktion aikana poistetut, persistoidut tai muokatut ilmentyvät ovat likaisia kunnes transaktio sitoutuu tai peruuttaa. Seuraavaksi esitellään joitakin JDO:n tiloja, tarkimpia yksityiskohtia on jätetty pois. Kuvassa 5 on kuvattu tiloja, sekä joitakin tilasiirtymiä niiden välillä, tähdellä merkityt tilat ovat JDO määritelmässä valinnaisia, toimittajan ei välttämättä tarvitse toteuttaa niitä. [Sun02] transient-clean * Read-ok persistentclean transient-dirty * persistent-new persistentnontransactional * hollow transient Write-ok persistent-dirty persistent-newdeleted persistentdeleted Transient Persistent Kuva 5 JDO ilmentymän tilat [Sun02] JDO ilmentymät ovat aina joko persistenttejä tai transientteja. Ilmentymä on newoperaattorilla tehdyn alustuksen jälkeen tilapäisessä eli transient tilassa, kunnes se annetaan JDO:n käsiteltäväksi. Transientit ilmentymät ovat olemassa vain niin kauan kuin niihin on viittauksia ja Javan virtuaalikone on käynnissä. Transientille ilmentymälle tehtyjä muutoksia ei talleteta tietovarastoon, ennen kuin se annetaan PersistentManagerin metodille makepersistent() parametrina. Tällöin ilmentymä siirtyy persistent-new tilaan ja PersistentManager huolehtii sen tilasiirtymistä, tallettaa ilmentymän arvoja mahdollista peruutusta varten ja haluttaessa asettaa ilmentymälle JDO identiteetin. Persistoidun ilmentymän tiedot sijaitsevat loogisesti tietovarastossa,
9 jos ilmentymän tietoja muutetaan, päivittyvät ne myös tietovarastoon, ellei transaktio peruunnu. Saman transaktion aikana luodut ja persistoidut ja sittemmin poistetut ilmentymät siirtyvät tilaan persistent-new-deleted. Ilmentymät, joiden tietoja on persistoitu tietovarastoon, mutta joiden kenttiä ei ole luettu sieltä, kuuluvat tilaan hollow. JDO toteutuksen sallitaan tehdä tilasiirtymä pois tilasta hollow milloin vain, ikään kuin kenttä olisi luettu, siten tila hollow saattaa olla sovellukselle näkymätön [Sun02]. Hollow tilassa olevan JDO identiteetti on ladattu, mutta ne kentät jotka eivät ole sen avainkenttiä ei ole ladattu, ne täytyykin lukea aina uudelleen kannasta transaktion käsitellessä ilmentymää. JDO identiteetillä onkin merkittävä osuus suorituskyvyn kannalta [Sha02]. Mikäli hollow tilan objekteihin ei ole vahvoja viittauksia, ne saattavat joutua roskienkerääjän poistamaksi. Persistent-clean, persistent-dirty ja persistent-new ilmentymät tulevat hollow tilaan sitoutumisen myötä. Hollow tilassa persistenttien ilmentymien yksilöllisyydestä huolehditaan transaktioiden välillä. [Sha02] JDO ilmentymät, joilla on persistoitua tietoa tietovarastossa ja joiden arvot on luettu suoritettavan transaktion aikana, muttei muutettu, kuuluvat tilaan persistent-clean. Mikäli ilmentymällä on persistoitua tietoa, jota on suoritettavan transaktion aikana muokattu, ilmentymän tila on persistent-dirty. Kun transaktio lopulta sitoutuu tai peruuntuu, seuraavaan tilasiirtymään vaikuttaa suoritetulle transaktiolle annetut parametrit; esimerkiksi sitoutumisen yhteydessä voidaan haluttaessa joko siirtyä tilaan hollow tai tilaan persistent-nontransactional, jolloin ilmentymä säilytetään välimuistissa transaktion loputtua. Ilmentymät, joilla on persitoitua tietoa ja jotka on transaktion aikana poistettu, kuuluvat tilaan persistent-deleted. Transaktion lopulta sitoutuessa ilmentymän tilaksi tulee transient.
10 Seuraavaksi esimerkki tilasiirtymistä yhden transaktion aikana tehdyn ilmentymän luomisen, persistoimisen ja poistamisen yhteydessä (Kuva 6). Kuva 6 Ilmentymän tilasiirtymät käsittelyn aikanan [Sun02] Person p = new Person() // tilassa transient Transaction t = pm.currenttransaction(); t.begin(); pm.makepersistent(p); // siirtymä tilaan persistent-new pm.deletepersistent(p) // tilaan persistent-new-deleted t.commit(); // tilaan transient [Sun02] 3 JDO esimerkki Seuraavaksi esitellään JDO käyttöesimerkki: Luokka Työntekijä:
11 public class Työntekijä{ private String nimi; private int ikä; private float palkka; private Työntekijä esimies; private Osasto osasto; public Työntekijä (String nimi, String ikä){ this.nimi = nimi; this.ikä = ikä; } public String getname(){ return nimi;} public Osasto getosasto() {return osasto;} public void setosasto(osasto o){osasto = o;} } Luokka Osasto: public class Osasto{ private String nimi; private Set työntekijät = new HashSet(); public Osasto(String nimi){this.nimi = nimi;} public String getnimi(){return nimi;} public void addtyöntekijä(työntekijä t){ t.setosasto(this); työntekijät.add(t); } } XML kuvaus Persistoitavista luokista kenttineen: <?xml version= 1.0?> <!DOCTYPE jdo SYSTEM jdo.dtd > <jdo> <package name = com.mycompany.example /> <class name= Työntekijä /> <class name= Osasto > <field name= työntekijä > <collection element-type= Työntekijä /> </field> </class> </jdo> Yhteydenotto PersistenManageriin: PersistentManagerFactory factory = new MyVendorPersistentManagerFactory(); factory.setconnectionurl(url) PersistentManger pm = factory.getpersistentmanager();
12 Suoritetaan kysely osastoihin suodinta käyttäen: Transaction tx = pm.currenttransaction(); tx.begin(); Extent osastot = pm.getextent(department.class); String suodin = nimi = osastonimi ; Query kysely = pm.newquery(osastot, suodin); kysely.declareparameters( String osastonimi ); Collection tulokset = pm.execute( hallinto ); Osasto osasto = (Department)tulokset.iterator().next(); Luo uusi työntekijä ja lisää se osastoon: Työntekijä työläinen = new Työntekijä( Maija Malli, 1000)); osasto.addtyöntekijä(työläinen); tx.commit(); 4 Yhteenveto JDO tarjoaa rajapinnan persistoitujen olioiden käsittelyyn Java sovelluksista, käyttäen transaktionaalisia prosesseja ja käyttäen rajapintaa, jonka käyttämää tietovarastoa voi vaihtaa, joutumatta muokkaamaan lähdekoodia. JDO:ta käyttävien sovellusten kirjoittaminen, testaaminen ja ylläpito helpottuu, sillä se käyttää oliokeskeistä tietomallia ja sovelluksen toiminta on yksinkertaisempaa kuin esimerkiksi JDBC:tä käytettäessä. JDO käytön arvioidaankin lyhentävän sovelluksen kehitysaikaa noin 20 prosentilla [Sha02]. JDO:ta voidaan pitää vaihtoehtona JDBC:lle, mutta se ei korvaa sitä kokonaan. Mikäli tarvitaan tietokantakohtaista koodia on JDBC parempi valinta [Big01]. Samoin, jos olioiden ja relaation nimien välinen sidonta (mapping) on liian raskasta suorituskyvyn kannalta verrattuna vastaavaan JDBC toteutukseen. JDO toteutuksissa on tätä sidontaa pyritty tehostamaan käyttämällä välimuistia ja parempaa resurssien hallintaa, mikä taas tekee JDO:sta JDBC totetuksia vakaamman.
13 Lukuisia JDO toimittajia on jo olemassa, kuten SolarMetric Kodo JDO, LIBeLIS LiDO, ObjectFrontierin FrontierSuite for JDO ja lisäksi avoimen lähdekoodin projekteja, kuten Jakarta OJB, Triactive JDO ja XORM, jotka eivät kaikki ole täysin toteuttaneet JDO määrittelyä.
14 Lähteet Alm02 Almaer D., Using Java Data Objects, O Reilly, February 2002. http://www.onjava.com/pub/a/onjava/2002/02/06/jdo1.html [15.3.2003] Big01 Biggs, M., JDO streamlines data access in Java, November 2001. http://archive.infoworld.com/articles/tc/xml/01/11/05/011105tcjdo.xml [15.3.2003] Bro02 Brown, J., An introduction to Java Data Objects, Object Computing, Inc. June 2002. http://www.ociweb.com/jnb/jnbjun2002.html [15.3.2003] Kru02 Kruszelnicki, J., Persist data with Java Data Objects, March 2002. http://www.javaworld.com/javaworld/jw-03-2002/jw-0301-jdo.html [15.3.2003] McC02 McCammon K., Database Access with Java Data Objects (JDO), Versant Corporation 2002. http://www.versant.com/resources/presentations/adi402-jdo.pdf [15.3.2003] Ros02 Roos, R., Java Data Objects, Addison-Wesley, November 2002. Shar02 Sharley, J., Java Data Objects, Cognitive Machines Pty Ltd, November 2002. http://www.cognitivemachines.com/jdochat.html [15.3.2003] Sun02 Java Data Objects Specification 1.0 Sun Microsystems, March 2002. http://access1.sun.com/jdo/ [15.3.2003] TeL02 Telem Y., Litvak S., Coming out of the JDO closet. Java Developers Journal 7, 2 (2002).