Agrupación por lotes de los cambios de recurso

Cuando sea necesario modificar recursos del área de trabajo, es importante recordar que otros conectores pueden estar trabajando con los mismos recursos. La API de recursos proporciona mecanismos robustos para mantener a los conectores informados acerca de los cambios realizados en el área de trabajo y para garantizar que varios conectores no modifiquen el mismo recurso simultáneamente. Cuando sea posible, las modificaciones realizadas por el conector en el área de trabajo deben agruparse por lotes en unidades de trabajo dentro de un ejecutable de área de trabajo. Estos ejecutables ayudan a reducir la cantidad de notificaciones de cambio generadas por los cambios. También permiten declarar qué parte del área de trabajo debe modificarse, a fin de evitar que otros conectores cambien la misma parte del área de trabajo.

El protocolo de IWorkspaceRunnable es bastante sencillo. Un ejecutable de área de trabajo tiene el mismo aspecto que una operación de larga ejecución o un trabajo de plataforma. El trabajo real se ejecuta dentro de un método run, y el progreso se notifica al IProgressMonitor suministrado. El código que manipula el área de trabajo se ejecuta dentro del método run.

IWorkspaceRunnable myRunnable = 
        new IWorkspaceRunnable() {
		public void run(IProgressMonitor monitor) throws CoreException {
			//realizar aquí el trabajo real
			...
		}
}

Cuando llega el momento de ejecutar el código, el conector indica al área de trabajo que ejecute el código en su nombre. De este modo, el área de trabajo puede generar los eventos de cambio necesarios y asegurarse de que no haya dos conectores que modifiquen el mismo recurso simultáneamente. (Aunque el conector no utilice trabajos de segundo plano y la infraestructura de concurrencia para modificar el área de trabajo, puede que otros conectores lo estén haciendo).

Normas de planificación y bloqueo

El protocolo IWorkspace se utiliza para ejecutar un ejecutable de área de trabajo. La técnica preferida consiste en utilizar el formato largo del método run, que suministra una norma de planificación y especifica cómo se transmiten los eventos de cambio de recurso.

La especificación de una norma de planificación al ejecutar un ejecutable de área de trabajo permite a ésta determinar si los cambios de recurso entrarán en conflicto con los cambios de área de trabajo ocurridos en otras hebras. (Consulte la sección Normas de planificación para obtener una visión general de las normas de planificación y del protocolo ISchedulingRule). Afortunadamente, el protocolo IResource incluye el protocolo para ISchedulingRule, lo que significa que un recurso puede utilizarse con frecuencia como norma de planificación para sí mismo.

¿Confundido? El código puede ayudar a clarificar este punto. Supongamos que el conector se está preparando para modificar un grupo de recursos de un proyecto determinado. Puede utilizar el propio proyecto como norma de planificación para realizar los cambios. El siguiente fragmento de código ejecuta el ejecutable de área de trabajo que hemos creado anteriormente:

    IWorkspace workspace = ResourcesPlugin.getWorkspace();
workspace.run(myRunnable, myProject, IWorkspace.AVOID_UPDATE, null);

El ejecutable se pasa al área de trabajo, seguido del proyecto que el código está manipulando. Esto índica al área de trabajo que todos los cambios del ejecutable se encuentran en myProject. Las peticiones de cambio de myProject realizadas por otras hebras quedarán bloqueadas hasta que finalice este ejecutable. Del mismo modo, esta llamada quedará bloqueada si alguna otra hebra ya está modificando myProject. Al especificar qué parte del árbol de recursos modificará el ejecutable, se permite a otras hebras continuar modificando otras partes del área de trabajo. Es importante asegurarse de que la norma de recurso coincide con el trabajo realizado dentro del ejecutable. Cualquier intento de acceder a un recurso situado fuera del ámbito de la norma de planificación desencadenará una excepción.

El tercer parámetro del método run especifica si los eventos de cambio de recurso periódico deben transmitirse durante el ámbito de esta llamada. La utilización de IWorkspace.AVOID_UPDATE indica a la plataforma que suprima los eventos de cambio de recurso mientras el ejecutable se esté ejecutando y que transmita un evento al final de los cambios. Durante esta llamada, los demás ejecutables creados en el ejecutable se considerarán parte de la operación por lotes padre. Los cambios de recurso efectuados en estos ejecutables aparecerán en la notificación de cambio de recurso del padre.

Fábrica de normas de recurso

En el ejemplo anterior, se presuponía que el código del ejecutable sólo modificaba recursos de un proyecto determinado. Esto facilitaba mucho la especificación de una norma de planificación para el ejecutable. En la práctica, puede ser más difícil calcular qué partes del área de trabajo resultan afectadas por un cambio determinado. Por ejemplo, el movimiento de un recurso de un proyecto a otro afecta a ambos proyectos. Puede utilizarse IResourceRuleFactory para facilitar el cálculo de una norma de recurso adecuada para determinados tipos de cambios de recursos. Puede obtener una fábrica de normas de recurso de la propia área de trabajo.

    IWorkspace workspace = ResourcesPlugin.getWorkspace();
IResourceRuleFactory ruleFactory = workspace.getRuleFactory();

La fábrica puede suministrar normas adecuadas para muchos tipos de operaciones. Si el ejecutable mueve un recurso de una ubicación a otra, puede obtener una norma adecuada para esta operación:

ISchedulingRule movingRule = ruleFactory.moveResource(sourceResource, destinationResource);
workspace.run(myRunnable, movingRule, IWorkspace.AVOID_UPDATE, null);

Consulte el javadoc de IResourceRuleFactory para obtener la lista de normas disponibles. El conector de recursos utiliza estas normas para implementar la mayoría de operaciones de recursos. El examen del código que hace referencia a estos métodos de norma ayudará a mostrar cómo se utilizan en la práctica.

Pueden combinarse varias normas mediante MultiRule.

ISchedulingRule movingRule = ruleFactory.moveResource(sourceResource, destinationResource);
ISchedulingRule modifyRule = ruleFactory.modifyResource(destinationResource);
workspace.run(myRunnable, MultiRule.combine(movingRule, modifyRule), IWorkspace.AVOID_UPDATE, null);

Ignorar las normas

También está disponible el formato corto del método run en IWorkspace. Se conserva a efectos de compatibilidad hacia atrás. El formato corto no incluye una norma ni un indicador de actualización.

workspace.run(myRunnable, null);

es en realidad lo mismo que llamar a

workspace.run(myRunnable, workspace.getRoot(), IWorkspace.AVOID_UPDATE, null);

Al especificar el directorio raíz del área de trabajo como norma de planificación, se colocará un bloqueo sobre toda el área de trabajo hasta que finalice el ejecutable. Esta es la forma más conservadora de realizar una actualización del área de trabajo, pero no es muy adecuada para otros conectores pensados para la concurrencia.