new fileWatcher method passes lock for changed file back to the caller.
[vamsas.git] / src / org / vamsas / client / simpleclient / FileWatcher.java
1 /**
2  * 
3  */
4 package org.vamsas.client.simpleclient;
5
6 import java.io.File;
7
8 import org.vamsas.client.SimpleClient;
9
10 /**
11  * @author jim Watches a particular file for its creation, deletion, or
12  *         modification.
13  */
14 public class FileWatcher {
15
16   private File subject = null;
17
18   private long lastStat[];
19   boolean waslocked=false;
20   boolean exists = false;
21   /**
22    * transient lock on subject - can be passed back to calling class
23    * to preserve new state of file for immediate reading.
24    */
25   private Lock subjectLock = null;
26   
27   private void clearLock() {
28     if (subjectLock!=null)
29       subjectLock.release();
30     subjectLock=null;
31   }
32   
33   private boolean checkLock() {
34     if (subject!=null && subject.exists()) {
35       if (subjectLock!=null) {
36         subjectLock.release();
37       }
38       subjectLock = new Lock(subject);
39       if (subjectLock.isLocked()) {
40         // subjectLock.release();
41         return false;
42       }
43       clearLock();
44       return true;
45     }
46     return false;
47   }
48   
49   private long[] getStat(File subject) {
50     return new long[] { subject.lastModified(), subject.length() };
51   }
52   private boolean compStat(long[] stat, long[] newstat) {
53     if (stat[0]!=newstat[0] || stat[1]!=newstat[1])
54       return false;
55     return true;
56   }
57   /**
58    * Detect changes in file state and release of any
59    * lock in place during change.
60    * @return true if file state has changed. Leaves lock in subjectLock (ready to be passed to caller)
61    */
62   private boolean check() {
63     if (subject != null) {
64       if (!subject.exists()) {
65         if (exists) {
66           if (!waslocked) {
67             // !checkLock()) {
68           
69             exists = false;
70             // waslocked=false;
71             return true;
72           }
73         }
74         // locked - state change registered after lock is released
75         return false;
76       } else {
77         long[] newStat = getStat(subject); // subject.lastModified();
78         if (!checkLock()) {
79           // file is free to access, return state change
80           if (!exists || !compStat(lastStat, newStat)) {
81             waslocked=false;
82             exists=true;
83             lastStat=newStat;
84             return true;
85           }
86           // no change
87           return false;
88         } else {
89           waslocked=true;
90           return false;
91         }
92       }
93     }
94     return false;
95   }
96   
97   public void setState() {
98     if (subject!=null) {
99       lastStat = getStat(subject);
100       exists = subject.exists();
101       waslocked = checkLock();
102     }
103   }
104   
105   /**
106    * Make a watcher for a particular file. If the file doesn't exist, the
107    * watcher will watch for its creation (and indicate a change of state) 
108    * For locked files, the removal of a lock constitutes a change of 
109    * state if the file was modified.
110    * 
111    * @param subject
112    */
113   
114   public FileWatcher(File subject) {
115     // TODO Auto-generated constructor stub
116     this.subject = subject;
117     setState();
118   }
119   /**
120    * Test for change in file state. Only indicates a change 
121    * after any lock on a file has been released.
122    * @return true if file has been modified.
123    */
124   public boolean hasChanged() {
125     boolean res = check();
126     clearLock();
127     return res;
128   }
129   /**
130    * passes lock back to caller if hasChanged returned true.
131    * @return
132    */
133   public Lock getChangedState() {
134     boolean res = check();
135     if (res)
136       return subjectLock;
137     else {
138       clearLock();
139       return null;
140     }
141   }
142 }