1 package org
.argeo
.cms
.acr
.fs
;
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
;
12 /** Synchronises two directory structures. */
13 public class BasicSyncFileVisitor
extends SimpleFileVisitor
<Path
> {
14 // TODO make it configurable
15 private boolean trace
= false;
17 private final Path sourceBasePath
;
18 private final Path targetBasePath
;
19 private final boolean delete
;
20 private final boolean recursive
;
22 private SyncResult
<Path
> syncResult
= new SyncResult
<>();
24 public BasicSyncFileVisitor(Path sourceBasePath
, Path targetBasePath
, boolean delete
, boolean recursive
) {
25 this.sourceBasePath
= sourceBasePath
;
26 this.targetBasePath
= targetBasePath
;
28 this.recursive
= recursive
;
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
;
41 public FileVisitResult
postVisitDirectory(Path sourceDir
, IOException exc
) throws IOException
{
43 Path targetDir
= toTargetPath(sourceDir
);
44 for (Path targetPath
: Files
.newDirectoryStream(targetDir
)) {
45 Path sourcePath
= sourceDir
.resolve(targetPath
.getFileName());
46 if (!Files
.exists(sourcePath
)) {
48 FsSyncUtils
.delete(targetPath
);
50 } catch (Exception e
) {
51 deleteFailed(targetPath
, exc
);
56 return FileVisitResult
.CONTINUE
;
60 public FileVisitResult
visitFile(Path sourceFile
, BasicFileAttributes attrs
) throws IOException
{
61 Path targetFile
= toTargetPath(sourceFile
);
63 if (!Files
.exists(targetFile
)) {
64 Files
.copy(sourceFile
, targetFile
);
65 added(sourceFile
, targetFile
);
67 if (shouldOverwrite(sourceFile
, targetFile
)) {
68 Files
.copy(sourceFile
, targetFile
, StandardCopyOption
.REPLACE_EXISTING
);
71 } catch (Exception e
) {
72 copyFailed(sourceFile
, targetFile
, e
);
74 return FileVisitResult
.CONTINUE
;
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
) {
83 FileTime sourceLastModif
= Files
.getLastModifiedTime(sourceFile
);
84 FileTime targetLastModif
= Files
.getLastModifiedTime(targetFile
);
85 if (sourceLastModif
.compareTo(targetLastModif
) > 0)
87 return shouldOverwriteLaterSameSize(sourceFile
, targetFile
);
90 protected boolean shouldOverwriteLaterSameSize(Path sourceFile
, Path targetFile
) {
95 // public FileVisitResult visitFileFailed(Path sourceFile, IOException exc) throws IOException {
96 // error("Cannot sync " + sourceFile, exc);
97 // return FileVisitResult.CONTINUE;
100 private Path
toTargetPath(Path sourcePath
) {
101 Path relativePath
= sourceBasePath
.relativize(sourcePath
);
102 Path targetPath
= targetBasePath
.resolve(relativePath
.toString());
106 public Path
getSourceBasePath() {
107 return sourceBasePath
;
110 public Path
getTargetBasePath() {
111 return targetBasePath
;
114 protected void added(Path sourcePath
, Path targetPath
) {
115 syncResult
.getAdded().add(targetPath
);
116 if (isTraceEnabled())
117 trace("Added " + sourcePath
+ " as " + targetPath
);
120 protected void modified(Path sourcePath
, Path targetPath
) {
121 syncResult
.getModified().add(targetPath
);
122 if (isTraceEnabled())
123 trace("Overwritten from " + sourcePath
+ " to " + targetPath
);
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
);
132 protected void deleted(Path targetPath
) {
133 syncResult
.getDeleted().add(targetPath
);
134 if (isTraceEnabled())
135 trace("Deleted " + targetPath
);
138 protected void deleteFailed(Path targetPath
, Exception e
) {
139 syncResult
.addError(null, targetPath
, e
);
140 if (isTraceEnabled())
141 error("Cannot delete " + targetPath
, e
);
145 protected void error(Object obj
, Throwable e
) {
146 System
.err
.println(obj
);
150 protected boolean isTraceEnabled() {
154 protected void trace(Object obj
) {
155 System
.out
.println(obj
);
158 public SyncResult
<Path
> getSyncResult() {