Constituir lotes de alterações a recursos

Quando é preciso modificar recursos no espaço de trabalho, é importante ter em mente que os plug-ins poderão estar a trabalhar com os mesmos recursos. A API de recursos proporciona mecanismos robustos para manter os plug-ins informados acerca de alterações no espaço de trabalho, e para assegurar que não são vários plug-ins a modificar o mesmo recurso em simultâneo. Onde for possível, as modificações que o seu plug-in fizer ao espaço de trabalho devem constituir lotes de unidades de trabalho dentro de um executável de espaço de trabalho. Estes executáveis ajudam a reduzir o volume de notificações de alterações gerado por estas. Também permitem declarar qual a parte do espaço de trabalho que será modificada, de modo a que os outros plug-ins possam ser bloqueados das alterações à mesma parte do espaço de trabalho.

O protocolo para IWorkspaceRunnable é muito simples. Um executável de espaço de trabalho assemelha-se a uma operação ou a um trabalho de plataforma de de longo curso. O trabalho propriamente dito é realizado dentro de um método run, sendo o progresso reportado ao IProgressMonitor fornecido. O código que manipula o espaço de trabalho é executado dentro do método run.

IWorkspaceRunnable myRunnable =
	new IWorkspaceRunnable() {
		public void run(IProgressMonitor monitor) throws CoreException {
			//do the actual work in here
			...
		}
}

Quando for altura de executar o código, o plug-in diz ao espaço de trabalho que execute o código em seu lugar. Desta forma, o espaço de trabalho pode gerar eventos de alteração necessários e assegurar que não há dois plug-ins a modificar o mesmo recurso ao mesmo tempo. (Mesmo quando o plug-in não está a utilizar trabalhos de segundo plano e o quadro de simultaneidade para modificar o espaço de trabalho, há outros plug-ins que o poderão estar a fazer.)

Regras de agendamento e bloqueio

O protocolo IWorkspace é utilizado para executar um executável de espaço de trabalho. A técnica preferencial consiste em utilizar o formato longo do método run que faculta uma regra de agendamento e especifica como são difundidos os eventos de alteração de recursos.

Especificar uma regra de agendamento quando se executa um executável de espaço de trabalho permite a este último determinar se as alterações aos recursos vão ou não colidir com alterações ao espaço de trabalho que aconteçam noutros módulos. (Consulte Regras de agendamento para ver uma descrição geral das regras de agendamento e do protocolo ISchedulingRule.) Felizmente, o protocolo IResource inclui o protocolo para ISchedulingRule, o que significa que um recurso pode ser utilizado como regra de agendamento para si próprio.

Isto parece algo confuso? O código pode ajudar a esclarecer este ponto. Suponha que o seu plug-in está a preparar-se para modificar vários recursos em determinado projecto. Poderá utilizar o projecto propriamente dito como regra de agendamento para realizar as alterações. A porção de código seguinte executa o executável de espaço de trabalho que criámos anteriormente:

IWorkspace espaço de trabalho = ResourcesPlugin.getWorkspace();
workspace.run(oMeuExecutável, oMeuProjecto, IWorkspace.AVOID_UPDATE, null);

O executável é transmitido ao espaço de trabalho, seguido do projecto que o código está a manipular. Isto indica ao espaço de trabalho que todas as alterações no executável se limitam a oMeuProjecto. Os eventuais pedidos de outros módulos para alterar oMeuProjecto serão bloqueados até que este executável seja concluído. Do mesmo modo, esta chamada será bloqueada se houver outro módulo já a modificar oMeuProjecto. Ao especificar que parte da árvore de recursos será modificada pelo executável, estará a permitir que outros módulos continuem a modificar outras partes do espaço de trabalho. É importante ter a certeza de que a regra de recurso corresponde ao trabalho efectuado dentro do executável. Quando é utilizada uma regra de agendamento não nula, qualquer tentativa de aceder a um recurso fora do âmbito da regra de agendamento desencadeará uma excepção.

Existem duas regras de agendamento especiais que devem ser levadas em consideração. Em primeiro lugar, se utilizar uma instância de IWorkspaceRoot como regra de agendamento, significa que o seu módulo está a bloquear o acesso a todos os recursos que estejam na árvore. Enquanto um módulo estiver a reter a regra de raiz, não é permitido que nenhum outro módulo modifique a sua área de trabalho. da mesma forma, uma regra nula indica que o módulo não bloqueará o acesso a nenhum recurso que esteja na árvore. Enquanto que um módulo com uma regra nula pode modificar a área de trabalho, os outros módulos não serão impedidos de executar as suas próprias modificações. O IWorkspaceRoot e as regras de agendamento nulas ocupam extremidades opostas no espectro de concorrência. No IWorkspaceRoot não há concorrência e apenas um módulo modifica a área de trabalho de cada vez. Na regra nula, há concorrência máxima e todos os módulos podem modificar a área de trabalho simultaneamente.

O terceiro parâmetro do método run especifica se os eventos de alteração de recursos periódicos devem ser difundidos durante o âmbito desta chamada. A utilização de IWorkspace.AVOID_UPDATE diz à plataforma que suprima eventos de alteração de recursos enquanto o executável estiver em execução e que difunda um evento no final das alterações. Durante esta chamada, os outros executáveis criados no executável serão considerados parte da operação por lotes ascendente. As alterações a recursos efectuadas nesses executáveis aparecem na notificação de alteração a recurso do ascendente.

Fábrica de regras de recursos

No exemplo supra, partimos do princípio de que o código do nosso executável só modificava recursos em determinado projecto. Assim se facilitava a especificação de uma regra de agendamento para o executável. Na prática, pode ser mais difícil calcular quais as partes do espaço de trabalho afectadas por determinada alteração. Por exemplo, mover um recurso de um projecto para outro afecta ambos os projectos. Pode ser utilizada uma IResourceRuleFactory para calcular uma regra de recursos apropriada para certos tipos de alterações a recursos. É possível obter uma fábrica de regras de recursos no próprio espaço de trabalho.

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

A fábrica pode fornecer regras apropriadas a muitos tipos de operações. Se o seu executável mover um recurso de um lado para outro, poderá obter uma regra apropriada a esta operação:

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

Consulte o javadoc sobre IResourceRuleFactory para ver uma lista de regras disponíveis. O plug-in de recursos utiliza ele próprio estas regras para implementar a maioria das operações de recursos. Observar o código que referencia estes métodos de regras ajudará a demonstrar como são utilizados na prática.

Podem ser combinadas várias regras com MultiRule.

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

Ignorar as regras

Também está disponível o formato curto do método run em IWorkspace. Está retida para fins de retrocompatibilidade. O formato curto não inclui nenhuma regra nem sinalizador de actualização.

workspace.run(oMeuExecutável, null);

é efectivamente o mesmo que chamar

workspace.run(oMeuExecutável, workspace.getRoot(), IWorkspace.AVOID_UPDATE, null);

Especificar a raiz do espaço de trabalho como regra de agendamento põe um bloqueio sobre todo o espaço de trabalho até o executável ser concluído. Trata-se da maneira mais conservadora de realizar uma actualização ao espaço de trabalho, mas não é muito amigável para outros plug-ins orientados para a simultaneidade.