Отслеживание изменений ресурсов

Мы рассмотрели, как происходит объединение изменений ресурсов во время выполнения (Пакетные изменения ресурсов). Теперь рассмотрим другую сторону вопроса. Как отслеживать изменения в рабочей области, которые происходят во время работы модуля? В рабочей области можно зарегистрировать объект IResourceChangeListener. Получатели запросов узнают об изменениях благодаря объекту IResourceChangeEvent, который описывает изменения.

Регистрация получателя запросов

Вначале необходимо зарегистрировать получатель запросов в рабочей области.

   IResourceChangeListener listener = new MyResourceChangeReporter();
   ResourcesPlugin.getWorkspace().addResourceChangeListener(
      listener, IResourceChangeEvent.POST_CHANGE);

При изменении ресурсов рабочей области получатель запросов получает соответствующее уведомление. Методы API ресурсов, которые изменяют ресурсы, инициируют эти события как часть своего документированного поведения. Комментарий для метода API ресурсов явным образом определяет, инициируется ли событие изменения ресурсов или нет. Например, комментарий IFile.setContents() содержит следующую информацию:

   Данный метод изменяет ресурсы; для уведомления об этих изменениях используется
   событие изменения ресурсов, которое указывает, что содержимое данного файла
   изменилось.

Методы, которые создают, удаляют или изменяют ресурсы, обычно инициируют эти события. Методы, которые читают, но не изменяют ресурсы, обычно не инициируют эти события.

События изменения ресурсов

Событие содержит подробную информацию об одном или нескольких изменениях, которые произошли в рабочей области. Событие включает поправку ресурса, которая описывает суммарное воздействий изменений. Например, если ресурс был вначале добавлен, а затем удален во время одной пакетной операции изменений, поправка не будет содержать информацию об этом ресурсе.

Поправка ресурса представляет собой дерево, корнем которого является корневой субъект рабочей области. Дерево поправки ресурса описывает следующие виды изменений:

Для просмотра дерева поправки ресурса можно использовать интерфейс IResourceDeltaVisitor или метод для прямой работы с деревом IResource.getAffectedChildren. Просмотрщики поправки ресурса используют метод visit, который вызывается поправкой ресурса по мере того, как перечисляются все изменения в дереве.

Примечание:  Изменения, которые вносятся в сеансовые свойства ресурса или постоянные свойства ресурса, не указываются в поправке ресурса.

События изменения ресурса отправляются каждый раз, когда изменяется рабочая область. Кроме того, события отправляются во время некоторых операций в рабочей области. В следующей таблице перечислены все виды событий вместе с их описанием.

Тип события

Описание

PRE_CLOSE

Уведомляет получателей запросов о том, что проект будет закрыт. Это событие используется для извлечения и сохранения необходимой информации проекта из записи в оперативной памяти (например, сеансовые свойства) перед закрытием проекта. (При закрытии проекта запись в оперативной памяти удаляется). Во время этого события рабочая область заблокирована (обновление ресурсов невозможно). Событие содержит проект, который будет закрыт.

PRE_DELETE

Уведомляет получателей запросов о том, что проект будет удален. Это событие используется для выполнения операции очистки, например, для удаления какого-либо сохраненного состояния, связанного с проектом, из каталога модуля.  Во время этого события рабочая область заблокирована (обновление ресурсов невозможно). Событие содержит проект, который будет удален.

PRE_AUTOBUILD

Уведомляет получателей запросов о том, что произойдет автоматическая компоновка.  Передача события выполняется, если платформа обнаруживает необходимость в автоматической компоновке, независимо от того, активна ли функция автоматической компоновки.  Во время этого события рабочая область не заблокирована (ресурсы могут обновляться). Событие содержит поправку ресурса, описывающую изменения, которые произошли с момента последнего уведомления о событии POST_CHANGE.

POST_AUTOBUILD

Уведомляет получателей запросов о том, что автоматическая компоновка выполнена. Это событие передается после того, как платформа уже выполнила автоматическую компоновку, независимо от того, активна ли функция автоматической компоновки.  Во время этого события рабочая область не заблокирована (ресурсы могут обновляться). Событие содержит поправку ресурса, описывающую изменения, которые произошли с момента последнего уведомления о событии POST_CHANGE.

POST_CHANGE

Описывает группу изменений, которые произошли в рабочей области с момента последнего уведомления о событии POST_CHANGE. Инициируется после использования API изменения ресурса в одном или нескольких изменениях рабочей области. Также инициируется после получения уведомления PRE_AUTOBUILD или POST_AUTOBUILD. Событие содержит поправку ресурса, описывающую суммарные изменения, которые произошли с момента последнего события POST_CHANGE.  Во время этого события рабочая область заблокирована (обновление ресурсов невозможно).

Реализация получателя запросов

