Resourcewijzigingen als batch verwerken

Als u resources in het werkgebied moet wijzigen, is het belangrijk om te weten dat andere plugins mogelijk met dezelfde resources werken. De resource-API biedt krachtige mechanismen om plugins op de hoogte te houden van wijzigingen in het werkgebied. Deze zorgt ook dat meerdere plugins niet op hetzelfde moment dezelfde resources kunnen wijzigen. Als het mogelijk is, moeten de wijzigingen in werkgebiedplugins als batch worden verwerkt als werkeenheden in een runnable in het werkgebied. Het werken met runnables vermindert de hoeveelheid gegenereerde wijzigingsmeldingen. Verder kunt u declareren welk deel van het werkgebied gewijzigd moet worden en zorgen dat andere plugins hetzelfde deel niet meer kunnen wijzigen.

Het protocol voor IWorkspaceRunnable is vrij eenvoudig. Een runnable in het werkgebied lijkt veel op een langdurige bewerking of een platformjob. Het feitelijke werk wordt in een run-methode gedaan en de voortgang wordt gemeld aan de verstrekte IProgressMonitor. Code die de het werkgebied wijzigt, wordt in de run-methode uitgevoerd.

IWorkspaceRunnable myRunnable = 
	new IWorkspaceRunnable() {
		public void run(IProgressMonitor monitor) throws CoreException {
			//hier gebeurt het eigenlijke werk
			...
		}
}

Als het tijd is om de code uit te voeren, geeft de plugin het werkgebied opdracht deze namens de plugin uit te voeren. Op deze manier kan het werkgebied de noodzakelijke wijzigingsevents genereren en zorgen dat verschillende plugins niet tegelijkertijd dezelfde resource kunnen bewerken. (Zelfs als uw plugin geen achtergrondjobs en het gemeenschappelijke framework gebruikt om het werkgebied te wijzigen, is het mogelijk dat een andere plugin dit wel doet.)

Planningsregels en vergrendeling

Het protocol IWorkspace wordt gebruikt om een werkgebiedrunnable uit te voeren. In de voorkeurstechniek wordt de lange vorm van de run-methode gebruikt die een planningsregel levert en opgeeft hoe de resourcewijzigingsevents worden gedistribueerd.

Door een planningsregel op te geven als er een werkgebiedrunnable actief is, kan het werkgebied vaststellen of de resourcewijzigingen een conflict opleveren met de werkgebiedwijzigingen die uit andere threads afkomstig zijn. (Zie Planningsregels voor een overzicht van planningsregels en het ISchedulingRule-protocol.) Gelukkig bevat het IResource-protocol het protocol voor ISchedulingRule, wat inhoudt dat een resource vaak als planningsregel voor zichzelf kan worden gebruikt.

Is dit verwarrend? Een stuk code kan het misschien duidelijker maken. Stel dat uw plugin voorbereidingen treft om een aantal resources in een bepaald project te wijzigen. De plugin kan het project zelf als planningsregel voor het maken van wijzigingen gebruiken. In het volgende codefragment wordt de runnable van het werkgebied uitgevoerd die we eerder hebben gemaakt:

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

De runnable wordt doorgegeven aan het werkgebied, gevolgd door het project dat de code wijzigt. Hierdoor weet het werkgebied dat de wijzigingen in de runnable zijn beperkt tot myProject. Aanvragen uit andere threads om myProject te wijzigen, worden geblokkeerd tot deze runnable gereed is. De aanvraag wordt ook geblokkeerd als een andere thread al wijzigingen aanbrengt in myProject. Door op te geven welk deel van de resourcestructuur door de runnable wordt gewijzigd, kunnen andere threads doorgaan met het bewerken van andere delen van het werkgebied. U moet zeker weten dat de resourceregel overeenkomt met het werk dat in de runnable wordt uitgevoerd. Als een planningsregel anders dan null wordt gebruikt, veroorzaken alle pogingen om buiten het bereik van de planningsregels toegang tot een resource te krijgen een uitzondering.

Er zijn twee speciale planningsregels waarmee u rekening dient te houden. Als u een instance van IWorkspaceRoot als planningsregel gebruikt, blokkeert de thread de toegang tot alle resources in de structuur. Zolang de thread de root-regel hanteert, krijgt geen enkele andere thread toestemming het werkgebied te wijzigen. De regel null geeft daarentegen aan dat de thread de toegang tot geen enkele resource in de structuur blokkeert. Een thread met de regel null kan het werkgebied zelf wijzigen, en andere threads kunnen hun eigen wijzigingen aanbrengen. De planningsregels IWorkspaceRoot en null zijn tegenovergestelden van elkaar wat gelijktijdige uitvoering betreft. Met IWorkspaceRoot is gelijktijdige uitvoering niet mogelijk; per keer kan slechts één thread het werkgebied wijzigen. Met de regel null kunnen alle threads het werkgebied gelijktijdig wijzigen.

Met de derde parameter van de methode run wordt aangegeven of periodiek resourcewijzigingsevents moeten worden gedistribueerd binnen het bereik van de aanroep. Door het gebruik van IWorkspace.AVOID_UPDATE weet het platform dat resourcewijzigingsevents onderdrukt moeten worden als de runnable actief is en dat aan het einde van de wijzigingen één event gedistribueerd moet worden. Tijdens de aanroep worden andere runnables die in de runnable zijn gemaakt, beschouwd als onderdeel van de overkoepelende batchbewerking. Resourcewijzigingen die in die runnables zijn gedaan, worden vermeld in de resourcewijzigingsmelding van het bovenliggende item.

Resourceregelfactory

In het bovenstaande voorbeeld zijn we ervan uitgegaan dat de code in de runnable alleen resources in een bepaald project wijzigt. Hierdoor is het eenvoudig een planningsregel voor de runnable op te stellen. In de praktijk kan het echter gecompliceerd zijn om te berekenen welke delen van het werkgebied door een bepaalde wijziging worden beïnvloed. Als u bijvoorbeeld een resource van het ene project naar het andere verplaatst, heeft dit gevolgen voor beide projecten. IResourceRuleFactory kan worden gebruikt om een toepasselijke resourceregel voor bepaalde soorten resourcewijzigingen te berekenen. U kunt overeen resourceregelfactory uit het werkgebied zelf beschikken.

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

De factory kan toepasselijke regels voor veel soorten bewerkingen leveren. Als de runnable een resource van de ene locatie naar de andere verplaatst, kan deze beschikken over een toepasselijke regel voor de bewerking:

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

Zie de javadoc voor IResourceRuleFactory voor een lijst met beschikbare regels. De resourcesplugin gebruikt deze regels zelf voor implementatie van de meeste resourcebewerkingen. Door te bladeren door de code die naar deze regelmethoden verwijst, leert u hoe ze in de praktijk worden gebruikt.

U kunt meerdere regels combineren met MultiRule.

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

De regels negeren

De korte vorm van de run-methode in IWorkspace is ook beschikbaar. Deze is behouden om compatibiliteit met oudere versies mogelijk te maken. De korte vorm bevat geen regel of bijwerkingsvlag.

workspace.run(myRunnable, null);

is in principe hetzelfde als de aanroep

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

Door de hoofdmap van het werkgebied op te geven als planningsregel, kunt u het gehele werkgebied blokkeren tot de runnable gereed is. Dit is de meest behoudende manier om een bijwerking van het werkgebied uit te voeren, maar is niet erg vriendelijk voor gelijktijdig actieve plugins.