Orientační plán modelu pro integraci logického modelu

Následuje přehled možností, v rámci nichž mohou poskytovatelé modulů využít podpory logických modelů týmu:

  1. Adaptovat prvky modelů v pohledech na ResourceMapping, aby se mohly operace na bázi prostředků objevit v prvcích modelů.
  2. Registrovat ModelProvider, aby byl model konzultován při provádění operací na prostředcích týkajících se vašeho modelu.
  3. Použít ResourceChangeValidator při provádění operací na prostředcích, aby byly případné vedlejší účinky na prvky modelů týkající se těchto prostředků dány uživateli na vědomí.
  4. Implementovat IResourceMappingMerger s cílem podílet se na sloučeních bez hlavičky zahrnujících prostředky týkající se vašeho modelu.
  5. Registrovat teamContentProvider s cílem podílet se na prohlížečích týmu, jako například náhledech sloučení.
  6. Poskytnout IHistoryPageSource pro zobrazení historie logického modelu v pohledu Týmová historie.
  7. Použít rozhraní API systému Eclipse File System pro přístup ke vzdálenému stavu modelových projektů.
  8. Použít rozhraní API SynchronizationStateTester pro zajištění správného zdobení prvků modelů, které nemají přímé mapování jeden na jednoho na prostředky.

Každý z těchto bodů je podrobněji popsán v následujících oddílech. Modul plug-in org.eclipse.team.examples.filesystem obsahuje příklad, který ilustruje několik těchto bodů. Při čtení tohoto návodu můžete přezkoušet projekt z úložiště CVS a použít jej jako odkaz. Bez záruky: Zdrojový kód v ukázkových modulech plug-in se může časem měnit. Chcete-li získat kód reflektující vše, co je použito v tomto příkladu, můžete si zapůjčit projekt za použití značky verze 3.2 (nejpravděpodobněji R3_2) nebo značky data 28. června 2006.

Mapování prostředků

Základní rozhraní API mapování prostředků

Rozhraní API mapování prostředků je záměrně jednoduché a jsou v něm vynechány manipulace s logickými modely. Toto rozhraní neumožňuje klientovi zobrazovat logické modely ani o nich získávat další zajímavé poznatky. Účelem tohoto rozhraní je pouze mapovat jeden nebo více prvků modelů na prostředky pracovního prostoru.

Rozhraní API se skládá z následujících tříd:

Existují dva typy modulů plug-in, které by měly být středem zájmu v mapování prostředků. Moduly poskytující model, který se skládá z nebo je obsažen v prostředcích v pracovním prostoru a moduly, které provádějí operace na prostředcích. První typ je popsán v následujícím oddílu, zatímco druhý typ je popsán v oddílu Orientační plán úložiště pro integraci logických modelů.

Přizpůsobení modelu na ResourceMapping

Moduly plug-in, které přizpůsobily své modelové objekty na IResource s cílem zobrazit akce specifické pro prostředky v kontextové nabídce mohou nyní adaptovat objekty na ResourceMapping, pokud je žádoucí bohatší popis adaptace objektu na prostředky. Není to ovšem nezbytně nutné, pokud by to nepředstavovalo žádoucí přínos. Například kompilační jednotka Java (tj. soubor *.java zobrazený v pohledu JDT), která se momentálně adaptuje na IFile se nemusí přizpůsobit na ResourceMapping, protože to s sebou nepřinese žádné výhody. Balíček Java by se nicméně měl přizpůsobit na ResourceMapping, aby indikoval, že se balíček skládá pouze ze souborů v příslušné složce, a nikoli v podsložkách.

Preferovaným způsobem adaptace prvků modelů na mapování prvků je použít továrnu na adaptéry. Následuje markup XML pro přidání továrny na adaptéry do manifestu modulu plug-in.

   <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>

Implementace továrny na adaptéry by vypadala nějak takto:

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};
}
}

Modelové objekty mohou implementovat rozhraní IAdaptable. Pokud se tak děje, musí být konzultován správce adaptéru platformy. To lze provést buď vytvořením podtřídy z PlatformObject, nebo pomocí následujícího řádku kódu:

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

Doporučuje se výše uvedený postup. Modelový objekt ovšem může implementovat rozhraní IAdaptable a poskytovat implementaci getAdapter(Class), která vytváří a vrací instanci ResourceMapping, pokud je explicitně vyžádána. Tento přístup je jasnější, ale nejméně žádoucí, protože model musí mít explicitní znalost adaptace na prostředky.

