Modelplan for logisk modelintegration

Her er en liste over, hvordan modeludbydere kan drage fordel af understøttelse af den logiske teammodel:

  1. Tilpas modelelementer i modeloversigter til ResourceMapping for at tillade ressourcebaserede funktioner på modelelementer.
  2. Registrér en ModelProvider for at sikre, at din model konsulteres, når der udføres funktioner på ressourcer med relation til modellen.
  3. Brug ResourceChangeValidator, når du udfører funktioner på ressourcer for at sikre, at enhver potentiel sideeffekt på modelelementer med relation til disse ressourcer gøres kendte for brugeren.
  4. Implementér en IResourceMappingMerger for at deltage i hovedløse fletoperationer, der involverer ressourcer med relation til modellen.
  5. Registrér en teamContentProvider for at deltage i teamoversigter, f.eks. fremvisning af resultater i fletoperationsoversigter.
  6. Stil en IHistoryPageSource til rådighed for at vise logisk modelhistorik i en teamhistorikoversigt.
  7. Brug API'et for Eclipse-filsystemet for at få adgang til eksterne tilstande af modelprojekter.
  8. Brug API'et SynchronizationStateTester for at sikre korrekt dekoration af modelelementer, der ikke har én-til-én-mapping til ressourcer.

De følgende afsnit beskriver hvert af disse punkter mere detaljeret. Plugin'en org.eclipse.team.examples.filesystem indeholder et eksempel, der illustrerer adskillige af disse punkter. Du kan tjekke projektet ud fra CVS-opbevaringsstedet og bruge det som reference, mens du læser denne øvelse. Ansvarsfraskrivelse: Kildekoden i eksempelplugins kan ændres over tid. Hvis du vil hente en kopi, der matcher den, som bruges i dette eksempel, kan du tjekke projektet ud ved brug af 3.0-versionskoden (sandsynligvis R3_2) eller datokoden 28. juni 2006.

Ressourcetilknytninger vha. mapping

API'et for grundlæggende ressoucemapping

API'et til ressource har et enkelt formål og har ikke inkluderet logiske modelmanipulationer. En klient kan ikke bruge denne grænseflade til at få vist logiske modeller eller skaffe sig yderligere oplysninger af interesse. Formålet er kun at tilknytte en eller flere modelelementer vha. mapping til arbejdsområderessourcer.

API'et består af følgende klasser:

To typer plugins har interesse i tilknytning af ressourcer vha. mapping. Dem, der stiller en model til rådighed eller er en del af ressourcer i et arbejdsområde, eller dem, der udfører funktioner på ressourcer. Den første behandles i næste afsnit, den sidste i Plan over opbevaringssted for logisk modelintegration.

Tilpasning af en model til en ResourceMapping

Plugins, der har tilpasset deres modelobjekter til IResource for at få ressourcespecifikke funktioner vist i kontekstmenuen, kan nu tilpasses til ResourceMapping, hvis en mere omfattende beskrivelse af, hvordan objekter tilpasser ressourcer, er til rådighed. De behøver ikke at gøre sådan, hvis det ikke er en fordel. F.eks. behøver en Java-kompileringsenhed, f.eks. en Javafil, der vises i en JDT-oversigt , der tilpasser sig til IFile, ikke at tilpasse sig ResourceMapping, da det ikke har nogen effekt. Imidlertid skal en Java-pakke tilpasses til ResourceMapping for at angive, at pakken kun består af filer i den tilsvarende folder og ikke i underordnede foldere.

Den foretrukne måde at tilpasse modelelementer til ressource-mapping er at bruge en adapterfabrik. Det følgende er en XML-markup, der leverer en adapterfabrik i et pluginmanifest.

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

Implementeringen af adapterfabrikken kan se således ud:

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

Modelobjekter kan implementere grænsefladen IAdaptable. Når du gør det, skal du sikre dig, at adapteradministrationen for platformen konsulteres. Det kan gøres ved enten at gør PlatformObject til underklasse eller ved at bruge følgende kodelinje:

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

Ovenstående er den foretrukne fremgangsmåde. Imidlertid kan modelobjektet implementere grænsefladen IAdaptable og stille en implementering af getAdapter(Class) til rådighed, der opretter returneringer af forekomster af ResourceMapping eksplicit, når der anmodes om det. Dette er en mere direkte fremgangsmåde, men den mindst ønskværdige, da modellen skal have eksplicit kendskab til tilpasning af metoden.

