Paikallisten historiatietojen esimerkki

Synkronoinnin ohjelmointirajapintojen toiminnasta saa parhaiten käsityksen luomalla yksinkertaisen, toimivan esimerkin. Tässä esimerkissä luodaan synkronointinäkymään sivu, joka näyttää työtilan kaikkien tiedostojen uusimmat paikalliset historiatiedot. Paikallisten historiatietojen synkronointi päivittyy automaattisesti, kun työtilaan tehdään muutoksia. Vertailun muokkausohjelma voi sitten avautua muutosten selausta ja yhdistämistä varten. Synkronointiin lisätään myös mukautettu koristelutoiminto, joka näyttää paikallisten historiatietojen elementin uusimman aikaleiman, sekä toiminto, joka palauttaa työtilan tiedostot edellisten tallennettujen historiatietojen mukaisiksi. Tämä on erinomainen esimerkki, sillä käytettävissä on jo resurssimuunnosten varasto, jota ei tarvitse hallita.

Tässä kuvauksessa käytetään ajettavaa esimerkkiä. Lähdekoodista suurin osa on tällä sivulla. Koko lähdekoodi on lisäosan org.eclipse.team.examples.filesystem paikallisten historiatietojen paketissa. Voit kuitata projektin ulos CVS-tietovarastosta ja käyttää sitä viitteenä, kun luet tätä opetusohjelmaa. Vastuunrajoituslauseke: Esimerkkilisäosien lähdekoodi saattaa muuttua ajan myötä. Jos haluat saada tässä esimerkissä käytettyä koodia vastaavan version, voit kuitata projektin ulos käyttämällä version 3.0 tunnistetta (luultavasti R3_0) tai päivämäärän 28. kesäkuuta 2004 tunnistetta.

paikallisten historiatietojen yleiskuva

Tässä kuvakaappauksessa näkyy paikallisten historiatietojen synkronointi synkronointinäkymässä. Sen avulla voit selata paikallisen resurssin ja historiatietojen uusimman tilan välisiä muutoksia. Siinä on mukautettu koristelutoiminto, jonka avulla voit näyttää paikallisten historiatietojen merkintään liittyvän aikaleiman, sekä mukautettu toiminto, jonka avulla voit palauttaa tiedoston vastaamaan paikallisten historiatietojen sisältöä. Huomaa myös, että käytössä on tavallinen synkronointinäkymän esitys, jossa voi käyttää ongelmia koskevia huomautuksia, tiivistettyjä kansioasetteluja sekä siirtymispainikkeita.

Muunnosten määritys paikallisiin historiatietoihin

Aluksi tulee määrittää muunnos, joka vastaa paikallisten historiatietojen elementtejä. Tällöin synkronoinnin ohjelmointirajapinnat voivat käsitellä paikallisten historiatietojen sisältöä, niin että tietoja voi verrata nykyiseen sisältöön ja tiedot voi tuoda käyttäjän näkyville.

public class LocalHistoryVariant implements IResourceVariant {
private final IFileState state;

public LocalHistoryVariant(IFileState state) {
this.state = state;
}

public String getName() {
return state.getName();
}

public boolean isContainer() {
return false;
}

public IStorage getStorage(IProgressMonitor monitor) throws TeamException {
return state;
}

public String getContentIdentifier() {
return Long.toString(state.getModificationTime());
}

public byte[] asBytes() {
return null;
}
}

IFileState-liittymä mahdollistaa jo tiedoston sisällön käsittelyn paikallisista historiatiedoista (eli käyttää IStorage-liittymää), joten tämä vaihe oli helppo. Muunnosta luotaessa on yleensä määritettävä sisällön käsittelytapa, sisältötunnistin, jonka avulla käyttäjä voi tunnistaa muunnoksen, sekä muunnoksen nimi. Metodia asBytes() tarvitaan vain, jos muunnos säilytetään istuntojen välillä.

Seuraavaksi luodaan vertailutoiminnon muunnos, joka sallii SyncInfo-laskutoimituksen verrata paikallisia resursseja niiden muunnoksiin. Tämäkin on helppoa, sillä paikallisten historiatietojen olemassaolo merkitsee sitä, että paikallisten historiatietojen sisältö eroaa tiedoston nykyisestä sisällöstä. Paikallisten historiatietojen määrityksessä nimittäin ilmoitetaan, että paikalliset historiatiedot luodaan vain, jos tiedosto on muuttunut.

