how to watch multiple hard disk partitions in FileWacther in java - java

I am using FileWatcher to watch a whole hard disk partition in my case its D drive eg: D:/ the code is working fine with one path i provided, all i want is to watch other hard disk partitions as well like C:,D: and E: how can i achieve that here is the code
public class FileWatcher {
private final WatchService watcher;
private final Map<WatchKey, Path> keys;
static Logger log = LoggerFactory.getLogger(GitCloneRepo.class);
/**
* Creates a WatchService and registers the given directory
*/
FileWatcher(Path dir) throws IOException {
this.watcher = FileSystems.getDefault().newWatchService();
this.keys = new HashMap<WatchKey, Path>();
walkAndRegisterDirectories(dir);
}
/**
* Register the given directory with the WatchService; This function will be called by FileVisitor
*/
private void registerDirectory(Path dir) throws IOException
{
WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
keys.put(key, dir);
}
/**
* Register the given directory, and all its sub-directories, with the WatchService.
*/
private void walkAndRegisterDirectories(final Path start) throws IOException {
// register directory and sub-directories
Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
registerDirectory(dir);
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
if (exc instanceof AccessDeniedException) {
return FileVisitResult.SKIP_SUBTREE;
}
return super.visitFileFailed(file, exc);
}
});
}
/**
* Process all events for keys queued to the watcher
*/
void processEvents() {
for (;;) {
// wait for key to be signalled
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException x) {
log.error("InterruptedException ",x);
return;
}
Path dir = keys.get(key);
if (dir == null) {
log.warn("WatchKey not recognized!!");
continue;
}
for (WatchEvent<?> event : key.pollEvents()) {
#SuppressWarnings("rawtypes")
WatchEvent.Kind kind = event.kind();
// Context for directory entry event is the file name of entry
#SuppressWarnings("unchecked")
Path name = ((WatchEvent<Path>)event).context();
Path child = dir.resolve(name);
log.info("watching files");
// print out event
if (kind == ENTRY_MODIFY) {
log.info("event.kind().name() {}: child {}", event.kind().name(), child);
log.info("child {} ends with docx? {} ",child,child.endsWith(".docx"));
String c= child.toString();
log.info("**child {}***c.endsWith(.docx)"
+ ""
+ " {}",c,c.endsWith(".docx"));
}
// if directory is created, and watching recursively, then register it and its sub-directories
if (kind == ENTRY_CREATE) {
try {
if (Files.isDirectory(child)) {
walkAndRegisterDirectories(child);
}
} catch (IOException x) {
// do something useful
}
}
}
// reset key and remove from set if directory no longer accessible
boolean valid = key.reset();
if (!valid) {
keys.remove(key);
// all directories are inaccessible
if (keys.isEmpty()) {
break;
}
}
}
}
//working code
public static void main(String[] args) throws IOException {
try{
Path dir = Paths.get("D:");
FileWatcher fileWatcher=new FileWatcher(dir);
fileWatcher.processEvents();
}
catch (AccessDeniedException xx) {
log.error("AccessDeniedException ",xx);
}
catch (FileSystemException x) {
log.error("exception",x);
}
}
}
i looked at this question but i did not seemed to solve my problem
How to implement file watcher to Watch multiple directories

Your processEvents method enters an infinite loop and doesn't return until either the thread is interrupted or the path is gone, which means any code after processEvents won't execute until it's done. If you want your main method to spin up multiple watchers, you'll need to call processEvents from other threads, e.g. with Java 8:
// Create watchers
List<FileWatcher> watchers = new ArrayList<>();
try{
watchers.add(new FileWatcher(Paths.get("D:")));
watchers.add(new FileWatcher(Paths.get("E:")));
} catch (AccessDeniedException xx) {
log.error("AccessDeniedException ",xx);
} catch (FileSystemException x) {
log.error("exception",x);
}
// Create and start threads
List<Thread> threads = watchers.stream()
.map(w -> new Thread(w::processEvents))
.peek(Thread::start)
.collect(Collectors.toList());
With Java 7:
// Create watchers
List<FileWatcher> watchers = new ArrayList<>();
try{
watchers.add(new FileWatcher(Paths.get("D:")));
watchers.add(new FileWatcher(Paths.get("E:")));
} catch (AccessDeniedException xx) {
log.error("AccessDeniedException ",xx);
} catch (FileSystemException x) {
log.error("exception",x);
}
// Create and start threads
List<Thread> threads = new ArrayList<>();
for (FileWatcher watcher : watchers) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
watcher.processEvents();
}
});
thread.start();
threads.add(thread);
}