I visse tilfælde vil udbyderen af en logisk model ikke tilpasse modellen til IResource i enhver kontekt eller ønske, at objektet tilpasses for objektbidragene i stedet for andre kontektster. Arbejdsbænk-UI'et stiller et speciel mellemliggende adapter-API IContributorResourceAdapter til rådighed for dette formål. Når objekter tilpasses til IResource i konteksten for objektbidrag, prøver arbejdsbænken først at tilpasse ressourcerne til IContributorResourceAdapter, før der forsøges med en direkte tilpasning til IResource. En ny undergrænseflade for denne grænseflade, IContributorResourceAdapter2, er tilføjet, der stiller de samme funktioner til rådighed for ResourceMapping. Den eneste forskel er, at modeludbyderen skal registrere en fabrik for IContributorResourceAdapter, da arbejdsbænken foretager en instanceof-kontrol for at se, om den leverede adapter også er en forekomst af IContributorResourceAdapter2.

Implementeringen af underklassen ResourceMapping for en Java-pakke kan se således ud:

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

Det er en rimelig enkel mapping, så implementeringen er ikke kompleks. Kompleksiteten af implementeringen af ressource-mapping varierer naturligvis fra model til model.

Kontekst for ressource-mapping.

En af fordelene ved et ressource-mapping-API er, at det tillader plugins at implementere enhver funktion i forhold til ressource-mapping, f.eks. CVS-opdatering, CVS-commit, CVS-kode, snavset dekoration osv. Det API, der er introduceret indtil nu, fungerer kun med modellens lokale tilstand. Når du arbejder med en model, der deles mellem udviklere, kan du ende i en situation, hvor modellens eksterne tilstand (dvs. den modeltilstand, en anden bruger har tjekket ind i opbevaringsstedet) afviger fra tilstanden i arbejdsområdet. Hvis du har udført en CVS-opdatering, vil du have modellens lokale tilstand til at matche den eksterne tilstand, også selvom det betyder, at der skal inkluderes nogle ekstra filer, eller at der skal fjernes nogen.

Det er ikke relevant for visse logiske modeller. F.eks. er en Java-pakke et opbevaringssted, der besøges med en dybde på én, uanset modellens eksterne tilstand. Forudsat dette kan en udbyder af opbevaringssted nemt bestemme, at udgående sletninger kan inkluderes ved commit, eller at indgående tilføjelser skal inkluderes ved opdatering. Ressourcerne, der konstituerer visse logiske modeller, kan imidlertid ændres efterhånden. F.eks. kan de ressourcer, der konstituerer en model, være afhængige af indholdet af en manifestfil eller en anden tilsvarende mekanisme. For at ressource-mapping skal returnere det korrekte gennemløb skal den have adgang til det eksterne indhold af manifestfilen, hvis det afviger fra det lokale indhold, for at undersøge, om der skal inkluderes ekstra ressourcer. Disse ekstra ressourcer findes måske ikke i arbejdsområdet, men udbyderen af opbevaringsstedet vil vide, hvordan man sikrer sig, at det fandtes, da den valgte funktion blev udført.

For at understøtte disse mere komplekse modeller kan en RemoteResourceMappingContext sendes til metoden ResourceMapping#getTraversals. Når en kontekst stilles til rådighed, kan mapping'en bruge den til at sikre, at alle nødvendige ressourcer er inkluderet i gennemløbet. Hvis der ikke er en kontekst, kan mapping'en antage, at kun den lokale tilstand er af interesse.

Hvornår skal en ResourceMapping bekymre sig om RemoteResourceMappingContext?

En ResourceMapping skal kun bekymre sig om en kontekst leveret til metoden getTraversals i tilfælde, hvor ressourcerne, der udgør modellen, ændres over tid og relationen mellem modellen og ressourcerne ikke kan beskrives af et enkelt gennemløb, der med garanti omfatter de og kun de ressourcer, der konstituerer modellen. Selvom f.eks. ressourcerne til en Java-pakke kan ændre sig, kan pakken beskrives som en folder med dybden én, så en ressource-mapping for Java-pakker skal ikke gøre brug af kontekst for ressource-mapping.

Et mere komplekst eksempel er en HTML-fil, der består af flere images. Antag, at enhver imagereference fra en HTML-fil er en del af modellen for filen. Når det lokale indhold i HTML-filen opdateres fra et opbevaringssted, vil brugeren forvente, at alle nye images inkluderes. Metoden getTraversals for en ResourceMapping for en HTML-filmodel kan så således ud:

