A continuación figura una lista de lo que los proveedores de modelo pueden realizar para aprovechar el soporte de modelos lógicos de equipo:
Las secciones que siguen describen cada uno de estos puntos con mayor detalle. El plug-in org.eclipse.team.examples.filesystem contiene un ejemplo que ilustra varios de estos puntos. Puede reservar el proyecto en el repositorio CVS y utilizarlo como referencia durante la lectura de esta guía de aprendizaje. Declaración de limitación de responsabilidad: el código fuente de los plug-ins de ejemplo puede cambiar en el futuro. Para obtener una copia que coincida con la utilizada en este ejemplo, puede reservar el proyecto mediante el código de la versión 3.2 (probablemente R3_2) o el código de fecha correspondiente a 28 de Junio de 2006.
La API de correlación de recursos es una API deliberadamente simple en la que se omiten las manipulaciones de modelos lógicos. El cliente no puede utilizar esta interfaz para visualizar modelos lógicos ni obtener conocimientos adicionales de interés acerca de ella. Su finalidad consiste simplemente en correlacionar uno o varios elementos de modelo con los recursos del espacio de trabajo.
La API consta de las siguientes clases:
Object getModelObject()
: el objeto de modelo del que se ha derivado (o
adaptado) la correlación. ResourceTraversal[]
getTraversals(ResourceMappingContext, IProgressMonitor)
: el cruce de recursos
que cubre los recursos que constituyen el objeto de modelo. ResourceTraversal
contiene un conjunto de recursos y un distintivo de profundidad que indica la
profundidad a la que los recursos del cruce se asocian con el objeto de modelo
originador. Una correlación de recursos suministra los cruces de recurso al
cliente a fin de describir el contenido de un modelo de modo que el cliente (por ejemplo,
un proveedor de repositorio) pueda realizar sus operaciones con la mayor eficacia
posible. Los métodos de interés son los siguientes: getResources()
getDepth()
ResourceMappingContext
y
RemoteResourceMappingContext
es un poco más complicada y se describe en la sección
Contexto de correlación de recursos. Existen dos tipos de plugins a los que afectan las correlaciones de recursos. Son aquellos que suministran un modelo que consta de recursos del espacio de trabajo o se hace persistente en ellos, y aquellos que desean realizar operaciones sobre los recursos. El primero se describe en la próxima sección, mientras que el segundo se describe en el Mapa de ruta de repositorios para integración de modelos lógicos.
Los plug-ins que adaptaban sus objetos de modelo a IResource
a fin de
que las acciones específicas de recurso se muestran en el menú de contexto pueden ahora
adaptarse a ResourceMapping
si requieren una descripción más detallada de
cómo se adapta el objeto a los recursos. Sin embargo, no es necesario que lo hagan si
ello no representa ninguna ventaja. Por ejemplo, una unidad de compilación Java (es
decir, un archivo *.java mostrado en una vista JDT) que actualmente se adapte a
IFile
no necesita adaptarse a ResourceMapping
, ya que no
ganaría nada. Sin embargo, un paquete Java debe adaptarse a ResourceMapping
para poder indicar que el paquete consta sólo de los archivos de la carpeta
correspondiente, y no de las subcarpetas.
El procedimiento preferido para adaptar elementos de modelo a una correlación de recursos es utilizar una fábrica de adaptadores. A continuación figura el código XML para añadir una fábrica de adaptadores a un manifiesto de plug-in.
<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>
La implementación de la fábrica de adaptadores será parecida a la siguiente:
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};
}
}
Los objetos de modelo pueden implementar la interfaz IAdaptable
. Si lo
hacen, deben asegurarse de que se consulte el gestor de adaptadores de plataforma. Esta
operación puede realizarse creando una subclase de PlatformObject
o utilizando la siguiente línea de código:
Platform.getAdapterManager().getAdapter(Object, Class)
Este último es el procedimiento recomendado. Sin embargo, el objeto de modelo puede
implementar la interfaz IAdaptable y suministrar una implementación de getAdapter(Class)
que cree y devuelva una instancia de ResourceMapping
explícitamente cuando
se le solicite una. Este es un procedimiento más directo pero menos deseable, ya que el
modelo debe tener conocimiento explícito de la adaptación a los recursos.
En algunos casos, es posible que el proveedor de un modelo lógico no desee que su
modelo se adapte a IResource
en todos los contextos, o puede desear que el
objeto se adapte de forma diferente a las contribuciones de objeto y a los demás
contextos. La UI del entorno de trabajo proporciona una API de adaptador intermedia
especial, IContributorResourceAdapter
, para este propósito. Cuando los
objetos se adaptan a IResource
en el contexto de contribuciones de objeto,
el entorno de trabajo intenta primero adaptar el recurso a
IContributorResourceAdapter
antes de intentar adaptarlo a IResource
directamente. Se ha añadido una nueva subinterfaz de esta interfaz, IContributorResourceAdapter2
,
que suministra las mismas prestaciones para ResourceMapping
.
La única diferencia consiste en que el proveedor de modelo debe registrar una fábrica
para IContributorResourceAdapter
, ya que el entorno de trabajo realiza una
comprobación instanceof para ver si el adaptador añadido es también una
instancia de IContributorResourceAdapter2
.
La implementación de la subclase ResourceMapping
para un paquete Java debe ser parecida a esta.
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)
}
}
}
Esta es una correlación bastante directa, por lo que la implementación no es compleja. Evidentemente, la complejidad de la implementación de la correlación de recursos variará en función del modelo.
Una de las ventajas de una API de correlación de recursos es que permite a los plug-ins implementar las operaciones deseadas en términos de correlaciones de recursos (por ejemplo, actualización CVS, compromiso CVS, distintivo CVS, decoración desechable. etc.). Sin embargo, la API que se ha presentado hasta ahora trata sólo con el estado local del modelo. Al trabajar con un modelo que los desarrolladores pueden compartir, se produce siempre una situación en la que el estado remoto del modelo (es decir, el estado del modelo que otro usuario ha reincorporado al repositorio) puede ser diferente del estado del espacio de trabajo. Si ha realizado una actualización CVS, deseará que el estado local del modelo coincida con el estado remoto aunque eso implique incluir archivos adicionales o eliminar algunos archivos.
Para algunos modelos lógicos, esto no representa un problema. Por ejemplo, un paquete Java es un contenedor visitado a una profundidad de uno, independientemente del estado remoto del modelo. Dada esta premisa, un proveedor de repositorio puede determinar fácilmente que deben incluirse supresiones de salida al comprometer o que deben incluirse adiciones de entrada al actualizar. Sin embargo, los recursos que constituyen algunos modelos lógicos pueden cambiar con el tiempo. Por ejemplo, los recursos que constituyen un elemento de modelo pueden depender del contenido de un archivo de manifiesto (o de algún otro mecanismo similar). Para que la correlación de recursos devuelva el cruce adecuado, debe acceder al contenido remoto del archivo de manifiesto (si es diferente del contenido local) a fin de comprobar si existen recursos adicionales que deban incluirse. Puede que estos recursos adicionales no existan en el espacio de trabajo, pero el proveedor de repositorio sabrá cómo asegurarse de que sí estaban allí cuando se ha realizado la acción seleccionada.
Para dar soporte a estos modelos más complejos, puede pasarse un RemoteResourceMappingContext
al método ResourceMapping#getTraversals
.
Si se suministra un contexto, la correlación puede utilizarlo para asegurarse de que
todos los recursos necesarios se incluyan en el cruce. Si no se suministra un contexto,
la correlación puede presuponer que sólo el estado local es de interés.
Una ResourceMapping
sólo debe preocuparse del contexto suministrado al
método getTraversals
en los casos en que los recursos que forman un modelo
cambien con el tiempo y la relación entre el modelo y los recursos no pueda describirse
mediante un cruce simple que garantice que abarcará los recursos (y sólo ellos) que
constituyen el modelo. Por ejemplo, aunque los recursos de un paquete Java pueden cambiar
con el tiempo, el paquete puede describirse como una carpeta con una profundidad de uno,
por lo que una correlación de recursos para paquetes Java no necesitará utilizar el
contexto de correlación de recursos.
Como ejemplo más complejo, considere un archivo HTML que contiene varias imágenes. Supongamos
que las referencias de imágenes de un archivo HTML forman parte del modelo de ese
archivo. Al actualizar el contenido local del archivo HTML desde el repositorio, el
usuario esperará que se incluyan las imágenes nuevas. El método getTraversals
de una ResourceMapping
para el modelo de archivo HTML será parecido al
siguiente:
public class HTMLResourceMapping extends ResourceMapping {
private HTMLFile htmlFile;
public ResourceTraversal[] getTraversals(ResourceMappingContext context,
IProgressMonitor monitor)
IResource[] resources = htmlFile.getResources();
if (context instanceof RemoteResourceMappingContext) {
// Buscar los recursos adicionales en el servidor
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)};
}
}
Observe que hay dos conjuntos de recursos incluidos en el modelo: los derivados del contenido local del archivo HTML en el espacio de trabajo y los obtenidos del contenido del archivo remoto y del archivo base. En cualquiera de estos dos conjuntos, puede haber recursos que no existan en el espacio de trabajo. Por ejemplo, el archivo HTML local puede contener un enlace relativo a una imagen que no existe en el espacio de trabajo. Este recurso debe incluirse a fin de que pueda extraerse si existe remotamente. En cuanto al archivo remoto, puede contener una copia nueva que hace referencia a imágenes adicionales que deben extraerse al descargar el contenido remoto nuevo.
Los proveedores de modelo son un medio de agrupar correlaciones de recursos relacionados. A continuación figura un enlace a la clase ModelProvider. Esta clase sirve a tres propósitos principales:
IResourceMappingMerger
del modelo se
obtiene adaptando el proveedor de modelo. A continuación figura un ejemplo de definición de extensión 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>
LibraryModelProvider
es una subclase de ModelProvider
.
La norma de habilitación se utiliza para comparar los recursos en los que el modelo de
Biblioteca (Library) es persistente. En el ejemplo anterior, el proveedor de modelo
comparará cualquier recurso de un proyecto que tenga la naturaleza library.
Una vez definido el proveedor, el método ResourceMapping#getModelProviderId()
debe alterarse temporalmente para que devuelva el ID del proveedor de modelo.
public String getModelProviderId() {
return "org.eclipse.team.examples.library.adapt.modelProvider";
}
Para obtener la correlación inversa adecuada de los recursos con la correlación de
los recursos coincidentes con la norma de habilitación del proveedor, también debe
alterar temporalmente uno de los métodos getMapping
, o ambos. El método que
necesitará alterar temporalmente depende de si el modelo contiene elementos que contienen
varios recursos. Si los elementos de modelo se correlacionan con un solo recurso, puede
alterar temporalmente el método que acepta un solo argumento IResource
. De
lo contrario, deberá alterar temporalmente el método que acepta una matriz de recursos. A
continuación figura un ejemplo de utilización de un solo recurso.
El método de ejemplo que sigue envuelve un archivo de modelo de biblioteca en una
correlación de recursos adecuada. También envuelve carpetas que contienen archivos que
son de interés para el proveedor de modelo.
public class LibraryModelProvider extends ModelProvider {
public ResourceMapping[] getMappings(IResource resource,
ResourceMappingContext context, IProgressMonitor monitor) {
if (isModelFile(resource)) {
// Devolver una correlación de recursos en el archivo
return new LibraryResourceMapping(resource);
} if (containsModelFiles(resource)) {
// Crear una correlación de recursos profunda en el contenedor
return new LibraryContainerResourceMapping(resource);
}
// El recurso no es de interés para este proveedor de modelo
return null;
}
}
A continuación, los clientes pueden acceder al proveedor de modelo para determinar si éste se preocupa se los recursos sobre los que va a operarse. La próxima sección describe la API que se suministrará a las operaciones de equipo que utilizan la API del proveedor de modelo para determinar el conjunto completo de correlaciones de recursos sobre las que debe operarse al realizar una operación de equipo sobre un conjunto de recursos o elementos de modelo seleccionados.
Las operaciones realizadas sobre los recursos deben validarse primero para garantizar que el usuario tiene conocimiento de los posibles efectos colaterales. Estos son los pasos necesarios para validar un cambio de recurso.
IResourceChangeDescriptionFactory
.
La fábrica produce un IResourceDelta
que refleja el aspecto que tendrá el
delta de recursos resultante una vez realizada la operación. ResourceChangeValidator
.
El validador consulta todos los proveedores de modelo que han registrado un interés en
los recursos afectados. El resultado es uno o varios estados que contienen el ID del
modelo originador y una descripción del posible efecto colateral de la operación sobre el
modelo.Cuando un proveedor de equipo intente una fusión autónoma, hará lo siguiente:
La infraestructura de navegador común hace posible la visualización de elementos de modelo en el contexto de una operación de equipo.
Los pasos anteriores permitirán que los modelos aparezcan en los diálogos utilizados por las operaciones del equipo. La integración en una vista previa de fusión implica algunos pasos adicionales.
En el área de historial de archivos e historial de elementos de modelo se han realizado las siguientes mejoras:
Se suministran los siguientes elementos para dar soporte al examen remoto:
Los proveedores de equipo pueden decorar elementos de modelo convirtiendo sus decoradores ligeros para que funcionen en correlaciones de recursos, del mismo modo que se convierten contribuciones de objeto para que funcionen en correlaciones de recursos. Sin embargo, existe un aspecto de la decoración de elementos de modelo lógico que es problemático. Su un elemento de modelo no tiene una correlación de uno a uno con un recurso, puede que el elemento de modelo no reciba una actualización de etiqueta cuando cambie el recurso subyacente.
Para solucionar este problema, se ha introducido
ITeamStateProvider
a fin de que los proveedores de modelo tengan acceso a los cambios de estado que pueden
afectar a los decoraciones de equipo. Además, las vistas de modelo pueden utilizar SynchronizationStateTester
para determinar cuándo deben actualizarse las etiquetas de elementos de modelo lógico.
Esta API se basa en la interfaz ITeamStateProvider
para determinar cuándo el
estado de equipo de un recurso ha cambiado y puede pasarse a un decorador de equipo como
parte de
un IDecorationContext
.