-package org.simantics.fileimport.dropins;\r
-\r
-import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;\r
-import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;\r
-import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;\r
-import static java.nio.file.StandardWatchEventKinds.OVERFLOW;\r
-\r
-import java.io.IOException;\r
-import java.io.RandomAccessFile;\r
-import java.nio.file.FileSystem;\r
-import java.nio.file.FileSystemException;\r
-import java.nio.file.FileVisitResult;\r
-import java.nio.file.Files;\r
-import java.nio.file.Path;\r
-import java.nio.file.SimpleFileVisitor;\r
-import java.nio.file.WatchEvent;\r
-import java.nio.file.WatchEvent.Kind;\r
-import java.nio.file.WatchKey;\r
-import java.nio.file.WatchService;\r
-import java.nio.file.attribute.BasicFileAttributes;\r
-import java.util.HashMap;\r
-import java.util.Map;\r
-import java.util.Optional;\r
-import java.util.concurrent.atomic.AtomicBoolean;\r
-\r
-import org.simantics.fileimport.Activator;\r
-import org.simantics.fileimport.FileImportService;\r
-\r
-/**\r
- * Directory watcher based on {@link java.nio.file.WatchService} which will listen to file changes inside the dropins directory\r
- * ~/workspace/.metadata/plugins/org.simantics.fileimport/dropins\r
- * \r
- * @author Jani Simomaa\r
- *\r
- */\r
-public class FileImportDropins {\r
- \r
- private static Thread watcherThread = null;\r
- private static DropinsFolderWatcher watcher = null;\r
-\r
- /**\r
- * Start watching the dropins folder which are located in\r
- * ~/workspace/.metadata/plugins/org.simantics.fileimport/dropins\r
- */\r
- public static void watchDropinsFolder() {\r
- if (watcher == null && watcherThread == null) {\r
- try {\r
- watcher = new DropinsFolderWatcher(Activator.getDropinsFolder());\r
- watcherThread = new Thread(watcher, "Simantics Dropins Folder watcher thread");\r
- watcherThread.setDaemon(true);\r
- watcherThread.start();\r
- } catch (IOException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
- }\r
- \r
- /**\r
- * Stop watching the dropins folder\r
- */\r
- public static void unwatchDropinsFolder() {\r
- watcher.stop();\r
- try {\r
- watcherThread.join(500);\r
- if (watcherThread.isAlive())\r
- watcherThread.interrupt();\r
- } catch (InterruptedException e) {\r
- e.printStackTrace();\r
- }\r
- watcherThread = null;\r
- watcher = null;\r
- }\r
- \r
- private static class DropinsFolderWatcher implements Runnable {\r
-\r
- private final Path dropinsFolder;\r
- private final WatchService ws;\r
- private final AtomicBoolean stopped = new AtomicBoolean(true);\r
- \r
- private final Map<WatchKey, Path> keys = new HashMap<>();\r
- \r
- public DropinsFolderWatcher(Path dropinsFolder) throws IOException {\r
- this.dropinsFolder = dropinsFolder;\r
- FileSystem fs = dropinsFolder.getFileSystem();\r
- this.ws = fs.newWatchService();\r
- registerAll(this.dropinsFolder);\r
- }\r
- \r
- private static void syncPath(Path f) throws IOException {\r
- // Does not seem to need 's' according to unit test in Windows\r
- boolean synced = false;\r
- int count = 0;\r
- while (!synced) {\r
- try (RandomAccessFile raf = new RandomAccessFile(f.toFile(), "rw")) {\r
- raf.getFD().sync();\r
- synced = true;\r
- } catch (IOException e) {\r
- if (count == 3) {\r
- throw e;\r
- } else {\r
- try {\r
- Thread.sleep(50);\r
- } catch (InterruptedException e1) {\r
- e1.printStackTrace();\r
- }\r
- count++;\r
- }\r
- }\r
- }\r
- }\r
- \r
- @Override\r
- public void run() {\r
- stopped.set(false);\r
-\r
- while (!stopped.get()) {\r
- try {\r
- WatchKey key = ws.take();\r
- for (WatchEvent<?> watchEvent : key.pollEvents()) {\r
- if (OVERFLOW == watchEvent.kind())\r
- continue; // loop\r
- \r
- @SuppressWarnings("unchecked")\r
- WatchEvent<Path> pathEvent = (WatchEvent<Path>) watchEvent;\r
- Kind<Path> kind = pathEvent.kind();\r
- \r
- Path parent = keys.get(key);\r
- Path newPath = parent.resolve(pathEvent.context());\r
- if (FileImportService.DB_FILE.equals(newPath.getFileName().toString()))\r
- continue;\r
- if (ENTRY_CREATE == kind) {\r
- System.out.println("New path created: " + newPath);\r
- int current = 0;\r
- \r
- while (!Files.isWritable(newPath) && current <= 10) {\r
- System.out.println("Sleeping for file import (current=" + current +")");\r
- Thread.sleep(200);\r
- current++;\r
- }\r
- \r
- FileImportService.performFileImport(newPath, Optional.of(t -> {\r
- if (t instanceof FileSystemException) {\r
- try {\r
- syncPath(newPath);\r
- } catch (IOException e) {\r
- e.printStackTrace();\r
- }\r
- FileImportService.performFileImport(newPath, Optional.empty());\r
- } else {\r
- t.printStackTrace();\r
- }\r
- }));\r
- register(newPath);\r
- \r
- } else if (ENTRY_MODIFY == kind) {\r
- System.out.println("New path modified: " + newPath);\r
- } else if (ENTRY_DELETE == kind) {\r
- System.out.println("New path deleted: " + newPath);\r
- FileImportService.removeResourceForFile(newPath.toAbsolutePath(), Optional.empty());\r
- }\r
- }\r
- if (!key.reset()) {\r
- keys.remove(key);\r
-// break; // loop\r
- }\r
- } catch (InterruptedException e) {\r
- if (!stopped.get())\r
- e.printStackTrace();\r
- } catch (Throwable t) {\r
- t.printStackTrace();\r
- }\r
- }\r
- }\r
- \r
- public void stop() {\r
- stopped.set(true);\r
- }\r
- \r
- private void registerAll(Path path) throws IOException {\r
- Files.walkFileTree(path, new SimpleFileVisitor<Path>() {\r
- \r
- @Override\r
- public FileVisitResult preVisitDirectory(Path file, BasicFileAttributes attrs) throws IOException {\r
- register(file);\r
- return FileVisitResult.CONTINUE;\r
- }\r
- });\r
- }\r
-\r
- private void register(Path path) throws IOException {\r
- if (Files.isDirectory(path)) {\r
- WatchKey key = path.toAbsolutePath().register(ws, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);\r
- keys.put(key, path);\r
- }\r
- }\r
- }\r
-}\r
+package org.simantics.fileimport.dropins;
+
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.simantics.fileimport.Activator;
+import org.simantics.fileimport.FileImportService;
+
+/**
+ * Directory watcher based on {@link java.nio.file.WatchService} which will listen to file changes inside the dropins directory
+ * ~/workspace/.metadata/plugins/org.simantics.fileimport/dropins
+ *
+ * @author Jani Simomaa
+ *
+ */
+public class FileImportDropins {
+
+ private static Thread watcherThread = null;
+ private static DropinsFolderWatcher watcher = null;
+
+ /**
+ * Start watching the dropins folder which are located in
+ * ~/workspace/.metadata/plugins/org.simantics.fileimport/dropins
+ */
+ public static void watchDropinsFolder() {
+ if (watcher == null && watcherThread == null) {
+ try {
+ watcher = new DropinsFolderWatcher(Activator.getDropinsFolder());
+ watcherThread = new Thread(watcher, "Simantics Dropins Folder watcher thread");
+ watcherThread.setDaemon(true);
+ watcherThread.start();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Stop watching the dropins folder
+ */
+ public static void unwatchDropinsFolder() {
+ if (watcher == null)
+ return;
+ watcher.stop();
+ try {
+ watcherThread.join(500);
+ if (watcherThread.isAlive())
+ watcherThread.interrupt();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ watcherThread = null;
+ watcher = null;
+ }
+
+ private static class DropinsFolderWatcher implements Runnable {
+
+ private final Path dropinsFolder;
+ private final WatchService ws;
+ private final AtomicBoolean stopped = new AtomicBoolean(true);
+
+ private final Map<WatchKey, Path> keys = new HashMap<>();
+
+ public DropinsFolderWatcher(Path dropinsFolder) throws IOException {
+ this.dropinsFolder = dropinsFolder;
+ FileSystem fs = dropinsFolder.getFileSystem();
+ this.ws = fs.newWatchService();
+ registerAll(this.dropinsFolder);
+ }
+
+ private static void syncPath(Path f) throws IOException {
+ // Does not seem to need 's' according to unit test in Windows
+ boolean synced = false;
+ int count = 0;
+ while (!synced) {
+ try (RandomAccessFile raf = new RandomAccessFile(f.toFile(), "rw")) {
+ raf.getFD().sync();
+ synced = true;
+ } catch (IOException e) {
+ if (count == 3) {
+ throw e;
+ } else {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e1) {
+ e1.printStackTrace();
+ }
+ count++;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void run() {
+ stopped.set(false);
+
+ while (!stopped.get()) {
+ try {
+ WatchKey key = ws.take();
+ for (WatchEvent<?> watchEvent : key.pollEvents()) {
+ if (OVERFLOW == watchEvent.kind())
+ continue; // loop
+
+ @SuppressWarnings("unchecked")
+ WatchEvent<Path> pathEvent = (WatchEvent<Path>) watchEvent;
+ Kind<Path> kind = pathEvent.kind();
+
+ Path parent = keys.get(key);
+ Path newPath = parent.resolve(pathEvent.context());
+ if (FileImportService.DB_FILE.equals(newPath.getFileName().toString()))
+ continue;
+ if (ENTRY_CREATE == kind) {
+ System.out.println("New path created: " + newPath);
+ int current = 0;
+
+ while (!Files.isWritable(newPath) && current <= 10) {
+ System.out.println("Sleeping for file import (current=" + current +")");
+ Thread.sleep(200);
+ current++;
+ }
+
+ FileImportService.performFileImport(newPath, Optional.empty(), Optional.of(t -> {
+ if ((t instanceof FileSystemException) || (t instanceof FileNotFoundException)) {
+ try {
+ syncPath(newPath);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ FileImportService.performFileImport(newPath, Optional.empty(), Optional.empty());
+ } else {
+ t.printStackTrace();
+ }
+ }));
+ register(newPath);
+
+ } else if (ENTRY_MODIFY == kind) {
+ System.out.println("New path modified: " + newPath);
+ } else if (ENTRY_DELETE == kind) {
+ System.out.println("New path deleted: " + newPath);
+ FileImportService.removeResourceForFile(newPath.toAbsolutePath(), Optional.empty());
+ }
+ }
+ if (!key.reset()) {
+ keys.remove(key);
+// break; // loop
+ }
+ } catch (InterruptedException e) {
+ if (!stopped.get())
+ e.printStackTrace();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ }
+
+ public void stop() {
+ stopped.set(true);
+ }
+
+ private void registerAll(Path path) throws IOException {
+ Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path file, BasicFileAttributes attrs) throws IOException {
+ register(file);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+
+ private void register(Path path) throws IOException {
+ if (Files.isDirectory(path)) {
+ WatchKey key = path.toAbsolutePath().register(ws, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
+ keys.put(key, path);
+ }
+ }
+ }
+}