1 package uk.ac.vamsas.client.simpleclient;
3 import java.io.BufferedInputStream;
4 import java.io.BufferedOutputStream;
6 import java.io.FileInputStream;
7 import java.io.FileNotFoundException;
8 import java.io.FileOutputStream;
9 import java.io.IOException;
10 import java.io.RandomAccessFile;
11 import java.nio.channels.ReadableByteChannel;
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
17 * Basic methods for classes handling locked IO on files
18 * monitored by all (simpleclient) clients in a vamsas session.
20 *TODO: support non nio file locking capable systems
22 public class SessionFile {
23 private static Log log = LogFactory.getLog(SessionFile.class);
24 protected File sessionFile;
25 protected Lock fileLock = null;
27 protected SessionFile(File file) {
32 protected boolean lockFile(Lock extantlock) {
33 if (fileLock!=null && !fileLock.isLocked()) {
34 fileLock.release();// tidy up invalid lock
37 if (extantlock!=null && extantlock.isLocked())
38 fileLock=extantlock; // THIS IS BROKEN - lockFile then nulls the lock.
41 private boolean ensureSessionFile() {
42 if (sessionFile != null) {
43 if (!sessionFile.exists()) {
46 if (!sessionFile.createNewFile()) {
47 log.error("Failed to create file prior to locking: "+sessionFile);
50 } catch (IOException e) {
51 log.error("Exception when trying to create file "+sessionFile, e);
57 log.error("ensureSessionFile called for non-initialised SessionFile!");
61 * Get a lock for the SessionFile
63 * @return true if lock was made
65 protected boolean lockFile() {
66 if (fileLock != null) {
67 if (fileLock.isLocked()) {
68 if (!ensureSessionFile())
72 // lock failed for some reason.
74 log.info("Unexpected session file lock failure. Trying to get it again.");
78 if (!ensureSessionFile())
80 // TODO: see if we need to loop-wait for locks or they just block until
85 if (fileLock==null || !fileLock.isLocked()) {
86 //try { Thread.sleep(1); } catch (Exception e) {};
87 fileLock = LockFactory.getLock(sessionFile,true); // TODO: wait around if we can't get the lock.
89 } while (tries>0 && !fileLock.isLocked());
90 if (!fileLock.isLocked())
91 log.error("Failed to get lock for "+sessionFile);
92 // fileLock = new Lock(sessionFile);
93 return fileLock.isLocked();
97 * Explicitly release the SessionFile's lock.
99 * @return true if lock was released.
101 protected void unlockFile() {
102 if (fileLock != null) {
109 * Makes a backup of the sessionFile.
110 * @return Backed up SessionFile or null if failed to make backup.
112 protected File backupSessionFile() {
113 return backupSessionFile(fileLock, sessionFile.getName(),".old", sessionFile.getParentFile());
116 protected File backupSessionFile(Lock extantLock, String backupPrefix, String backupSuffix, File backupDir) {
118 if (lockFile(extantLock)) {
120 tempfile = File.createTempFile(backupPrefix, backupSuffix, backupDir);
121 long sourceln = fileLock.length();
123 FileOutputStream tos = new FileOutputStream(tempfile);
124 ReadableByteChannel channel;
125 channel = fileLock.getRaChannel().position(0);
127 while (ntrans<sourceln)
130 ntrans+= tlen = tos.getChannel().transferFrom(channel, ntrans,
132 if (log.isDebugEnabled())
135 ("Transferred "+tlen+" out of "+sourceln+" bytes");
139 if (!channel.isOpen())
140 throw new Error("LIBRARY PORTABILITY ISSUE: "+tos.getChannel().getClass()+".transferFrom closes source channel!");
141 if (!lockFile(extantLock))
142 throw new Error("LIBRARY PORTABILITY ISSUE: Lost lock for "+sessionFile.getName()+" after backup.");
145 } catch (FileNotFoundException e1) {
146 log.warn("Can't create temp file for "+sessionFile.getName(),e1);
148 } catch (IOException e1) {
149 log.warn("Error when copying content to temp file for "+sessionFile.getName(),e1);
156 * Replaces data in sessionFile with data from file handled by another sessionFile
157 * passes up any exceptions.
158 * @param newData source for new data
160 protected void updateFrom(Lock extantLock, SessionFile newData) throws IOException {
161 log.debug("Updating "+sessionFile.getAbsolutePath()+" from "+newData.sessionFile.getAbsolutePath());
163 throw new IOException("Null newData object.");
164 if (newData.sessionFile==null)
165 throw new IOException("Null SessionFile in newData.");
167 if (!lockFile(extantLock))
168 throw new IOException("Failed to get write lock for "+sessionFile);
169 if (!newData.lockFile())
170 throw new IOException("Failed to get lock for updateFrom "+newData.sessionFile);
171 RandomAccessFile nrafile = newData.fileLock.getRaFile();
173 RandomAccessFile trafile = fileLock.getRaFile();
175 while (trafile==null && --tries>0) {
176 log.debug("Lost lock on "+sessionFile+"! Re-trying for a transfer.");
178 trafile = fileLock.getRaFile();
180 // TODO JBPNote: attempt to ensure save really saves the VamDoc.jar file
182 trafile.getChannel().transferFrom(nrafile.getChannel(), 0,
184 // JBPNote: attempt to close the streams to flush the data out
189 * remove all trace of the sessionFile file
192 protected void eraseExistence() {
194 if (sessionFile!=null) {
195 sessionFile.delete();
200 * @see uk.ac.vamsas.client.simpleclient.Lock#getBufferedInputStream(boolean)
202 public BufferedInputStream getBufferedInputStream(boolean atStart) throws IOException {
204 return fileLock.getBufferedInputStream(atStart);
208 * @see uk.ac.vamsas.client.simpleclient.Lock#getBufferedOutputStream(boolean)
210 public BufferedOutputStream getBufferedOutputStream(boolean clear) throws IOException {
212 return fileLock.getBufferedOutputStream(clear);
216 * @see uk.ac.vamsas.client.simpleclient.Lock#getFileInputStream(boolean)
218 public FileInputStream getFileInputStream(boolean atStart) throws IOException {
220 return fileLock.getFileInputStream(atStart);
224 * @see uk.ac.vamsas.client.simpleclient.Lock#getFileOutputStream(boolean)
226 public FileOutputStream getFileOutputStream(boolean clear) throws IOException {
228 return fileLock.getFileOutputStream(clear);