OSDN Git Service

画面のプロファイル生成処理で共通化できる部分を共通化
[coroid/inqubus.git] / frontend / src / yukihane / inqubus / filewatch / FileWatch.java
1 package yukihane.inqubus.filewatch;
2
3 import static java.nio.file.StandardWatchEventKinds.*;
4
5 import java.io.IOException;
6 import java.nio.file.DirectoryStream;
7 import java.nio.file.FileSystems;
8 import java.nio.file.Files;
9 import java.nio.file.Path;
10 import java.nio.file.WatchEvent;
11 import java.nio.file.WatchEvent.Kind;
12 import java.nio.file.WatchKey;
13 import java.nio.file.WatchService;
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.logging.Level;
20 import java.util.logging.Logger;
21
22 /**
23  *
24  * @author yuki
25  */
26 public final class FileWatch implements Runnable {
27
28     private static final Logger logger = Logger.getLogger(FileWatch.class.getName());
29     private final Set<Path> files;
30     private final Set<Path> directories;
31
32     public FileWatch(Collection<Path> dirs) {
33         FileDir res = new FileDir();
34         getFileDir(dirs, res);
35
36         this.files = new HashSet<>(res.files);
37         this.directories = new HashSet<>(res.dirs);
38         if (logger.isLoggable(Level.FINER)) {
39             logger.log(Level.FINER, "search dirs: {0}", directories);
40             logger.log(Level.FINER, "exist files: {0}", files);
41         }
42     }
43
44     public Set<Path> getFiles() {
45         synchronized (files) {
46             return new HashSet<>(files);
47         }
48     }
49
50     private void getFileDir(Iterable<Path> paths, FileDir result) {
51         for (Path p : paths) {
52             getFileDir(p, result);
53         }
54     }
55
56     private void getFileDir(Path path, FileDir result) {
57         try {
58             if (Files.isDirectory(path)) {
59                 result.dirs.add(path);
60                 DirectoryStream<Path> dir = Files.newDirectoryStream(path);
61                 getFileDir(dir, result);
62             } else if (Files.isRegularFile(path)) {
63                 result.files.add(path);
64             }
65         } catch (IOException ex) {
66             logger.log(Level.WARNING, "パスの処理中にエラー: {0}", new Object[]{path});
67         }
68     }
69
70     private static class FileDir {
71
72         private final Set<Path> files = new HashSet<>();
73         private final Set<Path> dirs = new HashSet<>();
74     }
75
76     @Override
77     public void run() {
78         logger.log(Level.FINER, "FileWatch start");
79         final Map<WatchKey, Path> keys = new HashMap<>();
80         try {
81             final WatchService ws = FileSystems.getDefault().newWatchService();
82             for (Path p : directories) {
83                 final WatchKey key = p.register(ws, ENTRY_CREATE, ENTRY_DELETE);
84                 keys.put(key, p);
85             }
86
87             while (true) {
88                 final WatchKey wk = ws.take();
89
90                 final Path dir = keys.get(wk);
91                 if (dir == null) {
92                     System.err.println("WatchKey not recognized!!");
93                     continue;
94                 }
95
96                 for (final WatchEvent<?> event : wk.pollEvents()) {
97                     final Kind<?> kind = event.kind();
98
99                     if (kind == OVERFLOW) {
100                         continue;
101                     }
102
103                     if (kind == ENTRY_CREATE) {
104                         final Path p = (Path) event.context();
105                         final Path target = dir.resolve(p);
106                         if (Files.isRegularFile(target)) {
107                             logger.log(Level.FINER, "ファイル追加: {0}", target);
108                             synchronized (files) {
109                                 files.add(target);
110                             }
111                         }
112                     } else if (kind == ENTRY_DELETE) {
113                         final Path p = (Path) event.context();
114                         final Path target = dir.resolve(p);
115                         logger.log(Level.FINER, "ファイル削除: {0}", target);
116                         synchronized (files) {
117                             files.remove(target);
118                         }
119                     }
120                 }
121
122                 if (!wk.reset()) {
123                     System.out.println("No longer valid");
124                     wk.cancel();
125                     ws.close();
126                     break;
127                 }
128
129             }
130         } catch (InterruptedException ex) {
131             ex.printStackTrace();
132         } catch (IOException ex) {
133             ex.printStackTrace();
134         }
135     }
136 }