Her er en liste over, hvordan modeludbydere kan drage fordel af understøttelse af den logiske teammodel:
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.
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:
Object getModelObject()
: Modelobjektet, som mapping'en er afledt af (eller tilpasset efter). ResourceTraversal[] getTraversals(ResourceMappingContext, IProgressMonitor)
: Det ressourcegennemløb, der dækker de ressourcer, der konstituerer modelobjektet.
ResourceTraversal
indeholder et sæt ressourcer og et dybdeflag, der angiver dybden, som ressourcerne i gennemløbet er knyttet til med det oprindelige modelobjekt. Ressourcegennemløb stilles til rådighed for en klient vha. en ressource-mapping for at beskrive indholdet af en model på en måde, så klienten (dvs. ressourceudbyderen) kan udføre sine funktioner så effektivt som muligt. De relevante metoder er:
getResources()
getDepth()
ResourceMappingContext
og RemoteResourceMappingContext
er lidt mere kompliceret og beskrives i afsnittet Kontekst for ressource-mapping. 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.
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.
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.
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 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:
IResourceMappingMerger
for modellen ved at tilpasse modeludbyderen. 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.
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.
IResourceChangeDescriptionFactory
.
Fabrikken producerer en IResourceDelta
, der spejler, hvordan det resulterende ressourcedelta vil se ud, når funktionen udføres.
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.
Når en teamudbyder forsøger en hovedløs fletoperation, gør den følgende:
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.
Der er følgende forbedringer inden for historik for filer og modelelementer:
Følgende stilles til rådighed for eksternt gennemsyn:
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
.