V některých případech nemusí poskytovatel logického modelu chtít, aby se model adaptoval na IResource v každém kontextu nebo může chtít, aby se objekt adaptoval jinak pro příspěvky objektů než pro ostatní kontexty. Uživatelské rozhraní pracovní plochy poskytuje pro tento účel speciální pomocné adaptační rozhraní API IContributorResourceAdapter. Při adaptaci objektů na IResource v kontextu příspěvků objektů se pracovní plocha nejprve pokouší adaptovat prostředek na IContributorResourceAdapter předtím, než se pokusí adaptovat přímo na IResource. Bylo přidáno nové podřízené rozhraní tohoto rozhraní, IContributorResourceAdapter2, které poskytuje stejnou schopnost pro ResourceMapping. Jediným rozdílem je, že poskytovatel modelů by měl registrovat továrnu pro IContributorResourceAdapter, jelikož Pracovní plocha provádí kontrolu instanceof pro zjištění, zda je přidaný adaptér rovněž instancí IContributorResourceAdapter2.

Implementace podtřídy ResourceMapping pro balíček Java by vypadala nějak takto.

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)
}
}
}

Jedná se o poměrně jasné mapování, proto není implementace příliš komplexní. Komplexnost implementace mapování prostředků se bude samozřejmě model od modelu různit.

Kontext mapování prostředků

Jednou z výhod rozhraní API mapování prostředků je, že umožňuje modulům plug-in implementovat libovolné operace co do mapování prostředků (např. aktualizace CVS, potvrzení CVS, značka CVS, nečisté zdobení apod.). Nicméně představené rozhraní API se zatím zabývá pouze lokálním stavem modelu. Při práci s modelem sdíleným mezi vývojáři se ocitnete v situaci, kdy se může vzdálený stav modelu (tzn. stav modelu, který jiný uživatel přihlásil do úložiště) lišit od stavu v pracovním prostoru. Pokud jste provedli aktualizaci CVS, budete pravděpodobně chtít, aby lokální stav modelu odpovídal vzdálenému stavu, i kdyby to znamenalo přidat nebo naopak odebrat některé soubory.

Toto neplatí pro některé logické modely. Například balíček java je kontejner navštěvovaný do hloubky jedna bez ohledu na vzdálený stav modelu. Poskytovatel úložiště tak může jednoduše stanovit, že odchozí odstranění by měla být zahrnuta při potvrzení nebo že příchozí přidání by měla být zahrnuta při aktualizaci. Prostředky tvořící logické modely se ovšem mohou v čase měnit. Například prostředky tvořící prvek modelu mohou záviset na obsahu souboru s manifestem (nebo jiném podobném mechanizmu). Aby mohlo mapování prostředku vrátit správný průchod, musí mít přístup ke vzdálenému obsahu souboru s manifestem (liší se od lokálního obsahu), aby mohlo zjistit, zda se vyskytují další prostředky, které je třeba zahrnout. Tyto dodatečné prostředky nemusí v pracovním prostoru existovat, ale poskytovatel úložiště by měl vědět, jak zajistit, aby tam byly při provádění vybrané akce.

Pro podporu těchto komplexnějších modelů může být RemoteResourceMappingContext přenesen na metodu ResourceMapping#getTraversals. Při poskytnutí kontextu jej může mapování použít k tomu, aby všechny nezbytné prostředky byly zahrnuty v průchodu. Pokud není kontext poskytován, mapování může předpokládat, že je předmětem zájmu pouze lokální stav.

Kdy by se mělo ResourceMapping zajímat o RemoteResourceMappingContext?

ResourceMapping se musí zajímat o kontext poskytovaný metodě getTraversals pouze v případech, kdy prostředky tvořící změnu modelu v čase a vztah mezi modelem a prostředky nelze popsat jednoduchým průchodem, který důsledně zahrnuje tyto (a pouze tyto) prostředky, které vytváří model. Přestože se například prostředky balíčku Java mohou měnit v čase, balíček lze popsat jako složku s hloubkou jedna, a tudíž mapování prostředků pro balíčky java nevyužije kontextu mapování prostředků.

