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