import java.util.Vector;
/**
- * @author jim Handler for the clientsFile within a vamsas session.
+ * @author jim Handler for the clientsFile within a vamsas session thread.
*/
public class ClientsFile {
private File filelist;
private Lock listlock = null;
+ protected boolean lockList(Lock extantlock) {
+ if (listlock!=null && !listlock.isLocked()) {
+ listlock.release();// tidy up invalid lock
+ }
+ listlock=extantlock;
+ return lockList();
+ }
/**
* Get a lock for the ClientsFile
*
* @return true if lock was made
*/
protected boolean lockList() {
- if (listlock != null && listlock.isLocked())
- return true;
+ if (listlock != null)
+ if (listlock.isLocked())
+ return true;
+ else
+ // lock failed for some reason.
+ listlock.release();
listlock = null;
if (filelist != null) {
if (filelist.exists()) {
*/
protected void unlockList() {
if (listlock != null) {
-
- if (listlock.isLocked()) {
- listlock.release();
- }
-
+ listlock.release();
listlock = null;
}
}
return null;
}
/**
- * get the clientList from the file. May return false if lock failed!
+ * get the clientList from the file. May return null if lock failed!
* @return clientList
*/
public ClientHandle[] retrieveClientList() {
}
return null;
}
+ /**
+ * get list from the locked ClientList.
+ * @param extantlock
+ * @return clientList or null if lock failed (or file was empty)
+ */
+ public ClientHandle[] retrieveClientList(Lock extantlock) {
+ if (lockList(extantlock)) {
+ ClientHandle[] clients = retrieveClientHandles();
+ unlockList();
+ return clients;
+ }
+ return null;
+ }
/**
* adds the ClientHandle to the list - if it is not unique, then the
/**
* removes 'me' from the session ClientList without complaint if 'me' isn't in the clientList already.
- * @param me
+ * @param me client handle to be removed
+ * @param clientlock existing lock passed from watcher.
*/
- public void removeClient(ClientHandle me) {
+ public void removeClient(ClientHandle me, Lock clientlock) {
int mynum=-1;
- if (lockList()) {
+ if (lockList(clientlock)) {
ClientHandle[] clients = retrieveClientHandles();
if (clients != null) {
- if (clients[syncnum-1]!=me) {
+ if ((syncnum<=0 || syncnum>clients.length) || clients[syncnum-1]!=me) {
for (int i = 0, j = clients.length; i < j; i++)
if (clients[i].equals(me)) {
mynum=i;
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)
- * For locked files, the removal of a lock constitutes a change of
- * state if the file was modified.
- *
- * @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()) {
- Lock tl = new Lock(subject);
- if (tl.isLocked()) {
- tl.release();
+ if (subjectLock!=null) {
+ subjectLock.release();
+ }
+ subjectLock = new Lock(subject);
+ if (subjectLock.isLocked()) {
+ // subjectLock.release();
return false;
}
- tl.release();
+ clearLock();
return true;
}
return false;
/**
* Detect changes in file state and release of any
* lock in place during change.
- * @return true if file state has changed
+ * @return true if file state has changed. Leaves lock in subjectLock (ready to be passed to caller)
*/
private boolean check() {
if (subject != null) {
}
return false;
}
+
public void setState() {
if (subject!=null) {
lastStat = getStat(subject);
}
}
+ /**
+ * 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;
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;
+ }
}
}
import org.vamsas.client.ClientHandle;
import org.vamsas.client.simpleclient.ClientsFile;
import org.vamsas.client.simpleclient.FileWatcher;
+import org.vamsas.client.simpleclient.Lock;
public class ClientsFileTest {
private static Vector commands;
ch=new ClientHandle(args[argc], args[argc+1]);
ch.setClientUrn(args[argc+2]);
argc+=3;
- cfhand.removeClient(ch);
+ cfhand.removeClient(ch, null);
System.out.println("Client removed (apparently)");
break;
case 2:
// watch
FileWatcher w=new FileWatcher(cf);
while (cf.exists()) {
- if (w.hasChanged()) {
- ClientHandle[] cl = cfhand.retrieveClientList();
+ // get watcher's lock to ensure state change is fixed for retrieval
+ Lock chlock=w.getChangedState();
+ if (chlock!=null) {
+ ClientHandle[] cl = cfhand.retrieveClientList(chlock);
System.out.println("-- Watching "+cf.getName());
//while (w.hasChanged())
// ;