Jako složitější příklad můžeme použít soubor HTML obsahující několik obrázků. Předpokládejme, že jakékoli odkazy na obrázky ze souboru HTML jsou součástí modelu daného souboru. Při aktualizaci lokálního obsahu souboru HTML z úložiště uživatel předpokládá, že případné nové obrázky budou zahrnuty. Metoda getTraversals pro ResourceMapping pro soubor HTML by vypadala nějak takto:

public class HTMLResourceMapping extends ResourceMapping {
private HTMLFile htmlFile;
public ResourceTraversal[] getTraversals(ResourceMappingContext context,
IProgressMonitor monitor)
IResource[] resources = htmlFile.getResources();
if (context instanceof RemoteResourceMappingContext) {
// Vyhledat případné další prostředky na serveru
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)};
}
}

Všimněte si, že v modelu jsou zahrnuty dvě sady prostředků: Prostředky odvozené z lokálního obsahu souboru HTML v pracovním prostoru a prostředky získané z obsahu vzdáleného a základního souboru. V obou těchto sadách mohou být prostředky, které neexistují v pracovním prostoru. Lokální soubor HTML může například obsahovat relativní odkaz na obrázek, který neexistuje v pracovním prostoru. Tento prostředek by měl být zahrnut, aby byl načten, pokud existuje vzdáleně. Vzdálený soubor může obsahovat novou kopii odkazující na další obrázky, které by měly být načteny při stažení nového vzdáleného obsahu.

Poskytovatelé modelů

Poskytovatelé modelů jsou prostředkem pro seskupování mapování souvisejících prostředků dohromady. Zde je odkaz na třídu ModelProvider. Tato třída plní tři hlavní funkce:

  1. Z poskytovatele modelů mohou klienti získávat další části rozhraní API pro provádění operací na souboru mapování prostředků pomocí adaptovatelných mechanizmů. Například IResourceMappingMerger pro určitý model je získáno adaptováním poskytovatele modelů.
  2. Při daném souboru prostředků systému souborů mohou klienti provádět dotazy, zda má poskytovatel modelů v těchto prostředcích obsaženy prvky modelů a pokud ano, mohou získat soubor mapování prostředků, který daný vztah popisuje.
  3. V případě operací na souboru prostředků bude validátor změn prostředků prostřednictvím dotazů na poskytovatele modelů zjišťovat případné vedlejší dopady operace, o kterých by měli uživatelé vědět. Bližší popis najdete v samostatném oddílu o ověřování změn.

Následuje příklad definice rozšíření 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 je podtřídou ModelProvider. Pravidlo zpřístupnění se používá pro porovnání prostředků, ve kterých uchovává svůj model Knihovna. Ve výše uvedeném příkladu porovná poskytovatel modelu jakýkoli prostředek v projektu, který má povahu knihovny.

Po definování poskytovatele modelů by měla být potlačena metoda ResourceMapping#getModelProviderId(), aby vrátila ID poskytovatele modelů.

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

Chcete-li získat správné inverzní mapování prostředků na mapování prostředků pro ty prostředky, které odpovídají pravidlu zpřístupnění vašeho modelu, měli byste rovněž potlačit jednu nebo obě metody getMapping. To, která metoda má být potlačena závisí na tom, zda má váš model prvky obsahující více prostředků či nikoli. Pokud se prvky modelu mapují na jediný prostředek, můžete potlačit metodu, která akceptuje jeden argument IResource. V opačném případě je třeba potlačit metodu, která akceptuje celou řadu prostředků. Zde je příklad případu s jediným prostředkem.

Následující vzorová metoda zabaluje model knihovny do odpovídajícího mapování prostředků. Zároveň zabaluje složky obsahující soubory, které jsou předmětem pozornosti poskytovatele modelů.

public class LibraryModelProvider extends ModelProvider {
public ResourceMapping[] getMappings(IResource resource,
ResourceMappingContext context, IProgressMonitor monitor) {
if (isModelFile(resource)) {
// Vrátit mapování prostředků na soubor
return new LibraryResourceMapping(resource);
} if (containsModelFiles(resource)) {
// Vytvořit hluboké mapování prostředků na kontejner
return new LibraryContainerResourceMapping(resource);
}
// Tento prostředek není pro poskytovatele modelu podstatný
return null;
}
}

