// Path: src/main/java/com/thinksincode/tailstreamer/watch/FileListener.java
// public interface FileListener {
//     public void fileChanged(FileUpdateEvent event);
// }
// 
// Path: src/main/java/com/thinksincode/tailstreamer/watch/FileUpdateEvent.java
// public class FileUpdateEvent extends ApplicationEvent {
//     
//     public FileUpdateEvent(final Object source) {
//         super(source);
//     }
// }
// 
// Path: src/main/java/com/thinksincode/tailstreamer/watch/WatchServiceFileWatcher.java
// public class WatchServiceFileWatcher extends AbstractFileWatcher implements FileWatcher {
//     private Logger logger = LoggerFactory.getLogger(WatchServiceFileWatcher.class);
// 
//     /** Flag that indicates whether the watch service should continue. */
//     private boolean watch = true;
// 
//     /**
//      * Starts watching a file.
//      */
//     public void watchFile(final java.nio.file.Path watchedFile) {
//         try {
//             WatchService watchService = FileSystems.getDefault().newWatchService();
//             // WatchService only watches directories, so watch the file's parent
//             Path parent = Paths.get(watchedFile.getParent().toFile().getAbsolutePath());
//             parent.register(watchService, StandardWatchEventKind.ENTRY_MODIFY);
// 
//             // Wait for changes
//             for (boolean valid = true; watch && valid; ) {
//                 WatchKey key = watchService.take();
//                 List<WatchEvent<?>> events = key.pollEvents();
//                 for (WatchEvent<?> event : events) {
//                     // overflow events can happen, we don't care about them
//                     if (event.kind() == StandardWatchEventKind.OVERFLOW) {
//                         continue;
//                     }
// 
//                     // Events will fire for any files in the directory. Only
//                     // respond to changes to the file being watched
//                     Path changedFile = (Path) event.context();
//                     if (changedFile.toString().equals(watchedFile.getFileName().toString())) {
//                         notifyListeners(new FileUpdateEvent(this));
//                     }
//                 }
// 
//                 valid = key.reset();
//             }
//         } catch (IOException | ClosedWatchServiceException e) {
//             logger.error("Error while watching file: " + e.getMessage(), e);
//         } catch (InterruptedException ie) {
//             logger.warn("Watch service was interrupted", ie);
//         }
//     }
// 
//     /**
//      * Signals the watcher to stop watching.
//      */
//     public void stop() {
//         watch = false;
//     }
// }


import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import com.thinksincode.tailstreamer.watch.FileListener;
import com.thinksincode.tailstreamer.watch.FileUpdateEvent;
import com.thinksincode.tailstreamer.watch.WatchServiceFileWatcher;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
package com.thinksincode.tailstreamer;



public class WatchServiceFileWatcherTests {
    @Rule
    public TemporaryFolder folder = new TemporaryFolder();    
    
    @Test
    public void testWatchFile() throws IOException, InterruptedException {
        File file = folder.newFile();
        
        FileWatcherThread thread = new FileWatcherThread(file);
        thread.start();
        
        Thread.sleep(1000);
        
        FileWriter writer = new FileWriter(file);
        writer.write("Hello world!\n");
        writer.close();
        
        thread.join();
        Assert.assertTrue(thread.updated());
    }
    
    class FileWatcherThread extends Thread {
        private File file;        
        
        private boolean updated;
        
        public FileWatcherThread(final File file) {
            this.file = file;
        }
        
        public void run() {
            final WatchServiceFileWatcher watcher = new WatchServiceFileWatcher();
            watcher.addFileListener(new FileListener() {
                @Override
// Path: src/main/java/com/thinksincode/tailstreamer/watch/FileListener.java
// public interface FileListener {
//     public void fileChanged(FileUpdateEvent event);
// }
// 
// Path: src/main/java/com/thinksincode/tailstreamer/watch/FileUpdateEvent.java
// public class FileUpdateEvent extends ApplicationEvent {
//     
//     public FileUpdateEvent(final Object source) {
//         super(source);
//     }
// }
// 
// Path: src/main/java/com/thinksincode/tailstreamer/watch/WatchServiceFileWatcher.java
// public class WatchServiceFileWatcher extends AbstractFileWatcher implements FileWatcher {
//     private Logger logger = LoggerFactory.getLogger(WatchServiceFileWatcher.class);
// 
//     /** Flag that indicates whether the watch service should continue. */
//     private boolean watch = true;
// 
//     /**
//      * Starts watching a file.
//      */
//     public void watchFile(final java.nio.file.Path watchedFile) {
//         try {
//             WatchService watchService = FileSystems.getDefault().newWatchService();
//             // WatchService only watches directories, so watch the file's parent
//             Path parent = Paths.get(watchedFile.getParent().toFile().getAbsolutePath());
//             parent.register(watchService, StandardWatchEventKind.ENTRY_MODIFY);
// 
//             // Wait for changes
//             for (boolean valid = true; watch && valid; ) {
//                 WatchKey key = watchService.take();
//                 List<WatchEvent<?>> events = key.pollEvents();
//                 for (WatchEvent<?> event : events) {
//                     // overflow events can happen, we don't care about them
//                     if (event.kind() == StandardWatchEventKind.OVERFLOW) {
//                         continue;
//                     }
// 
//                     // Events will fire for any files in the directory. Only
//                     // respond to changes to the file being watched
//                     Path changedFile = (Path) event.context();
//                     if (changedFile.toString().equals(watchedFile.getFileName().toString())) {
//                         notifyListeners(new FileUpdateEvent(this));
//                     }
//                 }
// 
//                 valid = key.reset();
//             }
//         } catch (IOException | ClosedWatchServiceException e) {
//             logger.error("Error while watching file: " + e.getMessage(), e);
//         } catch (InterruptedException ie) {
//             logger.warn("Watch service was interrupted", ie);
//         }
//     }
// 
//     /**
//      * Signals the watcher to stop watching.
//      */
//     public void stop() {
//         watch = false;
//     }
// }


// Path: src/test/java/com/thinksincode/tailstreamer/WatchServiceFileWatcherTests.java
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import com.thinksincode.tailstreamer.watch.FileListener;
import com.thinksincode.tailstreamer.watch.FileUpdateEvent;
import com.thinksincode.tailstreamer.watch.WatchServiceFileWatcher;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

package com.thinksincode.tailstreamer;



public class WatchServiceFileWatcherTests {
    @Rule
    public TemporaryFolder folder = new TemporaryFolder();    
    
    @Test
    public void testWatchFile() throws IOException, InterruptedException {
        File file = folder.newFile();
        
        FileWatcherThread thread = new FileWatcherThread(file);
        thread.start();
        
        Thread.sleep(1000);
        
        FileWriter writer = new FileWriter(file);
        writer.write("Hello world!\n");
        writer.close();
        
        thread.join();
        Assert.assertTrue(thread.updated());
    }
    
    class FileWatcherThread extends Thread {
        private File file;        
        
        private boolean updated;
        
        public FileWatcherThread(final File file) {
            this.file = file;
        }
        
        public void run() {
            final WatchServiceFileWatcher watcher = new WatchServiceFileWatcher();
            watcher.addFileListener(new FileListener() {
                @Override
                public void fileChanged(FileUpdateEvent event) {