Схема модели для интеграции логической модели

Ниже приведен список действий, которые поставщики моделей могут выполнить для того, чтобы воспользоваться поддержкой коллективной работы с логической моделью:

  1. Приспособить элементы модели на панелях модели к ResourceMapping, для того чтобы позволить операциям на основе ресурса появляться в них.
  2. Зарегистрировать ModelProvider, для того чтобы модель учитывалась при выполнении операций над ресурсами, связанными с ней.
  3. Использовать ResourceChangeValidator при выполнении операций над ресурсами, для того чтобы все потенциальные побочные эффекты, влияющие на элементы модели, связанные с этими ресурсами, были известны пользователю.
  4. Реализовать IResourceMappingMerger для участия в консольных слияниях, в которые вовлечены ресурсы, связанные с моделью.
  5. Зарегистрировать teamContentProvider для участия в программах просмотра коллективной работы, таких как предварительный просмотр слияния.
  6. Предоставить IHistoryPageSource для показа хронологии логической модели на панели Хронология коллективной работы.
  7. Использовать API Файловая система Eclipse для доступа к удаленному состоянию проектов модели.
  8. Использовать API SynchronizationStateTester для обеспечения правильного оформления элементов модели, которые не имеют соответствия один-к-одному с ресурсами.

В следующих разделах описан каждый из этих пунктов более подробно. Модуль org.eclipse.team.examples.filesystem содержит пример, иллюстрирующий несколько этих пунктов. Проект можно извлечь из хранилища CVS и при изучении этого материала пользоваться им как справочником. Оговорка: Исходный код модуля примера может измениться в любое время. Для получения копии, соответствующей этому примеру, следует выбрать проект по версии (3.2) (скорее всего, R3_2) или по дате: 28 июня 2006 г.

Преобразования ресурсов

API основного преобразования ресурсов

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

API состоит из следующих классов:

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

Приспособление модели к ResourceMapping

Модули, которые приспосабливают объекты своих моделей к IResource, чтобы получить связанные с ресурсом действия, показанные в контекстном меню, теперь могут быть приспособлены к ResourceMapping, если может оказаться полезным иметь расширенное описание способа приспособления объектов к ресурсам. Однако, это не требуется, если в этом нет необходимости. Например, модуль компиляции Java (т.е. файл *.java, показанный на панели JDT), который в данный момент приспосабливается к IFile, не требует приспособления к ResourceMapping, потому что нечего получать. Однако, пакет Java должен быть приспособлен к ResourceMapping для индикации того, что пакет состоит только из файлов соответствующей папки, но не вложенных папок.

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

   <extension
point="org.eclipse.core.runtime.adapters">
<factory
class="org.eclipse.example.library.logical.AdapterFactory"
adaptableType="org.eclipse.example.library.Book">
<adapter type="org.eclipse.core.resources.mapping.ResourceMapping"/>
</factory>
<factory
class="org.eclipse.example.library.logical.AdapterFactory"
adaptableType="org.eclipse.example.library.Library">
<adapter type="org.eclipse.core.resources.mapping.ResourceMapping"/>
</factory>
...
</extension>

Реализация фабрики адаптера будет выглядеть подобно следующему:

public class AdapterFactory implements IAdapterFactory {
public Object getAdapter(Object adaptableObject, Class adapterType) {
if((adaptableObject instanceof EObject) && adapterType == ResourceMapping.class) {
return new EObjectResourceMapping((EObject)adaptableObject);
}
return null;
}

public Class[] getAdapterList() {
return new Class[] {ResourceMapping.class};
}
}

Элементы модели могут реализовать интерфейс IAdaptable. Когда они это делают, они должны обеспечить соответствие с администратором адаптера платформы. Это можно сделать, или создав подкласс PlatformObject, или используя следующую строку исходного кода:

Platform.getAdapterManager().getAdapter(Object, Class)

Приведенный выше подход является предпочтительным. Однако, объект модели может реализовать интерфейс IAdaptable и предоставить реализацию getAdapter(Class), которая явно создает возвраты как экземпляры ResourceMapping при их запросе. Это более прямой подход, но он менее желателен, потому что модель должна явно знать о приспособлении к ресурсам.

В некоторых случаях, поставщик логической модели может потребовать, чтобы его модель не приспосабливалась к IResource в каждом контексте, или чтобы объект приспосабливался разным способом для его дополнений и для других контекстов. Для этой цели пользовательский интерфейс рабочей среды предоставляет специальный API промежуточного адаптера IContributorResourceAdapter. Когда объекты приспосабливаются к IResource в контексте дополнений объекта, рабочая среда сначала пытается приспособить ресурс к IContributorResourceAdapter, а только потом непосредственно к IResource. Был добавлен новый промежуточный интерфейс IContributorResourceAdapter2, который предоставляет такую же возможность для ResourceMapping. Единственное различие состоит в том, что поставщик модели должен регистрировать фабрику для IContributorResourceAdapter, в то время как рабочая среда проверяет экземпляр, чтобы убедится в том, что дополненный адаптер также является экземпляром IContributorResourceAdapter2.

