Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monitor file changes from Spring boot project

Tags:

spring-boot

I have this Java code which I want to use to monitor file changes into directory:

private static String folderPath = "D:\\Import";

public static void main(final String[] args) throws IOException, InterruptedException {

    System.out.println("Running file verifier");
    System.out.println("monitoring folder " + folderPath);
    EntityImportRequestsJob sql = new EntityImportRequestsJob();

    WatchService watchService = FileSystems.getDefault().newWatchService();
    Path path = Paths.get(folderPath);
    path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
    WatchKey key;

    while ((key = watchService.take()) != null) {
        for (WatchEvent<?> event : key.pollEvents()) {
            System.out.println("Event kind:" + event.kind() + ". File affected: " + event.context() + ".");
            
            if (event.kind().equals(StandardWatchEventKinds.ENTRY_DELETE)) {
                Instant start = Instant.now();

                boolean flag = true;

                while(flag) {
                    while ((key = watchService.take()) != null) {
                        HashMap<String, List> map = sql.checkFileImport();

                        List values = map.get(event.context()); // get values by file name
                        if(values.contains("Completed")){
                            // exit the monitoring while loop
                            flag = false;
                        }
                    }
                    Thread.sleep(1000);
                }

                Instant end = Instant.now();
                System.out.println(Duration.between(start,end));

                long seconds = TimeUnit.MILLISECONDS.toSeconds(Duration.between(start,end).getSeconds());
                long minutes = TimeUnit.MILLISECONDS.toMinutes(Duration.between(start,end).getSeconds());

                System.out.format("Execution time %d minutes %d seconds", minutes, seconds);
            }

        }

        key.reset();
    }

    watchService.close();
}

How I can start this code when Spring Project is successfully started?

like image 589
Peter Penzov Avatar asked Oct 18 '25 15:10

Peter Penzov


2 Answers

You can start this code when a Spring project is successfully started by creating a Bean for it and annotating it with @EventListener and ApplicationReadyEvent like this:

@Component
public class FileMonitor {
    private static String folderPath = "D:\\Import";

    @EventListener(ApplicationReadyEvent.class)
    public void startMonitoring() throws IOException, InterruptedException {
        System.out.println("Running file verifier");
        System.out.println("monitoring folder " + folderPath);
        EntitiesImportRequestsJob sql = new EntitiesImportRequestsJob();

        WatchService watchService = FileSystems.getDefault().newWatchService();
        Path path = Paths.get(folderPath);
        path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
        WatchKey key;

        while ((key = watchService.take()) != null) {
            for (WatchEvent<?> event : key.pollEvents()) {
                System.out.println("Event kind:" + event.kind() + ". File affected: " + event.context() + ".");

                if (event.kind().equals(StandardWatchEventKinds.ENTRY_DELETE)) {
                    Instant start = Instant.now();

                    boolean flag = true;

                    while(flag) {
                        while ((key = watchService.take()) != null) {
                            HashMap<String, List> map = sql.checkFileImport();

                            List values = map.get(event.context()); // get values by file name
                            if(values.contains("Completed")){
                                // exit the monitoring while loop
                                flag = false;
                            }
                        }
                        Thread.sleep(1000);
                    }

                    Instant end = Instant.now();
                    System.out.println(Duration.between(start,end));

                    long seconds = TimeUnit.MILLISECONDS.toSeconds(Duration.between(start,end).getSeconds());
                    long minutes = TimeUnit.MILLISECONDS.toMinutes(Duration.between(start,end).getSeconds());

                    System.out.format("Execution time %d minutes %d seconds", minutes, seconds);
                }

            }

            key.reset();
        }

        watchService.close();
    }
}

Make sure the FileMonitor class is in a package that is scanned by Spring.

And also make sure EntitiesImportRequestsJob is properly instantiated and managed by spring container, otherwise you will get a NullPointerException

like image 110
big Avatar answered Oct 20 '25 13:10

big


Your code looks like a constantly running background job. To run it and not block the main thread with all those watchService.take() and Thread.sleep(1000) the best approach would be to use the Spring's TaskExecutor abstraction. You'll have to wrap your code into a Runnable which then could be fed to a task executor. To launch this task I'd use an ApplicationRunner - Spring will run it after the application context is fully initialized.

Below is an example of what it might look like (uses lombok library).

Runnable:

@Slf4j
class FileVerificationTask implements Runnable {

    private static String folderPath = "D:\\Import";

    @SneakyThrows
    @Override
    public void run() {
        log.info("Running file verifier");

        // put your code here
    }
}

Launcher:

@Service
@Slf4j
public class FileVerifier implements ApplicationRunner {
    private final TaskExecutor taskExecutor;

    public FileVerifier(TaskExecutor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    @Override
    public void run(ApplicationArguments args) {
        taskExecutor.execute(new FileVerificationTask());
    }
}
like image 26
dekkard Avatar answered Oct 20 '25 13:10

dekkard