backtrack
[vamsas.git] / src / org / vamsas / client / simpleclient / ClientsFile.java
diff --git a/src/org/vamsas/client/simpleclient/ClientsFile.java b/src/org/vamsas/client/simpleclient/ClientsFile.java
new file mode 100644 (file)
index 0000000..96fa871
--- /dev/null
@@ -0,0 +1,295 @@
+package org.vamsas.client.simpleclient;
+
+import org.vamsas.client.*;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.util.Vector;
+
+/**
+ * Handler for the clientsFile within a vamsas session thread.
+ * @author jim 
+ */
+public class ClientsFile extends ListFile {
+  private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(ClientsFile.class);
+  /**
+   * number of my client in list - passed back when a client 
+   * is added to list, and used (if valid) for quickly 
+   * looking up presence of client handle in the list.
+   */
+  private int syncnum = 1;
+
+  public ClientsFile(File filelist) throws IOException {
+    super(filelist);
+  }
+
+  /**
+   * internal method for getting clientList - ensures a lock has been made but
+   * does not release it.
+   * 
+   * @return list of clients
+   */
+  private ClientHandle[] retrieveClientHandles() {
+    if (lockFile()) {
+      try {
+        ClientHandle[] clients=null;
+        if (fileLock.length()>0) {
+          
+          ObjectInputStream is = new ObjectInputStream(fileLock.getBufferedInputStream(true));
+          Object o;
+          o=is.readObject();
+          if (o!=null) {
+            try {
+              clients = (ClientHandle[]) o;
+            }
+            catch (Exception e) {
+              System.err.println("Garbage in the clientHandle list "+this.sessionFile);
+            }
+          }
+        }
+        return clients;
+      } catch (FileNotFoundException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace(System.err);
+      } catch (Exception e) {
+        e.printStackTrace(System.err);
+      }
+    }
+    return null;
+  }
+  /**
+   * get the clientList from the file. May return null if lock failed!
+   * @return clientList
+   */
+  public ClientHandle[] retrieveClientList() {
+    if (lockFile()) {
+      ClientHandle[] clients = retrieveClientHandles();
+      unlockFile();
+      return clients;
+    }
+    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 (lockFile(extantlock)) {
+      ClientHandle[] clients = retrieveClientHandles();
+      unlockFile();
+      return clients;
+    }
+    return null;
+  }
+  /**
+   * adds clientHandle me to the clientList under an existing lock extantLock.
+   * @param me
+   * @param extantLock
+   * @return client index in list or 0 if lock was invalid or addClient operation failed.
+   */
+  public int addClient(ClientHandle me, Lock extantLock) {
+    return addClient(me, true, extantLock);
+  }
+  
+  /**
+   * adds clientHandle me to the clientList under an existing lock.
+   * @param me - clientHandle
+   * @param disambig - if true then add will fail if an identical clientHandle already exists
+   * @param extantLock - existing lock
+   * @return client index in list or 0 if addClient (or the lock) failed.
+   */
+  
+  public int addClient(ClientHandle me, boolean disambig, Lock extantLock) {
+    if (lockFile(extantLock)) {
+      syncnum = addClient(me, disambig);
+      unlockFile();
+      return syncnum;
+    }
+    return 0;
+  }
+  
+  /**
+   * adds the ClientHandle to the list - if it is not unique, then the
+   * ClientHandle object is modified to make it unique in the list. returns the
+   * clientNumber for the client in the session.
+   * 
+   * @param me
+   * @return
+   */
+
+  public int addClient(ClientHandle me) {
+    syncnum = addClient(me, true);
+    unlockFile();
+    return syncnum;
+  }
+
+  /**
+   * removes 'me' from the session ClientList without complaint if 'me' isn't in the clientList already.
+   * @param me client handle to be removed
+   * @param clientlock existing lock passed from watcher.
+   */
+  public void removeClient(ClientHandle me, Lock clientlock) {
+    int mynum=-1;
+    if (lockFile(clientlock)) {
+      ClientHandle[] clients = retrieveClientHandles();
+      if (clients != null) {
+        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;
+              break;
+            }
+        } else {
+          mynum=syncnum-1;
+        }
+        if (mynum>-1) {
+          ClientHandle[] newlist = new ClientHandle[clients.length - 1];
+          for (int k=0,i = 0, j = clients.length; i < j; i++)
+            if (i!=mynum)
+              newlist[k++] = clients[i];
+          if (!putClientList(newlist))
+            throw new Error("Failed to write new clientList!"); // failed to put the clientList to disk.
+        }
+      }
+      unlockFile();
+    } else {
+      throw new Error("Couldn't get lock for "+((sessionFile==null) ? "Unitialised sessionFile in ClientsFile" : sessionFile.getAbsolutePath()));
+    }
+  }
+  /**
+   * Adds a ClientHandle to the ClientList file - optionally disambiguating 
+   * the ClientHandle (modifes the URN). 
+   * Note: Caller is left to release the lock on the ClientList.
+   * @param me
+   * @param disambiguate -
+   *          flag indicating if the URN for me should be disambiguated to
+   *          differentiate between sessions.
+   * @return index of clientHandle in new list, or -1-position of existing
+   *         clientHandle (if disambiguate is true)
+   */
+  protected int addClient(ClientHandle me, boolean disambiguate) {
+    int newclient = 0;
+    int tries=5;
+    while (tries-->0 && !lockFile())
+      try { Thread.sleep(1); } catch (Exception e){};
+    if (lockFile()) {
+      ClientHandle[] clients = retrieveClientHandles();
+      if (me.getClientUrn()==null) {
+        // TODO: move this into ClientUrn as a standard form method.
+        me.setClientUrn("vamsas://"+me.getClientName()+":"+me.getVersion()+"/");
+      }
+      if (clients == null) {
+        clients = new ClientHandle[1];
+        clients[0] = me;
+        newclient = 1;
+      } else {
+        int k = 0;
+        for (int i = 0, j = clients.length; i < j; i++) {
+          if (clients[i].equals(me)) {
+            if (disambiguate) {
+              while (clients[i].equals(me)) {
+                me.setClientUrn(me.getClientUrn() + k++); // TODO: make a better
+                                                          // disambiguation of
+                                                          // urn.
+              }
+            } else {
+              // will not write the ambiguous clientHandle to disk, just return
+              // its index.
+              return -1 - i;
+            }
+          }
+        }
+        int i, j;
+        ClientHandle[] newlist = new ClientHandle[clients.length + 1];
+        for (i = 0, j = clients.length; i < j; i++)
+          newlist[i] = clients[i];
+        newlist[j] = me;
+        clients = newlist;
+        newclient = j+1;
+      }
+      if (!putClientList(clients))
+        return 0; // failed to put the clientList to disk.
+    }
+    return newclient;
+  }
+  /**
+   * when set true - get FileNotFoundExceptions on WinXP when writing to locked stream after the backup has been made (via the backupFile method)
+   */
+  boolean backup=false;
+  /**
+   * safely writes clients array to the file referred to by sessionFile.
+   * 
+   * @param clients
+   * @return true if successful write. Throws Errors otherwise.
+   */
+  protected boolean putClientList(ClientHandle[] clients) {
+    if (lockFile()) {
+      File templist=null;
+      if (!backup || (templist = backupSessionFile()) != null) {
+        int retries=3;
+        while (retries-->0) {
+          try {
+            ObjectOutputStream os = 
+              new ObjectOutputStream(fileLock.getBufferedOutputStream(true));
+            log.debug("About to write "+clients.length+" clientHandles to output stream.");
+            os.writeObject(clients);
+            os.close();
+          // All done - remove the backup.
+          if (backup)
+            templist.delete();
+          templist = null;
+          retries=-1;
+          } catch (Exception e) {
+            System.err
+            .println("Serious - problems writing to sessionFile.");
+            if (retries>0 && templist != null) {
+              System.err.println("Recovering from Backup in "
+                      + templist.getAbsolutePath());
+              templist.renameTo(fileLock.target);
+            }
+            e.printStackTrace(System.err);
+          }
+        }
+        if (retries>-2) {
+          System.err
+          .println("Serious - problems writing to sessionFile. Giving Up.");
+          return false;
+        }
+      } else {
+        throw new Error(
+            "Couldn't create backup of the clientList before writing to it!");
+      }
+    } else {
+      throw new Error("Could not lock the clientList: "
+          + ((sessionFile == null) ? "Unitialized ClientsFile"
+              : " failed to get lock on " + sessionFile.getAbsolutePath()));
+    }
+    // successful!
+    return true;
+  }
+
+  public void clearList() {
+    if (lockFile()) {
+      try {
+        FileOutputStream fout = fileLock.getFileOutputStream(true);
+        fout.flush();
+        fout.close();
+      } catch (Exception e) {
+        throw new Error("Problems trying to clear clientlist!",e);
+        
+      }
+    }
+    
+  }
+}