import java.io.File;
+
/**
- * @author jim
- * Watches a particular file for its creation, deletion, or modification.
+ * @author jim Watches a particular file for its creation, deletion, or
+ * modification.
*/
public class FileWatcher {
- private File subject=null;
- private long lastStat;
- boolean exists=false;
+
+ private File subject = null;
+
+ private long lastStat[];
+ boolean waslocked=false;
+ boolean exists = false;
/**
- * Make a watcher for a particular file.
- * If the file doesn't exist, the watcher will watch
- * for its creation (and indicate a change of state)
- * @param subject
+ * transient lock on subject - can be passed back to calling class
+ * to preserve new state of file for immediate reading.
+ */
+ private Lock subjectLock = null;
+
+ private void clearLock() {
+ if (subjectLock!=null)
+ subjectLock.release();
+ subjectLock=null;
+ }
+
+ private boolean checkLock() {
+ if (subject!=null && subject.exists()) {
+ if (subjectLock!=null) {
+ subjectLock.release();
+ }
+ subjectLock = new Lock(subject);
+ if (subjectLock.isLocked()) {
+ // subjectLock.release();
+ return false;
+ }
+ clearLock();
+ return true;
+ }
+ return false;
+ }
+
+ private long[] getStat(File subject) {
+ return new long[] { subject.lastModified(), subject.length() };
+ }
+ private boolean compStat(long[] stat, long[] newstat) {
+ if (stat[0]!=newstat[0] || stat[1]!=newstat[1])
+ return false;
+ return true;
+ }
+ /**
+ * Detect changes in file state and release of any
+ * lock in place during change.
+ * @return true if file state has changed. Leaves lock in subjectLock (ready to be passed to caller)
*/
private boolean check() {
- if (subject!=null) {
+ if (subject != null) {
if (!subject.exists()) {
if (exists) {
- exists=false;
- return true;
- }
- return false;
- } else {
- long newStat=subject.lastModified();
- if (exists && lastStat==newStat) {
+ if (!waslocked) {
+ // !checkLock()) {
+
+ exists = false;
+ // waslocked=false;
+ return true;
+ }
+ }
+ // locked - state change registered after lock is released
return false;
+ } else {
+ long[] newStat = getStat(subject); // subject.lastModified();
+ if (!checkLock()) {
+ // file is free to access, return state change
+ if (!exists || !compStat(lastStat, newStat)) {
+ waslocked=false;
+ exists=true;
+ lastStat=newStat;
+ return true;
+ }
+ // no change
+ return false;
+ } else {
+ waslocked=true;
+ return false;
+ }
}
- lastStat=newStat;
- exists=true;
- return true;
}
- }
return false;
}
+ /**
+ * updates internal record of file state when caller has intentionally
+ * modified subject. (ignores locked-state of subject)
+ */
+ public void setState() {
+ if (subject!=null) {
+ if (exists = subject.exists()) {
+ lastStat = getStat(subject);
+ waslocked = false;
+ }
+ }
+ }
+ /**
+ * Make a watcher for a particular file. If the file doesn't exist, the
+ * watcher will watch for its creation (and indicate a change of state)
+ * For locked files, the removal of a lock constitutes a change of
+ * state if the file was modified.
+ *
+ * @param subject
+ */
public FileWatcher(File subject) {
// TODO Auto-generated constructor stub
this.subject = subject;
- check();
+ setState();
}
+ /**
+ * Test for change in file state. Only indicates a change
+ * after any lock on a file has been released.
+ * @return true if file has been modified.
+ */
public boolean hasChanged() {
- return check();
+ boolean res = check();
+ clearLock();
+ return res;
+ }
+ /**
+ * passes lock back to caller if hasChanged returned true.
+ * @return
+ */
+ public Lock getChangedState() {
+ boolean res = check();
+ if (res)
+ return subjectLock;
+ else {
+ clearLock();
+ return null;
+ }
}
}