public class LocalHistoryVariantComparator implements IResourceVariantComparator {
public boolean compare(IResource local, IResourceVariant remote) {
return false;
}

public boolean compare(IResourceVariant base, IResourceVariant remote) {
return false;
}

public boolean isThreeWay() {
return false;
}
}

Paikallisten historiatietojen olemassaolo merkitsee historiatietojen poikkeavan paikallisista tiedoista, joten metodi voi palauttaa arvon false, kun tiedostoa verrataan sen paikallisiin historiatietoihin. Lisäksi synkronointi paikallisten historiatietojen kanssa on vain kaksisuuntaista, koska perusresurssia ei voi käsitellä. Näin ollen kahden resurssimuunnoksen vertailumetodia ei tarvitse käyttää.

Huomaa, että synkronoinnin laskutoimitus ei kutsu vertailutoiminnon vertailumetodia, jos muunnosta ei ole (eli muunnoksen arvo on tyhjä). Vertailumetodi kutsutaan vain, jos molemmat elementit ovat olemassa. Tässä esimerkissä vertailumetodia ei kutsuta, jos käsiteltävillä tiedostoilla ei ole paikallisia historiatietoja tai jos käsiteltävänä on mikä tahansa kansio (kansioilla ei koskaan ole paikallisia historiatietoja). Näin ollen on määritettävä SyncInfo-aliluokka, jotta laskettua synkronointitilaa voi muokata tällaisia tilanteita varten.

public class LocalHistorySyncInfo extends SyncInfo {
  public LocalHistorySyncInfo(IResource local, IResourceVariant remote, IResourceVariantComparator comparator) {
    super(local, null, remote, comparator);
  }

  protected int calculateKind() throws TeamException {
    if (getRemote() == null)
      return IN_SYNC;
    else
      return super.calculateKind();
  }
}

Konstruktori on nyt ohitettu, joten perustana on aina tyhjäarvo (koska käytössä on vain kaksisuuntainen vertailu). Lisäksi synkronoinnin laskutoimitusta on muokattu niin, että se palauttaa arvon IN_SYNC, jos etäkohdetta ei ole (metodin tulee kiinnittää huomiota vain sellaisiin tilanteisiin, joissa käsiteltävänä on paikallinen tiedosto ja paikallisten historiatietojen tiedostotila).

Synkronoinnin valvontatoiminnon luonti

Seuraavaksi laaditaan synkronoinnin valvontatoiminto, jonka avulla voidaan käsitellä paikallisten historiatietojen resurssimuunnoksia. Paikallisia historiatietoja voi tallentua työtilan mille tahansa tiedostolle, joten paikallisten historiatietojen synkronoinnin valvontatoiminnon tulee tarkkailla jokaista resurssia, ja juurijoukkona ovat kaikki työtilan projektit. Toisaalta synkronoinnin valvontatoiminnolle ei tarvitse määrittää verestystoimintoa, koska paikalliset historiatiedot muuttuvat vain, kun paikallisen tiedoston sisältö muuttuu. Näin ollen tilan voi päivittää aina, kun resurssin delta-versio ilmenee. Paikallisten historiatietojen synkronoinnin valvontatoimintoon jää siis vain kaksi kiinnostavaa metodia: SyncInfo-olion haku ja työtilan läpikäynti.

public SyncInfo getSyncInfo(IResource resource) throws TeamException {
   try {
    IResourceVariant variant = null;
    if(resource.getType() == IResource.FILE) {
      IFile file = (IFile)resource;
      IFileState[] states = file.getHistory(null);
if(states.length > 0) {
        // vain viimeinen tila
        variant = new LocalHistoryVariant(states[0]);
      } 
    }
    SyncInfo info = new LocalHistorySyncInfo(resource, variant, comparator);
    info.init();
    return info;
  } catch (CoreException e) {
    throw TeamException.asTeamException(e);
  }
}

Synkronoinnin valvontatoiminto palauttaa uuden SyncInfo-ilmentymän, joka sisältää paikallisissa historiatiedoissa olevan tiedoston uusimman tilan. SyncInfo-ilmentymään luodaan paikallisten historiatietojen muunnos etäelementtiä varten. Jos käsiteltävänä on projekteja, kansioita tai tiedostoja, joilla ei ole paikallisia historiatietoja, resurssin etämuunnosta ei ole, joten LocalHistorySyncInfo-kohteen calculateKind-metodin johdosta järjestelmä tulkitsee resurssin olevan synkronoitu.