public class HTMLResourceMapping extends ResourceMapping {
private HTMLFile htmlFile;
public ResourceTraversal[] getTraversals(ResourceMappingContext context,
IProgressMonitor monitor)
IResource[] resources = htmlFile.getResources();
if (context instanceof RemoteResourceMappingContext) {
// Søg efter alle ekstra ressourcer på serveren
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)};
}
}

Bemærk, at to sæt ressourcer er inkluderet i modellen: dem, der er afledt fra det lokale indhold af HTML-filen i arbejdsområdet, og dem, der er hentet fra indholdet af den eksterne fil og basisfilen. I hvert af disse to sæt kan der være ressourcer, der ikke findes i arbejdsområdet. F.eks. kan den lokale HTML-fil indeholde et relativt link til et image, der ikke findes i arbejdsområdet. Denne ressource kan inkluderes, så den hentes, hvis den findes eksternt. Som for en ekstern fil kan den indeholde en ny kopi, der henviser til ekstra images, der skal hentes, når det nye eksterne indhold overføres.

Modeludbydere

Modeludbydere er en måde at gruppere beslægtede ressourcetilknytninger vha. mapping på. Her er et link til klassen ModelProvider. Denne klasse tjener tre hovedformål:

  1. Fra en modeludbyder kan klienter hente ekstra API-stykker for at udføre funktioner på et sæt ressourcetilknytninger vha. mapping vha. tilpasningsmekanismen. F.eks. hentes IResourceMappingMerger for modellen ved at tilpasse modeludbyderen.
  2. Med et sæt filsystemressourcer kan klienter rette forespørgsel, om en modeludbyder har modelelementer i disse ressourcer, og, hvis det er tilfældet, hente sættet af ressourcetilknytninger vha. mapping, der beskriver relationen.
  3. For funktioner på et sæt ressourcer vil ressourceændringsvalidatoren rette forespørgsel til modeludbydere for at bestemme, om der er nogle potentielle sideeffekter ved en funktion, som brugeren skal være opmærksom på. Dette behandles i et separat afsnit - Validering af ressourceændring.

Det følgende er et eksempel på en modelProvider-udvidelsesdefinition.

   <extension

id="modelProvider"
name="Bibliotekseksempel"
point="org.eclipse.core.resources.modelProviders">
<modelProvider
class="org.eclipse.team.examples.library.adapt.LibraryModelProvider"
name="Bibliotekseksempel"/>
<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 er en underklasse af ModelProvider. Aktiveringsreglen anvendes til at matche ressourcer, som biblioteksmodellen har sin model i. I eksemplet ovenfor vil modeludbyderen matche enhver ressource, der har biblioteksnaturen.

Når modeludbyderen er defineret, skal metoden ResourceMapping#getModelProviderId() tilsidesættes for at returnere modeludbyderens id.

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

For at få den korrekte omvendte mapping af ressourcer til ressource-mapping for de ressourcer, der matcher udbyderens aktiveringsregel, skal du også tilsidesætte en eller begge getMapping-metoder. Hvilken metode, du skal tilsidesætte, afhænger af, om modellen har elementer, der indeholder flere ressourcer. Hvis modelelementerne knyttes til en enkelt ressource, kan du tilsidesætte den metode, der accepterer et enkelt IResource-argument. Hvis det ikke er tilfældet, skal du overskrive metoden, der accepterer en array af ressourcer. Her er et eksempel, der bruger en enkelt ressource.

Følgende eksempelmetode pakker en biblioteksmodelfil i en bestemt ressource-mapping. Den pakker også foldere, der indeholder filer, der er af interesse for modeludbyderen.

public class LibraryModelProvider extends ModelProvider {
public ResourceMapping[] getMappings(IResource resource,
ResourceMappingContext context, IProgressMonitor monitor) {
if (isModelFile(resource)) {
// Returnerer en ressource-mapping på en fil
return new LibraryResourceMapping(resource);
} if (containsModelFiles(resource)) {
// Opretter en dyb ressource-mapping på et opbevaringssted
return new LibraryContainerResourceMapping(resource);
}
// Ressourcen har ikke betydning for denne modeludbyder
return null;
}
}