Related

Prevent Java FileWatcher to process the same file multiple times

I'm using Java WatchEvent to monitor an external process that creates an external file.
Java create multiple events until the file is eventually completed while the external process is creating the file:
Event kind:ENTRY_CREATE. File affected: fileArticoli (16).zip.
Event kind:ENTRY_MODIFY. File affected: fileArticoli (16).zip.
Event kind:ENTRY_MODIFY. File affected: fileArticoli (16).zip.
Event kind:ENTRY_MODIFY. File affected: fileArticoli (16).zip.
I need to be awaken at the end of the process when the file creation is done.
I'm exploring Java RX
PublishSubject<WatchEvent> fsEvents = PublishSubject.create();
fsEvents.subscribe(this);
...
fsEvents.onNext(event);
I'm searching for a JavaRx function similar to debounce that triggers when no new events have been triggered for a period of time es. 2000ms.
Is there such a function in java RX?
Here is a minimal example
#Component
public class FileWatcherComponent implements Action1<WatchEvent> {
Logger logger = Logger.getLogger("Upload Ordini");
#Value("${app.ecommerce.dirOrdini}")
String orderDir;
WatchService watchService;
Path path;
#PostConstruct
public void init(){
new Thread(()->{
PublishSubject<WatchEvent> fsEvents = PublishSubject.create();
fsEvents.throttleWithTimeout(2, TimeUnit.SECONDS).subscribe(this);
if (StringUtils.isNotEmpty(orderDir)){
try {
watchService = FileSystems.getDefault().newWatchService();
path = Paths.get(orderDir);
path.register(watchService,ENTRY_MODIFY);
WatchKey key;
while ((key = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
fsEvents.onNext(event);
}
key.reset();
}
} catch (Exception e) {
logger.config(e.getMessage());
e.printStackTrace();
}
}
}).start();
}
#Override
public void call(WatchEvent event) {
logger.config( "File affected: " + event.context() + ".");
//Process the file
}
}
Eventually in order avoid to process the same file multiple times I used a different approach. Each file can be processed after 2000 ms. The class tries to process all file in a map (mFiles) every 500ms.
Hope the some may take advantage of this solution.
The file is placed in the map by filewatcher and remove after processing.
#Component
public class FileWatcherComponent{
public static final long DELAY = 2000L;
#Value("${app.ecommerce.dirOrdini}")
String orderDir;
WatchService watchService;
Path path;
Map<String, Long> mFiles = new HashMap<>();
#PostConstruct
public void init(){
new Thread(()->{
if (StringUtils.isNotEmpty(orderDir)){
try {
watchService = FileSystems.getDefault().newWatchService();
path = Paths.get(orderDir);
path.register(watchService,ENTRY_MODIFY);
WatchKey key;
while ((key = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
mFiles.put(event.context()+"", (new Date()).getTime());
}
key.reset();
}
} catch (Exception e) {}
}
}).start();
}
#Scheduled(fixedRate = 500)
public void processFiles(){
long startfrom = (new Date()).getTime() - DELAY;
for (String fname : mFiles.keySet()) {
if (mFiles.get(fname) < startfrom){
new Thread(()->{
try {
processFile(fname);
} catch (Exception e){
logger.config(e.getMessage());
e.printStackTrace();
}
mFiles.remove(fname);
}).start();
}
}
}
public void processFile(String fileName) throws Exception{
//TODO process file
}
}
This solution is based on Spingboot for class init and scheduling.

stop watcher service on application quit

