--- /dev/null
+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);
+
+ }
+ }
+
+ }
+}