Resurssimuutosten eräajo

Kun on tarpeen muuttaa työtilan resursseja, on pidettävä mielessä, että muut lisäosat saattavat käyttää samoja resursseja. Resurssien sovellusohjelmaliittymä tarjoaa luotettavia menetelmiä, joiden avulla lisäosille voi tiedottaa työtilan muutoksista ja varmistaa, että useat lisäosat eivät muokkaa samaa resurssia samaan aikaan. Jos mahdollista, lisäosan tekemät muutokset työtilaan on ajettava eräajona työyksiköissä työtilan runnable-objektissa. Nämä runnable-objektit vähentävät muutosten tuottamien ilmoitusten määrää. Niiden avulla voit myös määrittää, mitä osaa työtilasta muokataan, jotta muita lisäosia voi estää muuttamasta työtilan samaa osaa samaan aikaan.

Kohteen IWorkspaceRunnable käytäntö on varsin yksinkertainen. Työtilan runnable-objekti näyttää aivan samalta kuin pitkäkestoinen toiminto tai ympäristön työ. Varsinainen työ tapahtuu run-metodissa, jonka tilannetiedot ilmoitetaan kohteessa IProgressMonitor. Työtilaa käsittelevä koodi toteutetaan run-metodissa.

IWorkspaceRunnable myRunnable = 
        new IWorkspaceRunnable() {
		public void run(IProgressMonitor monitor) throws CoreException {
			//tee varsinainen työ tässä
			...
		}
}

Kun on aika ajaa koodi, lisäosa käskee työtilaa ajamaan koodin puolestaan. Tällä tavoin työtila voi luoda tarvittavat muutostapahtumat ja varmistaa, ettei kaksi lisäosaa yritä muokata samaa resurssia samaan aikaan. (Vaikka lisäosa ei käyttäisi taustatöitä ja samanaikaisuuskehystä työtilan muokkaukseen, muut lisäosat saattavat tehdä niin.)

Ajoitussäännöt ja lukitus

IWorkspace-käytännön avulla ajetaan työtilan runnable-objekti. Suositeltu menetelmä on käyttää run-metodin pitkää muotoa, joka antaa ajoitussäännön ja määrittää, kuinka resurssien muutostapahtumista ilmoitetaan.

Ajoitussäännön määritys työtilan runnable-objektin ajossa mahdollistaa sen, että työtila voi selvittää, joutuvatko resurssimuutokset ristiriitaan muissa säikeissä tapahtuvien työtilan muutosten kanssa. (Kohdassa Ajoitussäännöt on yleiskuvaus ajoitussäännöistä ja ISchedulingRule-käytännöstä.) Onneksi IResource-käytännössä on ISchedulingRule-kohteen käytäntö, mikä tarkoittaa, että resurssia voi usein käyttää ajoitussääntönä itsessään.

Tämä voi kuulostaa epäselvältä. Asiaa voi selventää koodin avulla. Oletetaan, että lisäosa valmistautuu muokkaamaan joukkoa tietyn projektin resursseja. Se voi käyttää projektia itseään ajoitussääntönä muutosten toteutuksessa. Seuraava katkelma ajaa työtilan aiemmin luodun runnable-objektin:

IWorkspace workspace = ResourcesPlugin.getWorkspace();
workspace.run(myRunnable, myProject, IWorkspace.AVOID_UPDATE, null);

Runnable-objekti välitetään työtilaan sen projektin kanssa, jota koodi käsittelee. Tämä kertoo työtilalle, että kaikki runnable-objektin muutokset sisältyvät myProject-projektiin. Muiden säikeiden pyynnöt myProject-projektin muuttamiseksi estetään, kunnes tämä runnable-objekti on valmis. Samoin tämä kutsu estyy, jos jokin muu säie muokkaa jo myProject-projektia. Määrittämällä mitä osaa resurssirakenteesta runnable-objekti muokkaa voit sallia muiden säikeiden jatkavan työtilan muiden osien muokkausta. On tärkeää varmistua siitä, että resurssisääntö vastaa runnable-objektissa toteutettavaa työtä. Käytettäessä muuta kuin tyhjää ajoitussääntöä kaikki yritykset käyttää ajoitussäännön vaikutusalueen ulkopuolista resurssia liipaisevat poikkeuksen.