Klienti mají poté přístup k poskytovatelům modelů a mohou zjistit, zda jim záleží na prostředcích, na kterých se budou provádět operace. Následující oddíl popisuje rozhraní API, jež bude poskytnuto týmovým operacím, které používají rozhraní API poskytovatele modelů pro zjištění úplného souboru mapování prostředků, na kterých se budou provádět operace při provádění týmových operací na souboru vybraných prostředků nebo prvků modelů.

Ověření změn prostředků

Operace prováděné na prostředcích by měly být nejprve ověřeny, aby bylo zajištěno, že si je uživatel vědom případných vedlejších účinků. Následují kroky nezbytné pro ověření změny prostředku.

  1. Sestavte popis změny pomocí IResourceChangeDescriptionFactory. Továrna vytváří IResourceDelta, která odráží podobu výsledných rozdílových dat prostředku po provedení operace.
  2. Ověřte platnost změny pomocí ResourceChangeValidator. Validátor konzultuje všechny poskytovatele modelů, kteří projevili zájem na ovlivněných prostředcích. Výsledkem je jeden nebo více stavů, které obsahují ID původního modelu a popis případných vedlejších účinků operace na model.
  3. Seznamte uživatele s případnými vedlejšími účinky z modelů, které nejsou původci operace známy. Pokud například opětovná deklarace Java zaznamenala vedlejší účinek z modelu Java, může být tento účinek ignorován, protože opětovná deklarace rozumí sémantice modelu Java. Pokud je ovšem zaznamenán vedlejší účinek z modelu Knihovna, měl by být tento účinek oznámen uživateli, protože Java nezná model Knihovna.

Slučování na bázi modelů

Při pokusu o sloučení bez hlavičky provádí týmový poskytovatel následující:

  1. Získává mapování prostředků z vybraných prvků.
  2. Určuje příslušné poskytovatele modelů pomocí metody ResourceMapping#getModelProvider().
  3. Rozšiřuje rozsah operace, aby zahrnoval všechna nezbytná mapování prostředků.
  4. Sestavuje popis stavu synchronizace mezi lokálním a vzdáleným. Tento popis je poskytován modelům prostřednictvím rozhraní API IMergeContext.
  5. Adaptuje poskytovatele modelů na IResourceMappingMerger.
  6. Vyvolává metodu validateMerge na každém sloučení, s uvedením v popisu synchronizace, aby se neobjevily podmínky zabraňující pokusu o sloučení.
  7. Deleguje provedení sloučení na sloučení modelů.
  8. Poskytovatelé modelů mohou delegovat provedení sloučení jednotlivých souborů zpět na týmového poskytovatele, pokud chtějí ovlivňovat pouze pořadí sloučení, nebo mohou provést sloučení sami a oznámit týmovému poskytovateli dokončení sloučení.

Obsah modelu v pohledech týmových operací

Prvky modelu lze zobrazit v kontextu týmové operace prostřednictvím rámce společného navigátoru Common Navigator.

Výše uvedené kroky umožní zobrazení modelů v dialogových oknech použitých týmovými operacemi. Pro integraci do náhledu sloučení jsou nezbytné další kroky.

Pohled Historie

V oblasti historie souborů a historie prvků modelů bylo dosaženo následujících zlepšení:

Vzdálené procházení

Pro podporu vzdáleného procházení je k dispozici následující:

Zdobení prvků modelů týmovým stavem

Týmoví poskytovatelé mohou zdobit prvky modelů převedením jejich odlehčených dekorátorů pro fungování s mapováním prostředků, podobně jako jsou takto převáděny příspěvky objektů. Jeden aspekt zdobení prvku logického modelu je ovšem problematický. Pokud prvek modelu nemá jedinečné mapování na prostředek, nemusí při změně základních prostředků obdržet aktualizaci štítku.

Ve snaze o vyřešení této záležitosti byl představen ITeamStateProvider, který umožňuje poskytovatelům modelů přístup ke změnám stavu, které mohou ovlivnit zdobení týmu. Kromě toho mohou pohledy modelů použít SynchronizationStateTester pro zjištění, kdy musí být štítky prvků logických modelů aktualizovány. Toto API závisí na rozhraní ITeamStateProvider při zjišťování, zda se týmový stav prostředku změnil a zda může být předán na týmový dekorátor jako součást IDecorationContext.