Poniżej przedstawiono listę informującą, w jaki sposób dostawcy modeli mogą skorzystać z obsługi zespołowej modeli logicznych:
W poniższych sekcjach opisano każdy z powyższych punktów nieco bardziej szczegółowo. Wtyczka org.eclipse.team.examples.filesystem zawiera przykład, który odnosi się do kilku z powyższych punktów. Odpowiedni projekt można pobrać z repozytorium CVS i używać jako odwołania podczas lektury tego kursu. Zastrzeżenie: kod źródłowy w przykładowej wtyczce może się zmieniać. Aby uzyskać kopię zgodną z tym przykładem, można pobrać projekt ze znacznikiem wersji 3.2 (najprawdopodobniej R3_2) lub znacznikiem daty 28 czerwca 2006 r.
Interfejs API odwzorowywania zasobów jest z założenia uproszczony i pomija manipulacje modelami logicznymi. W kliencie nie można użyć tego interfejsu do wyświetlania modeli logicznych ani uzyskiwać żadnych dodatkowych informacji na ich temat. Jego celem jest po prostu odwzorowanie jednego lub większej liczby elementów modeli na zasoby obszaru roboczego.
Interfejs API składa się z następujących klas:
Object getModelObject()
: obiekt modelu, z którego pochodzi odwzorowanie (lub z którego zostało dopasowane).ResourceTraversal[]
getTraversals(ResourceMappingContext, IProgressMonitor)
: ścieżka przejścia po zasobach, która obejmuje zasoby składające się na obiekt modelu.ResourceTraversal
zawiera zbiór zasobów oraz flagę głębokości, która wskazuje głębokość, do której zasoby w ścieżce przejścia są powiązane ze źródłowym obiektem modelu. Ścieżki przejścia po zasobach są udostępniane klientom za pośrednictwem odwzorowywania zasobów, co umożliwia opisanie treści modelu w taki sposób, aby klient (np. dostawca repozytorium) mógł wykonywać działania w jak najbardziej efektywny sposób. Interesujące metody to:
getResources()
getDepth()
ResourceMappingContext
i RemoteResourceMappingContext
jest nieco bardziej skomplikowane i zostało opisane w sekcji Kontekst odwzorowania zasobu.Istnieją dwa typy wtyczek, które mogą być interesujące z punktu widzenia odwzorowań zasobów. Są to takie wtyczki, które udostępniają model składający się z zasobów obszaru roboczego lub w nich utrwalony, a także takie, które mają wykonywać operacje na zasobach. Pierwszy z nich jest opisany w następnej sekcji, zaś drugi w sekcji Przewodnik przejścia po integracji modeli logicznych dotyczący repozytoriów.
Wtyczki, które dopasowały swoje obiekty modeli do interfejsu IResource
w celu wyświetlenia akcji specyficznych dla zasobu w menu kontekstowym, mogą obecnie dopasowywać się do klasy ResourceMapping
, jeśli niezbędny jest szerszy opis tego, jak obiekty dopasowują się do zasobów. Nie jest to jednak konieczne, jeśli nie przynosi żadnych korzyści. Na przykład jednostka kompilacji Java (tzn. plik *.java widoczny w widoku JDT), która obecnie dopasowuje się do interfejsu IFile
, nie musi dopasowywać się do klasy
ResourceMapping
, ponieważ nie przynosi to żadnych korzyści. Jednak pakiet Java powinien dopasowywać się do klasy ResourceMapping
w celu wskazania, że pakiet składa się tylko z plików w odpowiednim folderze, a nie w folderach podrzędnych.
Preferowanym sposobem dopasowywania elementów modeli do odwzorowania zasobów jest wykorzystanie fabryki adapterów. Poniżej przedstawiono kod XML wnoszący fabrykę adapterów w manifeście wtyczki.
<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>
Implementacja fabryki adapterów może wyglądać w następujący sposób:
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};
}
}
Obiekty modeli mogą implementować interfejs IAdaptable
. Jeśli go implementują, należy zagwarantować sprawdzenie z menedżerem adapterów platformy. Można to zrobić, tworząc klasę pochodną klasy PlatformObject
lub korzystając z następującego kodu:
Platform.getAdapterManager().getAdapter(Object, Class)
Preferowaną metodą jest ta przedstawiona powyżej. Obiekt modelu może jednak implementować interfejs IAdaptable i dostarczyć implementację metodygetAdapter(Class)
,
która zwraca instancję klasy ResourceMapping
przy jawnym żądaniu. Jest to metoda bardziej bezpośrednia, ale najmniej polecana, ponieważ model musi mieć jawne informacje o dopasowaniu do zasobów.
W niektórych przypadkach dostawca modelu logicznego może nie chcieć, aby model był dopasowywany do interfejsu IResource
we wszystkich kontekstach lub może chcieć, aby obiekt był dopasowywany inaczej w przypadku obiektów wnoszonych przez kontrybutora niż w przypadku innych kontekstów. Interfejs użytkownika środowiska roboczego udostępnia w tym celu specjalny pośredni interfejs API adaptera
IContributorResourceAdapter
. Kiedy obiekty są dopasowywane do interfejsu
IResource
w kontekście obiektów wnoszonych przez kontrybutora, środowisko robocze najpierw próbuje dopasować zasób do adapteraIContributorResourceAdapter
, a dopiero potem bezpośrednio do interfejsu
IResource
. Został też dodany nowy interfejs podrzędny tego interfejsu,
IContributorResourceAdapter2
, który daje takie same możliwości w przypadku klasy
ResourceMapping
.
Jedyna różnica polega na tym, że dostawca modelu powinien zarejestrować fabrykę dla interfejsu
IContributorResourceAdapter
, ponieważ środowisko robocze wykonuje sprawdzenie instanceof, aby określić, czy wnoszony adapter jest też instancją interfejsu IContributorResourceAdapter2
.
Implementacja podklasy ResourceMapping
dla pakietu Java może wyglądać następująco.
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)
}
}
}
Jest to w miarę bezpośrednie odwzorowanie, więc jego implementacja nie jest zbyt złożona. Złożoność implementacji odwzorowania zasobów będzie oczywiście różna dla różnych modeli.
Jedną z zalet korzystania z interfejsu API do odwzorowywania zasobów jest fakt, że umożliwia on implementowanie we wtyczkach dowolnych działań w zakresie odwzorowywania zasobów (np. aktualizacja CVS, zatwierdzanie CVS, znakowanie CVS, dekoracje ze zmianami itp.). Wprowadzony interfejs API obejmuje dotychczas jedynie lokalny stan modelu. Podczas pracy z modelem, który może być współużytkowany przez różnych programistów, występuje więc sytuacja, w której zdalny stan modelu (czyli stan modelu, jaki inny użytkownik zwrócił do repozytorium) może być inny, niż stan w obszarze roboczym. Jeśli wykonano aktualizację CVS, lokalny stan modelu powinien być zgodny ze stanem zdalnym, nawet jeśli oznacza to, że muszą być dodane lub usunięte jakieś pliki.
Nie stanowi to problemu w przypadku niektórych modeli logicznych. Na przykład pakiet Java jest kontenerem odwiedzanym do głębokości równej jeden, niezależnie od zdalnego stanu modelu. Z tego powodu dostawca repozytorium może w łatwy sposób określić, że usunięcia wychodzące powinny być uwzględnione przy zatwierdzaniu, zaś przychodzące elementy dodane powinny być uwzględnione przy aktualizacji. Zasoby, z których składają się niektóre modele logiczne, mogą jednak zmieniać się w czasie. Na przykład zasoby, z których składa się element modelu, mogą być zależne od pliku manifestu (lub podobnego mechanizmu). Aby odwzorowanie zasobów zwracało prawidłową ścieżkę przejścia, musi mieć dostęp do zdalnej treści pliku manifestu (jeśli jest ona różna od treści lokalnej), aby uzyskać informacje na temat tego, czy istnieją dodatkowe zasoby, które należy uwzględnić. Te dodatkowe zasoby mogą nie istnieć w obszarze roboczym, ale dostawca repozytorium powinien wiedzieć jak upewnić się, że istniały podczas wykonywania wybranej akcji.
Aby obsługiwać takie bardziej złożone modele, można przekazać klasę
RemoteResourceMappingContext
do metody ResourceMapping#getTraversals
.
Jeśli udostępniony jest kontekst, odwzorowanie może z niego skorzystać, aby zagwarantować, że wszystkie niezbędne zasoby są uwzględnione w ścieżce przejścia. Jeśli nie udostępniono kontekstu, odwzorowanie może założyć, że interesuje je tylko stan lokalny.
ResourceMapping
musi mieć informacje o kontekście dostarczonym do metody
getTraversals
w przypadkach, w których zasoby, z których składa się model, zmieniają się w czasie, a relacja między modelem i zasobami nie może być opisana prostą ścieżką przejścia, która gwarantuje obejmowanie tych zasobów (i tylko tych), z których składa się model. Na przykład, chociaż zasoby pakietu Java mogą zmieniać się w czasie, pakiet można opisać jako folder z głębokością równą jeden, tak więc odwzorowanie zasobów dla pakietów Java nie musi korzystać z kontekstu odwzorowania zasobów.
Jako bardziej złożony przykład weźmy pod uwagę plik HTML, który zawiera kilka obrazków. Załóżmy, że wszelkie obrazki, do których występują odwołania w pliku HTML, są częścią modelu tego pliku. Użytkownik może oczekiwać, że przy aktualizowaniu treści lokalnej pliku HTML z repozytorium będą dołączone wszelkie nowe obrazki. Metoda getTraversals
dla klasy ResourceMapping
w modelu pliku HTML może wyglądać następująco:
public class HTMLResourceMapping extends ResourceMapping {
private HTMLFile htmlFile;
public ResourceTraversal[] getTraversals(ResourceMappingContext context,
IProgressMonitor monitor)
IResource[] resources = htmlFile.getResources();
if (context instanceof RemoteResourceMappingContext) {
// Look for any additional resources on the server
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)};
}
}
Należy zauważyć, że w modelu uwzględnione są dwa zbiory zasobów: te, które uzyskano z lokalnej treści pliku HTML w obszarze roboczym, oraz te uzyskane z treści pliku zdalnego oraz pliku bazowego. W obu przypadkach mogą istnieć zasoby, których nie ma w obszarze roboczym. Na przykład lokalny plik HTML może zawierać względny odsyłacz do obrazka, który nie istnieje w obszarze roboczym. Ten zasób powinien zostać uwzględniony, tak aby był pobierany w przypadku, gdy istnieje zdalnie. Jeśli chodzi o plik zdalny, może on zawierać nową kopię, która odwołuje się do dodatkowych obrazków, które należy pobrać przy pobieraniu treści zdalnej.
Dostawcy modeli to sposób na grupowanie pokrewnych odwzorowań zasobów. Oto odsyłacz do klasy ModelProvider. Klasa ta spełnia trzy główne funkcje:
IResourceMappingMerger
dla modelu można uzyskać, dopasowując dostawcę modelu.Poniżej przedstawiono przykład definicji rozszerzenia modelProvider.
<extension
id="modelProvider"
name="Przykład biblioteki"
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>
Klasa LibraryModelProvider
jest podklasą klasy ModelProvider
.
Aby uzgodnić zasoby, w których model biblioteki utrwala swój model, używana jest reguła włączania. W powyższym przykładzie dostawca modelu uzgodni dowolny zasób w projekcie, który ma naturę biblioteki.
Po zdefiniowaniu dostawcy modelu metoda ResourceMapping#getModelProviderId()
powinna zostać przesłonięta, aby uzyskać identyfikator dostawcy modelu.
public String getModelProviderId() {
return "org.eclipse.team.examples.library.adapt.modelProvider";
}
Aby uzyskać prawidłowe odwrotne odwzorowanie zasobów na odwzorowanie zasobów dla tych zasobów, które są zgodne z regułą włączania dostawcy, należy dodatkowo przesłonić jedną lub obie
metody getMapping
. Metoda, którą należy przesłonić, zależy od tego, czy model ma elementy zawierające wiele zasobów, czy też nie. Jeśli elementy modelu odwzorowują na pojedynczy zasób, można przesłonić metodę, która przyjmuje pojedynczy argument interfejsu IResource
. W przeciwnym razie należy przsłonić metodę, która przyjmuje tablicę zasobów. Poniżej przedstawiono przykład wykorzystania przy pojedynczym zasobie.
Poniższa metoda przykładowa opakowuje plik modelu biblioteki w odpowiednie odwzorowanie zasobów. Opakowuje też foldery, które zawierają pliki interesujące z punktu widzenia dostawcy modelu.
public class LibraryModelProvider extends ModelProvider {
public ResourceMapping[] getMappings(IResource resource,
ResourceMappingContext context, IProgressMonitor monitor) {
if (isModelFile(resource)) {
// Zwróć odwzorowanie zasobów pliku
return new LibraryResourceMapping(resource);
} if (containsModelFiles(resource)) {
// Utwórz głębokie odwzorowanie zasobu w kontenerze
return new LibraryContainerResourceMapping(resource);
}
// Zasób nie jest interesujący z punktu widzenia tego dostawcy modelu
return null;
}
}
Klienty mogą następnie uzyskać dostęp do dostawcy modelu, aby określić, czy dostawcę modelu interesują zasoby, na których mają być wykonane działania. W następnej sekcji opisano interfejs API, który będzie udostępniony do działań zespołowych wykorzystujących interfejs API dostawcy modelu, aby określić cały zbiór odwzorowań zasobów, na których mają być wykonywane działania w sytuacji, gdy wykonywane jest działanie zespołowe na zbiorze wybranych zasobów lub elementów modelu.
Przed wykonaniem działań na zasobach należy sprawdzić poprawność tych działań, aby upewnić się, że użytkownik jest świadom potencjalnych efektów ubocznych. Poniżej przedstawiono działania niezbędne do sprawdzenia poprawności zmiany zasobu.
IResourceChangeDescriptionFactory
.
Fabryka produkuje klasę IResourceDelta
, który odzwierciedla wynikowy wygląd zmiany zasobu po wykonaniu działania.ResourceChangeValidator
.
Analizator poprawności uzyskuje informacje od wszystkich dostawców modeli, które zarejestrowały się jako zainteresowane odpowiednimi zasobami. Wynikiem jest jeden lub więcej statusów, które zawierają identyfikator modelu źródłowego oraz opis potencjalnych efektów ubocznych działania na tym modelu.Kiedy dostawca zespołu usiłuje wykonać scalenie beznagłówkowe, wykonuje następujące czynności:
Wyświetlanie elementów modeli w kontekście operacji zespołowej jest możliwe dzięki środowisku wspólnego nawigatora.
Powyższe czynności umożliwią wyświetlanie modeli w oknach dialogowych wykorzystywanych w operacjach zespołowych. Aby zintegrować je w podglądzie scalenia, niezbędne jest wykonanie dodatkowych czynności.
W zakresie historii plików i elementu modelu wprowadzono następujące udoskonalenia:
Udostępniono następujące elementy obsługi zdalnego przeglądania:
Dostawcy zespołu mogą dekorować elementy modelu, przekształcając ich proste dekoracje tak, aby działały dla odwzorowań zasobów, w ten sam sposób jak obiekty wnoszone przez kontrybutora są przekształcane, aby mogły działać z odwzorowaniami zasobów. Jest jednak pewien aspekt dekoracji elementów modelu logicznego, który sprawia problemy. Jeśli element modelu nie jest w relacji "jeden do jednego" z zasobem, element modelu może nie uzyskać aktualizacji etykiety, gdy zmienią się zasoby stanowiące jego podstawę.
Aby rozwiązać ten problem, wprowadzono interfejs ITeamStateProvider
, umożliwiający dostawcom modeli dostęp do zmian stanu, które mogą mieć wpływ na dekoracje zespołu. Dodatkowo widoki modeli mogą wykorzystywać klasę
SynchronizationStateTester
, aby określić, kiedy trzeba zaktualizować etykiety elementów modelu logicznego. Ten interfejs API opiera się na interfejsie ITeamStateProvider
i umożliwia określenie, kiedy stan zespołu danego zasobu został zmieniony, a także może być przekazywany do dekoracji zespołu jako część kontekstu IDecorationContext
.