Mapa de ruta de modelos para integración de modelos lógicos

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:

  1. Adaptar elementos de modelo de las vistas de modelo a ResourceMapping para permitir que las operaciones basadas en recursos aparezcan en los elementos de modelo.
  2. Registrar un ModelProvider para asegurarse de que se consulte el modelo al realizar operaciones en los recursos relacionados con el modelo.
  3. Utilizar ResourceChangeValidator al realizar operaciones sobre los recursos para asegurarse de que el usuario conozca los posibles efectos colaterales sobre los elementos de modelo relacionados con dichos recursos.
  4. Implementar un IResourceMappingMerger para poder participar en fusiones autónomas que impliquen a los recursos relacionados con el modelo.
  5. Registrar un teamContentProvider para poder participar en visores de equipo, como por ejemplo vistas previas de fusión.
  6. Suministrar un IHistoryPageSource para mostrar el historial de modelos lógicos en la vista de historial del equipo.
  7. Utilizar la API de Sistema de archivos de Eclipse para acceder al estado remoto de los proyectos del modelo.
  8. Utilizar la API SynchronizationStateTester para garantizar una correcta decoración de los elementos de modelo que no tienen una correlación de uno a uno con los recursos.

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.

Correlaciones de recursos

La API de correlación básica de recursos

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:

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.

Adaptar un modelo a una ResourceMapping

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.

Contexto de correlación de recursos

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.

¿Cuándo debe preocuparse una ResourceMapping del RemoteResourceMappingContext?

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.

Proveedores de modelo

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:

  1. Desde un proveedor de modelo, los clientes pueden obtener partes de API adicionales para realizar operaciones sobre un conjunto de correlaciones de recursos mediante el mecanismo adaptable. Por ejemplo, el IResourceMappingMerger del modelo se obtiene adaptando el proveedor de modelo.
  2. Dado un conjunto de recursos de sistema de archivos, los clientes pueden consultar si un proveedor de modelo contiene elementos de modelo que son persistentes en dichos recursos y, si es así, obtener el conjunto de correlaciones de recursos que describen la relación.
  3. En operaciones sobre un conjunto de recursos, el validador de cambios de recurso consultará los proveedores de modelo para determinar si existen posibles efectos colaterales de una operación que los usuarios deben conocer. Esto se describe en una sección independiente relativa a la validación de cambios.

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.

Validación de cambios de recurso

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.

  1. Cree una descripción del cambio mediante IResourceChangeDescriptionFactory. La fábrica produce un IResourceDelta que refleja el aspecto que tendrá el delta de recursos resultante una vez realizada la operación.
  2. Valide los cambios mediante 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.
  3. Ponga en conocimiento del usuario los posibles efectos colaterales de los modelos que el originador de la operación desconoce. Por ejemplo, si una refactorización Java ha recibido un efecto colateral del modelo Java, puede pasarse por alto, ya que la refactorización entiende la semántica del modelo Java. Sin embargo, si se devuelve un efecto colateral desde el modelo Library, debe ponerse en conocimiento del usuario, ya que Java no conoce el modelo Library.

Fusión basada en modelo

Cuando un proveedor de equipo intente una fusión autónoma, hará lo siguiente:

  1. Obtener las correlaciones de recursos de los elementos seleccionados
  2. Determinar los proveedores de modelo implicados mediante el método ResourceMapping#getModelProvider().
  3. Ampliar el ámbito de la operación para incluir todas las correlaciones de recursos necesarias.
  4. Crear una descripción del estado de sincronización entre el local y el remoto. Esta descripción se suministra a los modelos a través de la API IMergeContext.
  5. Adaptar los proveedores de modelo a IResourceMappingMerger.
  6. Invocar el método validateMerge en cada fusionador, pasando la descripción de sincronización, para garantizar que no existe ninguna condición que impida una fusión intentada.
  7. Delegar la fusión en los fusionadores de modelo para realizar la fusión.
  8. Los proveedores de modelo pueden delegar de nuevo la fusión de archivos individuales al proveedor de equipo si sólo desean controlar el orden de la fusión, o pueden realizar la fusión ellos mismos e informar al proveedor de equipo cuando han terminado.

Contenido del modelo en vistas de operaciones de equipo

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.

Vista Historial

En el área de historial de archivos e historial de elementos de modelo se han realizado las siguientes mejoras:

Examen remoto

Se suministran los siguientes elementos para dar soporte al examen remoto:

Decorar elementos de modelo con estado de equipo

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.