Paikallisten historiatietojen synkronoinnin valvontatoiminnon loppukoodissa toteutetaan members-metodi:

public IResource[] members(IResource resource) throws TeamException {
   try {
    if(resource.getType() == IResource.FILE)
      return new IResource[0];
    IContainer container = (IContainer)resource;
    List existingChildren = new ArrayList(Arrays.asList(container.members()));
    existingChildren.addAll(
      Arrays.asList(container.findDeletedMembersWithHistory(IResource.DEPTH_INFINITE, null)));
    return (IResource[]) existingChildren.toArray(new IResource[existingChildren.size()]);
  } catch (CoreException e) {
    throw TeamException.asTeamException(e);
  }
}

Tässä metodissa kiinnostavaa on se, että jos poistetulla resurssilla on paikalliset historiatiedot, metodi palauttaa aliobjekteja, joita ei ole. Tällä tavalla synkronoinnin valvontatoiminto voi palauttaa SyncInfo-olion elementeille, jotka ovat vain paikallisissa historiatiedoissa eivätkä enää työtilassa.

Paikallisten historiatietojen synkronoinnin osapuolen lisäys

Tähän mennessä on luotu luokat, joiden avulla voidaan käsitellä paikallisissa historiatiedoissa olevien elementtien SyncInfo-olioita. Seuraavaksi luodaan käyttöliittymän elementit, joiden avulla synkronointinäkymän sivulla voidaan näyttää kunkin paikallisten historiatietojen elementin edelliset historiatiedot. Käytössä on jo synkronoinnin valvontatoiminto, joten tarpeelliset osat voi lisätä synkronointinäkymään helposti. Lisätään ensin synkronoinnin osapuolen laajennuspiste:

<extension
       point="org.eclipse.team.ui.synchronizeParticipants">
<participant
persistent="false"
icon="synced.png"
class="org.eclipse.team.synchronize.example.LocalHistoryParticipant"
name="Latest From Local History"
id="org.eclipse.team.synchronize.example"/>
</extension>

Seuraavaksi tulee toteuttaa LocalHistoryParticipant-luokka. Siitä tehdään SubscriberParticipant-luokan aliluokka, ja SubscriberParticipant-luokka toteuttaa kaikki oletustoiminnot, jotka liittyvät SyncInfo-tietojen keräykseen synkronoinnin valvontatoiminnosta ja synkronointitilan päivitykseen työtilamuutosten yhteydessä. Lisäksi luokkaan lisätään toiminto, joka palauttaa työtilan resurssit paikallisten historiatietojen aiempien tietojen mukaisiksi.

Lisätään ensin osapuoleen mukautettu toiminto.

public static final String CONTEXT_MENU_CONTRIBUTION_GROUP = "context_group_1"; //$NON-NLS-1$
  
private class LocalHistoryActionContribution extends SynchronizePageActionGroup {
  public void initialize(ISynchronizePageConfiguration configuration) {
    super.initialize(configuration);
    appendToGroup(
      ISynchronizePageConfiguration.P_CONTEXT_MENU, CONTEXT_MENU_CONTRIBUTION_GROUP, 
      new SynchronizeModelAction("Revert to latest in local history", configuration) { //$NON-NLS-1$
        protected SynchronizeModelOperation getSubscriberOperation(ISynchronizePageConfiguration configuration, IDiffElement[] elements) {
          return new RevertAllOperation(configuration, elements);
        }
      });
  }
}

Esimerkissä lisättiin erityinen SynchronizeModelAction-luokka ja -toiminto. Samalla saadaan mahdollisuus ajaa toiminnot taustalla ja näyttää käsiteltävinä oleville solmuille varattu-tila. Toiminto palauttaa kaikki työtilan resurssit vastaamaan niiden edellistä tilaa paikallisissa historiatiedoissa. Toiminto lisätään lisäämällä toiminto-osa osapuolen kokoonpanoon. Kokoonpanon avulla kuvataan sen osapuolisivun koontiin käytettävät ominaisuudet, jossa synkronoinnin varsinainen käyttöliittymä näytetään.