I use gradle and application plugin to run the application that watches the changes in the directory.
My main class looks like this
public static void main(String[] args) throws IOException {
WatcherThread thread = new WatcherThread(EXTENSION_FOLDER);
thread.start();
try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
String input = null;
ConsoleInputController controller = new ConsoleInputController(br);
while (!QUIT_COMMAND.equals(StringUtils.trim(input))) {
System.out.println(CONSOLE_TEMPLATE);
System.out.println("input (to exit write [quit]):> ");
input = br.readLine();
controller.handleInput(input);
}
} catch (IOException exc) {
LOGGER.error("Failed to process input.", exc);
}
thread.stopThread();
}
WatcherThread is a thread class that uses WatcherService (some wrapper over WatchService of java)
public class WatcherThread extends Thread {
private static final Logger LOGGER = LoggerFactory.getLogger(WatcherThread.class);
private boolean watch = true;
private WatcherService watcherService;
public WatcherThread(String searchingPath) throws IOException {
watcherService = new WatcherService(Paths.get(searchingPath));
}
#Override
public void run() {
LOGGER.info("Artifact watching thread started.");
while(watch) {
if (!watcherService.watch()) {
break;
}
}
LOGGER.info("Artifact watching thread stopped.");
}
public void stopThread() {
watch = false;
}
}
WatcherService looks like this
public class WatcherService {
private static final Logger LOGGER = LoggerFactory.getLogger(WatcherThread.class);
private final WatchService watcher;
private final Map<WatchKey, Path> keys;
private boolean trace;
WatcherService(Path dir) throws IOException {
watcher = FileSystems.getDefault().newWatchService();
keys = new HashMap<>();
register(dir);
trace = true;
}
private void register(Path dir) throws IOException {
WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
if (trace) {
Path prev = keys.get(key);
if (null == prev) {
LOGGER.info("Register path: [{}].", dir);
} else {
if (!dir.equals(prev)) {
LOGGER.info("Updated path: [{}] -> [{}].", prev, dir);
}
}
}
keys.put(key, dir);
}
boolean watch() {
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException exc) {
return false;
}
Path dir = keys.get(key);
if (null == dir) {
LOGGER.warn("WatchKey is not recognized!");
return false;
}
// forEach?
for (WatchEvent event: key.pollEvents()) {
LOGGER.info("Polling events");
WatchEvent.Kind kind = event.kind();
if (OVERFLOW == kind) {
continue;
}
WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path name = ev.context();
Path child = dir.resolve(name);
LOGGER.info("Event occurred [{}] in [{}].", event.kind().name(), child);
WatchEventResolver.resolveEvent(ev, child);
}
boolean valid = key.reset();
if (!valid) {
keys.remove(key);
if (keys.isEmpty()) {
return false;
}
}
return true;
}
}
When I do not start my WatcherThread - console input works fine. I can quit for example without problems. But when I run thread and want to quit, it is waiting for couple of seconds and then only ends.
As far as I understand it is something with WatchService that cannot stop watching the directory.
How to stop it on quit application immediately?
It looks like you need an extra method in your WatcherService class, that calls to watcher.close(). Then, in your WatcherThread class you can call to that method inside stopThread().
In the Javadoc for WatchService you can see that take() keeps waiting. You can force it to finish by closing it.

Divide all the files present in the directory/folder to different thread for faster execution

