Di seguito viene riportato un elenco delle attività che i fornitori di modelli possono eseguire per beneficiare del supporto per il modello logico Team:
Le seguenti sezioni descrivono ciascun punto in maniera più dettagliata. Il plig-in org.eclipse.team.examples.filesystem contiene un esempio che illustra diversi di questi punti. È possibile estrarre il progetto dal repository CVS e utilizzarlo come riferimento durante la lettura di questa esercitazione. Dichiarazione di responsabilità: il codice di origine nel plug-ins di esempio può cambiare con il tempo. Per ottenere una copia che corrisponda a codice utilizzato in questo esempio, è possibile estrarre il progetto utilizzando il tag della versione 3.2 (quasi sicuramente R3_2) oppure un tag con data 28 giugno 2006.
L'API per l'associazione di risorse è semplice e non presenta le manipolazioni del modello logico. Un client non può utilizzare questa interfaccia per visualizzare modelli logici oppure per ottenere ulteriori informazioni su di essi. La sua funzione è semplicemente quella di associare uno o più elementi modello alle risorse dello spazio di lavoro.
Questa API è formata dalle seguenti classi:
Object getModelObject()
: l'oggetti modello fa cui
è stata derivata oppure adattata l'associazione.ResourceTraversal[]
getTraversals(ResourceMappingContext, IProgressMonitor)
: il passaggio delle
risorse che copre le risorse che costituiscono l'oggetto modello.ResourceTraversal
contiene un insieme di risorse e di indicatori di livello che segnalano il livello al quale
le risorse nel passaggio vengono associate all'oggetto modello di
origine. Passaggi delle risorse vengono fornite a un client
attraverso l'associazione di risorse per descrivere il contenuto di un modello in
modo che il client (un fornitore di repository, ad esempio) possa eseguire le
proprie operazioni nella maniera più efficiente possibile. I metodi principali
sono:
getResources()
getDepth()
ResourceMappingContext
e RemoteResourceMappingContext
è un po' più complicato e viene decsritto nella sezione Contesto per l'associazione di risorse.Esistono due tipi di plugin che dovrebbero essere interessati nell'associazione di risorse. Quelli che forniscono un modello composto di risorse nello spazio di lavoro e quelli che desiderano eseguire operazioni su risorse. I primi verranno trattati nella sezione successiva, mentre gli altri verranno descritti nella sezione Readmap del repository per l'integrazione dei modello logici.
I plugin che hanno adattato i propri oggetti modello a IResource
allo scopo di ottenere azioni specifiche delle risorse visualizzate nel menu di scelta
rapida possono ora adattarsi a ResourceMapping
se una descrizione più ricca del modo
in cui l'oggetto si adatta alle risorse è utile. Tuttavia, se non c'è alcun
vantaggio, non è necessario che effettuino questa operazione. Ad esempio, un'unità di compilazione
Java (ossia un file *.java mostrato in una vista JDT) che ora si adatta
a IFile
non deve necessariamente adattarsi a ResourceMapping
, poiché
non si ottiene nulla. Ad ogni modo, un pacchetto Java dovrebbe adattarsi a ResourceMapping
per indicare che il pacchetto è formato solo da file della cartella corrispondente
e non delle sottocartelle.
Il modo preferito per adattare elementi di modello a un'associazione di risorse consiste nell'utilizzare un factory per adattatore. La seguente è la markup XML per fornire un factory per adattatore in un manifest di plugin.
<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>
L'implementazione del factory per adattatore dovrebbe essere simile a quanto riportato di seguito:
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};
}
}
Gli oggetti modello possono implementare l'interfaccia
IAdaptable
. In questi casi, devono assicurare che il gestore adattatori della piattaforma
venga consultato. Questa operazione può essere eseguita creando delle sottoclassi di PlatformObject
oppure utilizzando la seguente riga di codice:
Platform.getAdapterManager().getAdapter(Object, Class)
È questo l'approccio preferibile. Tuttavia, l'oggetto modello può
implementare l'interfaccia IAdaptable e fornire un'implementazione di getAdapter(Class)
crea un'istanza di ResourceMapping
esplicitamente quando ne viene
richiesta una. Questo è l'approccio più semplice ma il meno
opportuno, in quanto il modello deve avere la conoscenza esplicita dell'adattamento
alle risorse.
In alcuni casi, è possibile che il fornitore di un modello logico non desideri
che il proprio modello si adatti a IResource
in ogni contesto oppure che
l'oggetto si adatti in maniera diversa ai contributi di oggetti rispetto ad altri
contesti. A tale scopo, l'interfaccia utente del workbench fornisce una speciale API di adattatore intermedio
IContributorResourceAdapter
. Quando gli oggetti si adattano
a IResource
nel contesto dei contributi di oggetti, come prima cosa il
workbench cerca di adattare la risorsa a IContributorResourceAdapter
prima di
provare ad adattarla direttamente a IResource
. Una nuova sottointerfaccia
di questa interfaccia, IContributorResourceAdapter2
,
è stata aggiunta e che fornisce la stessa funzionalità per ResourceMapping
.
L'unica differenza è che il fornitore di modelli dovrebbe registrare un factory
per IContributorResourceAdapter
in quanto il Workbench esegue un controllo
instanceof per vedere se l'adattatore fornito è anche un'istanza di
IContributorResourceAdapter2
.
L'implementazione della sottoclasse ResourceMapping
per un pacchetto
Java dovrebbe essere simile a quella riportata di seguito.
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)
}
}
}
Questa è un'associazione piuttosto semplice, quindi l'implementazione non è complessa. La complessita dell'implementazione dell'associazione di risorse varierà, naturalmente, da modello a modello.
Uno dei vantaggi dell'API di associazione di risorse è che consente ai plugin di implementare qualsiasi operazioni desiderino in termini di associazione di risorse (ad esempio, aggiornamento CVS, commit CVS, tag CVS, decorazioni non finali e così via). However, the API that has been introduced so far deals only with the local state of the model. When working with a model that may be shared between developers, you end up in a situation where the remote state of the model (i.e. the state of the model that another user has checked-in to the repository) may differ from the state in the workspace. If you performed a CVS update, you would want the local state of the model to match the remote state even if it meant that additional files needed to be included or some files needed to be removed.
This is not an issue for some logical models. Ad esempio, un pacchetto java è un contenitore visitato in profondità uno, indipendentemente dallo stato remoto del modello. Dato questo, un provider di repository può facilmente stabilire che le eliminazioni in uscita devono essere incluse durante il commit o che le aggiunte in arrivo debbano essere incluse durante l'aggiornamento. Tuttavia, le risorse che costituiscono alcuni modelli logici possono cambiare nel tempo. Ad esempio, le risorse che costituiscono un elemento di modello dipendono dal contenuto di un file manifest (o qualche altro meccanismo simile). Affinché l'associazione di risorsa ritorni al passaggio corretto, deve accedere al contenuto remoto del file manifest (differisce dal contenuto locale) per vedere se ci sono risorse aggiuntive che devono essere incluse. Queste risorse aggiuntive possono non esistere nello spazio di lavoro, ma il fornitore di repository sa come accertarsi che erano presenti quando l'azione selezionata è stata eseguita.
Per supportare questi modelli più complessi, un RemoteResourceMappingContext
può passare a un metodo ResourceMapping#getTraversals
.
Quando viene fornito un contesto, la mappatura può utililizzarlo per garantire che tutte le
risorse necessarie siano incluse nel passaggio. Se un contesto
non viene fornito, la mappatura può presumere che solo lo stato locale è di
interesse.
A ResourceMapping
need only worry about a context
supplied to the getTraversals
method in cases were the
resources that make up a model change over time and the relationship
between the model and resources cannot be described by a simple
traversal that is guaranteed to encompass those resources (and only
those resources) that constitute the model. For example, although the
resources of a Java package may change over time, the package can be
described as a folder of depth of one so a resource mapping for java
packages would not ned to make use of the resource mapping context.
As a more complicated example, consider an HTML file that
contains several images. Let's make the assumption that any images
references from an HTML file are part of the model of that file. When
updating the local contents of the HTML file from a repository, the user
would expect that any new images would be included. The getTraversals
method for a ResourceMapping
for the HTML file model would
look something like this:
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)};
}
}
Notice that there are two sets of resources included in the model: those derived from the local contents of the HTML file in the workspace and those obtained from the contents of the remote file and base file. In either of these two sets, there may be resources that do not exist in the workspace. For instance, the local HTML file may contain a relative link to an image that does not exist in the workspace. This resource should be included so that it will be fetched if it exists remotely. As for the remote file, it may contain a new copy that references additional images that should be fetched when the new remote contents are downloaded.
Model providers are a means to group related resource mappings together. Here is a link to the ModelProvider class. This class serves three main purposes:
IResourceMappingMerger
for the model is obtained by adapting the model provider.The following is an example of a modelProvider extension definition.
<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>
The LibraryModelProvider
is a subclass of ModelProvider
.
The enablement rule is used to match resources that the Library model
persists its model in. In the above example, the model provider will
match any resource in a project that has the library nature.
Once the model provider is defined, the ResourceMapping#getModelProviderId()
method should be overridden to return the id of the model provider.
public String getModelProviderId() {
return "org.eclipse.team.examples.library.adapt.modelProvider";
}
To get the proper inverse mapping of resources to resource
mapping for those resources that match your provider's enablement rule,
you should also override one or both of the getMapping
methods. The method that you need to override depends on whether your
model has elements that contain multiple resources or not. If your model
elements map to a single resource, you can override the method that
accepts a singleIResource
argument. Otherwise, you will
need to override the method that accepts an array of resources. Here's
an example using the single resource case.
The following example method wraps a library model file in an
appropriate resource mapping. It also wraps folders that contain files
that are of interest to the model provider.
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 can then access the model provider to determine whether the model providers cares about the resources that are about to be operated on. The next section describes API that will be provided to team operations that use the model provider API to determine the complete set of resource mappings to be operated on when a team operation is performed on a set of selected resources or model elements.
Operations performed on resources should be validated first to ensure that the user is aware of any potential side effects. Here are the steps required to validate a resource change.
IResourceChangeDescriptionFactory
.
The factory produces an IResourceDelta
that mirrors what
the resulting resource delta will look like once the operation is
performed.ResourceChangeValidator
.
The validator consults all the model providers that have registered an
interest in the affected resources. The result is one or more status
that contain the id of the originating model and a description of the
potential side effect of the operation on the model.Quando un fornitore Team tenta un'unione senza intestazione:
La visualizzazione degli elemento di modello nel contesto di una operazione team è possibile grazie al framework Selezione comune.
La procedura riportata sopra consentirà ai modelli di essere visualizzati in finestre utilizzate dalle operazioni del team. Ci sono ulteriori passaggi da completare per l'integrazione nell'anteprima di un'unione.
I seguenti miglioramenti sono stati apportati all'area della cronologia dei file e alla cronologia degli elementi del modello:
Per supportare la navigazione in remoto:
I fornitori team pososno decorare gli elemento del modello convertendo i propri decoratori per utilizzare le associazioni per risorse cosi come i contributi oggetto vengono convertiti per utilizzare associzioni per le risorse. Tuttavia, c'è un aspetto della decorazione degli elemento del modello logico che è problematico. Se un modello non presenta un'associazione uno-a-uno con una risorsa, l'elemento di modello potrebbe non ricevere l'aggiornamento dell'etichetta quando le risorse sottostanti cambiano.
Per risolvere questo problema, è stato introdotto un ITeamStateProvider
per consentire al fornitore di
modleli di accedere alla modifiche allo stato che possono influire sulle decorazioni team. Inoltre, le viste del modello
possono utilizzare un SynchronizationStateTester
per determinare quando
occorre aggiornare le etichette degli elementi dei modello logici. Questa API utilizza
l'interfaccia ITeamStateProvider
per determinare quando lo stato team della
risorsa è cambiato ed è possibile passare a un decoratore team come parte di IDecorationContext
.