test clientsFile handlers.
[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  * @author jim Handler for the clientsFile within a vamsas session.
21  */
22 public class ClientsFile {
23   private File filelist;
24
25   /**
26    * number of my client in list (not known at start but used when known to make
27    * lock)
28    */
29   private int syncnum = 1;
30
31   public ClientsFile(File filelist) throws IOException {
32     this.filelist = filelist;
33     if (!this.filelist.exists())
34       this.filelist.createNewFile();
35   }
36
37   private Lock listlock = null;
38
39   /**
40    * Get a lock for the ClientsFile
41    * 
42    * @return true if lock was made
43    */
44   protected boolean lockList() {
45     if (listlock != null && listlock.isLocked())
46       return true;
47     listlock = null;
48     if (filelist != null) {
49       if (filelist.exists()) {
50         // TODO: see if we need to loop-wait for locks or they just block until
51         // lock is made...
52         // do {
53         // listlock = new Lock(filelist); // TODO: wait around if we can't get
54         // the lock.
55         // } while (!listlock.isLocked());
56         listlock = new Lock(filelist);
57         return listlock.isLocked();
58       }
59     } else
60       throw new Error(
61           "org.vamsas.client.simpleclient.ClientsFile.lockList called for non-initialised ClientsFile!");
62
63     // no lock possible
64     return false;
65   }
66
67   /**
68    * Explicitly release the ClientsFile lock.
69    * 
70    * @return true if lock was released.
71    */
72   protected boolean unlockList() {
73     if (listlock != null) {
74
75       if (listlock.isLocked()) {
76         try {
77           listlock.lock.release();
78         } catch (IOException e) {
79           // TODO Deal with unlock Lock.release exception!
80           e.printStackTrace(System.err);
81         }
82       }
83
84       listlock = null;
85       return true;
86     }
87     return false;
88   }
89
90   /**
91    * internal method for getting clientList - ensures a lock has been made but
92    * does not release it.
93    * 
94    * @return list of clients
95    */
96   private ClientHandle[] retrieveClientHandles() {
97     if (lockList()) {
98       try {
99         ClientHandle[] clients=null;
100         if (this.listlock.rafile.length()>0) {
101           ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(
102               new java.io.FileInputStream(filelist)));
103           Object o;
104           o=is.readObject();
105           if (o!=null) {
106             try {
107               clients = (ClientHandle[]) o;
108             }
109             catch (Exception e) {
110               System.err.println("Garbage in the clientHandle list "+this.filelist);
111             }
112           }
113         }
114         return clients;
115       } catch (FileNotFoundException e) {
116         // TODO Auto-generated catch block
117         e.printStackTrace(System.err);
118       } catch (Exception e) {
119         e.printStackTrace(System.err);
120       }
121     }
122     return null;
123   }
124   /**
125    * get the clientList from the file. May return false if lock failed!
126    * @return clientList
127    */
128   public ClientHandle[] retrieveClientList() {
129     if (lockList()) {
130       ClientHandle[] clients = retrieveClientHandles();
131       if (unlockList())
132         return clients;
133     }
134     return null;
135   }
136
137   /**
138    * adds the ClientHandle to the list - if it is not unique, then the
139    * ClientHandle object is modified to make it unique in the list. returns the
140    * clientNumber for the client in the session.
141    * 
142    * @param me
143    * @return
144    */
145
146   public int addClient(ClientHandle me) {
147     syncnum = addClient(me, true);
148     unlockList();
149     return syncnum;
150   }
151
152   /**
153    * removes 'me' from the session ClientList without complaint if 'me' isn't in the clientList already.
154    * @param me
155    */
156   public void removeClient(ClientHandle me) {
157     int mynum=-1;
158     if (lockList()) {
159       ClientHandle[] clients = retrieveClientHandles();
160       if (clients != null) {
161         if (clients[syncnum-1]!=me) {
162           for (int i = 0, j = clients.length; i < j; i++) 
163             if (clients[i].equals(me)) {
164               mynum=i;
165               break;
166             }
167         } else {
168           mynum=syncnum-1;
169         }
170         if (mynum>-1) {
171           ClientHandle[] newlist = new ClientHandle[clients.length - 1];
172           for (int k=0,i = 0, j = clients.length; i < j; i++)
173             if (i!=mynum)
174               newlist[k++] = clients[i];
175           if (!putClientList(clients))
176             throw new Error("Failed to write new clientList!"); // failed to put the clientList to disk.
177         }
178       }
179       unlockList();
180     } else {
181       throw new Error("Couldn't get lock for "+((filelist==null) ? "Unitialised filelist in ClientsFile" : filelist.getAbsolutePath()));
182     }
183   }
184   /**
185    * Adds a ClientHandle to the ClientList file - optionally disambiguating 
186    * the ClientHandle (modifes the URN). 
187    * Note: Caller is left to release the lock on the ClientList.
188    * @param me
189    * @param disambiguate -
190    *          flag indicating if the URN for me should be disambiguate to
191    *          differentiate between sessions.
192    * @return index of clientHandle in new list, or -1-position of existing
193    *         clientHandle (if disambiguate is true)
194    */
195   protected int addClient(ClientHandle me, boolean disambiguate) {
196     int newclient = 0;
197     if (lockList()) {
198       ClientHandle[] clients = retrieveClientHandles();
199       if (me.getClientUrn()==null) {
200         // TODO: move this into ClientUrn as a standard form method.
201         me.setClientUrn("vamsas://"+me.getClientName()+":"+me.getVersion()+"/");
202       }
203       if (clients == null) {
204         clients = new ClientHandle[1];
205         clients[0] = me;
206         newclient = 1;
207       } else {
208         int k = 0;
209         for (int i = 0, j = clients.length; i < j; i++) {
210           if (clients[i].equals(me)) {
211             if (disambiguate) {
212               while (clients[i].equals(me)) {
213                 me.setClientUrn(me.getClientUrn() + k++); // TODO: make a better
214                                                           // disambiguation of
215                                                           // urn.
216               }
217             } else {
218               // will not write the ambiguous clientHandle to disk, just return
219               // its index.
220               return -1 - i;
221             }
222           }
223         }
224         int i, j;
225         ClientHandle[] newlist = new ClientHandle[clients.length + 1];
226         for (i = 0, j = clients.length; i < j; i++)
227           newlist[i] = clients[i];
228         newlist[j] = me;
229         clients = newlist;
230         newclient = j+1;
231       }
232       if (!putClientList(clients))
233         return 0; // failed to put the clientList to disk.
234     }
235     return newclient;
236   }
237
238   /**
239    * safely writes clients array to the file referred to by filelist.
240    * 
241    * @param clients
242    * @return true if successful write. Throws Errors otherwise.
243    */
244   protected boolean putClientList(ClientHandle[] clients) {
245     if (lockList()) {
246       File templist = null;
247       try {
248         templist = File.createTempFile(filelist.getName(),".old", filelist.getParentFile());
249         FileOutputStream tos = new FileOutputStream(templist);
250         tos.getChannel().transferFrom(listlock.rafile.getChannel(), 0,
251             listlock.rafile.length());
252         tos.close();
253       } catch (FileNotFoundException e1) {
254         System.err.println("Can't create temp file for clientlist");
255         e1.printStackTrace(System.err);
256       } catch (IOException e1) {
257         System.err
258             .println("Error when copying content to temp file for clientlist");
259         e1.printStackTrace(System.err);
260       }
261       if (templist != null) {
262         try {
263           listlock.rafile.setLength(0);
264           ObjectOutputStream os = new ObjectOutputStream(
265               new BufferedOutputStream(new FileOutputStream(this.filelist)));
266           os.writeObject(clients);
267           os.close();
268           // All done - remove the backup.
269           templist.delete();
270           templist = null;
271         } catch (Exception e) {
272           if (templist != null) {
273             System.err
274                 .println("Serious - problems writing to filelist. Backup in "
275                     + templist.getAbsolutePath());
276             e.printStackTrace(System.err);
277           }
278         }
279       } else {
280         throw new Error(
281             "Couldn't create backup of the clientList before writing to it!");
282       }
283     } else {
284       throw new Error("Could not lock the clientList: "
285           + ((filelist == null) ? "Unitialized ClientsFile"
286               : " failed to get lock on " + filelist.getAbsolutePath()));
287     }
288     // successful!
289     return true;
290   }
291 }