Created
August 22, 2016 17:40
-
-
Save lenidh/d9fcae91fe36d30bc2003d8cb9214b9a to your computer and use it in GitHub Desktop.
Monitor file and directory pathnames to fire an event after the referenced file or directory was changed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright (c) 2016 Moritz J. Heindl | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
* SOFTWARE. | |
*/ | |
import java.util.TimerTask; | |
import java.util.Timer; | |
import java.io.File; | |
import java.io.IOException; | |
/** | |
* Monitors file and directory pathnames to fire an event after the referenced | |
* file or directory was changed. | |
* The monitoring method is polling. | |
* This class is thread-safe. | |
* <p> | |
* A change is either one of the following filesystem events: | |
* <ul> | |
* <li>The file or directory represented by the monitored pathname is modified, | |
* deleted or moved. | |
* <li>A file or directory is created at or moved to the monitored pathname. | |
* </ul> | |
* <p class="bug"> | |
* Some events are not fired for files and directories last modified at epoch | |
* (00:00:00 GMT, January 1, 1970). | |
* | |
* @see File | |
*/ | |
public abstract class FilePathObserver { | |
private final File monitored; | |
private final long period; | |
private final Object syncLock = new Object(); | |
// time that the file was last modified when last checked | |
private long timestamp; | |
private Timer timer; | |
/** | |
* Creates a new FilePathObserver for the specified pathname. | |
* Monitoring does not start on creation. | |
* <p> | |
* In the long run, the frequency of polling will generally be slightly | |
* lower than the reciprocal of the specified period (assuming the system | |
* clock underlying Object.wait(long) is accurate). | |
* | |
* @param pathname the pathname | |
* @param period time in milliseconds between polls | |
* @throws IllegalArgumentException if period is <= 0 | |
* @throws NullPointerException if pathname is null | |
* | |
* @see #startWatching() | |
*/ | |
public FilePathObserver(File pathname, long period) { | |
if(pathname == null) | |
throw new NullPointerException("Pathname must not be null."); | |
if(period <= 0) | |
throw new IllegalArgumentException("Period must be positive."); | |
this.monitored = pathname; | |
this.period = period; | |
this.timestamp = this.monitored.lastModified(); | |
} | |
/** | |
* The event handler, which must be implemented by subclasses. | |
* This method is invoked on the polling thread. | |
*/ | |
public abstract void onChange(); | |
/** | |
* Start watching for changes. | |
* If monitoring is already started, this call has no effect. | |
* | |
* @see #stopWatching() | |
*/ | |
public void startWatching() { | |
synchronized(this.syncLock) { | |
if(this.timer == null) { | |
this.timer = new Timer(); | |
this.timer.schedule(new CheckModifiedTask(), 0, period); | |
} | |
} | |
} | |
/** | |
* Stop watching for changes. | |
* If monitoring is already stopped, this call has no effect. | |
* | |
* @see #startWatching() | |
*/ | |
public void stopWatching() { | |
synchronized(this.syncLock) { | |
if(this.timer != null) { | |
this.timer.cancel(); | |
this.timer.purge(); | |
this.timer = null; | |
} | |
} | |
} | |
private class CheckModifiedTask extends TimerTask { | |
public void run() { | |
long lastModified = monitored.lastModified(); | |
if(lastModified != timestamp) { | |
timestamp = lastModified; | |
onChange(); | |
} | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment