cab03cddad35eb0c6b1db6bb564425e1f0197ebc
[vamsas.git] / src / org / vamsas / client / simpleclient / ClientsFile.java
1 package org.vamsas.client.simpleclient;
2
3 import org.vamsas.client.*;
4
5 import java.io.BufferedInputStream;
6 import java.io.BufferedOutputStream;
7 import java.io.File;
8 import java.io.FileInputStream;
9 import java.io.FileNotFoundException;
10 import java.io.FileOutputStream;
11 import java.io.IOException;
12 import java.io.InputStreamReader;
13 import java.io.ObjectInputStream;
14 import java.io.ObjectOutput;
15 import java.io.ObjectOutputStream;
16 import java.io.OutputStream;
17 import java.util.Vector;
18
19 /**
20  * Handler for the clientsFile within a vamsas session thread.
21  * @author jim 
22  */
23 public class ClientsFile extends ListFile {
24   /**
25    * number of my client in list - passed back when a client 
26    * is added to list, and used (if valid) for quickly 
27    * looking up presence of client handle in the list.
28    */
29   private int syncnum = 1;
30
31   public ClientsFile(File filelist) throws IOException {
32     super(filelist);
33   }
34
35   /**
36    * internal method for getting clientList - ensures a lock has been made but
37    * does not release it.
38    * 
39    * @return list of clients
40    */
41   private ClientHandle[] retrieveClientHandles() {
42     if (lockFile()) {
43       try {
44         ClientHandle[] clients=null;
45         if (this.fileLock.rafile.length()>0) {
46           
47           ObjectInputStream is = new ObjectInputStream(fileLock.getBufferedInputStream(true));
48           Object o;
49           o=is.readObject();
50           if (o!=null) {
51             try {
52               clients = (ClientHandle[]) o;
53             }
54             catch (Exception e) {
55               System.err.println("Garbage in the clientHandle list "+this.sessionFile);
56             }
57           }
58         }
59         return clients;
60       } catch (FileNotFoundException e) {
61         // TODO Auto-generated catch block
62         e.printStackTrace(System.err);
63       } catch (Exception e) {
64         e.printStackTrace(System.err);
65       }
66     }
67     return null;
68   }
69   /**
70    * get the clientList from the file. May return null if lock failed!
71    * @return clientList
72    */
73   public ClientHandle[] retrieveClientList() {
74     if (lockFile()) {
75       ClientHandle[] clients = retrieveClientHandles();
76       unlockFile();
77       return clients;
78     }
79     return null;
80   }
81   /**
82    * get list from the locked ClientList.
83    * @param extantlock
84    * @return clientList or null if lock failed (or file was empty)
85    */
86   public ClientHandle[] retrieveClientList(Lock extantlock) {
87     if (lockFile(extantlock)) {
88       ClientHandle[] clients = retrieveClientHandles();
89       unlockFile();
90       return clients;
91     }
92     return null;
93   }
94   /**
95    * adds clientHandle me to the clientList under an existing lock extantLock.
96    * @param me
97    * @param extantLock
98    * @return client index in list or 0 if lock was invalid or addClient operation failed.
99    */
100   public int addClient(ClientHandle me, Lock extantLock) {
101     return addClient(me, true, extantLock);
102   }
103   
104   /**
105    * adds clientHandle me to the clientList under an existing lock.
106    * @param me - clientHandle
107    * @param disambig - if true then add will fail if an identical clientHandle already exists
108    * @param extantLock - existing lock
109    * @return client index in list or 0 if addClient (or the lock) failed.
110    */
111   
112   public int addClient(ClientHandle me, boolean disambig, Lock extantLock) {
113     if (lockFile(extantLock)) {
114       syncnum = addClient(me, disambig);
115       unlockFile();
116       return syncnum;
117     }
118     return 0;
119   }
120   
121   /**
122    * adds the ClientHandle to the list - if it is not unique, then the
123    * ClientHandle object is modified to make it unique in the list. returns the
124    * clientNumber for the client in the session.
125    * 
126    * @param me
127    * @return
128    */
129
130   public int addClient(ClientHandle me) {
131     syncnum = addClient(me, true);
132     unlockFile();
133     return syncnum;
134   }
135
136   /**
137    * removes 'me' from the session ClientList without complaint if 'me' isn't in the clientList already.
138    * @param me client handle to be removed
139    * @param clientlock existing lock passed from watcher.
140    */
141   public void removeClient(ClientHandle me, Lock clientlock) {
142     int mynum=-1;
143     if (lockFile(clientlock)) {
144       ClientHandle[] clients = retrieveClientHandles();
145       if (clients != null) {
146         if ((syncnum<=0 || syncnum>clients.length) || clients[syncnum-1]!=me) {
147           for (int i = 0, j = clients.length; i < j; i++) 
148             if (clients[i].equals(me)) {
149               mynum=i;
150               break;
151             }
152         } else {
153           mynum=syncnum-1;
154         }
155         if (mynum>-1) {
156           ClientHandle[] newlist = new ClientHandle[clients.length - 1];
157           for (int k=0,i = 0, j = clients.length; i < j; i++)
158             if (i!=mynum)
159               newlist[k++] = clients[i];
160           if (!putClientList(newlist))
161             throw new Error("Failed to write new clientList!"); // failed to put the clientList to disk.
162         }
163       }
164       unlockFile();
165     } else {
166       throw new Error("Couldn't get lock for "+((sessionFile==null) ? "Unitialised sessionFile in ClientsFile" : sessionFile.getAbsolutePath()));
167     }
168   }
169   /**
170    * Adds a ClientHandle to the ClientList file - optionally disambiguating 
171    * the ClientHandle (modifes the URN). 
172    * Note: Caller is left to release the lock on the ClientList.
173    * @param me
174    * @param disambiguate -
175    *          flag indicating if the URN for me should be disambiguated to
176    *          differentiate between sessions.
177    * @return index of clientHandle in new list, or -1-position of existing
178    *         clientHandle (if disambiguate is true)
179    */
180   protected int addClient(ClientHandle me, boolean disambiguate) {
181     int newclient = 0;
182     int tries=5;
183     while (tries-->0 && !lockFile())
184       try { Thread.sleep(1); } catch (Exception e){};
185     if (lockFile()) {
186       ClientHandle[] clients = retrieveClientHandles();
187       if (me.getClientUrn()==null) {
188         // TODO: move this into ClientUrn as a standard form method.
189         me.setClientUrn("vamsas://"+me.getClientName()+":"+me.getVersion()+"/");
190       }
191       if (clients == null) {
192         clients = new ClientHandle[1];
193         clients[0] = me;
194         newclient = 1;
195       } else {
196         int k = 0;
197         for (int i = 0, j = clients.length; i < j; i++) {
198           if (clients[i].equals(me)) {
199             if (disambiguate) {
200               while (clients[i].equals(me)) {
201                 me.setClientUrn(me.getClientUrn() + k++); // TODO: make a better
202                                                           // disambiguation of
203                                                           // urn.
204               }
205             } else {
206               // will not write the ambiguous clientHandle to disk, just return
207               // its index.
208               return -1 - i;
209             }
210           }
211         }
212         int i, j;
213         ClientHandle[] newlist = new ClientHandle[clients.length + 1];
214         for (i = 0, j = clients.length; i < j; i++)
215           newlist[i] = clients[i];
216         newlist[j] = me;
217         clients = newlist;
218         newclient = j+1;
219       }
220       if (!putClientList(clients))
221         return 0; // failed to put the clientList to disk.
222     }
223     return newclient;
224   }
225   
226   /**
227    * safely writes clients array to the file referred to by sessionFile.
228    * 
229    * @param clients
230    * @return true if successful write. Throws Errors otherwise.
231    */
232   protected boolean putClientList(ClientHandle[] clients) {
233     if (lockFile()) {
234       File templist = backupSessionFile();
235       if (templist != null) {
236         try {
237           // fileLock.rafile.setLength(0);
238           ObjectOutputStream os = 
239             new ObjectOutputStream(fileLock.getBufferedOutputStream(true));
240           
241 //              new BufferedOutputStream(new FileOutputStream(this.sessionFile)));
242           //    new BufferedOutputStream(new FileOutputStream(this.fileLock.rafile.getFD())));
243           os.writeObject(clients);
244           os.close(); // close destroys lock!
245           // All done - remove the backup.
246           templist.delete();
247           templist = null;
248         } catch (Exception e) {
249           if (templist != null) {
250             System.err
251                 .println("Serious - problems writing to sessionFile. Backup in "
252                     + templist.getAbsolutePath());
253             e.printStackTrace(System.err);
254           }
255         }
256       } else {
257         throw new Error(
258             "Couldn't create backup of the clientList before writing to it!");
259       }
260     } else {
261       throw new Error("Could not lock the clientList: "
262           + ((sessionFile == null) ? "Unitialized ClientsFile"
263               : " failed to get lock on " + sessionFile.getAbsolutePath()));
264     }
265     // successful!
266     return true;
267   }
268 }