1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.datamodel.niofs.utils;
20
21 import java.io.IOException;
22 import java.nio.file.FileAlreadyExistsException;
23 import java.nio.file.FileSystemLoopException;
24 import java.nio.file.FileVisitResult;
25 import java.nio.file.FileVisitor;
26 import java.nio.file.Files;
27 import java.nio.file.NoSuchFileException;
28 import java.nio.file.Path;
29 import java.nio.file.StandardCopyOption;
30 import java.nio.file.attribute.BasicFileAttributes;
31 import java.nio.file.attribute.FileTime;
32
33 import org.apache.logging.log4j.LogManager;
34 import org.apache.logging.log4j.Logger;
35 import org.mycore.common.MCRSessionMgr;
36 import org.mycore.common.MCRTransactionHelper;
37
38
39
40
41
42
43 public class MCRTreeCopier implements FileVisitor<Path> {
44 private static final Logger LOGGER = LogManager.getLogger(MCRTreeCopier.class);
45
46 private final Path source;
47
48 private final Path target;
49
50 private final boolean renameExisting;
51
52 private final boolean restartTransaction;
53
54 public MCRTreeCopier(Path source, Path target) throws NoSuchFileException {
55 this(source, target, false, false);
56 }
57
58 public MCRTreeCopier(Path source, Path target, boolean renameOnExisting) throws NoSuchFileException {
59 this(source, target, renameOnExisting, false);
60 }
61
62 public MCRTreeCopier(Path source, Path target, boolean renameOnExisting, boolean restartTransaction)
63 throws NoSuchFileException {
64 this.renameExisting = renameOnExisting;
65 if (Files.notExists(target)) {
66 throw new NoSuchFileException(target.toString(), null, "Target directory does not exist.");
67 }
68 this.source = source;
69 this.target = target;
70 this.restartTransaction = restartTransaction;
71 }
72
73 @Override
74 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
75 Path newdir = target.resolve(toTargetFS(source.relativize(dir)));
76 try {
77 Files.copy(dir, newdir, StandardCopyOption.COPY_ATTRIBUTES);
78 } catch (FileAlreadyExistsException x) {
79
80
81 } catch (IOException x) {
82 LOGGER.error("Unable to create: {}", newdir, x);
83 return FileVisitResult.SKIP_SUBTREE;
84 }
85 return FileVisitResult.CONTINUE;
86 }
87
88 private void copyFile(Path source, Path target) {
89 try {
90 if (renameExisting && Files.exists(target)) {
91 int nameTry = 1;
92 String fileName = target.getFileName().toString();
93 int numberPosition = fileName.lastIndexOf(".") == -1 ? fileName.length() : fileName.lastIndexOf(".");
94 String prefixString = fileName.substring(0, numberPosition);
95 String suffixString = fileName.substring(numberPosition);
96 String newName = null;
97 Path parent = target.getParent();
98 do {
99 newName = prefixString + nameTry++ + suffixString;
100 target = parent.resolve(newName);
101 } while (Files.exists(target));
102 }
103 if (restartTransaction && MCRSessionMgr.hasCurrentSession()) {
104 MCRTransactionHelper.commitTransaction();
105 MCRTransactionHelper.beginTransaction();
106 }
107 Files.copy(source, target, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING);
108 } catch (IOException x) {
109 LOGGER.error("Unable to copy: {}", source, x);
110 }
111 }
112
113 private Path toTargetFS(Path source) {
114 if (target.getFileSystem().equals(source.getFileSystem())) {
115 return source;
116 }
117 String[] nameParts = new String[source.getNameCount() - 1];
118 for (int i = 0; i < nameParts.length; i++) {
119 nameParts[i] = source.getName(i + 1).toString();
120 }
121 return target.getFileSystem().getPath(source.getName(0).toString(), nameParts);
122 }
123
124 @Override
125 public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
126
127 if (exc == null) {
128 Path newdir = target.resolve(toTargetFS(source.relativize(dir)));
129 try {
130 FileTime time = Files.getLastModifiedTime(dir);
131 Files.setLastModifiedTime(newdir, time);
132 } catch (IOException x) {
133 LOGGER.error("Unable to copy all attributes to: {}", newdir, x);
134 }
135 }
136 return FileVisitResult.CONTINUE;
137 }
138
139 @Override
140 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
141 copyFile(file, target.resolve(toTargetFS(source.relativize(file))));
142 return FileVisitResult.CONTINUE;
143 }
144
145 @Override
146 public FileVisitResult visitFileFailed(Path file, IOException exc) {
147 if (exc instanceof FileSystemLoopException) {
148 LOGGER.error("cycle detected: {}", file);
149 } else {
150 LOGGER.error("Unable to copy: {}", file, exc);
151 }
152 return FileVisitResult.CONTINUE;
153 }
154 }