Klienter kan derefter få adgang til modeludbyderen for at bestemme, om modeludbyderen har interesse i de ressourcer, der skal behandles. Det næste afsnit beskriver det API, der stilles til rådighed for teamfunktioner, der anvender modeludbyder-API'et til at bestemme det komplette sæt ressourcetilknytninger vha. mapping, der skal behandles, når en teamfunktion udføres på et sæt af valgte ressourcer eller modelelementer.

Validering af ressourceændring

Funktioner, der udføres på ressourcer, skal valideres først for at sikre, at brugeren er opmærksom på enhver potentiel sideeffekt. Nedenfor beskrives fremgangsmåden for validering af en ressourceændring.

  1. Byg en beskrivelse af ændringen vha. IResourceChangeDescriptionFactory. Fabrikken producerer en IResourceDelta, der spejler, hvordan det resulterende ressourcedelta vil se ud, når funktionen udføres.
  2. Validér ændringen ved at bruge ResourceChangeValidator. Validatoren konsulterer alle de modeludbydere, der har registreret en interesse i den berørte ressource. Resultatet er en eller flere statuser, der indeholder id'en på den oprindelige model og en beskrivelse af funktionens potentielle sideeffekt på modellen.
  3. Gør brugeren opmærksom på enhver potentiel sideeffekt fra modeller, der er ukendte for den oprindelige funktion. Hvis f.eks. en Java-refactoring har modtaget en sideeffekt fra en Java-model, kan den ignoreres, da refactoring forstår Java-modellens semantik. Hvis en sideeffekt derimod returneres fra en biblioteksmodel, skal den gøres kendt for brugeren, da Java ikke har kendskab til biblioteksmodellen.

Modelbaseret fletning

Når en teamudbyder forsøger en hovedløs fletoperation, gør den følgende:

  1. Hent ressourcetilknytninger vha. mapping fra de valgte elementer
  2. Bestem den berørte modeludbyder med metoden ResourceMapping#getModelProvider().
  3. Udvid funktionens omfang til at omfatte alle nødvendige ressourcetilknytninger vha. mapping.
  4. Opbyg en beskrivelse af synkroniseringstilstanden mellem lokal og ekstern. Denne beskrivelse stilles til rådighed for modellerne via API'et IMergeContext.
  5. Tilpas modeludbyderne til IResourceMappingMerger.
  6. Start metoden validateMerge på hver sammenfletning, og overfør synkroniseringsbeskrivelsen for at sikre, at der ikke er en betingelse, der forhindrer forsøget på fletning.
  7. Delegér sammenfletningen til modelsammenfletninger for at udføre fletningen.
  8. Modeludbydere kan delegere fletningen af individuelle filer tilbage til teamudbyderen, hvis de blot vil kontrollere rækkefølgen af fletningen eller vil udføre fletningen selv og signalere til teamudbyderen, når de er færdige.

Modelindhold i oversigter over teamfunktioner

Visning af modelelementer i konteksten for en teamfunktion gøres mulig af strukturen Common Navigator.

Ovenstående trin gør det muligt at vise modeller i dialogbokse, der anvendes af teamfunktioner. Der skal foretages yderligere for at integrere med resultatfremvisning af en fletning.

Historikoversigt

Der er følgende forbedringer inden for historik for filer og modelelementer:

Eksternt gennemsyn

Følgende stilles til rådighed for eksternt gennemsyn:

Dekoration af modelelementer med teamtilstand

Teamudbydere kan dekorere modelelementer ved at konvertere deres letvægtsdekoratører til at arbejde for ressourcetilknytninger vha. mapping på samme måde, som objektbidrag konverteres til at arbejde for ressourcetilknytninger vha. mapping. Der er imidlertid et aspekt af logisk modelelementdekoration, der er problematisk. Hvis et modelelement ikke har en én-til-én-mapping til en ressource, modtager modelelementet måske ikke etiketopdatering, når den underliggende ressource ændres.

For at løse problemet er ITeamStateProvider introduceret for at give modeludbydere adgang til tilstandsændringer, der kan påvirke teamdekorationer. Desuden kan modeloversigter anvende en SynchronizationStateTester til at bestemme, hvornår etiketter for logiske modelelementer skal opdateres. Dette API er afhængigt af grænsefladen ITeamStateProvider, når det skal bestemmes, hvornår teamtilstanden for ressourcen er ændret og kan sendes til en teamdekoratør som en del af en IDecorationContext.