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; /** * @author jim Handler for the clientsFile within a vamsas session. */ public class ClientsFile { private File filelist; /** * number of my client in list (not known at start but used when known to make * lock) */ private int syncnum = 1; public ClientsFile(File filelist) throws IOException { this.filelist = filelist; if (!this.filelist.exists()) this.filelist.createNewFile(); } private Lock listlock = null; /** * Get a lock for the ClientsFile * * @return true if lock was made */ protected boolean lockList() { if (listlock != null && listlock.isLocked()) return true; listlock = null; if (filelist != null) { if (filelist.exists()) { // TODO: see if we need to loop-wait for locks or they just block until // lock is made... do { listlock = new Lock(filelist); // TODO: wait around if we can't get the lock. } while (!listlock.isLocked()); // listlock = new Lock(filelist); return listlock.isLocked(); } } else throw new Error( "org.vamsas.client.simpleclient.ClientsFile.lockList called for non-initialised ClientsFile!"); // no lock possible return false; } /** * Explicitly release the ClientsFile lock. * * @return true if lock was released. */ protected void unlockList() { if (listlock != null) { if (listlock.isLocked()) { listlock.release(); } listlock = null; } } /** * internal method for getting clientList - ensures a lock has been made but * does not release it. * * @return list of clients */ private ClientHandle[] retrieveClientHandles() { if (lockList()) { try { ClientHandle[] clients=null; if (this.listlock.rafile.length()>0) { ObjectInputStream is = new ObjectInputStream(new BufferedInputStream( new java.io.FileInputStream(filelist))); Object o; o=is.readObject(); if (o!=null) { try { clients = (ClientHandle[]) o; } catch (Exception e) { System.err.println("Garbage in the clientHandle list "+this.filelist); } } } 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 false if lock failed! * @return clientList */ public ClientHandle[] retrieveClientList() { if (lockList()) { ClientHandle[] clients = retrieveClientHandles(); unlockList(); return clients; } return null; } /** * 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); unlockList(); return syncnum; } /** * removes 'me' from the session ClientList without complaint if 'me' isn't in the clientList already. * @param me */ public void removeClient(ClientHandle me) { int mynum=-1; if (lockList()) { ClientHandle[] clients = retrieveClientHandles(); if (clients != null) { if (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. } } unlockList(); } else { throw new Error("Couldn't get lock for "+((filelist==null) ? "Unitialised filelist in ClientsFile" : filelist.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; if (lockList()) { 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; } /** * safely writes clients array to the file referred to by filelist. * * @param clients * @return true if successful write. Throws Errors otherwise. */ protected boolean putClientList(ClientHandle[] clients) { if (lockList()) { File templist = null; try { templist = File.createTempFile(filelist.getName(),".old", filelist.getParentFile()); FileOutputStream tos = new FileOutputStream(templist); tos.getChannel().transferFrom(listlock.rafile.getChannel(), 0, listlock.rafile.length()); tos.close(); } catch (FileNotFoundException e1) { System.err.println("Can't create temp file for clientlist"); e1.printStackTrace(System.err); } catch (IOException e1) { System.err .println("Error when copying content to temp file for clientlist"); e1.printStackTrace(System.err); } if (templist != null) { try { listlock.rafile.setLength(0); ObjectOutputStream os = new ObjectOutputStream( new BufferedOutputStream(new FileOutputStream(this.filelist))); os.writeObject(clients); os.close(); // All done - remove the backup. templist.delete(); templist = null; } catch (Exception e) { if (templist != null) { System.err .println("Serious - problems writing to filelist. Backup in " + templist.getAbsolutePath()); e.printStackTrace(System.err); } } } else { throw new Error( "Couldn't create backup of the clientList before writing to it!"); } } else { throw new Error("Could not lock the clientList: " + ((filelist == null) ? "Unitialized ClientsFile" : " failed to get lock on " + filelist.getAbsolutePath())); } // successful! return true; } }