Przewodnik przejścia po integracji modeli logicznych dotyczący modeli

Poniżej przedstawiono listę informującą, w jaki sposób dostawcy modeli mogą skorzystać z obsługi zespołowej modeli logicznych:

  1. Dopasowywanie elementów modeli w widokach modeli do klasy ResourceMapping w celu umożliwienia wyświetlania działań opartych na zasobach w elementach modeli.
  2. Rejestrowanie klasy ModelProvider, aby zagwarantować, że wykonywane jest sprawdzenie z modelem przy wykonywaniu operacji na zasobach związanych z modelem.
  3. Wykorzystanie klasy ResourceChangeValidator przy wykonywaniu działań na zasobach, aby zagwarantować że wszelkie potencjalne efekty uboczne dotyczące elementów modeli powiązanych z tymi zasobami są znane użytkownikowi.
  4. Zaimplementowanie interfejsu IResourceMappingMerger w celu udziału w scaleniach beznagłówkowych, które obejmują zasoby powiązane z modelem.
  5. Rejestrowanie metody teamContentProvider w celu udziału w przeglądarkach zespołowych, na przykład podglądach scalenia.
  6. Udostępnienie interfejsu IHistoryPageSource, aby wyświetlić historię modelu logicznego w widoku Historia zespołu.
  7. Używanie interfejsu API systemu plików Eclipse w celu uzyskania dostępu do zdalnego stanu projektów modeli.
  8. Użycie interfejsu API SynchronizationStateTester w celu zagwarantowania poprawnej dekoracji elementów modeli, które nie są w relacji "jeden do jednego" z zasobami.

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.

Odwzorowania zasobów

Podstawowy interfejs API odwzorowywania zasobów

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:

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.

Dopasowywanie modelu do klasy ResourceMapping

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.

Kontekst odwzorowania zasobów

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.

W jakich sytuacjach ResourceMapping musi mieć informacje o kontekście RemoteResourceMappingContext?

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

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:

  1. Od dostawcy modelu klienty mogą otrzymywać dodatkowe fragmenty interfejsu API, aby móc wykonywać działania na zbiorze odwzorowań zasobów przy użyciu dopasowywalnego mechanizmu. Na przykład interfejs IResourceMappingMerger dla modelu można uzyskać, dopasowując dostawcę modelu.
  2. Mając zbiór zasobów systemu plików, klienty mogą zadawać zapytania, aby dowiedzieć się, czy dostawca modelu ma elementy modelu ustalone w tych zasobach, a jeśli ma, uzyskać zbiór odwzorowań zasobów, które opisują relację.
  3. W przypadku działań na zbiorach zasobów analizator poprawności zmian zasobów zada dostawcom modeli zapytanie, aby określić, czy mogą wystąpić efekty uboczne operacji, o których powinni wiedzieć użytkownicy. Ten mechanizm opisano w oddzielnej sekcji dotyczącej sprawdzania poprawności zmian.

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.

Sprawdzenie poprawności zmiany zasobów

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.

  1. Zbuduj opis zmiany przy użyciu interfejsu IResourceChangeDescriptionFactory. Fabryka produkuje klasę IResourceDelta, który odzwierciedla wynikowy wygląd zmiany zasobu po wykonaniu działania.
  2. Sprawdź poprawność zmiany przy użyciu klasy 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.
  3. Uświadom użytkownika o potencjalnych efektach ubocznych pochodzących z modeli, które nie są znane dla źródła operacji. Jeśli na przykład refaktoryzacja Java podlega efektom ubocznym modelu Java, można tę sytuację zignorować, ponieważ refaktoryzacja rozumie semantykę modelu Java. Jeśli jednak zostanie zwrócony efekt uboczny z modelu biblioteki, użytkownik powinien zostać o tym powiadomiony, ponieważ Java nie zna modelu biblioteki.

Scalanie oparte na modelach

Kiedy dostawca zespołu usiłuje wykonać scalenie beznagłówkowe, wykonuje następujące czynności:

  1. Uzyskuje odwzorowania zasobów z wybranych elementów.
  2. Określa zaangażowanych w proces dostawców modelu przy użyciu metody ResourceMapping#getModelProvider().
  3. Rozszerza zakres operacji, aby objąć wszystkie niezbędne odwzorowania zasobów.
  4. Buduje opis stanu synchronizacji elementów lokalnych i zdalnych. Ten opis jest udostępniany modelom przez interfejs API IMergeContext.
  5. Dopasowuje dostawców modeli do interfejsu IResourceMappingMerger.
  6. Uruchamia metodę validateMerge przy każdym scaleniu, przekazując opis synchronizacji, aby upewnić się, że nie istnieją warunki uniemożliwiające scalenie.
  7. Deleguje scalenie do scaleń modeli, aby móc je wykonać.
  8. Dostawcy modeli mogą delegować scalenie poszczególnych plików z powrotem do dostawcy zespołu, jeśli chcą tylko sterować kolejnością scalenia. Mogą też same wykonać scalenie i przekazać dostawcy zespołu stosowny komunikat, kiedy zostanie ono zakończone.

Treść modeli w widokach operacji zespołowych

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.

Widok Historia

W zakresie historii plików i elementu modelu wprowadzono następujące udoskonalenia:

Zdalne przeglądanie

Udostępniono następujące elementy obsługi zdalnego przeglądania:

Dekorowanie elementów modelu przy użyciu stanu zespołu

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.