I got a program in which I have to write two thread that will perform same operation on the files present in a particular folder. That operation is to read all the files in that folder and then delete all of them present there. These two thread will have same operation but just to increase the process time I have to divide the files between two thread so that execution time is saved. I tried this way but it is not dividing the no. of files between threads but takes all the files and do the operation and if the file is deleted by one thread then other thread should not pick that file up. The code I wrote is:
public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(2);
service.submit(new thread1());
service.submit(new thread2());
service.shutdown();
service.awaitTermination(1, TimeUnit.DAYS);
System.exit(0);
}
public static class thread1 implements Callable<Object> {
#Override
public Object call() throws Exception {
t1();
return null;
}
}
public static class thread2 implements Callable<Object> {
#Override
public Object call() throws Exception {
t1();
return null;
}
}
public static void t1() {
Path myDir = Paths.get("D:/Astha/");
File file = new File("D:/Astha/");
boolean running = true;
while (running) {
try {
WatchService watcher = myDir.getFileSystem().newWatchService();
myDir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
WatchKey watckKey = watcher.take();
List<WatchEvent<?>> events = watckKey.pollEvents();
for (#SuppressWarnings("rawtypes")
WatchEvent event : events) {
if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
System.out.println("Created: " + event.context().toString() + "By "
+ Thread.currentThread().getName());
}
}
if (file.exists()) {
File[] files = file.listFiles();
for (File f : files) {
if (f.delete()) {
System.out.println("Deleting the file: " + f.getName() + "By "
+ Thread.currentThread().getName());
}
}
} else {
System.out.println("No files in the folder");
}
} catch (Exception e) {
System.out.println("Error: " + e.toString());
}
}
}
In this above program, I also need to apply lock on one thread so that no other thread can perform operation on that. How do I implement lock here?
Based on your (updated) code, you have two basic task. You have a "watch" task and you have a "process" task
WatcherService
The WatcherService basically takes a Path and a ExecutorService, it monitors the given path and creates new FileTask tasks
public class WatcherService implements Callable<Object> {
private Path path;
private ExecutorService service;
public WatcherService(Path path, ExecutorService service) {
this.path = path;
this.service = service;
}
#Override
public Object call() throws Exception {
do {
try {
WatchService watcher = path.getFileSystem().newWatchService();
path.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
WatchKey watckKey = watcher.take();
List<WatchEvent<?>> events = watckKey.pollEvents();
for (#SuppressWarnings("rawtypes") WatchEvent event : events) {
WatchEvent<Path> we = (WatchEvent<Path>)event;
service.submit(new FileTask(we.context()));
}
} catch (IOException | InterruptedException exp) {
exp.printStackTrace();
}
} while (true && !Thread.currentThread().isInterrupted());
return null;
}
}
FileTask
The FileTask takes a Path and performs some operation upon it
public class FileTask implements Callable<Object> {
private Path path;
public FileTask(Path file) {
this.path = file;
}
#Override
public Object call() throws Exception {
File file = path.toFile();
if (file.exists()) {
if (file.delete()) {
//...
}
}
return null;
}
}
Hooking it up
Basically, you create a ExecutorService and submit a WatcherService and let it run...
Path path = Paths.get("D:/Astha/");
ExecutorService service = Executors.newFixedThreadPool(3);
service.submit(new WatcherService(path, service));
This creates a pooled service of three threads, one for the watcher and two for the FileTasks
You may find that this still does not offer you any benefit, as the disk I/O won't allow multiple operations to carried out in parallel and will block until the first operation completes before the next can be carried out
You could put all Files to edit in a HashSet or Map.
private static volatile Set<String> filenames;
If one of your threads is able to get the next File, use a synchronized Method to deliver it.
public synchronized String getNextMessage() {
if(filenames.size()<1) {
return null;
} else {
final String result = filenames.get(0);
filenames.remove(0);
return result;
}
Instead of a String, you could also use File, URI or Path, depending on your needs.

Directory watch, locked files

I´m try to build a application which, by threads, are listening to directory for changes. Everything works fine, but there is a little bug. I´m very new to the whole threads-thing... So, this problem probably based on my ignorance...
The program can se all the changes in the picked directory, BUT, when the threads are running, i cant modify the files inside the directory... Those are locked in the process...
I will be very happy if someone perhaps can give me some tips in how i can solve this.
Thank you in advance
DirWatch
public class DirWatch implements Runnable{
Path dirPath;
private boolean run = true;
private boolean created = false;
private boolean modified = false;
private boolean compressed = false;
private boolean isJSON = false;
/**
*
* #param path
* #throws IOException
*/
public void setWatchPath(String path) throws IOException {
dirPath = Paths.get(path);
try {
Boolean isFolder = (Boolean) Files.getAttribute(dirPath, "basic:isDirectory", new LinkOption[]{NOFOLLOW_LINKS});
if (!isFolder) {
throw new IllegalArgumentException("Path: " + dirPath + " is not a folder");
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
System.out.println("Watching path: " + path);
}
public void setDirPathWatchRun(boolean run){
this.run = run;
}
public boolean isCreated() {
return created;
}
public void setCreated(boolean created) {
this.created = created;
}
public boolean isModified() {
return modified;
}
public void setModified(boolean modified) {
this.modified = modified;
}
public boolean isCompressed() {
return compressed;
}
public void setCompressed(boolean compressed) {
this.compressed = compressed;
}
public boolean isJSON() {
return isJSON;
}
public void setJSON(boolean JSON) {
isJSON = JSON;
}
private void checkFileType(String fileName){
String extension = fileName.substring(fileName.length() - 4);
if(extension.equalsIgnoreCase(FILE_TYPE.TAR.getFileType())){
setCompressed(true);
System.out.println(extension);
}
if(extension.equalsIgnoreCase(".json")){
setJSON(true);
}
}
#Override
public void run() {
FileSystem fs = dirPath.getFileSystem ();
try(WatchService service = fs.newWatchService()) {
dirPath.register(service, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
WatchKey key = null;
while(run) {
key = service.take();
WatchEvent.Kind<?> kind = null;
for(WatchEvent<?> watchEvent : key.pollEvents()) {
kind = watchEvent.kind();
if (OVERFLOW == kind) {
System.out.println("OVERFLOW");
continue;
} else if (ENTRY_CREATE == kind) {
System.out.println("New path created: " + watchEvent.context().toString());
setCreated(true);
checkFileType(watchEvent.context().toString());
} else if (ENTRY_DELETE == kind){
System.out.println("Path deleted: " + watchEvent.context().toString());
setModified(true);
checkFileType(watchEvent.context().toString());
} else if (ENTRY_MODIFY == kind) {
System.out.println("Path modified: " + watchEvent.context().toString());
setModified(true);
checkFileType(watchEvent.context().toString());
}
}
if(!key.reset()) {
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Method Watch in another class
private void watch() throws IOException {
watchJSON = new DirWatch();
watchTAR = new DirWatch();
watchTAR.setWatchPath(serverArgs.getCompressedPath());
watchJSON.setWatchPath(serverArgs.getExtractedPath());
Runnable checkSourceActions = new Runnable() {
#Override
public void run() {
while(true) {
if (watchJSON.isCreated() || (watchJSON.isModified())) {
server();
}
if(watchTAR.isCreated() || (watchTAR.isModified())) {
extractFiles(fileHandler);
createManifest(fileHandler);
server();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread thread1 = new Thread(watchJSON);
Thread thread3 = new Thread(watchTAR);
Thread thread2 = new Thread(checkSourceActions);
thread1.start();
thread2.start();
thread3.start();
}
When I try to change the file while the program is running

Java watching directory is giving me wrong file path for events

I am using JDK7 "Watching a Directory for Changes" feature. But i found that sometimes it is giving me wrong file path for a particular event on file. Even though the file name is correct. I am facing this problem in fedora and ubuntu
Has some one else has faced the same problem.
Steps to reproduce:
Download and extract the zip from https://dl.dropboxusercontent.com/u/39897681/code/fileOperation.zip for generating files. Please configure it to generate files by reading the README.txt
Run the Sample java code by giving a empty source folder and a file[for log purpose] as a input. And wait for some time
Run the Main.py from the downloaded content by configuring it so that it generated files and folders.
The java program will display the list of files that was present on the disk but not in the list [list generated from the files events received from the watch directory]
Initally the java output is i.e not events are lost
Program Output
Pending file count=2398
No files are missed
#
But we end up missing some events for files or get wrong path after some time
Pending file count=4552
findFilesPresentOnDiskButNotInList
The files that have been missed are
/data/home/developer/test/folder_0.689628351684/folder_0.0451760705904/folder_0.000447662431096/folder_0.264689686702/folder_0.849536150754/folder_0.216092330336/folder_0.677792564103/folder_0.796242073532
#
Here the folder_0.0451760705904 is created with absolute path /data/home/developer/test/folder_0.689628351684/folder_0.0451760705904 but in the log file it is printing some other path for the folder.
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.AccessDeniedException;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
public class DirectoryWatcher implements Runnable {
// list of files whose events were received during creation,modification and delete operation
public static List<String> filesList = new ArrayList<String>();
// list of source folder path that we want to monitor
public static List<Path> srcPaths;
private WatchService watcher;
private Map<WatchKey, Path> keys;
private String module = "DirectoryWatcher-";
private boolean trace = false;
FilesetSimpleFileVisitor SFRFileVisitor = new FilesetSimpleFileVisitor();
/**
* Points to the log file which contains all the information about the
* events received by directory watcher. Any event that is received by
* directory watcher is logged into this file with the type of event. eg
* CREATE <full file path>
*/
public static String LOG_FILE_PATH = null;
public static PrintWriter logFileWriter = null;
public DirectoryWatcher(List<Path> srcPaths) throws IOException {
super();
this.srcPaths = srcPaths;
initWatchService();
registerTopLevelSrcFolder();
new Thread(this).start();
}
#SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
return (WatchEvent<T>) event;
}
private void initWatchService() throws IOException {
watcher = FileSystems.getDefault().newWatchService();
keys = Collections.synchronizedMap(new HashMap<WatchKey, Path>());
}
private void registerTopLevelSrcFolder() throws IOException {
for (Path dir : srcPaths) {
try {
// logger.print(logger.INFO, logger.PFR,
// "registerTopLevelSrcFolder",
// "Top level directory to be registered is " + dir);
System.out.println("Top level directory to be registered is "
+ dir);
register(dir);
// doScan(dir);
// scanAllFilesOnly(dir);
} catch (AccessDeniedException e) {
e.printStackTrace();
} catch (NoSuchFileException e) {
e.printStackTrace();
}
}
}
/**
* Exception Register the given directory with the WatchService
*/
private void register(Path dir) throws IOException {
final String subModule = module + "register";
File file = dir == null ? null : dir.toFile();
if (file == null || !file.exists()) {
return;
}
WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE,
ENTRY_MODIFY);
if (trace) {
Path prev = keys.get(key);
if (prev == null) {
} else {
if (!dir.equals(prev)) {
addToScannedListOnDirRename(file, true);
}
}
}
keys.put(key, dir);
}
/**
* On rename of a directory it adds all the child folders and files.
*
* #param dir
* #throws PFRScanFailedException
*/
/**
* On rename of a directory it adds all the child folders and files.
*
* #param dir
* #throws PFRScanFailedException
*/
private void addToScannedListOnDirRename(File dir, boolean rename)
throws IOException {
// System.out.println("addToScannedListOnDirRename" + dir);
String subModule = module + "addToScannedListOnDirRename";
try {
if (dir.isDirectory()) {
if (!rename) {
try {
register(Paths.get(dir.getAbsolutePath()));
} catch (NoSuchFileException e1) {
// consume.
}
}
File[] files = dir.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file == null) {
continue;
}
// doScan(file);
if (file.isDirectory()) {
addToScannedListOnDirRename(file, rename);
}
}
}
} finally {
}
}
boolean closed = false;
private String uniqueFSName = "directoryWatcher";
public void close() {
if (closed) {
return;
}
String subModule = module + "close";
try {
if (watcher != null) {
watcher.close();
}
} catch (IOException e) {
} finally {
freeResources();
}
closed = true;
}
private void freeResources() {
watcher = null;
if (keys != null) {
keys.clear();
}
// logger.print(logger.VERBOSE, logger.PFR,
// "DirectoryWatcher-freeResources ",
// "end of Directory Watcher. Freeing up resources");
}
private void DirectoryWatcherCore() {
String subModule = module + "DirectoryWatcherCore";
// enable trace after initial registration
trace = true;
for (;;) {
// wait for key to be signalled
try {
WatchKey key = null;
try {
key = watcher.take();
} catch (InterruptedException x) {
x.printStackTrace();
return;
} catch (ClosedWatchServiceException x) {
x.printStackTrace();
return;
}
if (key == null) {
System.out.println("key is nulllllllllllllllllllllll");
}
Path dir = keys.get(key);
// System.out.println("**********" + dir);
if (dir == null) {
// logger.print(logger.ERROR, logger.PFR, subModule,
// "WatchKey not recognized!!");
continue;
}
for (WatchEvent<?> event : key.pollEvents()) {
final WatchEvent.Kind kind = event.kind();
if (kind == OVERFLOW) {
logFileWriter.println("OVERFLOW");
System.out
.println("XXXXXXXXXXXXXXXXXXX----->>>OVERFLOW<<<--------XXXXXXXXXXXXXXXXXXX");
// triggerFullScan();
continue;
}
// Context for directory entry event is the file name of
// entry
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
File childPath = child.toFile();
File parent = dir.toFile();
// logger.print(logger.VERBOSE2, logger.PFR, subModule,
// event
// .kind().name() + " filename "+name+" child " + child +
// " parent "+dir + " watchable="+key.watchable());
if (!childPath.getParentFile().getAbsolutePath()
.equals(parent.getAbsolutePath())) {
System.out
.println("ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR");
System.out.println(childPath.getParentFile()
.getAbsoluteFile());
System.out.println(parent.getAbsolutePath());
}
// System.out.println(event.kind().name() +
// " name "+name+" child " + child + " dir "+dir);
// if directory is created, and watching recursively, then
// register it and its sub-directories
if (kind == ENTRY_CREATE) {
// System.out.println("created-" + child);
logFileWriter.println("CREATE:" + child);
try {
if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
try {
registerAll(child);
// addToScannedListOnDirRename(child.toFile(),
// false);
} catch (NoSuchFileException ex) {
// logger.print(logger.VERBOSE, logger.PFR,
// moduleName,
// "Received ENTRY_CREATE and NoSuchFileException continuing from here "
// + ex+" for dir "+child);
continue;
}
}
} catch (AccessDeniedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
triggerFullScan();
return;
}
}
File file = child.toFile();
if (kind == ENTRY_CREATE || kind == ENTRY_MODIFY) {
// System.out.println("created/modify-" + child);
logFileWriter.println("CREATE/MODIFY: " + child);
try {
// logger.print(logger.VERBOSE2, logger.PFR,
// subModule, "Adding create event = " + fileInfo);
filesList.add(file.getCanonicalPath());
if (file.isDirectory()) {
}
} catch (Exception e) {
triggerFullScan();
return;
}
} else if (kind == ENTRY_DELETE) {
logFileWriter.println("DELETE: " + child);
deleteDir(file);
}
}
// reset key and remove from set if directory no longer
// accessible
boolean valid = key.reset();
if (!valid) {
keys.remove(key);
// all directories are inaccessible
if (keys.isEmpty()) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
triggerFullScan();
String failureCause = e.getMessage();
return;
} catch (Throwable e) {
triggerFullScan();
e.printStackTrace();
return;
}
}
}
private void deleteDir(File file) {
// TODO Auto-generated method stub
}
private void triggerFullScan() {
// TODO Auto-generated method stub
}
/**
* Register the given directory, and all its sub-directories, with the
* WatchService.
*
* #throws PFRScanFailedException
*/
private void registerAll(final Path start) throws Exception {
// register directory and sub-directories
walkFileTree(start);
}
private void walkFileTree(Path start) throws IOException {
int retryCount = 0;
int maxRetry = 5;
String subModule = module + "walkFileTree";
while (true) {
try {
if (start == null) {
return;
}
Files.walkFileTree(start, SFRFileVisitor);
break;
} catch (AccessDeniedException adx) {
retryCount++;
if (retryCount == maxRetry) {
throw adx;
}
File file = start.toFile();
if (file == null || !file.exists()) {
break;
}
waitFor(5000);
continue;
} catch (IOException iex) {
retryCount++;
if (retryCount == maxRetry) {
throw iex;
}
waitFor(5000);
continue;
}
}
}
public static void waitFor(int milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Process all events for keys queued to the watcher
*/
#Override
public void run() {
Thread.currentThread().setName(uniqueFSName);
try {
DirectoryWatcherCore();
} finally {
freeResources();
}
}
class FilesetSimpleFileVisitor extends SimpleFileVisitor<Path> {
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
try {
// doScan(file);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
// logger.printStackTrace(logger.PFR,
// "PFRScanFailedException-visitFile", e);
}
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
String subModule = "preVisitDirectory";
try {
register(dir);
// doScan(dir);
return FileVisitResult.CONTINUE;
} catch (NoSuchFileException e) {
return FileVisitResult.SKIP_SUBTREE;
} catch (Exception e) {
e.printStackTrace();
throw new IOException(e);
}
}
}
public void startDirectoryRegisterProcess() throws Exception {
// registering all path
String subModule = "-startDirectoryRegisterProcess-";
// logger.print(logger.INFO, logger.PFR, subModule,
// "Initaited registering process");
long startTime = System.currentTimeMillis();
for (Path dir : srcPaths) {
// logger.print(logger.INFO, logger.PFR, subModule,
// "Started registring directory" + dir);
try {
// registering sub directories
File folder = dir.toFile();
if (folder == null) {
continue;
}
File[] listOfFiles = folder.listFiles();
if (listOfFiles == null || listOfFiles.length == 0) {
continue;
}
for (File file : listOfFiles) {
if (file.exists() && file.isDirectory()) {
try {
registerAll(Paths.get(file.getCanonicalPath()));
} catch (NoSuchFileException iox) {
// consume NoSuchFileException exception
}
}
}
} catch (AccessDeniedException e) {
// handleAccessDeniedException(e, true);
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
// handleException(e, true);
}
}
long registrationTime = System.currentTimeMillis() - startTime;
}
public static void testWatchDir(List<Path> dirs) throws Exception {
final DirectoryWatcher dw = new DirectoryWatcher(dirs);
Runnable runner = new Runnable() {
#Override
public void run() {
while (true) {
try {
waitFor(10 * 1000);
System.out.println("Pending file count="
+ filesList.size());
findFilesPresentOnDiskButNotInList();
System.out
.println("----------------------------------");
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
new Thread(runner).start();
dw.startDirectoryRegisterProcess();
}
/**
* Checks if the file is present on Disk but not on the list which was
* created by the events that was received by Directory Watcher
*
* #throws Exception
*/
public static void findFilesPresentOnDiskButNotInList() throws Exception {
List<String> missedFiles = new ArrayList<String>();
for (Path src : srcPaths) {
findDiff(src.toFile(), missedFiles);
}
if (missedFiles.size() == 0) {
System.out.println("No files are missed");
} else {
System.out.println("findFilesPresentOnDiskButNotInList");
System.out.println("The files that have been missed are");
for (String filePath : missedFiles) {
System.out.println(filePath);
}
}
System.out.println("###################################");
}
public static void findDiff(File folder, List<String> missedFiles)
throws Exception {
File[] files = folder.listFiles();
if (files != null && files.length > 0) {
for (File child : files) {
if (!filesList.contains(child.getCanonicalPath())) {
missedFiles.add(child.getCanonicalPath());
}
if (child.isDirectory()) {
findDiff(child, missedFiles);
}
}
}
}
public static void main(String[] args) throws Exception {
System.out.println("started");
List<String> pathNames = new ArrayList<String>();
List<Path> dirPaths = new ArrayList<Path>();
// if two arguments are passed to the main function then
// we assume that the first argument represents the directory where the
// files and folders are getting created. And the second argument is for
// the
// path to the log file.
// else we ask the user to enter input through command line
if (args.length < 2) {
getUserInput(pathNames);
} else {
// arg[0] is the folder to be watched
pathNames.add(args[0]);
// arg[1] is the log file that has been created
LOG_FILE_PATH = args[1];
}
// code for log file
System.out.println("The log file is " + LOG_FILE_PATH);
new File(LOG_FILE_PATH).deleteOnExit();
new File(LOG_FILE_PATH).createNewFile();
logFileWriter = new PrintWriter(LOG_FILE_PATH);
for (String path : pathNames) {
dirPaths.add(Paths.get(path));
}
testWatchDir(dirPaths);
System.out.println("ended");
}
private static void getUserInput(List<String> pathNames) {
System.out
.println("please enter the path of directory to be watched for events");
Scanner input = new Scanner(System.in);
if (input.hasNext()) {
pathNames.add(input.nextLine());
}
System.out.println("Please enter the log file path");
if (input.hasNext()) {
LOG_FILE_PATH = input.nextLine();
}
}
}

Categories

Resources