]> 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 r33216.
[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.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
25 \r
26 import org.simantics.fileimport.Activator;\r
27 import org.simantics.fileimport.FileImportService;\r
28 \r
29 /**\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
32  * \r
33  * @author Jani Simomaa\r
34  *\r
35  */\r
36 public class FileImportDropins {\r
37     \r
38     private static Thread watcherThread = null;\r
39     private static DropinsFolderWatcher watcher = null;\r
40 \r
41     /**\r
42      * Start watching the dropins folder which are located in\r
43      * ~/workspace/.metadata/plugins/org.simantics.fileimport/dropins\r
44      */\r
45     public static void watchDropinsFolder() {\r
46         if (watcher == null && watcherThread == null) {\r
47             try {\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
54             }\r
55         }\r
56     }\r
57     \r
58     /**\r
59      * Stop watching the dropins folder\r
60      */\r
61     public static void unwatchDropinsFolder() {\r
62         if (watcher == null)\r
63             return;\r
64         watcher.stop();\r
65         try {\r
66             watcherThread.join(500);\r
67             if (watcherThread.isAlive())\r
68                 watcherThread.interrupt();\r
69         } catch (InterruptedException e) {\r
70             e.printStackTrace();\r
71         }\r
72         watcherThread = null;\r
73         watcher = null;\r
74     }\r
75     \r
76     private static class DropinsFolderWatcher implements Runnable {\r
77 \r
78         private final Path dropinsFolder;\r
79         private final WatchService ws;\r
80         private final AtomicBoolean stopped = new AtomicBoolean(true);\r
81         \r
82         private final Map<WatchKey, Path> keys = new HashMap<>();\r
83         \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
89         }\r
90         \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
94             int count = 0;\r
95             while (!synced) {\r
96                 try (RandomAccessFile raf = new RandomAccessFile(f.toFile(), "rw")) {\r
97                     raf.getFD().sync();\r
98                     synced = true;\r
99                 } catch (IOException e) {\r
100                     if (count == 3) {\r
101                         throw e;\r
102                     } else {\r
103                         try {\r
104                             Thread.sleep(50);\r
105                         } catch (InterruptedException e1) {\r
106                             e1.printStackTrace();\r
107                         }\r
108                         count++;\r
109                     }\r
110                 }\r
111             }\r
112         }\r
113         \r
114         @Override\r
115         public void run() {\r
116             stopped.set(false);\r
117 \r
118             while (!stopped.get()) {\r
119                 try {\r
120                     WatchKey key = ws.take();\r
121                     for (WatchEvent<?> watchEvent : key.pollEvents()) {\r
122                         if (OVERFLOW == watchEvent.kind())\r
123                             continue; // loop\r
124                         \r
125                         @SuppressWarnings("unchecked")\r
126                         WatchEvent<Path> pathEvent = (WatchEvent<Path>) watchEvent;\r
127                         Kind<Path> kind = pathEvent.kind();\r
128                         \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
132                             continue;\r
133                         if (ENTRY_CREATE == kind) {\r
134                             System.out.println("New path created: " + newPath);\r
135                             int current = 0;\r
136                             \r
137                             while (!Files.isWritable(newPath) && current <= 10) {\r
138                                 System.out.println("Sleeping for file import (current=" + current +")");\r
139                                 Thread.sleep(200);\r
140                                 current++;\r
141                             }\r
142                             \r
143                             FileImportService.performFileImport(newPath, Optional.of(t -> {\r
144                                 if (t instanceof FileSystemException) {\r
145                                     try {\r
146                                         syncPath(newPath);\r
147                                     } catch (IOException e) {\r
148                                         e.printStackTrace();\r
149                                     }\r
150                                     FileImportService.performFileImport(newPath, Optional.empty());\r
151                                 } else {\r
152                                     t.printStackTrace();\r
153                                 }\r
154                             }));\r
155                             register(newPath);\r
156                             \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
162                         }\r
163                     }\r
164                     if (!key.reset()) {\r
165                         keys.remove(key);\r
166 //                        break; // loop\r
167                     }\r
168                 } catch (InterruptedException e) {\r
169                     if (!stopped.get())\r
170                         e.printStackTrace();\r
171                 } catch (Throwable t) {\r
172                     t.printStackTrace();\r
173                 }\r
174             }\r
175         }\r
176         \r
177         public void stop() {\r
178             stopped.set(true);\r
179         }\r
180         \r
181         private void registerAll(Path path) throws IOException {\r
182             Files.walkFileTree(path, new SimpleFileVisitor<Path>() {\r
183                 \r
184                 @Override\r
185                 public FileVisitResult preVisitDirectory(Path file, BasicFileAttributes attrs) throws IOException {\r
186                     register(file);\r
187                     return FileVisitResult.CONTINUE;\r
188                 }\r
189             });\r
190         }\r
191 \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
196             }\r
197         }\r
198     }\r
199 }\r