Die folgende Liste erläutert, wie Modellprovider die Teamunterstützung für logische Modelle nutzen können:
Die folgenden Abschnitte beschreiben die obigen Aspekte ausführlicher. Das Plug-in org.eclipse.team.examples.filesystem enthält ein Beispiel, das einige dieser Punkte veranschaulicht. Sie können das Projekt aus dem CVS-Repository auschecken und während dieses Lernprogramms als Referenz verwenden. Hinweis: Der Quellcode der Beispiel-Plug-ins kann sich im Laufe der Zeit ändern. Um eine Kopie zu erhalten, die diesem Beispiel entspricht, können Sie das Projekt mit der Kennung der Version 3.2 (wahrscheinlich R3_2) oder einer Datumskennung vom 28. Juni 2006 auschecken.
Die API für die Ressourcenzuordnung ist absichtlich einfach und ermöglicht keine Bearbeitung von logischen Modellen. Ein Client kann diese Schnittstelle nicht dazu verwenden, logische Modelle anzuzeigen oder zusätzliche Informationen über sie zu erhalten. Sie ist lediglich dazu gedacht, einem oder mehreren Modellelementen Arbeitsbereichsressourcen zuzuordnen.
Die API besteht aus den folgenden Klassen:
Object getModelObject()
: Das Modellobjekt, aus dem die Zuordnung abgeleitet (also übernommen) wurde.ResourceTraversal[]
getTraversals(ResourceMappingContext, IProgressMonitor)
: Die Ressourcentraversierung, die die Ressourcen abdeckt, aus denen das Modellobjekt besteht.ResourceTraversal
enthält eine Reihe von Ressourcen sowie ein Attribut für die Verschachtelungstiefe, das die Tiefe angibt, in der die Ressourcen in der Traversierung dem entsprechenden Modellobjekt zugeordnet sind. Ressourcentraversierungen werden für einen Client durch eine Ressourcenzuordnung bereitgestellt, um den Inhalt eines Modells so zu beschreiben, dass der Client (z. B. ein Repository-Provider) seine Operationen so effizient wie möglich ausführen kann. Wichtige Methoden:getResources()
getDepth()
ResourceMappingContext
und RemoteResourceMappingContext
ist etwas komplexer und im Abschnitt Ressourcenzuordnungskontext erläutert.Es gibt zwei Typen von Plug-ins, die für Ressourcenzuordnungen wichtig sind. Zum einen handelt es sich hierbei um Plug-ins, von denen ein Modell bereitgestellt wird, das aus Ressourcen im Arbeitsbereich besteht bzw. in diesen permanent enthalten ist, sowie um Plug-ins, die Operationen für Ressourcen ausführen sollen. Der erste Typ wird im nächsten Abschnitt behandelt. Angaben zum zweiten Typ finden Sie im Thema Repository-Übersicht für die Integration logischer Modelle.
Plug-ins, deren Modellobjekte die Schnittstelle IResource
übernehmen, um ressourcenspezifische Aktionen für das Kontextmenü abzurufen, können nun die Klasse ResourceMapping
übernehmen, wenn eine umfangreichere Beschreibung für die Übernahme von Ressourcen durch das Objekt gewünscht wird. Wenn dies nicht der Fall ist, ist eine Übernahme der Klasse jedoch nicht erforderlich. Beispiel: Eine Java-Kompiliereinheit
(d. h. eine Datei "*.java", die in einer JDT-Sicht angezeigt wird), die gegenwärtige
IFile
übernimmt, muss die Klasse ResourceMapping
nicht unbedingt übernehmen, weil dies keinen nennenswerten Nutzen mit sich bringt. Ein Java-Paket hingegen sollte die Klasse ResourceMapping
übernehmen, um anzugeben, dass die im Paket enthaltenen Dateien ausschließlich aus dem entsprechenden Ordner und nicht aus den Unterordnern stammen.
Es hat sich bewährt, zur Übernahme von Ressourcenzuordnungen durch Modellelemente eine Adapterfactory zu verwenden. Die folgende XML-Markup-Formatierung ergänzt eine Adapterfactory in einem Plug-in-Manifest:
<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>
Die Implementierung der Adapterfactory könnte in etwa so aussehen:
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};
}
}
Modellobjekte können die Schnittstelle IAdaptable
implementieren. In diesem Fall müssen sie sicherstellen, dass der Adaptermanager der Plattform einbezogen wird. Hierzu kann entweder eine Unterklasse von PlatformObject
gebildet oder die folgende Codezeile verwendet werden:
Platform.getAdapterManager().getAdapter(Object, Class)
Die Verwendung der Codezeile ist die bessere Methode. Das Modellobjekt kann jedoch die
Schnittstelle "IAdaptable" implementieren und eine Implementierung von getAdapter(Class)
bereitstellen, die ein Exemplar von ResourceMapping
erstellt und zurückgibt, wenn dies ausdrücklich angefordert wird. Dieser Ansatz ist zwar stringenter, aber weniger wünschenswert, weil das Modell explizites Konstruktionswissen über die Übernahme von Ressourcen besitzen muss.
In manchen Fällen gibt der Provider eines logischen Modells vor, dass das Modell die Schnittstelle IResource
nicht in jedem Kontext übernehmen soll. Außerdem kann es sein, dass das Objekt bei Objektergänzungen andere Übernahmen vollziehen soll, als bei anderen Kontexten. Die Benutzerschnittstelle der Workbench stellt zu diesem Zweck eine spezielle temporäre Adapter-API namens
IContributorResourceAdapter
bereit. Wenn Objekte im Kontext von Objektergänzungen die Schnittstelle IResource
übernehmen, versucht die Workbench zunächst,
die Schnittstelle IContributorResourceAdapter
durch die Ressource übernehmen zu lassen, bevor
eine direkte Übernahme der Schnittstelle IResource
vorgenommen wird. Es wurde die neue untergeordnete
Schnittstelle IContributorResourceAdapter2
dieser Schnittstelle hinzugefügt,
die dieselbe Funktionalität für die Klasse ResourceMapping
bereitstellt.
Der einzige Unterschied besteht darin, dass der Modellprovider eine Factory
für IContributorResourceAdapter
registrieren sollte, da die Workbench mit einer Prüfung des Typs
instanceof feststellt, ob der ergänzte Adapter ebenfalls ein Exemplar
von IContributorResourceAdapter2
ist.
Die Implementierung der Unterklasse ResourceMapping
für ein Java-Paket könnte etwa folgendermaßen aussehen:
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)
}
}
}
Diese Zuordnung ist ziemlich stringent, weshalb die Implementierung nicht komplex ist. Die Komplexität der Implementierung für die Ressourcenzuordnung variiert jedoch natürlich je nach Modell.
Einer der Vorteile einer Ressourcenzuordnungs-API ist die Tatsache, dass Plug-ins jede gewünschte Operation im Hinblick auf Ressourcenzuordnungen implementieren können (z. B. CVS-Aktualisierung, CVS-Festschreibung, CVS-Tags, Änderungsdekorationen usw.). Die bislang eingeführte API kann jedoch lediglich zur Bearbeitung des lokalen Statuswerts des Modells verwendet werden. Bei der Arbeit an einem Modell, das von Entwicklern gemeinsam genutzt werden kann, ergibt sich irgendwann die Situation, dass der ferne Status des Modells (also der Status des Modells, den ein anderer Benutzer im Repository eingecheckt hat) möglicherweise vom Status im Arbeitsbereich abweicht. Im Anschluss an eine CVS-Aktualisierung sollte der lokale Status des Modells mit dem fernen Status übereinstimmen, selbst wenn zu diesem Zweck zusätzliche Dateien aufgenommen oder einige Dateien entfernt werden müssten.
Bei einigen logischen Modellen stellt dies kein Problem dar. Ein Java-Paket ist beispielsweise ein Container, der - unabhängig vom fernen Status des Modells - nur eine Tiefenebene aufweist, die verwendet werden kann. Infolgedessen kann ein Repositoryprovider ohne großen Aufwand feststellen, dass beim Festschreiben abgehende Löschvorgänge oder bei der Aktualisierung eingehende Ergänzungen aufgenommen werden sollten. Es kann jedoch sein, dass sich die Ressourcen, aus denen sich einige logische Modelle zusammensetzen, mit der Zeit ändern. So sind die Ressourcen, die ein Modellelement bilden, möglicherweise vom Inhalt einer Manifestdatei (oder einem anderen ähnlichen Mechanismus) abhängig. Damit die Ressourcenzuordnung die richtige Traversierung zurückgibt, muss sie auf den fernen Inhalt der Manifestdatei zugreifen (falls dieser sich vom lokalen Inhalt unterscheidet), um feststellen zu können, ob zusätzliche Ressourcen aufgenommen werden müssen. Diese zusätzlichen Ressourcen sind zwar unter Umständen nicht im Arbeitsbereich vorhanden, aber der Repository-Provider ist in diesem Fall in der Lage sicherzustellen, dass sie bei einer Ausführung der ausgewählten Aktion zur Verfügung stehen.
Um diese komplexeren Modelle zu unterstützen, kann ein Objekt RemoteResourceMappingContext
an die Methode ResourceMapping#getTraversals
übergeben werden.
Wenn ein Kontext zur Verfügung steht, kann die Zuordnung mithilfe dieses Objekts sicherstellen, dass alle erforderlichen Ressourcen in der Traversierung enthalten sind. Wird kein Kontext bereitgestellt, kann die Zuordnung davon ausgehen, dass nur der lokale Status von Bedeutung ist.
Eine Klasse ResourceMapping
muss nur in solchen Fällen den Kontext berücksichtigen, der für die Methode getTraversals
bereitgestellt wird, in denen sich die Ressourcen, aus denen ein Modell besteht,
mit der Zeit ändern und die Beziehung zwischen dem Modell und den Ressourcen nicht durch eine einfache Traversierung beschrieben werden kann, die diese Ressourcen (und nur diese Ressourcen) als Bestandteile des Modells garantiert berücksichtigt. Beispiel: Obwohl sich die Ressourcen eines Java-Pakets mit der Zeit ändern können, kann das Paket als Ordner mit einer Tiefe von einer Ebene beschrieben werden. Daher muss eine Ressourcenzuordnung für Java-Pakete den Ressourcenzuordnungskontext nicht verwenden.
Nehmen wir zur Veranschaulichung eines etwas komplizierteren Falls an, dass eine HTML-Datei mehrere Images enthält. Alle Imageverweise aus einer HTML-Datei sind Bestandteil des Modells für diese Datei. Bei einer Aktualisierung des lokalen Inhalts der HTML-Datei aus einem Repository würde der Benutzer erwarten, dass alle neuen Images aufgenommen werden. Die Methode getTraversals
für ein Objekt ResourceMapping
für das Modell der HTML-Datei könnte etwa folgendermaßen aussehen:
public class HTMLResourceMapping extends ResourceMapping {
private HTMLFile htmlFile;
public ResourceTraversal[] getTraversals(ResourceMappingContext context,
IProgressMonitor monitor)
IResource[] resources = htmlFile.getResources();
if (context instanceof RemoteResourceMappingContext) {
// Look for any additional resources on the server
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)};
}
}
Sie können feststellen, dass das Modell zwei Gruppen von Ressourcen enthält, nämlich Ressourcen, die aus dem lokalen Inhalt der HTML-Datei im Arbeitsbereich abgeleitet sind, sowie Ressourcen, die aus dem Inhalt der fernen Datei und der Basisdatei abgerufen werden. Beiden Gruppen können Ressourcen enthalten, die im Arbeitsbereich nicht vorhanden sind. Beispielsweise kann die lokale HTML-Datei einen relativen Link zu einem Image enthalten, das im Arbeitsbereich nicht vorhanden ist. Diese Ressource sollte aufgenommen werden, damit sie abgerufen wird, wenn sie in der fernen Position vorhanden ist. Die ferne Datei könnte eine neue Kopie enthalten, in der auf zusätzliche Images verwiesen wird, die beim Download des neuen fernen Inhalts abgerufen werden müssen.
Mit Modellprovidern können zusammengehörige Ressourcenzuordnungen gruppiert werden. Die Klasse ModelProvider (Link) dient drei Hauptzwecken:
IResourceMappingMerger
für das Modell wird beispielsweise durch die Übernahme des Modellproviders abgerufen.Das folgende Beispiel zeigt eine Erweiterungsdefinition für "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>
Die Klasse LibraryModelProvider
ist eine Unterklasse von ModelProvider
.
Mit der Aktivierungsregel werden Ressourcen abgeglichen, in denen das Modell des Bibliotheksmodells permanent gespeichert ist. Im obigen Beispiel gleicht der Modellprovider alle Ressourcen in einem Projekt ab, für das die Gattung "Bibliothek" definiert ist.
Sobald der Modellprovider definiert wurde, sollte die Methode ResourceMapping#getModelProviderId()
so überschrieben werden, dass sie die ID des Modellproviders zurückgibt.
public String getModelProviderId() {
return "org.eclipse.team.examples.library.adapt.modelProvider";
}
Um für solche Ressourcen, die mit der Aktivierungsregel des Providers übereinstimmen, die richtige umgekehrte Zuordnung von Ressourcen zur Ressourcenzuordnung abzurufen, sollen Sie außerdem eine oder beide
der Methoden getMapping
überschreiben. Welche Methode Sie überschreiben müssen, richtet sich danach, ob Ihr Modell Elemente verwendet, die mehrere Ressourcen enthalten. Falls die Elemente des Modells einer einzelnen Ressource zugeordnet sind,
können Sie die Methode überschreiben, die ein einziges Argument
für IResource
akzeptiert. Andernfalls müssen Sie die Methode überschreiben, die einen Bereich von Ressourcen akzeptiert. Das folgende Beispiel verwendet den Fall einer einzelnen Ressource.
In diesem Beispiel wird eine Bibliotheksmodelldatei in eine entsprechende Ressourcenzuordnung eingeschlossen. Außerdem sind Ordner eingeschlossen, in denen Dateien enthalten sind, die für den Modellprovider von Bedeutung sind.
public class LibraryModelProvider extends ModelProvider {
public ResourceMapping[] getMappings(IResource resource,
ResourceMappingContext context, IProgressMonitor monitor) {
if (isModelFile(resource)) {
// Return a resource mapping on the file
return new LibraryResourceMapping(resource);
} if (containsModelFiles(resource)) {
// Create a deep resource mapping on the container
return new LibraryContainerResourceMapping(resource);
}
// The resource is not of interest to this model provider
return null;
}
}
Clients können anschließend auf den Modellprovider zugreifen, um festzustellen, ob die Ressourcen, für die Operationen ausgeführt werden sollen, für den Modellprovider von Bedeutung sind. Der nächste Abschnitt beschreibt die API, die für Teamoperationen bereitgestellt wird, bei denen mit der Modellprovider-API die vollständige Gruppe der Ressourcenzuordnungen ermittelt wird, für die eine Operation erforderlich ist, wenn eine Teamoperation für eine Gruppe von ausgewählten Ressourcen oder Modellelementen ausgeführt wird.
Operationen, die für Ressourcen ausgeführt werden, sollten zunächst ausgewertet werden, um sicherzustellen, dass der Benutzer über mögliche Nebeneffekte unterrichtet wird. Die folgenden Schritte sind erforderlich, um eine Ressourcenänderung auszuwerten.
IResourceChangeDescriptionFactory
eine Beschreibung der Änderung.
Die Factory erzeugt ein Objekt IResourceDelta
, in dem das Aussehen des Ressourcendeltas angegeben ist, das aus der Ausführung der Operation resultieren würde.ResourceChangeValidator
aus.
Das Prüfprogramm fragt alle Modellprovider ab, für die registriert ist, dass die betroffenen Ressourcen von Bedeutung sind. Das Ergebnis besteht aus einer oder mehreren Statusangaben, die die ID des ursprünglichen Modells sowie eine Beschreibung der möglichen Nebeneffekte der Operation auf das Modell enthalten.Wenn ein Team-Provider versucht, einen automatischen Mischvorgang vorzunehmen, führt er hierzu die folgenden Aktionen durch:
Die Anzeige von Modellelementen im Kontext einer Teamoperation ist im allgemeinen Navigatorgerüst möglich.
Die obigen Schritte ermöglichen das Anzeigen von Modellen in Dialogen, die von Teamoperationen verwendet werden. Die Integration in eine Vorschau für einen Mischvorgang erfordert zusätzliche Schritte.
Die Bereiche des Dateiprotokolls und des Modellelementprotokolls wurden folgendermaßen erweitert:
Die folgende Unterstützung wurde für das Anzeigen ferner Positionen hinzugefügt:
Team-Provider können Modellelemente mit Dekoratoren versehen, indem sie ihre einfachen Dekoratoren so konvertieren, dass sie zusammen mit Ressourcenzuordnungen verwendet werden können. Die Konvertierung erfolgt genauso wie bei Objektergänzungen, die für die Zusammenarbeit mit Ressourcenzuordnungen konvertiert werden. Es gibt jedoch einen problematischen Aspekt bei der Dekoration von logischen Modellelementen. Falls ein Modellelement keine Eins-zu-eins-Zuordnung zu einer Ressource aufweist, empfängt das Modellelement möglicherweise keine Bezeichnungsaktualisierung, wenn sich die zu Grunde liegende Ressource ändert.
Um dieses Problemstellung zu lösen, wurde ITeamStateProvider
eingeführt, damit Modellprovider auf Statusänderungen zugreifen können, die sich möglicherweise auf Teamdekorationen auswirken. Außerdem können Modellsichten mit der Testfunktion
SynchronizationStateTester
ermitteln, ob die Bezeichnungen von logischen Modellelementen aktualisiert werden müssen. Diese API nutzt die Schnittstelle ITeamStateProvider
, um zu ermitteln, ob sich der Teamstatus einer Ressource geändert hat und als Teil von IDecorationContext
an einen Teamdekorator übergeben werden kann.