1 package org.simantics.fileimport.dropins;
\r
3 import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
\r
4 import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
\r
5 import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
\r
6 import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
\r
8 import java.io.IOException;
\r
9 import java.io.RandomAccessFile;
\r
10 import java.nio.file.FileSystem;
\r
11 import java.nio.file.FileSystemException;
\r
12 import java.nio.file.FileVisitResult;
\r
13 import java.nio.file.Files;
\r
14 import java.nio.file.Path;
\r
15 import java.nio.file.SimpleFileVisitor;
\r
16 import java.nio.file.WatchEvent;
\r
17 import java.nio.file.WatchEvent.Kind;
\r
18 import java.nio.file.WatchKey;
\r
19 import java.nio.file.WatchService;
\r
20 import java.nio.file.attribute.BasicFileAttributes;
\r
21 import java.util.HashMap;
\r
22 import java.util.Map;
\r
23 import java.util.Optional;
\r
24 import java.util.concurrent.atomic.AtomicBoolean;
\r
26 import org.simantics.fileimport.Activator;
\r
27 import org.simantics.fileimport.FileImportService;
\r
30 * Directory watcher based on {@link java.nio.file.WatchService} which will listen to file changes inside the dropins directory
\r
31 * ~/workspace/.metadata/plugins/org.simantics.fileimport/dropins
\r
33 * @author Jani Simomaa
\r
36 public class FileImportDropins {
\r
38 private static Thread watcherThread = null;
\r
39 private static DropinsFolderWatcher watcher = null;
\r
42 * Start watching the dropins folder which are located in
\r
43 * ~/workspace/.metadata/plugins/org.simantics.fileimport/dropins
\r
45 public static void watchDropinsFolder() {
\r
46 if (watcher == null && watcherThread == null) {
\r
48 watcher = new DropinsFolderWatcher(Activator.getDropinsFolder());
\r
49 watcherThread = new Thread(watcher, "Simantics Dropins Folder watcher thread");
\r
50 watcherThread.setDaemon(true);
\r
51 watcherThread.start();
\r
52 } catch (IOException e) {
\r
53 e.printStackTrace();
\r
59 * Stop watching the dropins folder
\r
61 public static void unwatchDropinsFolder() {
\r
62 if (watcher == null)
\r
66 watcherThread.join(500);
\r
67 if (watcherThread.isAlive())
\r
68 watcherThread.interrupt();
\r
69 } catch (InterruptedException e) {
\r
70 e.printStackTrace();
\r
72 watcherThread = null;
\r
76 private static class DropinsFolderWatcher implements Runnable {
\r
78 private final Path dropinsFolder;
\r
79 private final WatchService ws;
\r
80 private final AtomicBoolean stopped = new AtomicBoolean(true);
\r
82 private final Map<WatchKey, Path> keys = new HashMap<>();
\r
84 public DropinsFolderWatcher(Path dropinsFolder) throws IOException {
\r
85 this.dropinsFolder = dropinsFolder;
\r
86 FileSystem fs = dropinsFolder.getFileSystem();
\r
87 this.ws = fs.newWatchService();
\r
88 registerAll(this.dropinsFolder);
\r
91 private static void syncPath(Path f) throws IOException {
\r
92 // Does not seem to need 's' according to unit test in Windows
\r
93 boolean synced = false;
\r
96 try (RandomAccessFile raf = new RandomAccessFile(f.toFile(), "rw")) {
\r
99 } catch (IOException e) {
\r
105 } catch (InterruptedException e1) {
\r
106 e1.printStackTrace();
\r
115 public void run() {
\r
116 stopped.set(false);
\r
118 while (!stopped.get()) {
\r
120 WatchKey key = ws.take();
\r
121 for (WatchEvent<?> watchEvent : key.pollEvents()) {
\r
122 if (OVERFLOW == watchEvent.kind())
\r
125 @SuppressWarnings("unchecked")
\r
126 WatchEvent<Path> pathEvent = (WatchEvent<Path>) watchEvent;
\r
127 Kind<Path> kind = pathEvent.kind();
\r
129 Path parent = keys.get(key);
\r
130 Path newPath = parent.resolve(pathEvent.context());
\r
131 if (FileImportService.DB_FILE.equals(newPath.getFileName().toString()))
\r
133 if (ENTRY_CREATE == kind) {
\r
134 System.out.println("New path created: " + newPath);
\r
137 while (!Files.isWritable(newPath) && current <= 10) {
\r
138 System.out.println("Sleeping for file import (current=" + current +")");
\r
143 FileImportService.performFileImport(newPath, Optional.of(t -> {
\r
144 if (t instanceof FileSystemException) {
\r
147 } catch (IOException e) {
\r
148 e.printStackTrace();
\r
150 FileImportService.performFileImport(newPath, Optional.empty());
\r
152 t.printStackTrace();
\r
157 } else if (ENTRY_MODIFY == kind) {
\r
158 System.out.println("New path modified: " + newPath);
\r
159 } else if (ENTRY_DELETE == kind) {
\r
160 System.out.println("New path deleted: " + newPath);
\r
161 FileImportService.removeResourceForFile(newPath.toAbsolutePath(), Optional.empty());
\r
164 if (!key.reset()) {
\r
168 } catch (InterruptedException e) {
\r
169 if (!stopped.get())
\r
170 e.printStackTrace();
\r
171 } catch (Throwable t) {
\r
172 t.printStackTrace();
\r
177 public void stop() {
\r
181 private void registerAll(Path path) throws IOException {
\r
182 Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
\r
185 public FileVisitResult preVisitDirectory(Path file, BasicFileAttributes attrs) throws IOException {
\r
187 return FileVisitResult.CONTINUE;
\r
192 private void register(Path path) throws IOException {
\r
193 if (Files.isDirectory(path)) {
\r
194 WatchKey key = path.toAbsolutePath().register(ws, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
\r
195 keys.put(key, path);
\r