package com.bc.util.watch;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
public class DirectoryWatch {
public DirectoryWatch() {
directoryList = new ArrayList();
watchedFiles = new ArrayList();
listeners = new ArrayList();
directoriesContent = new ArrayList();
addedFileList = new ArrayList();
removedFileList = new ArrayList();
}
synchronized public int getNumDirectories() {
return directoryList.size();
}
synchronized public void add(File dir) {
if (dir != null) {
if (!dir.isDirectory()) {
throw new IllegalArgumentException("The argument: " + dir.getPath() + " is not a directory");
}
if (getDirectoryIndex(dir) < 0) {
directoryList.add(dir);
}
}
}
synchronized public void remove(File dir) {
final int index = getDirectoryIndex(dir);
if (index >= 0) {
directoryList.remove(index);
ArrayList toDelete = new ArrayList();
for (Iterator iterator = directoriesContent.iterator(); iterator.hasNext();) {
File file = (File) iterator.next();
if (dir.equals(file.getParentFile())) {
toDelete.add(file);
}
}
for (Iterator iterator = toDelete.iterator(); iterator.hasNext();) {
File file = (File) iterator.next();
directoriesContent.remove(file);
}
}
}
synchronized public int getNumListeners() {
return listeners.size();
}
synchronized public void addListener(DirectoryWatchListener listener) {
if ((listener != null) && (!listeners.contains(listener))) {
listeners.add(listener);
}
}
synchronized public void removeListener(DirectoryWatchListener listener) {
listeners.remove(listener);
}
synchronized public File[] getDirectoriesContent() {
File result[] = new File[directoriesContent.size()];
return (File[]) directoriesContent.toArray(result);
}
public void start(long rate) {
timer = new Timer();
timer.scheduleAtFixedRate(new DirectoryWatchTask(), 0, rate);
}
public void stop() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
///////////////////////////////////////////////////////////////////////////
/////// END OF PUBLIC
///////////////////////////////////////////////////////////////////////////
private final ArrayList directoryList;
private final ArrayList watchedFiles;
private final ArrayList directoriesContent;
private final ArrayList listeners;
private final ArrayList addedFileList;
private final ArrayList removedFileList;
private Timer timer;
synchronized File[] getWatchedFiles() {
File[] result = new File[watchedFiles.size()];
int idx = 0;
for (Iterator iterator = watchedFiles.iterator(); iterator.hasNext();) {
FileContainer container = (FileContainer) iterator.next();
result[idx] = container.getFile();
++idx;
}
return result;
}
synchronized void checkDirectories() {
addNewFilesToWatch();
checkForFileChanges();
checkForRemovedFiles();
notifyListeners();
}
///////////////////////////////////////////////////////////////////////////
/////// END OF PROTECTED
///////////////////////////////////////////////////////////////////////////
private int getDirectoryIndex(File dir) {
return directoryList.indexOf(dir);
}
private void checkForRemovedFiles() {
removedFileList.clear();
for (Iterator iterator = directoriesContent.iterator(); iterator.hasNext();) {
File file = (File) iterator.next();
if (!file.exists()) {
removedFileList.add(file);
}
}
for (Iterator iterator = removedFileList.iterator(); iterator.hasNext();) {
File file = (File) iterator.next();
directoriesContent.remove(file);
}
}
private void checkForFileChanges() {
final ArrayList stableFiles = new ArrayList();
addedFileList.clear();
for (Iterator iterator = watchedFiles.iterator(); iterator.hasNext();) {
final FileContainer container = (FileContainer) iterator.next();
final File file = container.getFile();
final long length = file.length();
final long lastModified = file.lastModified();
if ((container.getLastModified() == lastModified)
&& (container.getSize() == length)) {
container.setStableCount(1 + container.getStableCount());
if (container.getStableCount() > 2) {
stableFiles.add(file);
}
} else {
container.setLastModified(lastModified);
container.setSize(length);
container.setStableCount(0);
}
}
FileContainer comparer = new FileContainer();
for (Iterator iterator = stableFiles.iterator(); iterator.hasNext();) {
File file = (File) iterator.next();
addedFileList.add(file);
directoriesContent.add(file);
comparer.setFile(file);
watchedFiles.remove(comparer);
}
}
private void notifyListeners() {
if (addedFileList.size() > 0) {
File added[] = new File[addedFileList.size()];
added = (File[]) addedFileList.toArray(added);
for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
DirectoryWatchListener listener = (DirectoryWatchListener) iterator.next();
listener.filesAdded(added);
}
addedFileList.clear();
}
if (removedFileList.size() > 0) {
File removed[] = new File[removedFileList.size()];
removed = (File[]) removedFileList.toArray(removed);
for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
DirectoryWatchListener listener = (DirectoryWatchListener) iterator.next();
listener.filesRemoved(removed);
}
removedFileList.clear();
}
}
private void addNewFilesToWatch() {
final FileContainer comparer = new FileContainer();
for (Iterator iterator = directoryList.iterator(); iterator.hasNext();) {
File dir = (File) iterator.next();
File fileArray[] = dir.listFiles();
for (int i = 0; i < fileArray.length; i++) {
File file = fileArray[i];
if (!directoriesContent.contains(file)) {
comparer.setFile(file);
if (!watchedFiles.contains(comparer)) {
final FileContainer container = new FileContainer();
container.setFile(file);
container.setLastModified(file.lastModified());
container.setSize(file.length());
container.setStableCount(0);
watchedFiles.add(container);
}
}
}
}
}
private class FileContainer {
private File file;
private long lastModified;
private long size;
private int stableCount;
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public long getLastModified() {
return lastModified;
}
public void setLastModified(long lastModified) {
this.lastModified = lastModified;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public int getStableCount() {
return stableCount;
}
public void setStableCount(int stableCount) {
this.stableCount = stableCount;
}
/**
* @noinspection InstanceofInterfaces
*/
public boolean equals(Object obj) {
boolean result = false;
if (obj instanceof FileContainer) {
result = this.file.equals(((FileContainer) obj).getFile());
}
return result;
}
}
private class DirectoryWatchTask extends TimerTask {
/**
* The action to be performed by this timer task.
*/
public void run() {
checkDirectories();
}
}
}