Ниже приведен список действий, которые поставщики моделей могут выполнить для того, чтобы воспользоваться поддержкой коллективной работы с логической моделью:
В следующих разделах описан каждый из этих пунктов более подробно. Модуль org.eclipse.team.examples.filesystem содержит пример, иллюстрирующий несколько этих пунктов. Проект можно извлечь из хранилища CVS и при изучении этого материала пользоваться им как справочником. Оговорка: Исходный код модуля примера может измениться в любое время. Для получения копии, соответствующей этому примеру, следует выбрать проект по версии (3.2) (скорее всего, R3_2) или по дате: 28 июня 2006 г.
API преобразования ресурсов умышленно просто работает с логической моделью. Клиент не может использовать этот интерфейс для показа логических моделей или получения дополнительной информации о них. Его назначение состоит в простом преобразовании одного или нескольких элементов в ресурсы рабочей области.
API состоит из следующих классов:
Object getModelObject()
: Объект модели, из которого
порождено (или приспособлено) преобразование. ResourceTraversal[] getTraversals(ResourceMappingContext,
IProgressMonitor)
: Прохождение ресурсов, которые составляют объект
модели. ResourceTraversal
содержит набор ресурсов и флаг глубины, который указывает на глубину, на
которой ресурсы в прохождении связаны с исходящим объектом модели.
Прохождения ресурсов предоставлены клиенту с помощью преобразования
ресурсов с целью описать содержимое модели таким образом, чтобы клиент
(т.е. класс хранилища) мог выполнять свои операции наиболее эффективно.
Нам интересны следующие методы: getResources()
getDepth()
ResourceMappingContext
и
RemoteResourceMappingContext
немного более сложно и будет описано в разделе
Контекст преобразования ресурсов.Существует два типа модулей, которые относятся к преобразованиям ресурсов. Те, которые обеспечивают модель, состоящую из ресурсов в рабочей области или хранящуюся в них, и те, которые выполняют операции над ресурсами. Первый описан в следующем разделе, а второй в книге Схема хранилища для интеграции логической модели.
Модули, которые приспосабливают объекты своих моделей к
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
должен беспокоиться о предоставляемом
контексте для метода 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. Этот класс служит трем основным целям:
IResourceMappingMerger
для модели получается с помощью
приспособления поставщика модели. Ниже приведен пример определения расширения 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 поставщика модели для определения полного набора преобразований ресурсов, над которыми нужно произвести операцию, при ее выполнении над набором выбранных ресурсов или элементов модели.
Операции, которые выполняются над ресурсами, должны быть сначала проверены, чтобы убедиться в том, что пользователь знает обо всех потенциальных побочных эффектах. Ниже приведены шаги, требуемые для проверки изменения ресурса.
IResourceChangeDescriptionFactory
.
Фабрика создает IResourceDelta
, в котором отражено, как будет
выглядеть измененный результирующий ресурс после выполнения операции. ResourceChangeValidator
.
Агент проверки принимает во внимание всех поставщиков моделей,
зарегистрированных для затронутых ресурсов. В результате появляется одно
или несколько состояний, содержащих ИД исходной модели и описание
потенциальных побочных эффектов операции над моделью. Когда класс коллективной работы пытается совершить консольное слияние, он делает следующее:
Просмотр элементов модели в контексте операции коллективной работы возможно осуществить с помощью структуры Общего навигатора.
Указанные шаги позволят моделям появиться в окнах диалога, которые используются в операциях коллективной работы. Существуют дополнительные действия, требуемые для интеграции в предварительном просмотре слияния.
Следующие усовершенствования были внесены в область хронологии файла и хронологии элемента модели:
Для поддержки удаленного обзора было предоставлено следующее:
Классы коллективной работы могут оформить элементы модели, переделав их упрощенный оформитель для работы с преобразованиями ресурсов таким же образом, как дополнения объекта переделываются для работы с преобразованиями ресурсов. Однако, один аспект оформления элемента логической модели является проблематичным. Если элемент модели не имеет преобразования один-к-одному по отношению к ресурсу, то он не может получить обновление метки при соответствующем изменении ресурса.
Для решения этой проблемы был введен
ITeamStateProvider
,
чтобы предоставить поставщикам модели доступ к изменениям состояния,
которые могут повлиять на оформление. Кроме того, панели модели могут
использовать
SynchronizationStateTester
для определения того, когда необходимо изменение меток элементов
логической модели. Этот API зависит от интерфейса
ITeamStateProvider
при определении того, когда состояние
ресурса меняется и может быть передано оформителю как часть
IDecorationContext
.