Monitorizar archivos con Java

Escrito por el .
software programacion java planeta-codigo
Enlace permanente Comentarios

Java

Java a partir de la versión 7 del JDK ofrece el soporte para recibir notificaciones de cambios en el sistema de archivos sin tener que estar monitorizándolos constantemente en busca de actividad. No tener que estar monitorizando los archivos de forma «polling» para buscar cambios además de hacer que el código sea más sencillo desde el punto de vista de la programación hace que no se malgasten recursos del sistema si los cambios son esporádicos.

Para ofrecer esta funcionalidad y a partir de Java 7 hay disponibles unas pocas nuevas clases dentro de lo que se conoce como la nueva API de entrada y salida (NIO) que sustituye al método tradicional de entrada y salida con las clases del paquete java.io entre otras cosas para trabajar con el sistema de archivos.

Para monitorizar los archivos y recibir notificaciones cuando se produzcan cambios en ellos deberemos emplear las clases Path y WatchService. Empleando estas dos clases el código para monitorizar cambios en los archivos de un directorio sería: registrar el servicio de monitorización obtenido de la clase FileSystems, escuchar los eventos cuando se produzcan y procesarlos de forma secuencial en un bucle. En el ejemplo se monitoriza el archivo fuente de una clase Java que es compilado en memoria e instanciada como explicaba en el anterior artículo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package io.github.picodotdev.blogbitix.config;

import java.io.FileReader;
import java.io.Reader;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;

public class ConfiguracionManager {

	...

	public ConfiguracionManager monitor() throws Exception {
		closed = false;

		Runnable task = new Runnable() {
			@Override
			public void run() {
				while (!closed) {
					try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
						path.getParent().register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
						WatchKey watchKey = watchService.take();
						if (watchKey == null) {
							return;
						}
						for (WatchEvent<?> event : watchKey.pollEvents()) {
							Path p = (Path) event.context();							
							Path pp = path.getParent().resolve(p);
							if (path.equals(pp)) {
								load();
							}
						}
					} catch (Exception e) {
						throw new RuntimeException(e);
					}
				}
			}
		};

		thread = new Thread(task);
		thread.setDaemon(true);
		thread.start();

		return this;
	}

	...
}
ConfiguracionManager.java

En este ejemplo solo se monitorizan los cambios de los archivos pero usando otras propiedades se pueden monitorizar la eliminación y creación, en la clase StandardWatchEventKinds pueden verse estas propiedades. Una cosa a tener en cuenta es que se pueden monitorizar directorios no archivos en concreto, pero como en el ejemplo una vez que recibimos las notificaciones de monitorización es algo que podemos hacer nosotros. Ejecutando el programa una salida del su funcionamiento podría ser la siguiente en el que la clase se recarga cuando se detectan cambios en ella variando los valores que se emiten en la consola.

Salida programa Main.java

Esta funcionalidad de monitorización de cambios de archivos junto con la compilación y carga dinámica de archivos con código fuente Java puede utilizarse para hacer que la configuración de una aplicación esté definida en código Java y se cargue dinámicamente sin tener que reiniciar la aplicación. Y esto es lo que mostraré en la siguiente entrada y explicaré con más detalles que ventajas tienen esta idea.

El código fuente completo puede encontrarse en el siguiente repositorio de GitHub.


Comparte el artículo: