При изменении ресурсов в рабочей области важно помнить, что другие модули также могут использовать эти ресурсы. API ресурсов обеспечивает надежные механизмы для уведомления модулей об изменениях в рабочей области, а также для исключения возможности одновременного изменения одного и того же ресурса несколькими модулями. По возможности изменения должны объединяться модулем в пакетные операции внутри объекта runnable рабочей области. Эти объекты позволяют уменьшить число уведомлений, сгенерированных изменениями. Кроме того, они позволяют объявить, какая часть рабочей области подлежит изменению, чтобы другие модули не могли параллельно изменять эту же часть рабочей области.
Протокол для IWorkspaceRunnable довольно прост. IWorkspaceRunnable представляет собой длительную операцию или задание платформы. Собственно алгоритм выполняется внутри метода run, ход выполнения которого сигнализируется в IProgressMonitor. Код операций с рабочей областью выполняется внутри метода run.
IWorkspaceRunnable myRunnable = new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) throws CoreException { //собственно алгоритм ... } }
Когда необходимо выполнить код, модуль делегирует его исполнение рабочей области. Таким образом, рабочая область может генерировать любые необходимые события и исключить возможность одновременного изменения одного и того же ресурса разными модулями. (Даже если ваш модуль не использует фоновые задания и механизмы параллельной обработки для изменения рабочей области, другие модули могут их использовать.)
Протокол IWorkspace используется для выполнения объекта runnable рабочей области. Предпочтительным вариантом является использование полной формы метода run, который задает правило планирования и указывает, как должны передаваться сигналы события изменения ресурса.
С помощью правила планирования рабочая область определяет, возможны ли конфликты между изменениями ресурса и изменениями рабочей области, происходящие в других нитях. (Обзор правил планирования и протокола ISchedulingRule приведен в разделе Правила планирования.) К счастью, протокол IResource включает в себя протокол для ISchedulingRule, что позволяет часто использовать сам ресурс в качестве правила планирования.
Слишком сложно? Рассмотрим код, поясняющий это на примере. Предположим, что модуль собирается изменить группу ресурсов в определенном проекте. Он может использовать сам проект в качестве правила планирования для этих изменений. Следующий фрагмент кода запускает объект runnable, который была создан ранее:
IWorkspace workspace = ResourcesPlugin.getWorkspace(); workspace.run(myRunnable, myProject, IWorkspace.AVOID_UPDATE, null);
Объект runnable передается рабочей области, за ним следует проект, обрабатываемый кодом. Так рабочая область узнает, что все изменения в объекте runnable относятся к проекту myProject. Если другие нити отправляют запросы на изменение myProject, они блокируются до завершения выполнения данного объекта runnable. Вызовы блокируются, если другая нить в данный момент изменяет myProject. Определение изменяемой объектом runnable части дерева ресурса позволяет другим нитям изменять остальные части рабочей области. Правило для ресурса должно совпадать с заданием, которое выполняется внутри объекта runnable. Любая попытка обращения к ресурсу вне области действия правила планирования генерирует исключительную ситуацию.
Третий параметр в методе run определяет, будут ли создаваться периодические события изменения ресурсов во время этого вызова. Значение IWorkspace.AVOID_UPDATE указывает платформе подавлять любые события изменения ресурса во время выполнения объекта runnable и генерировать только одно событие по завершении всех изменений. Во время этого вызова любые дочерние объекты, созданные в объекте runnable, считаются частью родительской пакетной операции. Изменения ресурса, которые произошли в этих объектах runnable, появятся в уведомлении об изменении ресурса родительского объекта.
В предыдущем примере мы исходили из допущения, что код внутри объекта runnable изменяет только ресурсы определенного проекта. Это позволяло значительно упростить определение правила планирования для объекта runnable. На практике часто сложно определить, какие части рабочей области будут изменены. Например, перемещение ресурса из одного проекта в другой изменяет оба проекта. Для облегчения анализа правил для некоторых видов изменений ресурсов используется интерфейс IResourceRuleFactory. Фабрику правил ресурсов можно получить из самой рабочей области.
IWorkspace workspace = ResourcesPlugin.getWorkspace(); IResourceRuleFactory ruleFactory = workspace.getRuleFactory();
Фабрика содержит правила, соответствующие различным видам операций. Если объект runnable изменяет расположение ресурса, он может получить правило, соответствующее данной операции:
ISchedulingRule movingRule = ruleFactory.moveResource(sourceResource, destinationResource); workspace.run(myRunnable, movingRule, IWorkspace.AVOID_UPDATE, null);
Список доступных правил приведен в Javadoc для интерфейса IResourceRuleFactory. Модуль ресурсов использует эти правила для реализации различных операций с ресурсами. Код, в котором применяются эти методы, поможет разобраться в их реализации на практике.
Для связывания нескольких правил используется класс MultiRule.
ISchedulingRule movingRule = ruleFactory.moveResource(sourceResource, destinationResource); ISchedulingRule modifyRule = ruleFactory.modifyResource(destinationResource); workspace.run(myRunnable, MultiRule.combine(movingRule, modifyRule), IWorkspace.AVOID_UPDATE, null);
Помимо полной формы метода run, интерфейс IWorkspace также содержит его краткую форму. Она используется для сохранения совместимости с предыдущими версиями. Краткая форма не содержит правил или флагов обновления.
workspace.run(myRunnable, null);
аналогичен вызову
workspace.run(myRunnable, workspace.getRoot(), IWorkspace.AVOID_UPDATE, null);
Если в качестве правила планирования выбран корневой субъект рабочей области, то до окончания выполнения объекта runnable вся рабочая область будет заблокирована. Это самый безопасный способ обновления рабочей области, но он может мешать другим параллельно работающих модулям.