From dd7bd4453364b77861e875ce40313658e01bf37b Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Mon, 22 Apr 2019 00:07:26 -0700 Subject: [PATCH 1/2] + Added directory monitor and Monitored File --- src/core/DirectoryMonitor.java | 158 ++++++++++++++++++++++++++ src/dataStructures/MonitoredFile.java | 37 ++++++ 2 files changed, 195 insertions(+) create mode 100644 src/core/DirectoryMonitor.java create mode 100644 src/dataStructures/MonitoredFile.java diff --git a/src/core/DirectoryMonitor.java b/src/core/DirectoryMonitor.java new file mode 100644 index 0000000..86ff654 --- /dev/null +++ b/src/core/DirectoryMonitor.java @@ -0,0 +1,158 @@ +package core; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import dataStructures.MonitoredFile; + +public class DirectoryMonitor +{ + private void Log(String s) { System.out.println("[Log] " + s); } + private void Warn(String s) { System.out.println("[Warn] " + s); } + private void Error(String s) { System.out.println("[ERROR] " + s); } + + private String directory; + private ArrayList last; + + // Constructs a new file monitor and logs initialization + public DirectoryMonitor(String directory) + { + Log("Reading initial file set in: " + directory.toString()); + + this.directory = directory; + this.last = Scrape(); + + Print(last); + } + + // Check when a file was last modified by path + private Long LastModified(Path path) + { + File file = new File(path.toString()); + + if(file.exists()) + { + return file.lastModified(); + } + else + { + Error("File does not exist."); + return null; + } + } + + // Scrape the target directory for all files and store them as custom objects in the list + private ArrayList Scrape() + { + ArrayList files = new ArrayList(); + + try + { + try (Stream paths = Files.walk(Paths.get(directory))) + { + paths.filter(Files::isRegularFile).forEach((path)-> + { + files.add(new MonitoredFile(path, LastModified(path))); + }); + } + } + catch(Exception e) + { + Error(e.getMessage()); + } + + return files; + } + + // Update function - the first callback is called if a new item is added to the directory, + // second is called if an item is updated, and third is called if an item is removed. + @SuppressWarnings("unchecked") + public void Update(Consumer onAdd, Consumer onUpdate, Consumer onDelete) + { + // Unparsed + ArrayList active = Scrape(); + ArrayList curr = (ArrayList)active.clone(); + ArrayList prev = (ArrayList)last.clone(); + + // Parsed + ArrayList added = new ArrayList(); + ArrayList updated = new ArrayList(); + ArrayList deleted = new ArrayList(); + ArrayList existing = new ArrayList(); + + // Iterate over everything + for(int i = 0; i < active.size(); ++i) + { + // If we contain the previous, remove it. + if(prev.contains(active.get(i))) + { + MonitoredFile item = active.get(i); + + prev.remove(item); + curr.remove(item); + existing.add(item); + } + + // Check all other cases + for(int j = 0; j < prev.size(); ++j) + { + MonitoredFile l1 = active.get(i); + MonitoredFile l2 = prev.get(j); + + // Check if item is updated. + if(l1.path.toString().equals(l2.path.toString())) + { + updated.add(l1); + prev.remove(l2); + curr.remove(l1); + onUpdate.accept(l2); + } + } + } + + // Anything that wasn't removed from prev has been removed. + for(int j = 0; j < prev.size(); ++j) + { + MonitoredFile item = prev.get(j); + + deleted.add(item); + onDelete.accept(item); + } + + prev.clear(); + + // Add all the remaining things in the current directory as added items. + for(int i = 0; i < curr.size(); ++i) + { + MonitoredFile item = curr.get(i); + + added.add(item); + onAdd.accept(item); + } + + // Rebuild local state + last.clear(); + last.addAll(existing); + last.addAll(added); + last.addAll(updated); + Collections.sort(last); + + if(last.size() == 0) + Warn("There's nothing at all in a FileMonitor's target folder!"); + } + + // Prints out an arraylist of items from a directory by path + private void Print(ArrayList toPrint) + { + for(int i = 0; i < toPrint.size(); ++i) + Log(toPrint.get(i).path.toString()); + } +} diff --git a/src/dataStructures/MonitoredFile.java b/src/dataStructures/MonitoredFile.java new file mode 100644 index 0000000..ae53ca3 --- /dev/null +++ b/src/dataStructures/MonitoredFile.java @@ -0,0 +1,37 @@ +package dataStructures; + +import java.nio.file.Path; + +public class MonitoredFile implements Comparable +{ + public final Path path; + public final Long lastModified; + + public MonitoredFile(Path path, Long lastModified) + { + this.path = path; + this.lastModified = lastModified; + } + + // Override equals operator - used for .contains(...) on list items + @Override + public boolean equals(Object other) + { + if(this.compareTo(other) == 0) + return true; + + return false; + } + + @Override + // Comparison + public int compareTo(Object other) + { + int strCmp = path.getFileName().toString().compareTo(((MonitoredFile)other).path.getFileName().toString()); + + if(strCmp == 0) + return lastModified.compareTo(((MonitoredFile)other).lastModified); + + return strCmp; + } +} From 291f70b2aef385676ed6d01c93e08c9cc6f60cb3 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Mon, 22 Apr 2019 00:59:08 -0700 Subject: [PATCH 2/2] = Updated directory monitor to remove warnings and improve logging --- src/{core => utils}/DirectoryMonitor.java | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) rename src/{core => utils}/DirectoryMonitor.java (86%) diff --git a/src/core/DirectoryMonitor.java b/src/utils/DirectoryMonitor.java similarity index 86% rename from src/core/DirectoryMonitor.java rename to src/utils/DirectoryMonitor.java index 86ff654..59a80e8 100644 --- a/src/core/DirectoryMonitor.java +++ b/src/utils/DirectoryMonitor.java @@ -1,11 +1,9 @@ -package core; +package utils; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.function.Consumer; @@ -13,19 +11,23 @@ import java.util.stream.Stream; import dataStructures.MonitoredFile; +// NOTE: Consider shifting internal behavior to https://docs.oracle.com/javase/tutorial/essential/io/notification.html +// for external stability and support public class DirectoryMonitor { - private void Log(String s) { System.out.println("[Log] " + s); } - private void Warn(String s) { System.out.println("[Warn] " + s); } - private void Error(String s) { System.out.println("[ERROR] " + s); } + // Logging + private void Log(String s) { GlobalLog.Log(LogFilter.Util, s); } + private void Warn(String s) { GlobalLog.Warn(LogFilter.Util, s); } + private void Error(String s) { GlobalLog.Error(LogFilter.Util, s); } + // Variables private String directory; private ArrayList last; // Constructs a new file monitor and logs initialization public DirectoryMonitor(String directory) { - Log("Reading initial file set in: " + directory.toString()); + Log("Reading directory files for montioring in: " + directory.toString()); this.directory = directory; this.last = Scrape(); @@ -44,7 +46,7 @@ public class DirectoryMonitor } else { - Error("File does not exist."); + Error("File looking for doesn't exist for directory monitor at path: " + path); return null; } } @@ -146,7 +148,7 @@ public class DirectoryMonitor Collections.sort(last); if(last.size() == 0) - Warn("There's nothing at all in a FileMonitor's target folder!"); + Warn("There's nothing at all in a FileMonitor's target folder! Folder: " + directory); } // Prints out an arraylist of items from a directory by path