Реализация подкласса ResourceMapping для пакета Java будет выглядеть подобно следующей.

public class JavaPackageResourceMapping extends ResourceMapping {
IPackageFragment package;
...
public getModelObject() {
return package;
}
public ResourceTraversals[] getTraversals(
ResourceMappingContext context,
IProgressMonitor monitor) {
return new ResourceTraversal[] {
new ResourceTraversal(
new IResource[] { package.getCorrespondingResource() },
IResource.DEPTH_ONE, IResource.NONE)
}
}
}

Это прямое преобразование, поэтому реализация не сложна. Сложность реализации преобразования ресурса будет, конечно, изменяться от модели к модели.

Контекст преобразования ресурса

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

Это не является проблемой для некоторых логических моделей. Например, пакет java - контейнер, осматривающий глубину 1, независимо от удаленного состояния модели. При этом, класс хранилища может легко определить, что исходящие удаления должны быть включены при фиксации, или что входящие добавления должны быть включены при изменении. Однако, ресурсы, составляющие несколько логических моделей, могут со временем меняться. Например, ресурсы, составляющие элемент модели, могут зависеть от содержимого файла манифеста (или некоторого другого подобного механизма). Для того чтобы преобразование ресурса возвращало правильное прохождение, оно должно иметь доступ к удаленному содержимому файла манифеста (если оно отличается от локального содержимого), чтобы видеть, существуют ли дополнительные ресурсы, которые должны быть включены. Эти дополнительные ресурсы могут не существовать в рабочей области, но класс хранилища должен знать, как обеспечить, чтобы они там были, когда выполняется выбранное действие.

Для поддержки этих более сложных моделей RemoteResourceMappingContext может быть передан в метод ResourceMapping#getTraversals. Когда предоставляется контекст, преобразование может использовать его, чтобы все необходимые ресурсы были включены в прохождение. Если контекст не предоставлен, преобразование может считать, что интересно только локальное состояние.

Когда ResourceMapping должен беспокоиться о RemoteResourceMappingContext?

ResourceMapping должен беспокоиться о предоставляемом контексте для метода getTraversals в случаях, когда составляющие модель ресурсы меняются во времени, и взаимосвязи между моделью и ресурсами не могут быть описаны простым прохождением, которое гарантирует охват этих ресурсов (и только их), составляющих модель. Например, хотя ресурсы пакета Java могут меняться во времени, пакет может быть описан как папка глубины 1, так что преобразование ресурсов для пакетов java не требует использования контекста преобразования ресурсов.

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

public class HTMLResourceMapping extends ResourceMapping {
private HTMLFile htmlFile;
public ResourceTraversal[] getTraversals(ResourceMappingContext context,
IProgressMonitor monitor)
IResource[] resources = htmlFile.getResources();
if (context instanceof RemoteResourceMappingContext) {
// Поиск любых дополнительных ресурсов на сервере
RemoteResourceMappingContext remoteContext = (RemoteResourceMappingContext)context;
IFile file = htmlFile.getFile();
if (remoteContext.hasRemoteChange(file, monitor)) {
IStorage storage = remoteContext.fetchRemoteContents(file, monitor);
IResource[] additionalResources = getReferences(storage.getContents());
resources = combine(resources, additionalResources);
}
if (remoteContext.isThreeWay() && remoteContext.hasLocalChange(file, monitor)) {
IStorage storage = remoteContext.fetchBaseContents(file, monitor);
IResource[] additionalResources = getReferences(storage.getContents());
resources = combine(resources, additionalResources);
}
}
return new ResourceTraversal[] {
new ResourceTraversal(resources, IResource.DEPTH_ZERO, IResource.NONE)};
}
}

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

Провайдеры моделей

Провайдеры моделей - это средства группировки связанных преобразований ресурсов. Здесь приведена ссылка на класс ModelProvider. Этот класс служит трем основным целям:

  1. Из поставщика модели клиенты могут получать дополнительные части API для выполнения операций над набором преобразований ресурсов с помощью легко приспосабливаемого механизма. Например, IResourceMappingMerger для модели получается с помощью приспособления поставщика модели.
  2. Имея набор ресурсов файловой системы, клиенты могут запрашивать, имеет ли поставщик модели хранящиеся в этих ресурсах элементы модели, и если да, то получить набор преобразований ресурсов, которые описывают эту взаимосвязь.
  3. Для операций над набором ресурсов, агент проверки изменения ресурса будет посылать запрос поставщикам моделей, чтобы определить, существуют ли потенциальные побочные эффекты от операции, о которых должен знать пользователь. Это описано в отдельном разделе Проверка изменений.

Ниже приведен пример определения расширения modelProvider.

   <extension
