1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.resourceloader.file;
35
36 import static info.magnolia.resourceloader.ResourceOriginChange.Type.*;
37 import static info.magnolia.resourceloader.ResourceOriginChange.resourceChange;
38
39 import info.magnolia.dirwatch.WatcherCallback;
40 import info.magnolia.resourceloader.ResourceOriginChange;
41
42 import java.io.IOException;
43 import java.nio.file.FileVisitOption;
44 import java.nio.file.FileVisitResult;
45 import java.nio.file.Files;
46 import java.nio.file.Path;
47 import java.nio.file.SimpleFileVisitor;
48 import java.nio.file.attribute.BasicFileAttributes;
49 import java.util.Collections;
50
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import com.google.common.base.Predicate;
55
56
57
58
59 class FileWatcherCallback implements WatcherCallback {
60
61 private static final Logger log = LoggerFactory.getLogger(FileWatcherCallback.class);
62
63 private final FileSystemResourceOrigin origin;
64 private final Predicate<Path> watchedPathFilter;
65
66 FileWatcherCallback(FileSystemResourceOrigin origin, Predicate<Path> watchedPathFilter) {
67 this.origin = origin;
68 this.watchedPathFilter = watchedPathFilter;
69 }
70
71
72
73
74
75
76
77 @Override
78 public void added(Path path) {
79 dispatchResourceChange(path, ADDED, true);
80 }
81
82
83
84
85
86
87
88 @Override
89 public void modified(Path path) {
90 dispatchResourceChange(path, MODIFIED, false);
91 }
92
93
94
95
96
97
98 @Override
99 public void removed(Path path) {
100 dispatchResourceChange(path, REMOVED, false);
101 }
102
103
104
105
106
107
108 private void dispatchResourceChange(Path changedResourcePath, ResourceOriginChange.Type type, boolean handleDirectoryContents) {
109 if (!watchedPathFilter.apply(changedResourcePath)) {
110 return;
111 }
112
113 final ResourceOriginChange.Builder resourceChange =
114 resourceChange().
115 ofType(type).
116 at(origin.parseResourcePath(changedResourcePath)).
117 inOrigin(origin);
118
119 origin.dispatchResourceChange(resourceChange.build());
120
121 if (handleDirectoryContents && Files.isDirectory(changedResourcePath)) {
122 try {
123 Files.walkFileTree(changedResourcePath, Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
124 @Override
125 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
126 if (watchedPathFilter.apply(file)) {
127 origin.dispatchResourceChange(resourceChange.at(origin.parseResourcePath(file)).build());
128 }
129 return FileVisitResult.CONTINUE;
130 }
131
132 @Override
133 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
134 if (!watchedPathFilter.apply(dir)) {
135 return FileVisitResult.SKIP_SUBTREE;
136 }
137 return FileVisitResult.CONTINUE;
138 }
139
140 @Override
141 public FileVisitResult visitFileFailed(Path file, IOException e) throws IOException {
142 log.warn("Visiting failed for {}", file);
143 return FileVisitResult.SKIP_SUBTREE;
144 }
145
146 });
147 } catch (IOException e) {
148 log.error("Failed to communicate file system resource changes recursively: {}", e.getMessage(), e);
149 }
150 }
151 }
152 }