В следующем примере используется консольный получатель запросов. Получатель запросов об изменении ресурсов регистрируется для определенных типов событий, а информация об этих событиях выводится на консоль:

   IResourceChangeListener listener = new MyResourceChangeReporter();
   ResourcesPlugin.getWorkspace().addResourceChangeListener(listener,
      IResourceChangeEvent.PRE_CLOSE
      | IResourceChangeEvent.PRE_DELETE
      | IResourceChangeEvent.PRE_AUTO_BUILD
      | IResourceChangeEvent.POST_AUTO_BUILD
      | IResourceChangeEvent.POST_CHANGE);

Получатель запросов выполняет проверку для каждого типа событий и отправляет информацию об измененном ресурсе и видах изменений.  Хотя в этом примере используется общий получатель запросов, обрабатывающий все типы событий, обычно получатель запросов регистрируется только для одного типа событий.

В реализации события POST_CHANGE используется другой класс, который применяется для просмотра изменений в поправке ресурса.

   import org.eclipse.resources.*;
   import org.eclipse.runtime.*;

   public class MyResourceChangeReporter implements IResourceChangeListener {
      public void resourceChanged(IResourceChangeEvent event) {
         IResource res = event.getResource();
         switch (event.getType()) {
            case IResourceChangeEvent.PRE_CLOSE:
               System.out.print("Project ");
               System.out.print(res.getFullPath());
               System.out.println(" is about to close.");
      break;
            case IResourceChangeEvent.PRE_DELETE:
               System.out.print("Project ");
               System.out.print(res.getFullPath());
               System.out.println(" is about to be deleted.");
               break;
            case IResourceChangeEvent.POST_CHANGE:
               System.out.println("Resources have changed.");
               event.getDelta().accept(new DeltaPrinter());
      break;
            case IResourceChangeEvent.PRE_AUTO_BUILD:
               System.out.println("Auto build about to run.");
               event.getDelta().accept(new DeltaPrinter());
      break;
            case IResourceChangeEvent.POST_AUTO_BUILD:
               System.out.println("Auto build complete.");
               event.getDelta().accept(new DeltaPrinter());
      break;
         }
      }
   }

Для просмотра поправки ресурса класс DeltaPrinter использует интерфейс IResourceDeltaVisitor. Метод visit() вызывается для каждого изменения ресурса в поправке. Возвращаемое им значение определяет, следует ли просматривать поправки для вложенных ресурсов.

   class DeltaPrinter implements IResourceDeltaVisitor {
      public boolean visit(IResourceDelta delta) {
         IResource res = delta.getResource();
         switch (delta.getKind()) {
            case IResourceDelta.ADDED:
               System.out.print("Resource ");
               System.out.print(res.getFullPath());
               System.out.println(" was added.");
      break;
            case IResourceDelta.REMOVED"
               System.out.print("Resource ");
               System.out.print(res.getFullPath());
               System.out.println(" was removed.");
               break;
   case IResourceDelta.CHANGED:
               System.out.print("Resource ");
               System.out.print(res.getFullPath());
               System.out.println(" has changed.");
               break;
         }
         return true; // просмотр вложенных объектов
      }
   }

Дополнительная информация может быть получена из поправки ресурса. Следующий фрагмент кода демонстрирует, как можно использовать IResourceDelta.CHANGED для дальнейшего описания изменений ресурса.

   ...
   case IResourceDelta.CHANGED:
      System.out.print("Resource ");
      System.out.print(delta.getFullPath());
      System.out.println(" has changed.");
      int flags = delta.getFlags();
      if ((flags & IResourceDelta.CONTENT) != 0) {
            System.out.println("--> Content Change");
      }
      if ((flags & IResourceDelta.REPLACED) != 0) {
            System.out.println("--> Content Replaced");
      }
      if ((flags & IResourceDelta.MARKERS) != 0) {
            System.out.println("--> Marker Change");
            IMarkerDelta[] markers = delta.getMarkerDeltas();
            // если нужны маркеры, выполняется проверка поправок
      }
      break;
   ...

Полное описание поправок ресурсов, просмотрщиков и поправок маркеров см. в спецификации API для интерфейсов IResourceDelta, IResourceDeltaVisitor и IMarkerDelta.

Примечание:  Получатели запросов об изменении ресурсов применяются для отслеживания изменений в ресурсах во время активации модуля. Если модуль регистрирует получателей запросов во время своего запуска, возможно, что многие события были инициированы до активации модуля. Поправка ресурса, входящая в первое событие изменения ресурса, полученное модулем, не будет содержать все изменения, которые произошли с момента последней активации модуля. Если необходимо отслеживать изменения, которые происходят между активациями модуля, следует использовать имеющиеся возможности для сохранения рабочей области. Их описание приведено в разделе Участие в сохранении рабочей области.
Примечание:  Некоторые события изменения ресурсов инициируются во время обработки, которая происходит в фоновой нити. Получатели запросов об изменении ресурсов должны поддерживать работу с несколькими нитями. Вопросы поддержки нитей в пользовательском интерфейсе описаны в разделе Поддержка нитей.