id="modelProvider"
name="Library Example"
point="org.eclipse.core.resources.modelProviders">
<modelProvider
class="org.eclipse.team.examples.library.adapt.LibraryModelProvider"
name="Library Example"/>
<extends-model id="org.eclipse.core.resources.modelProvider"/>
<enablement> <test property="org.eclipse.core.resources.projectNature" value="org.eclipse.team.examples.library.view.nature" />
</enablement>
</extension>

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

После определения поставщика модели необходимо переопределить метод ResourceMapping#getModelProviderId(), чтобы он возвращал ИД поставщика модели.

   public String getModelProviderId() {
return "org.eclipse.team.examples.library.adapt.modelProvider";
}

Для получения обратного преобразования по отношению к преобразованию ресурсов, соответствующих правилу включения поставщика, необходимо также переопределить один или оба метода getMapping. Метод, который необходимо переопределить, зависит от того, имеет ли модель элементы, содержащие множественные ресурсы, или нет. Если элементы модели соответствуют одному ресурсу, вы можете переопределить метод с единственным аргументом IResource. В противном случае, необходимо переопределить метод, который принимает массив ресурсов. Ниже приведен пример, использующий одиночный ресурс.

Следующий пример метода заключает файл модели библиотеки в соответствующее преобразование ресурса. Он также заключает папки, содержащие файлы, относящиеся к поставщику модели.

public class LibraryModelProvider extends ModelProvider {
public ResourceMapping[] getMappings(IResource resource,
ResourceMappingContext context, IProgressMonitor monitor) {
if (isModelFile(resource)) {
// Возвращает преобразование ресурса в файл
return new LibraryResourceMapping(resource);
} if (containsModelFiles(resource)) {
// Создает глубокое преобразование ресурса в контейнере
return new LibraryContainerResourceMapping(resource);
}
// Ресурс не представляет интереса для этого поставщика модели
return null;
}
}

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

Проверка изменения ресурса

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

  1. Составьте описание изменения с помощью IResourceChangeDescriptionFactory. Фабрика создает IResourceDelta, в котором отражено, как будет выглядеть измененный результирующий ресурс после выполнения операции.
  2. Проверьте изменение с помощью ResourceChangeValidator. Агент проверки принимает во внимание всех поставщиков моделей, зарегистрированных для затронутых ресурсов. В результате появляется одно или несколько состояний, содержащих ИД исходной модели и описание потенциальных побочных эффектов операции над моделью.
  3. Известите пользователя обо всех потенциальных побочных эффектах, которые неизвестны инициатору операции. Например, если рефакторинг Java получил побочный эффект из модели Java, он может быть проигнорирован, потому что рефакторинг понимает семантику модели Java. Однако, если возвращен побочный эффект из модели Библиотека, о нем должно быть сообщено пользователю, потому что Java не знает модели Библиотека.

Слияние на основе модели

Когда класс коллективной работы пытается совершить консольное слияние, он делает следующее:

  1. Получает преобразования ресурсов из выбранных элементов.
  2. Определяет вовлеченных поставщиков моделей с помощью метода ResourceMapping#getModelProvider().
  3. Расширяет область действия операции, включая все необходимые преобразования ресурсов.
  4. Составляет описание состояния синхронизации между локальным и удаленным содержимым. Это описание предоставляется модели посредством API IMergeContext.
  5. Приспосабливает поставщиков моделей к IResourceMappingMerger.
  6. Вызывает метод validateMerge для всех участников слияния, передавая описание синхронизации, чтобы убедиться в том, что отсутствуют какие-либо условия, которые должны прервать попытку слияния.
  7. Перенаправляет слияние его участникам для выполнения.
  8. Поставщики моделей могут перенаправлять слияние отдельных файлов назад классу коллективной работы, если они должны только контролировать порядок слияния или сливаться сами, сообщая об этом поставщику коллективной работы.

Содержимое модели в программах просмотра операции при коллективной работе

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

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

Панель Хронология

Следующие усовершенствования были внесены в область хронологии файла и хронологии элемента модели:

Удаленный обзор

Для поддержки удаленного обзора было предоставлено следующее:

Оформление элементов модели с помощью состояния коллективной работы

Классы коллективной работы могут оформить элементы модели, переделав их упрощенный оформитель для работы с преобразованиями ресурсов таким же образом, как дополнения объекта переделываются для работы с преобразованиями ресурсов. Однако, один аспект оформления элемента логической модели является проблематичным. Если элемент модели не имеет преобразования один-к-одному по отношению к ресурсу, то он не может получить обновление метки при соответствующем изменении ресурса.

Для решения этой проблемы был введен ITeamStateProvider, чтобы предоставить поставщикам модели доступ к изменениям состояния, которые могут повлиять на оформление. Кроме того, панели модели могут использовать SynchronizationStateTester для определения того, когда необходимо изменение меток элементов логической модели. Этот API зависит от интерфейса ITeamStateProvider при определении того, когда состояние ресурса меняется и может быть передано оформителю как часть IDecorationContext.