]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/file/BasicSyncFileVisitor.java
Make tree view more robust
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / file / BasicSyncFileVisitor.java
1 package org.argeo.cms.file;
2
3 import java.io.IOException;
4 import java.nio.file.FileVisitResult;
5 import java.nio.file.Files;
6 import java.nio.file.Path;
7 import java.nio.file.SimpleFileVisitor;
8 import java.nio.file.StandardCopyOption;
9 import java.nio.file.attribute.BasicFileAttributes;
10 import java.nio.file.attribute.FileTime;
11
12 /** Synchronises two directory structures. */
13 public class BasicSyncFileVisitor extends SimpleFileVisitor<Path> {
14 // TODO make it configurable
15 private boolean trace = false;
16
17 private final Path sourceBasePath;
18 private final Path targetBasePath;
19 private final boolean delete;
20 private final boolean recursive;
21
22 private SyncResult<Path> syncResult = new SyncResult<>();
23
24 public BasicSyncFileVisitor(Path sourceBasePath, Path targetBasePath, boolean delete, boolean recursive) {
25 this.sourceBasePath = sourceBasePath;
26 this.targetBasePath = targetBasePath;
27 this.delete = delete;
28 this.recursive = recursive;
29 }
30
31 @Override
32 public FileVisitResult preVisitDirectory(Path sourceDir, BasicFileAttributes attrs) throws IOException {
33 if (!recursive && !sourceDir.equals(sourceBasePath))
34 return FileVisitResult.SKIP_SUBTREE;
35 Path targetDir = toTargetPath(sourceDir);
36 Files.createDirectories(targetDir);
37 return FileVisitResult.CONTINUE;
38 }
39
40 @Override
41 public FileVisitResult postVisitDirectory(Path sourceDir, IOException exc) throws IOException {
42 if (delete) {
43 Path targetDir = toTargetPath(sourceDir);
44 for (Path targetPath : Files.newDirectoryStream(targetDir)) {
45 Path sourcePath = sourceDir.resolve(targetPath.getFileName());
46 if (!Files.exists(sourcePath)) {
47 try {
48 FsSyncUtils.delete(targetPath);
49 deleted(targetPath);
50 } catch (Exception e) {
51 deleteFailed(targetPath, exc);
52 }
53 }
54 }
55 }
56 return FileVisitResult.CONTINUE;
57 }
58
59 @Override
60 public FileVisitResult visitFile(Path sourceFile, BasicFileAttributes attrs) throws IOException {
61 Path targetFile = toTargetPath(sourceFile);
62 try {
63 if (!Files.exists(targetFile)) {
64 Files.copy(sourceFile, targetFile);
65 added(sourceFile, targetFile);
66 } else {
67 if (shouldOverwrite(sourceFile, targetFile)) {
68 Files.copy(sourceFile, targetFile, StandardCopyOption.REPLACE_EXISTING);
69 }
70 }
71 } catch (Exception e) {
72 copyFailed(sourceFile, targetFile, e);
73 }
74 return FileVisitResult.CONTINUE;
75 }
76
77 protected boolean shouldOverwrite(Path sourceFile, Path targetFile) throws IOException {
78 long sourceSize = Files.size(sourceFile);
79 long targetSize = Files.size(targetFile);
80 if (sourceSize != targetSize) {
81 return true;
82 }
83 FileTime sourceLastModif = Files.getLastModifiedTime(sourceFile);
84 FileTime targetLastModif = Files.getLastModifiedTime(targetFile);
85 if (sourceLastModif.compareTo(targetLastModif) > 0)
86 return true;
87 return shouldOverwriteLaterSameSize(sourceFile, targetFile);
88 }
89
90 protected boolean shouldOverwriteLaterSameSize(Path sourceFile, Path targetFile) {
91 return false;
92 }
93
94 // @Override
95 // public FileVisitResult visitFileFailed(Path sourceFile, IOException exc) throws IOException {
96 // error("Cannot sync " + sourceFile, exc);
97 // return FileVisitResult.CONTINUE;
98 // }
99
100 private Path toTargetPath(Path sourcePath) {
101 Path relativePath = sourceBasePath.relativize(sourcePath);
102 Path targetPath = targetBasePath.resolve(relativePath.toString());
103 return targetPath;
104 }
105
106 public Path getSourceBasePath() {
107 return sourceBasePath;
108 }
109
110 public Path getTargetBasePath() {
111 return targetBasePath;
112 }
113
114 protected void added(Path sourcePath, Path targetPath) {
115 syncResult.getAdded().add(targetPath);
116 if (isTraceEnabled())
117 trace("Added " + sourcePath + " as " + targetPath);
118 }
119
120 protected void modified(Path sourcePath, Path targetPath) {
121 syncResult.getModified().add(targetPath);
122 if (isTraceEnabled())
123 trace("Overwritten from " + sourcePath + " to " + targetPath);
124 }
125
126 protected void copyFailed(Path sourcePath, Path targetPath, Exception e) {
127 syncResult.addError(sourcePath, targetPath, e);
128 if (isTraceEnabled())
129 error("Cannot copy " + sourcePath + " to " + targetPath, e);
130 }
131
132 protected void deleted(Path targetPath) {
133 syncResult.getDeleted().add(targetPath);
134 if (isTraceEnabled())
135 trace("Deleted " + targetPath);
136 }
137
138 protected void deleteFailed(Path targetPath, Exception e) {
139 syncResult.addError(null, targetPath, e);
140 if (isTraceEnabled())
141 error("Cannot delete " + targetPath, e);
142 }
143
144 /** Log error. */
145 protected void error(Object obj, Throwable e) {
146 System.err.println(obj);
147 e.printStackTrace();
148 }
149
150 protected boolean isTraceEnabled() {
151 return trace;
152 }
153
154 protected void trace(Object obj) {
155 System.out.println(obj);
156 }
157
158 public SyncResult<Path> getSyncResult() {
159 return syncResult;
160 }
161
162 }