Podpora synchronizace

V Eclipse 3.0 se nově objevují rozhraní API pro správu a zobrazování stavu synchronizace mezi prostředky pracovního prostoru a prostředky v jiném umístění. Prostředek umístěný mimo pracovní prostor označujeme jako variantu. Synchronizace spočívá v zobrazení změn mezi prostředky na různých umístěních a volitelně i v možnosti, aby uživatel ovlivnil stav synchronizace provedením určité akce. Rozhraní API pro synchronizaci jsou ortogonální vzhledem k rozhraním API RepositoryProvider a lze je používat nezávisle na poskytovateli úložiště. Účelem rozhraní API pro synchronizaci je usnadnit implementační úlohu různých možností prezentace stavu synchronizace prostředků. Rozhraní API jako takové vyžaduje nějaký způsob jak se dotazovat na stav synchronizace prostředků, ale již nevyžaduje způsob, jak tento stav ovlivňovat. Způsob ovlivňování stavu zůstává na implementátorovi (uživatelské rozhraní nicméně poskytuje záchytné body pro přidávání položek nabídky konkrétního poskytovatele).

Terminologie

Před vlastním popisem rozhraní API pro synchronizaci bude užitečné představit základní terminologii a koncepty týkající se synchronizace pracovního prostoru.

Varianta prostředku: Jako varianta prostředku se označuje lokální prostředek mapovaný na prostředek existující na jiném místě. To znamená, že prostředky jsou obvykle velmi podobné, ale mohou se mírně lišit (buďto z důvodu změn lokálního prostředku, nebo změn provedených na vzdálené kopii jinými uživateli). Budeme se zabývat touto záležitostí z pohledu pracovního prostoru. Na lokální kopii se budeme odkazovat jako na prostředek a na vzdálenou kopii jako na varianty prostředku.

Synchronizace: Synchronizace je zde akce, kdy se uživateli zobrazí rozdíly mezi variantami prostředku. Synchronizací se neovlivní stav variant, ale namísto toho se vytvoří pohled napomáhající uživateli pochopit rozdíly mezi různými sadami variant. Na druhé straně je však běžné dát uživatelům možnost stav variant při synchronizaci nějak ovlivnit (např. umožnit vrátit do úložiště, nebo vrátit do původního stavu).

Oboustranná vs. trojstranná synchronizace: Existují dva základní typy určení stavu synchronizace: oboustranně a trojstranně. Při oboustranném porovnání se pracuje pouze s lokálním prostředkem a jednou variantou prostředku, kterou označujeme jako variantu vzdáleného prostředku. Tento typ porovnání může zobrazovat pouze rozdíly mezi dvěma prostředky, ale již nemůže nabídnout žádné pokyny, jak tyto změny vzájemně souvisí. Většina systémů s úložišti podporuje trojstranné porovnání za účelem určení stavu synchronizace. Tento typ porovnání zahrnuje lokální prostředek, variantu vzdáleného prostředku a variantu základního prostředku. Varianta základního prostředku představuje společného předchůdce lokálního a vzdáleného prostředku. Díky tomu jsou možné i složitější stavy synchronizace, které indikují směr provedené změny.

Tabulka 1: Stavy synchronizace

Oboustranná Trojstranná
Změněno
Odstraněno
Přidáno
Odchozí změna
Příchozí změna
Odchozí odstranění
Příchozí odstranění
Odchozí přidání
Příchozí přidání
Konfliktní změna
Konfliktní odstranění
Konfliktní přidání

Základy - třída SyncInfo

Třídy obsažené v org.eclipse.team.core.synchronize se používají k popisu stavu synchronizace. Nejdůležitější třídou je SyncInfo, protože to je třída, která skutečně definuje stav synchronizace. Lze ji použít takto:

SyncInfo info = getSyncInfo(resource); // toto je simulovaná metoda získání synchronizační informace prostředku 
int changekind = info.getKind();
if(info.getResourceComparator().isThreeWay()) {
if((changeKind & SyncInfo.DIRECTION_MASK) == SyncInfo.INCOMING) {
// dělej něco
}
} else if(changeKind == SyncInfo.CHANGE) {
// dělej něco jiného
}

Třída SyncInfo poskytuje algoritmus oboustranného i trojstranného porovnání. Klient musí poskytnout prostředky a třídu, která může prostředky porovnat (IResourceVariantComparator). Zde je ukázkový komparátor variant:

public class TimestampVariantComparator implements IResourceVariantComparator {	
protected boolean compare(IResourceVariant e1, IResourceVariant e2) {
if(e1.isContainer()) {
if(e2.isContainer()) {
return true;
}
return false;
}
if(e1 instanceof MyResourceVariant && e2 instanceof MyResourceVariant) {
MyResourceVariant myE1 = (MyResourceVariant)e1;
MyResourceVariant myE2 = (MyResourceVariant)e2;
return myE1.getTimestamp().equals(myE2.getTimestamp());
}
return false;
}
protected boolean compare(IResource e1, IResourceVariant e2) {

}
public boolean isThreeWay() {
return true;
}
}

SyncInfo info = new SyncInfo(resource, variant1, variant2, new TimestampComparator());
info.init(); // vypočítat synchronizační informace

Tento balíček rovněž obsahuje kolekce výslovně navržené pro použití třídy SyncInfo a filtrů, které lze aplikovat na instance třídy SyncInfo.

Správa stavu synchronizace

Jak jsme viděli v příkladech výše, třídy SyncInfo a IResourceVariantComparator poskytují přístup ke stavu synchronizace prostředků. Dosud jsme si však neukázali, jak je tento stav řízen. Odběratel poskytuje přístup ke stavu synchronizace mezi prostředky v lokálním pracovním prostoru a sadou variant pro tyto prostředky za použití buďto oboustranného, nebo trojstranného porovnání, a to v závislosti na charakteru odběratele. Odběratel nabízí následující možnosti:

Rozhraní API nedefinují, jak je odběratel vytvořen. Toto je ponecháno na konkrétní implementaci. Například modul plug-in CVS vytváří odběratele při slučování, dalšího pro porovnání a dalšího při synchronizaci lokálního pracovního prostoru s aktuální větví.

Nyní se znovu podívejme na náš první příklad použití třídy SyncInfo zaměříme se na to, jak využít odběratele pro přístup k této třídě.

// Vytvořit odběratele systému souborů a určit,
// že odběratel se bude synchronizovat s poskytnutým umístěním systému souborů
Subscriber subscriber = new FileSystemSubscriber("c:\temp\repo");

// Umožnit odběrateli aktualizovat svůj stav
subscriber.refresh(subscriber.roots(), IResource.DEPTH_INFINITE, monitor);

// Shromáždit veškeré stavy synchronizace a vypsat
IResource[] children = subscriber.roots();
for(int i=0; i < children.length; i++) {
printSyncState(children[i]);
}

...

void printSyncState(Subscriber subscriber, IResource resource) {
System.out.println(subscriber.getSyncInfo(resource).toString());
IResource[] children = subscriber.members(resource);
for(int i=0; i < children.length; i++) {
IResource child = children[i];
if(! child.exists()) {
System.out.println(resource.getFullPath() + " v pracovním prostoru neexistuje");
}
printSyncState(subscriber, children[i]);
}
}

Je důležité si zapamatovat, že odběratel ví o prostředcích, které v pracovním prostoru neexistují, přičemž neexistující prostředky lze vrátit prostřednictvím metod Subscriber#members() a SyncInfo#getLocal().

Zobrazení stavu synchronizace v uživatelském rozhraní

Mohli bychom se věnovat hlouběji vysvětlování, jak řídit stav synchronizace, ale namísto toho se podívejme jak zajistit, aby se stav zobrazil uživateli. ISynchronizeParticipant představuje komponentu uživatelského rozhraní, jenž zobrazuje stav synchronizace a umožňuje uživateli tento stav ovlivňovat. Pohled Synchronizace zobrazuje účastníky synchronizace, nicméně je možné tyto zobrazovat i v dialogových oknech a průvodcích. Účastník představuje velmi generickou komponentu v případě, když chcete poskytnout podporu uživatelům pro zobrazení všech typů synchronizačních stavů, i těch, které nejsou založeny na SyncInfo a Subscribers.

K dispozici je i bod rozšíření s názvem org.eclipse.team.ui.synchronizeWizards umožňující přidat průvodce vytvořením synchronizace. Tento vloží váš průvodce do globální akce Synchronizovat a do pohledu Synchronizace tak, aby uživatelé mohli snadno vytvářet synchronizaci vašeho typu.

Pokud jste však implementovali odběratele, můžete s výhodou využít konkrétního účastníka s názvem SubscriberParticipant , který poskytuje následující funkčnost:

Tyto koncepty se nejlépe vysvětlí v kontextu jednoduchého příkladu. Přejděte na příklad synchronizace lokální historie, kde uvidíte, jak lze tyto jednotlivé kousky použít společně. Chcete-li pomoci s tím, jak použít pokročilejší rozhraní API, přejděte na Kudy dál.