/* EMBL - The European Bioinformatics institute * MSD Group * VAMSAS Project * * Copyright (c) 2005-2006 Thr European Bioinformatics Institute. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name MSD must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact msd-help@ebi.ac.uk * * 4. Products derived from this software may not be called "MSD" * nor may "MSD" appear in their names without prior written * permission of the MSD developers. * * 5. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by MSD * (http://www.ebi.ac.uk/)" * * THIS SOFTWARE IS PROVIDED BY THE MSD GROUP ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ENSEMBL GROUP OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * The European Bioinformatics Institute may publish revised and/or new * versions of this license with new releases of VAMSAS software. *============================================================================== * * @author Pierre MARGUERITE * * Dec 13, 2006 - VamsasClientV4 * */ package uk.ac.vamsas.client.simpleclient; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import uk.ac.vamsas.client.SessionHandle; /** * @author Pierre MARGUERITE * * */ public class SessionsFile extends ListFile { private static Log log = LogFactory.getLog(SessionsFile.class); /** * 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; /** * number of my session in list - passed back when a session * is added to list, and used (if valid) for quickly * looking up presence of session handle in the list. */ private int syncnum = 1; /** * @param file */ public SessionsFile(File file) throws java.io.IOException { super(file); } /** * internal method for getting sessionsList - ensures a lock has been made but * does not release it. * * @return list of clients */ private SessionHandle[] retrieveSessionHandles() { if (lockFile()) { try { SessionHandle[] clients=null; if (this.fileLock.length()>0) { ObjectInputStream is = new ObjectInputStream(this.fileLock.getBufferedInputStream(true)); Object o; o=is.readObject(); if (o!=null) { try { clients = (SessionHandle[]) o; } catch (Exception e) { log.error("Garbage in the clientHandle list "+this.sessionFile,e); } } } return clients; } catch (FileNotFoundException e) { // e.printStackTrace(System.err); log.error(e); } catch (Exception e) { log.error(e); //e.printStackTrace(System.err); } } return null; } /** * get the SessionsList from the file. May return null if lock failed! * @return sessionsList */ public SessionHandle[] retrieveSessionsList() { if (lockFile()) { SessionHandle[] clients = retrieveSessionHandles(); 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 SessionHandle[] retrieveSessionsList(Lock extantlock) { if (lockFile(extantlock)) { SessionHandle[] clients = retrieveSessionHandles(); 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 addSession(SessionHandle me, Lock extantLock) { return addSession(me, true, extantLock); } /** * adds SessionsHandle me to the sessionsList under an existing lock. * @param me - sessionsHandle * @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 addSession(SessionHandle session, boolean disambig, Lock extantLock) { if (lockFile(extantLock)) { this.syncnum = addSession(session, disambig); unlockFile(); return this.syncnum; } return 0; } /** * removes the current session from the SessionsList without complaint if the session isn't in the sessionsList already. * @param me client handle to be removed * @param clientlock existing lock passed from watcher. */ public void removeSession(SessionHandle session, Lock clientlock) { int mynum =-1; if (lockFile(clientlock)) { SessionHandle[] sessions = retrieveSessionHandles(); if (sessions != null) { if ((this.syncnum<=0 || this.syncnum>sessions.length) || sessions[this.syncnum-1]!=session) { for (int i = 0, j = sessions.length; i < j; i++) if (sessions[i].equals(session)) { mynum=i; break; } } else { mynum=this.syncnum-1; } if (mynum>-1) { SessionHandle[] newlist = new SessionHandle[sessions.length - 1]; for (int k=0,i = 0, j = sessions.length; i < j; i++) if (i!=mynum) newlist[k++] = sessions[i]; if (!putSessionsList(newlist)) throw new Error("Failed to write new sessionsList!"); // failed to put the sessionList to disk. } } unlockFile(); } else { throw new Error("Couldn't get lock for "+((sessionFile==null) ? "Unitialised sessionFile in SessionsFile" : this.sessionFile.getAbsolutePath())); } } /** * Adds a SessionHandle to the SessionList file - optionally disambiguating * the SessionHandle (modifes the URN). * Note: Caller is left to release the lock on the SessionList. * @param me * @param disambiguate - * flag indicating if the URN for me should be disambiguated to * differentiate between sessions. * @return index of sessionHandle in new list, or -1-position of existing * sessionHandle (if disambiguate is true) */ protected int addSession(SessionHandle session, boolean disambiguate) { int newsession = 0; int tries=5; while (tries-->0 && !lockFile()) try { Thread.sleep(1); } catch (Exception e){}; if (lockFile()) { SessionHandle[] sessions = retrieveSessionHandles(); if (sessions == null) { sessions = new SessionHandle[1]; sessions[0] = session; newsession = 1; } else { int k = 0; for (int i = 0, j = sessions.length; i < j; i++) { if ( sessions[i].equals(session)) { if (disambiguate) { while (sessions[i].equals(session)) { // 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; SessionHandle[] newlist = new SessionHandle[sessions.length + 1]; for (i = 0, j = sessions.length; i < j; i++) newlist[i] = sessions[i]; newlist[j] = session; sessions = newlist; newsession = j+1; } if (!putSessionsList(sessions)) return 0; // failed to put the clientList to disk. } return newsession; } /** * safely writes sessions array to the file referred to by sessionFile. * * @param clients * @return true if successful write. Throws Errors otherwise. */ protected boolean putSessionsList(SessionHandle[] clients) { if (lockFile()) { File templist=null; if (!this.backup || (templist = backupSessionFile()) != null) { int retries=3; while (retries-->0) { try { ObjectOutputStream os = new ObjectOutputStream(this.fileLock.getBufferedOutputStream(true)); log.debug("About to write "+clients.length+" sessionHandles to output stream."); os.writeObject(clients); os.close(); // All done - remove the backup. if (this.backup) templist.delete(); templist = null; retries=-1; } catch (Exception e) { // System.err //.println("Serious - problems writing to sessionFile."); log.error("Serious - problems writing to sessionFile.",e); if (retries>0 && templist != null) { // System.err.println("Recovering from Backup in " // + templist.getAbsolutePath()); log.error("Recovering from Backup in "+ templist.getAbsolutePath()); templist.renameTo(this.fileLock.target); } //e.printStackTrace(System.err); log.error(e); } } if (retries>-2) { // System.err // .println("Serious - problems writing to sessionFile. Giving Up."); log.error("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: " + ((this.sessionFile == null) ? "Unitialized ClientsFile" : " failed to get lock on " + this.sessionFile.getAbsolutePath())); } // successful! return true; } public void clearList() { if (lockFile()) { try { FileOutputStream fout = this.fileLock.getFileOutputStream(true); fout.flush(); fout.close(); } catch (Exception e) { throw new Error("Problems trying to clear clientlist!",e); } } } }