/* * This file is part of the Vamsas Client version 0.1. * Copyright 2009 by Jim Procter, Iain Milne, Pierre Marguerite, * Andrew Waterhouse and Dominik Lindner. * * Earlier versions have also been incorporated into Jalview version 2.4 * since 2008, and TOPALi version 2 since 2007. * * The Vamsas Client is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The Vamsas Client is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the Vamsas Client. If not, see . */ package uk.ac.vamsas.client.simpleclient; import uk.ac.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(); } if (!backup || (templist != 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); } } } }