2 * This file is part of the Vamsas Client version 0.2.
\r
3 * Copyright 2010 by Jim Procter, Iain Milne, Pierre Marguerite,
\r
4 * Andrew Waterhouse and Dominik Lindner.
\r
6 * Earlier versions have also been incorporated into Jalview version 2.4
\r
7 * since 2008, and TOPALi version 2 since 2007.
\r
9 * The Vamsas Client is free software: you can redistribute it and/or modify
\r
10 * it under the terms of the GNU Lesser General Public License as published by
\r
11 * the Free Software Foundation, either version 3 of the License, or
\r
12 * (at your option) any later version.
\r
14 * The Vamsas Client is distributed in the hope that it will be useful,
\r
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
17 * GNU Lesser General Public License for more details.
\r
19 * You should have received a copy of the GNU Lesser General Public License
\r
20 * along with the Vamsas Client. If not, see <http://www.gnu.org/licenses/>.
\r
22 package uk.ac.vamsas.client.simpleclient;
\r
24 import java.io.BufferedInputStream;
\r
25 import java.io.BufferedOutputStream;
\r
26 import java.io.File;
\r
27 import java.io.FileInputStream;
\r
28 import java.io.FileNotFoundException;
\r
29 import java.io.FileOutputStream;
\r
30 import java.io.IOException;
\r
31 import java.io.RandomAccessFile;
\r
32 import java.nio.channels.ReadableByteChannel;
\r
34 import org.apache.commons.logging.Log;
\r
35 import org.apache.commons.logging.LogFactory;
\r
38 * Basic methods for classes handling locked IO on files monitored by all
\r
39 * (simpleclient) clients in a vamsas session.
\r
41 * @author jimp TODO: support non nio file locking capable systems
\r
43 public class SessionFile {
\r
44 private static Log log = LogFactory.getLog(SessionFile.class);
\r
46 protected File sessionFile;
\r
48 protected Lock fileLock = null;
\r
50 protected SessionFile(File file) {
\r
55 protected boolean lockFile(Lock extantlock) {
\r
56 if (fileLock != null && !fileLock.isLocked()) {
\r
57 fileLock.release();// tidy up invalid lock
\r
60 if (extantlock != null && extantlock.isLocked())
\r
61 fileLock = extantlock; // THIS IS BROKEN - lockFile then nulls the lock.
\r
65 private boolean ensureSessionFile() {
\r
66 if (sessionFile != null) {
\r
67 if (!sessionFile.exists()) {
\r
70 if (!sessionFile.createNewFile()) {
\r
71 log.error("Failed to create file prior to locking: " + sessionFile);
\r
74 } catch (IOException e) {
\r
75 log.error("Exception when trying to create file " + sessionFile, e);
\r
81 log.error("ensureSessionFile called for non-initialised SessionFile!");
\r
86 * Get a lock for the SessionFile
\r
88 * @return true if lock was made
\r
90 protected boolean lockFile() {
\r
91 if (fileLock != null) {
\r
92 if (fileLock.isLocked()) {
\r
93 if (!ensureSessionFile())
\r
97 // lock failed for some reason.
\r
100 .info("Unexpected session file lock failure. Trying to get it again.");
\r
104 if (!ensureSessionFile())
\r
106 // TODO: see if we need to loop-wait for locks or they just block until
\r
111 if (fileLock == null || !fileLock.isLocked()) {
\r
112 // try { Thread.sleep(1); } catch (Exception e) {};
\r
113 fileLock = LockFactory.getLock(sessionFile, true); // TODO: wait around
\r
117 } while (tries > 0 && !fileLock.isLocked());
\r
118 if (!fileLock.isLocked())
\r
119 log.error("Failed to get lock for " + sessionFile);
\r
120 // fileLock = new Lock(sessionFile);
\r
121 return fileLock.isLocked();
\r
125 * Explicitly release the SessionFile's lock.
\r
127 * @return true if lock was released.
\r
129 protected void unlockFile() {
\r
130 if (fileLock != null) {
\r
131 fileLock.release();
\r
137 * Makes a backup of the sessionFile.
\r
139 * @return Backed up SessionFile or null if failed to make backup.
\r
141 protected File backupSessionFile() {
\r
142 return backupSessionFile(fileLock, sessionFile.getName(), ".old",
\r
143 sessionFile.getParentFile());
\r
146 protected File backupSessionFile(Lock extantLock, String backupPrefix,
\r
147 String backupSuffix, File backupDir) {
\r
148 File tempfile = null;
\r
149 if (lockFile(extantLock)) {
\r
151 tempfile = File.createTempFile(backupPrefix, backupSuffix, backupDir);
\r
152 long sourceln = fileLock.length();
\r
153 if (sourceln > 0) {
\r
154 FileOutputStream tos = new FileOutputStream(tempfile);
\r
155 ReadableByteChannel channel;
\r
156 channel = fileLock.getRaChannel().position(0);
\r
158 while (ntrans < sourceln) {
\r
160 ntrans += tlen = tos.getChannel().transferFrom(channel, ntrans,
\r
162 if (log.isDebugEnabled()) {
\r
163 log.debug("Transferred " + tlen + " out of " + sourceln
\r
168 if (!channel.isOpen())
\r
169 throw new Error("LIBRARY PORTABILITY ISSUE: "
\r
170 + tos.getChannel().getClass()
\r
171 + ".transferFrom closes source channel!");
\r
172 if (!lockFile(extantLock))
\r
173 throw new Error("LIBRARY PORTABILITY ISSUE: Lost lock for "
\r
174 + sessionFile.getName() + " after backup.");
\r
177 } catch (FileNotFoundException e1) {
\r
178 log.warn("Can't create temp file for " + sessionFile.getName(), e1);
\r
180 } catch (IOException e1) {
\r
181 log.warn("Error when copying content to temp file for "
\r
182 + sessionFile.getName(), e1);
\r
190 * Replaces data in sessionFile with data from file handled by another
\r
191 * sessionFile passes up any exceptions.
\r
194 * source for new data
\r
196 protected void updateFrom(Lock extantLock, SessionFile newData)
\r
197 throws IOException {
\r
198 log.debug("Updating " + sessionFile.getAbsolutePath() + " from "
\r
199 + newData.sessionFile.getAbsolutePath());
\r
200 if (newData == null)
\r
201 throw new IOException("Null newData object.");
\r
202 if (newData.sessionFile == null)
\r
203 throw new IOException("Null SessionFile in newData.");
\r
205 if (!lockFile(extantLock))
\r
206 throw new IOException("Failed to get write lock for " + sessionFile);
\r
207 if (!newData.lockFile())
\r
208 throw new IOException("Failed to get lock for updateFrom "
\r
209 + newData.sessionFile);
\r
210 RandomAccessFile nrafile = newData.fileLock.getRaFile();
\r
212 RandomAccessFile trafile = fileLock.getRaFile();
\r
214 * long tries=5000; while (trafile==null && --tries>0) {
\r
215 * log.debug("Lost lock on "+sessionFile+"! Re-trying for a transfer.");
\r
216 * lockFile(); trafile = fileLock.getRaFile(); }
\r
218 // TODO JBPNote: attempt to ensure save really saves the VamDoc.jar file
\r
220 trafile.getChannel()
\r
221 .transferFrom(nrafile.getChannel(), 0, nrafile.length());
\r
222 // JBPNote: attempt to close the streams to flush the data out
\r
223 // trafile.close();
\r
224 // nrafile.close();
\r
228 * remove all trace of the sessionFile file
\r
231 protected void eraseExistence() {
\r
233 if (sessionFile != null) {
\r
234 sessionFile.delete();
\r
235 sessionFile = null;
\r
242 * @see uk.ac.vamsas.client.simpleclient.Lock#getBufferedInputStream(boolean)
\r
244 public BufferedInputStream getBufferedInputStream(boolean atStart)
\r
245 throws IOException {
\r
247 return fileLock.getBufferedInputStream(atStart);
\r
253 * @see uk.ac.vamsas.client.simpleclient.Lock#getBufferedOutputStream(boolean)
\r
255 public BufferedOutputStream getBufferedOutputStream(boolean clear)
\r
256 throws IOException {
\r
258 return fileLock.getBufferedOutputStream(clear);
\r
264 * @see uk.ac.vamsas.client.simpleclient.Lock#getFileInputStream(boolean)
\r
266 public FileInputStream getFileInputStream(boolean atStart) throws IOException {
\r
268 return fileLock.getFileInputStream(atStart);
\r
274 * @see uk.ac.vamsas.client.simpleclient.Lock#getFileOutputStream(boolean)
\r
276 public FileOutputStream getFileOutputStream(boolean clear) throws IOException {
\r
278 return fileLock.getFileOutputStream(clear);
\r