On kaksi tärkeää erikoisajoitussääntöä. Ensiksi, jos käytät ajoitussääntönä IWorkspaceRoot-ilmentymää, säie estää rakenteen kaikkien resurssien käytön. Kun säie pitää juurisääntöä, mikään muu säie ei voi muokata työtilaa. Tyhjä sääntö osoittaa päinvastoin, että säie ei estä rakenteen minkään resurssin käyttöä. Vaikka säie, jolla on tyhjä sääntö, voi vapaasti muokata työtilaa, muita säikeitä ei ole estetty tekemästä omia muutoksiaan. Ajoitussääntö IWorkspaceRoot ja tyhjä ajoitussääntö ovat samanaikaisuusjatkumon vastakkaisissa päissä. Jos käytössä on IWorkspaceRoot, samanaikaisuutta ei ole, vaan ainoastaan yksi säie kerrallaan voi muokata työtilaa. Jos käytössä on tyhjä sääntö, samanaikaisuutta on enimmäismäärä, koska kaikki säikeet voivat muokata työtilaa samaan aikaan.

run-metodin kolmas parametri määrittää, lähetetäänkö jotkin säännölliset resurssien muutostapahtumat yleisjakeluna tämän kutsun vaikutusaikana. IWorkspace.AVOID_UPDATE-kohteen käyttö käskee ympäristöä estämään resurssien muutostapahtumat runnable-objektin ollessa ajossa ja lähettämään yleisjakeluna yhden tapahtuman muutosten lopuksi. Tämän kutsun aikana kaikki muut runnable-objektissa luodut runnable-objektit katsotaan osaksi pääeräajotoimintoa. Näissä runnable-objekteissa tehdyt muutokset näkyvät pääobjektin resurssien muutosilmoituksessa.

Resurssisäännön factory-metodi

Edellä olevassa esimerkissä oletettiin, että runnable-objektissa oleva koodi muokkasi vain tietyn projektin resursseja. Tämän ansiosta oli hyvin helppoa määrittää runnable-objektille ajoitussääntö. Käytännössä voi olla vaikeampaa selvittää, mihin työtilan osiin tietty muutos vaikuttaa. Esimerkiksi resurssin siirto projektista toiseen vaikuttaa kumpaankin projektiin. IResourceRuleFactory-kohteen avulla voit laskea asianmukaisen resurssisäännön tietynlaisille resurssimuutoksille. Voit noutaa resurssisäännön factory-metodin työtilasta itsestään.

IWorkspace workspace = ResourcesPlugin.getWorkspace();
IResourceRuleFactory ruleFactory = workspace.getRuleFactory();

Factory-metodi voi toimittaa useisiin eri toimintoihin sopivia sääntöjä. Jos runnable-objekti siirtää resurssin paikasta toiseen, se voi noutaa tätä toimintoa varten sopivan säännön seuraavasti:

ISchedulingRule movingRule = ruleFactory.moveResource(sourceResource, destinationResource);
workspace.run(myRunnable, movingRule, IWorkspace.AVOID_UPDATE, null);

IResourceRuleFactory-kohteen javadoc-ohjeissa on luettelo käytettävissä olevista säännöistä. Resurssien lisäosa käyttää näitä sääntöjä itse useimpien resurssitoimintojen toteutuksessa. Näihin sääntömetodeihin viittaavien sääntöjen selaus auttaa havainnollistamaan, kuinka niitä käytetään.

Useita sääntöä voi yhdistää MultiRule-kohteen avulla.

ISchedulingRule movingRule = ruleFactory.moveResource(sourceResource, destinationResource);
ISchedulingRule modifyRule = ruleFactory.modifyResource(destinationResource);
workspace.run(myRunnable, MultiRule.combine(movingRule, modifyRule), IWorkspace.AVOID_UPDATE, null);

Sääntöjen ohitus

Run-metodista on käytettävissä myös lyhyt muoto kohteessa IWorkspace. Se varmistaa yhteensopivuuden aiempiin versioihin. Lyhyt muoto ei sisällä sääntöä eikä päivitysmääritettä.

workspace.run(myRunnable, null);

on käytännössä sama kuin kutsu

workspace.run(myRunnable, workspace.getRoot(), IWorkspace.AVOID_UPDATE, null);

Työtilan juuren määritys ajoitussäännöksi lukitsee koko työtilan, kunnes runnable-objekti on valmis. Tämä on perinteisin tapa päivittää työtila, mutta se ei ole kovin hyvä muita samanaikaisuuteen tähtääviä lisäosia ajatellen.