package org.jzonic.jlo;
import org.jzonic.jlo.events.FileListener;
import org.jzonic.jlo.events.FileListenerEvent;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
/**
* A class which implements an event dispatching mechanism to all
* classes supporting the FileListener interface. This class will
* notify all FileListeners when the configuration changes. Once
* the FileWatcher has been shutdown, the class needs to be
* reinstanciated and restarted.
*
* @author Andreas Mecky <andreas.mecky@xcom.de>
* @author Terry R. Dye <terry.dye@xcom.de>
*/
public class FileWatcher extends Thread {
private HashMap fileMap;
private HashMap fileListenerList;
private HashMap configMap;
private volatile Thread watcher;
private int interval = 1000;
private boolean running = true;
/**
* Creates a new instance of FileWatcher by calling the FileWatcher( File )
* Constructor.
*
* @param filename A String representing the path to the file to be watched.
*/
public FileWatcher() {
fileMap = new HashMap();
configMap = new HashMap();
fileListenerList = new HashMap();
setDaemon(true);
start();
}
public void addFile(String fileName) {
File file = new File(fileName);
if ( file.exists() ) {
long lastModified = file.lastModified();
fileMap.put(fileName,new Long(lastModified));
}
}
/**
* Adds FileListener
*
* @param fileListener The FileListener
*/
public void addFileListener( FileListener fileListener,String configurationName ) {
if ( !configMap.containsValue(configurationName)) {
List all = (List)fileListenerList.get(configurationName);
if ( all == null ) {
all = new Vector();
}
all.add(fileListener);
fileListenerList.put(configurationName, all );
String fn = configurationName;
if ( configurationName.equals("Default")) {
fn = "jlo_logging.xml";
}
else {
fn += "_logging.xml";
}
ClassLoader cl = getClass().getClassLoader();
java.net.URL url = cl.getResource(fn);
if (url != null) {
File file = new File(url.getFile());
addFile(file.getAbsolutePath()) ;
configMap.put(file,configurationName);
}
}
}
/**
* Set the timer interval. The default is 10 seconds
*
* @param seconds The number of seconds to set the interval when
* to check for the changes to the file.
*/
public void setInterval( int seconds ) {
this.interval = seconds*1000;
}
/**
* Tell thread to stop watching. Currently once a Thread is started
* and stopped, a new FileWatcher will be required.
*/
public void stopWatching() {
this.watcher = null;
}
/**
* Start the Thread on its journey to scan for changes to the
* file it is watching.
*/
public void start() {
watcher = new Thread( this );
watcher.setDaemon(true);
watcher.start();
}
/**
* Start the thread to call checkFile()
*/
public void run() {
Thread thisThread = Thread.currentThread();
//while (thisThread == watcher) {
while ( running ) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
// can't do much from here with Exception
watcher = null;
}
Iterator it = fileMap.keySet().iterator();
while ( it.hasNext() ) {
String fileName = (String)it.next();
long lastModified = ((Long)fileMap.get(fileName)).longValue();
lastModified = checkFile(fileName,lastModified);
fileMap.put(fileName,new Long(lastModified));
}
}
}
/**
* Retrieve an array of FileListeners.
*
* @return FileListeners as array of FileListener
*/
public FileListener[] getFileListeners() {
//return (FileListener[])fileListenerList.toArray();
//FIXME: fix the bug and get all listeners
return null;
}
private long checkFile(String fileName,long lm) {
File newFile = new File(fileName);
if( newFile.lastModified() > lm ) {
lm = newFile.lastModified();
String configName = (String)configMap.get(newFile);
List all = (List)fileListenerList.get(configName);
Iterator iterator = all.iterator();
while( iterator.hasNext() ) {
FileListener listener = (FileListener)iterator.next();
listener.fileChanged( new FileListenerEvent( newFile, configName) );
}
}
return lm;
}
}