/* * 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 java.io.File; /** * Watches a particular file for its creation, deletion, or modification. The * watcher is thread safe and different instances watching the state of a * particular file carry their own state record for the file. */ public class FileWatcher { private File subject = null; private long lastStat[]; boolean waslocked = false; boolean exists = false; /** * transient lock on subject - can be passed back to calling class to preserve * new state of file for immediate reading. */ private Lock subjectLock = null; /** * clear local locks on subject. * */ private void clearLock() { if (subjectLock != null) subjectLock.release(); subjectLock = null; } /** * * @return true if subject exists and is locked by another process. */ private boolean checkLock() { if (subject != null && subject.exists()) { if (subjectLock != null) { subjectLock.release(); } subjectLock = LockFactory.tryLock(subject); if (subjectLock.isLocked()) { return false; } clearLock(); return true; } return false; } private long[] getStat(File subject) { return new long[] { subject.lastModified(), subject.length() }; } private boolean compStat(long[] stat, long[] newstat) { if (stat[0] != newstat[0] || stat[1] != newstat[1]) return false; return true; } /** * Detect changes in file state and release of any lock in place during * change. * * @return true if file state has changed. Leaves lock in subjectLock (ready * to be passed to caller) */ private boolean check() { if (subject != null) { if (!subject.exists()) { if (exists) { if (!waslocked) { // !checkLock()) { exists = false; // waslocked=false; return true; } } // locked - state change registered after lock is released return false; } else { long[] newStat = getStat(subject); // subject.lastModified(); if (!checkLock()) { // file is free to access, return state change if (!exists || !compStat(lastStat, newStat)) { waslocked = false; exists = true; lastStat = newStat; return true; } // no change return false; } else { waslocked = true; return false; } } } return false; } /** * updates internal record of file state when caller has intentionally * modified subject. (ignores locked-state of subject) */ public void setState() { if (subject != null) { if (exists = subject.exists()) { lastStat = getStat(subject); waslocked = false; } } } /** * Make a watcher for a particular file. If the file doesn't exist, the * watcher will watch for its creation (and indicate a change of state) For * locked files, the removal of a lock constitutes a change of state if the * file was modified. * * @param subject */ public FileWatcher(File subject) { this.subject = subject; setState(); } /** * Test for change in file state. Only indicates a change after any lock on a * file has been released. * * @return true if file has been modified. */ public boolean hasChanged() { boolean res = check(); clearLock(); return res; } /** * passes lock back to caller if hasChanged returned true. * * @return */ public Lock getChangedState() { boolean res = check(); if (res) return subjectLock; else { clearLock(); return null; } } /** * safely? getting current state of the watched file * * @return */ public long[] getCurrentState() { return getStat(subject); } /** * safely compare an externally recorded state with the current state for * significant modifications. * * @param a * @param b * @return */ public boolean diffState(long[] a, long[] b) { return compStat(a, b); } /** * @return the subject */ public File getSubject() { return subject; } }