package de.axone.tools.watcher;
import java.io.File;
import java.io.Serializable;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.axone.exception.Assert;
/**
* Watches one file and can report if it has changed.
* To minimize io this check is only done in a given
* interval.
*
* @author flo
*/
public class FileWatcher implements Watcher<File>, Serializable {
private static final long serialVersionUID = 1L;
public static final Logger log =
LoggerFactory.getLogger( FileWatcher.class );
private static final double TIMEOUT = 2000; //2 s
private final File file;
private double lastModifiedTime = -1;
private double lastCheckTime = -1;
private double timeout;
/**
* Create a FileWatcher for one file with the given
* timeout.
*
* @param file to watch
* @param timeout which has to pass until a new check is done
*/
public FileWatcher( File file, double timeout ){
Assert.notNull( file, "file" );
this.file = file;
this.timeout = timeout;
}
/**
* Create a Filewatcher with a default timeout of 2s
*
* @param file
*/
public FileWatcher( File file ){
this( file, TIMEOUT );
}
@Override
public boolean haveChanged(){
boolean result = false;
double time = System.currentTimeMillis();
double div = time - lastCheckTime;
// See if timeout has passed to do a recheck
if( div >= timeout ){
lastCheckTime = time;
if( ! file.exists() ){
log.warn( "File " + file.getAbsolutePath() + " does not exist" );
return true;
}
double modifiedTime = file.lastModified();
if( lastModifiedTime < modifiedTime ){
if( log.isDebugEnabled() ) log.debug(
String.format( "File %s has changed (%d<%d)",
file.getAbsolutePath(),
(int)(lastModifiedTime/1000),
(int)(modifiedTime/1000) )
);
result = true;
lastModifiedTime = modifiedTime;
}
}
return result;
}
@Override
public File getWatched(){
return file;
}
@Override
public String toString(){
return
"FileWatcher for: " + file.getAbsolutePath() +
" timeout: " + timeout +
" Last modified: " + lastModifiedTime +
" Last check: + " + lastCheckTime;
}
/* STATIC METHODS for persistent Watchers */
private static HashMap<String, FileWatcher> staticWatchers = new HashMap<String, FileWatcher>();
public synchronized static FileWatcher staticWatcher( File file, double timeout ){
String key = file.getAbsolutePath() + "/" + timeout;
if( ! staticWatchers.containsKey( key ) ){
staticWatchers.put( key, new FileWatcher( file, timeout ) );
}
return staticWatchers.get( key );
}
public static FileWatcher staticWatcher( File file ){
return staticWatcher( file, TIMEOUT );
}
/**
* HashCode and equals work only on the unterlying file making FileWatcher
* useable as Map key for files
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( file == null ) ? 0 : file.hashCode() );
return result;
}
@Override
public boolean equals( Object obj ) {
if( this == obj )
return true;
if( obj == null )
return false;
if( !( obj instanceof FileWatcher ) )
return false;
FileWatcher other = (FileWatcher) obj;
if( file == null ) {
if( other.file != null )
return false;
} else if( !file.equals( other.file ) )
return false;
return true;
}
}