]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.fileimport/src/org/simantics/fileimport/dropins/FileImportDropins.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.fileimport / src / org / simantics / fileimport / dropins / FileImportDropins.java
1 package org.simantics.fileimport.dropins;
2
3 import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
4 import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
5 import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
6 import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
7
8 import java.io.FileNotFoundException;
9 import java.io.IOException;
10 import java.io.RandomAccessFile;
11 import java.nio.file.FileSystem;
12 import java.nio.file.FileSystemException;
13 import java.nio.file.FileVisitResult;
14 import java.nio.file.Files;
15 import java.nio.file.Path;
16 import java.nio.file.SimpleFileVisitor;
17 import java.nio.file.WatchEvent;
18 import java.nio.file.WatchEvent.Kind;
19 import java.nio.file.WatchKey;
20 import java.nio.file.WatchService;
21 import java.nio.file.attribute.BasicFileAttributes;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.Optional;
25 import java.util.concurrent.atomic.AtomicBoolean;
26
27 import org.simantics.fileimport.Activator;
28 import org.simantics.fileimport.FileImportService;
29
30 /**
31  * Directory watcher based on {@link java.nio.file.WatchService} which will listen to file changes inside the dropins directory
32  * ~/workspace/.metadata/plugins/org.simantics.fileimport/dropins
33  * 
34  * @author Jani Simomaa
35  *
36  */
37 public class FileImportDropins {
38     
39     private static Thread watcherThread = null;
40     private static DropinsFolderWatcher watcher = null;
41
42     /**
43      * Start watching the dropins folder which are located in
44      * ~/workspace/.metadata/plugins/org.simantics.fileimport/dropins
45      */
46     public static void watchDropinsFolder() {
47         if (watcher == null && watcherThread == null) {
48             try {
49                 watcher = new DropinsFolderWatcher(Activator.getDropinsFolder());
50                 watcherThread = new Thread(watcher, "Simantics Dropins Folder watcher thread");
51                 watcherThread.setDaemon(true);
52                 watcherThread.start();
53             } catch (IOException e) {
54                 e.printStackTrace();
55             }
56         }
57     }
58     
59     /**
60      * Stop watching the dropins folder
61      */
62     public static void unwatchDropinsFolder() {
63         if (watcher == null)
64             return;
65         watcher.stop();
66         try {
67             watcherThread.join(500);
68             if (watcherThread.isAlive())
69                 watcherThread.interrupt();
70         } catch (InterruptedException e) {
71             e.printStackTrace();
72         }
73         watcherThread = null;
74         watcher = null;
75     }
76     
77     private static class DropinsFolderWatcher implements Runnable {
78
79         private final Path dropinsFolder;
80         private final WatchService ws;
81         private final AtomicBoolean stopped = new AtomicBoolean(true);
82         
83         private final Map<WatchKey, Path> keys = new HashMap<>();
84         
85         public DropinsFolderWatcher(Path dropinsFolder) throws IOException {
86             this.dropinsFolder = dropinsFolder;
87             FileSystem fs = dropinsFolder.getFileSystem();
88             this.ws = fs.newWatchService();
89             registerAll(this.dropinsFolder);
90         }
91         
92         private static void syncPath(Path f) throws IOException {
93             // Does not seem to need 's' according to unit test in Windows
94             boolean synced = false;
95             int count = 0;
96             while (!synced) {
97                 try (RandomAccessFile raf = new RandomAccessFile(f.toFile(), "rw")) {
98                     raf.getFD().sync();
99                     synced = true;
100                 } catch (IOException e) {
101                     if (count == 3) {
102                         throw e;
103                     } else {
104                         try {
105                             Thread.sleep(50);
106                         } catch (InterruptedException e1) {
107                             e1.printStackTrace();
108                         }
109                         count++;
110                     }
111                 }
112             }
113         }
114         
115         @Override
116         public void run() {
117             stopped.set(false);
118
119             while (!stopped.get()) {
120                 try {
121                     WatchKey key = ws.take();
122                     for (WatchEvent<?> watchEvent : key.pollEvents()) {
123                         if (OVERFLOW == watchEvent.kind())
124                             continue; // loop
125                         
126                         @SuppressWarnings("unchecked")
127                         WatchEvent<Path> pathEvent = (WatchEvent<Path>) watchEvent;
128                         Kind<Path> kind = pathEvent.kind();
129                         
130                         Path parent = keys.get(key);
131                         Path newPath = parent.resolve(pathEvent.context());
132                         if (FileImportService.DB_FILE.equals(newPath.getFileName().toString()))
133                             continue;
134                         if (ENTRY_CREATE == kind) {
135                             System.out.println("New path created: " + newPath);
136                             int current = 0;
137                             
138                             while (!Files.isWritable(newPath) && current <= 10) {
139                                 System.out.println("Sleeping for file import (current=" + current +")");
140                                 Thread.sleep(200);
141                                 current++;
142                             }
143                             
144                             FileImportService.performFileImport(newPath, Optional.empty(), Optional.of(t -> {
145                                 if ((t instanceof FileSystemException) || (t instanceof FileNotFoundException)) {
146                                     try {
147                                         syncPath(newPath);
148                                     } catch (IOException e) {
149                                         e.printStackTrace();
150                                     }
151                                     FileImportService.performFileImport(newPath, Optional.empty(), Optional.empty());
152                                 } else {
153                                     t.printStackTrace();
154                                 }
155                             }));
156                             register(newPath);
157                             
158                         } else if (ENTRY_MODIFY == kind) {
159                             System.out.println("New path modified: " + newPath);
160                         } else if (ENTRY_DELETE == kind) {
161                             System.out.println("New path deleted: " + newPath);
162                             FileImportService.removeResourceForFile(newPath.toAbsolutePath(), Optional.empty());
163                         }
164                     }
165                     if (!key.reset()) {
166                         keys.remove(key);
167 //                        break; // loop
168                     }
169                 } catch (InterruptedException e) {
170                     if (!stopped.get())
171                         e.printStackTrace();
172                 } catch (Throwable t) {
173                     t.printStackTrace();
174                 }
175             }
176         }
177         
178         public void stop() {
179             stopped.set(true);
180         }
181         
182         private void registerAll(Path path) throws IOException {
183             Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
184                 
185                 @Override
186                 public FileVisitResult preVisitDirectory(Path file, BasicFileAttributes attrs) throws IOException {
187                     register(file);
188                     return FileVisitResult.CONTINUE;
189                 }
190             });
191         }
192
193         private void register(Path path) throws IOException {
194             if (Files.isDirectory(path)) {
195                 WatchKey key = path.toAbsolutePath().register(ws, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
196                 keys.put(key, path);
197             }
198         }
199     }
200 }