Osapuoli alustaa kokoonpanon seuraavasti ja lisää paikallisten historiatietojen toimintoryhmän pikavalikkoon:

protected void initializeConfiguration(ISynchronizePageConfiguration configuration) {
super.initializeConfiguration(configuration);
configuration.addMenuGroup(
ISynchronizePageConfiguration.P_CONTEXT_MENU,
CONTEXT_MENU_CONTRIBUTION_GROUP);
configuration.addActionContribution(new LocalHistoryActionContribution()); configuration.addLabelDecorator(new LocalHistoryDecorator());
}

Seuraavaksi toteutetaan mukautettu koristeluobjekti. Edellä olevan metodin viimeinen rivi rekisteröi seuraavan koristelutoiminnon sivun kokoonpanoon.

public class LocalHistoryDecorator extends LabelProvider implements ILabelDecorator {
public String decorateText(String text, Object element) {
if(element instanceof ISynchronizeModelElement) {
ISynchronizeModelElement node = (ISynchronizeModelElement)element;
if(node instanceof IAdaptable) {
SyncInfo info = (SyncInfo)((IAdaptable)node).getAdapter(SyncInfo.class);
if(info != null) {
LocalHistoryVariant state = (LocalHistoryVariant)info.getRemote();
return text+ " ("+ state.getContentIdentifier() + ")";
}
}
}
return text;
}

public Image decorateImage(Image image, Object element) {
return null;
}
}

Koristelutoiminto hakee resurssin synkronointinäkymän mallielementistä ja lisää paikallisten historiatietojen resurssimuunnoksen sisältötunnuksen näkymässä olevaan tekstinimiöön.

Lopuksi toteutetaan ohjattu toiminto, joka luo paikallisten historiatietojen osapuolen. Ryhmän synkronointiperspektiivi määrittää yleisen synkronointitoiminnon, jonka avulla käyttäjät voivat nopeasti luoda synkronoinnin. Synkronointien luontimahdollisuus on käytettävissä myös synkronointinäkymän työkalupalkissa. Luodaan aluksi synchronizeWizards-laajennuspiste:

<extension
point="org.eclipse.team.ui.synchronizeWizards">
<wizard
class="org.eclipse.team.synchronize.example.LocalHistorySynchronizeWizard"
icon="synced.png"
description="Creates a synchronization against the latest local history state of all resources in the workspace"
name="Latest From Local History Synchronize"
id="ExampleSynchronizeSupport.wizard1"/>
</extension>

Ohjattu toiminto lisätään luetteloon, ja ohjatun toiminnon finish()-metodiin laaditaan oma osapuoli, joka lisätään synkronoinnin hallintaohjelmaan.

LocalHistoryPartipant participant = new LocalHistoryPartipant();
ISynchronizeManager manager = TeamUI.getSynchronizeManager();
manager.addSynchronizeParticipants(new ISynchronizeParticipant[] {participant});
ISynchronizeView view = manager.showSynchronizeViewInActivePage();
view.display(participant);

Tiivistelmä

Edellä on kuvattu yksinkertainen esimerkki synkronoinnin ohjelmointirajapintojen käytöstä. Osa toiminnoista on selvitetty yksityiskohtaisesti, jotta esimerkki olisi helposti ymmärrettävissä. Mukautuvien ja tarkkojen synkronoinnin tukitoimintojen kirjoitus on melko haastavaa, ja vaikeinta on synkronointitietojen hallinta ja synkronoinnin tilamuutoksista ilmoittaminen. Käyttöliittymän määritys on helppoa, jos SubscriberParticipants-kohteeseen liittyvä käyttöliittymä on sopiva, kunhan synkronoinnin valvontatoiminnon käyttöönotto on tehty. Lisäosassa org.eclipse.team.example.filesystem on lisää esimerkkejä, minkä lisäksi voit selata aliluokkia Subscriber- ja ISynchronizeParticipant-kohteiden työtilassa.

Seuraavassa osassa kuvataan luokkia ja käyttöliittymiä, joiden avulla voit kirjoittaa synkronoinnin valvontatoiminnon aivan alusta alkaen. Osassa kuvataan myös, kuinka synkronointitilat tallennetaan välimuistiin työympäristöistuntojen välissä.