1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.datamodel.niofs.ifs2;
20
21 import java.io.IOException;
22 import java.net.URI;
23 import java.nio.channels.FileChannel;
24 import java.nio.channels.SeekableByteChannel;
25 import java.nio.file.AccessDeniedException;
26 import java.nio.file.AccessMode;
27 import java.nio.file.AtomicMoveNotSupportedException;
28 import java.nio.file.CopyOption;
29 import java.nio.file.DirectoryNotEmptyException;
30 import java.nio.file.DirectoryStream;
31 import java.nio.file.DirectoryStream.Filter;
32 import java.nio.file.FileAlreadyExistsException;
33 import java.nio.file.FileStore;
34 import java.nio.file.FileSystem;
35 import java.nio.file.FileSystemAlreadyExistsException;
36 import java.nio.file.FileSystemNotFoundException;
37 import java.nio.file.Files;
38 import java.nio.file.InvalidPathException;
39 import java.nio.file.LinkOption;
40 import java.nio.file.NoSuchFileException;
41 import java.nio.file.NotDirectoryException;
42 import java.nio.file.OpenOption;
43 import java.nio.file.Path;
44 import java.nio.file.StandardCopyOption;
45 import java.nio.file.StandardOpenOption;
46 import java.nio.file.attribute.BasicFileAttributeView;
47 import java.nio.file.attribute.BasicFileAttributes;
48 import java.nio.file.attribute.FileAttribute;
49 import java.nio.file.attribute.FileAttributeView;
50 import java.nio.file.attribute.FileTime;
51 import java.nio.file.spi.FileSystemProvider;
52 import java.util.Collections;
53 import java.util.EnumSet;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.Map;
57 import java.util.Objects;
58 import java.util.Set;
59 import java.util.stream.Collectors;
60
61 import org.mycore.common.MCRException;
62 import org.mycore.common.config.MCRConfiguration2;
63 import org.mycore.datamodel.ifs2.MCRDirectory;
64 import org.mycore.datamodel.ifs2.MCRFile;
65 import org.mycore.datamodel.ifs2.MCRFileCollection;
66 import org.mycore.datamodel.ifs2.MCRStoredNode;
67 import org.mycore.datamodel.metadata.MCRObjectID;
68 import org.mycore.datamodel.niofs.MCRAbstractFileSystem;
69 import org.mycore.datamodel.niofs.MCRFileAttributes;
70 import org.mycore.datamodel.niofs.MCRMD5AttributeView;
71 import org.mycore.datamodel.niofs.MCRPath;
72 import org.mycore.frontend.fileupload.MCRUploadHelper;
73
74 import com.google.common.collect.Sets;
75
76
77
78
79 public class MCRFileSystemProvider extends FileSystemProvider {
80
81 public static final String SCHEME = "ifs2";
82
83 public static final URI FS_URI = URI.create(SCHEME + ":///");
84
85 private static MCRAbstractFileSystem FILE_SYSTEM_INSTANCE;
86
87 private static final Set<? extends CopyOption> SUPPORTED_COPY_OPTIONS = Collections.unmodifiableSet(EnumSet.of(
88 StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING));
89
90 private static final Set<? extends OpenOption> SUPPORTED_OPEN_OPTIONS = EnumSet.of(StandardOpenOption.APPEND,
91 StandardOpenOption.DSYNC, StandardOpenOption.READ, StandardOpenOption.SPARSE, StandardOpenOption.SYNC,
92 StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
93
94
95
96
97 @Override
98 public String getScheme() {
99 return SCHEME;
100 }
101
102
103
104
105 @Override
106 public FileSystem newFileSystem(URI uri, Map<String, ?> env) throws IOException {
107 throw new FileSystemAlreadyExistsException();
108 }
109
110
111
112
113 @Override
114 public MCRIFSFileSystem getFileSystem(URI uri) {
115 if (FILE_SYSTEM_INSTANCE == null) {
116 synchronized (this) {
117 if (FILE_SYSTEM_INSTANCE == null) {
118 FILE_SYSTEM_INSTANCE = new MCRIFSFileSystem(this);
119 }
120 }
121 }
122 return getMCRIFSFileSystem();
123 }
124
125
126
127
128 @Override
129 public Path getPath(final URI uri) {
130 if (!FS_URI.getScheme().equals(Objects.requireNonNull(uri).getScheme())) {
131 throw new FileSystemNotFoundException("Unkown filesystem: " + uri);
132 }
133 String path = uri.getPath().substring(1);
134 String owner = null;
135 for (int i = 0; i < path.length(); i++) {
136 if (path.charAt(i) == MCRAbstractFileSystem.SEPARATOR) {
137 break;
138 }
139 if (path.charAt(i) == ':') {
140 owner = path.substring(0, i);
141 path = path.substring(i + 1);
142 break;
143 }
144
145 }
146 return MCRAbstractFileSystem.getPath(owner, path, getMCRIFSFileSystem());
147 }
148
149
150
151
152 @Override
153 public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs)
154 throws IOException {
155 if (attrs.length > 0) {
156 throw new UnsupportedOperationException("Atomically setting of file attributes is not supported.");
157 }
158 MCRPath ifsPath = MCRFileSystemUtils.checkPathAbsolute(path);
159 Set<? extends OpenOption> fileOpenOptions = options.stream()
160 .filter(option -> !(option == StandardOpenOption.CREATE || option == StandardOpenOption.CREATE_NEW))
161 .collect(Collectors.toSet());
162 boolean create = options.contains(StandardOpenOption.CREATE);
163 boolean createNew = options.contains(StandardOpenOption.CREATE_NEW);
164 if (create || createNew) {
165 checkNewPathName(ifsPath);
166 for (OpenOption option : fileOpenOptions) {
167
168 checkOpenOption(option);
169 }
170 }
171 boolean channelCreateEvent = createNew || Files.notExists(ifsPath);
172 MCRFile mcrFile = MCRFileSystemUtils.getMCRFile(ifsPath, create, createNew, !channelCreateEvent);
173 if (mcrFile == null) {
174 throw new NoSuchFileException(path.toString());
175 }
176 boolean write = options.contains(StandardOpenOption.WRITE) || options.contains(StandardOpenOption.APPEND);
177 FileChannel baseChannel = (FileChannel) Files.newByteChannel(mcrFile.getLocalPath(), fileOpenOptions);
178 return new MCRFileChannel(ifsPath, mcrFile, baseChannel, write, channelCreateEvent);
179 }
180
181 private static void checkNewPathName(MCRPath ifsPath) throws IOException {
182
183 if (MCRConfiguration2.getBoolean("MCR.NIO.PathCreateNameCheck").orElse(true)) {
184 try {
185 MCRUploadHelper.checkPathName(ifsPath.getFileName().toString(), true);
186 } catch (MCRException e) {
187 throw new IOException(e.getMessage(), e);
188 }
189 }
190 }
191
192 static void checkOpenOption(OpenOption option) {
193 if (!SUPPORTED_OPEN_OPTIONS.contains(option)) {
194 throw new UnsupportedOperationException("Unsupported OpenOption: " + option.getClass().getSimpleName()
195 + "." + option);
196 }
197 }
198
199
200
201
202 @Override
203 public DirectoryStream<Path> newDirectoryStream(Path dir, Filter<? super Path> filter) throws IOException {
204 MCRPath mcrPath = MCRFileSystemUtils.checkPathAbsolute(dir);
205 MCRStoredNode node = MCRFileSystemUtils.resolvePath(mcrPath);
206 if (node instanceof MCRDirectory) {
207 return MCRDirectoryStreamHelper.getInstance((MCRDirectory) node, mcrPath);
208 }
209 throw new NotDirectoryException(dir.toString());
210 }
211
212
213
214
215 @Override
216 public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException {
217 if (attrs.length > 0) {
218 throw new UnsupportedOperationException("Setting 'attrs' atomically is unsupported.");
219 }
220 MCRPath mcrPath = MCRFileSystemUtils.checkPathAbsolute(dir);
221 MCRDirectory rootDirectory;
222 if (mcrPath.isAbsolute() && mcrPath.getNameCount() == 0) {
223 MCRObjectID derId = MCRObjectID.getInstance(mcrPath.getOwner());
224 org.mycore.datamodel.ifs2.MCRFileStore store = MCRFileSystemUtils.getStore(derId.getBase());
225 if (store.retrieve(derId.getNumberAsInteger()) != null) {
226 throw new FileAlreadyExistsException(mcrPath.toString());
227 }
228 store.create(derId.getNumberAsInteger());
229 return;
230 } else {
231
232 checkNewPathName(mcrPath);
233 }
234 rootDirectory = MCRFileSystemUtils.getFileCollection(mcrPath.getOwner());
235 MCRPath parentPath = mcrPath.getParent();
236 MCRPath absolutePath = getAbsolutePathFromRootComponent(parentPath);
237 MCRStoredNode childByPath = (MCRStoredNode) rootDirectory.getNodeByPath(absolutePath.toString());
238 if (childByPath == null) {
239 throw new NoSuchFileException(parentPath.toString(), dir.getFileName().toString(),
240 "parent directory does not exist");
241 }
242 if (childByPath instanceof MCRFile) {
243 throw new NotDirectoryException(parentPath.toString());
244 }
245 MCRDirectory parentDir = (MCRDirectory) childByPath;
246 String dirName = mcrPath.getFileName().toString();
247 if (parentDir.getChild(dirName) != null) {
248 throw new FileAlreadyExistsException(mcrPath.toString());
249 }
250 parentDir.createDir(dirName);
251 }
252
253 static MCRPath getAbsolutePathFromRootComponent(MCRPath mcrPath) {
254 if (!mcrPath.isAbsolute()) {
255 throw new InvalidPathException(mcrPath.toString(), "'path' must be absolute.");
256 }
257 String path = mcrPath.toString().substring(mcrPath.getOwner().length() + 1);
258 return MCRAbstractFileSystem.getPath(null, path, mcrPath.getFileSystem());
259 }
260
261
262
263
264 @Override
265 public void delete(Path path) throws IOException {
266 MCRPath mcrPath = MCRFileSystemUtils.checkPathAbsolute(path);
267 MCRStoredNode child = MCRFileSystemUtils.resolvePath(mcrPath);
268 if (child instanceof MCRDirectory && child.hasChildren()) {
269 throw new DirectoryNotEmptyException(mcrPath.toString());
270 }
271 try {
272 child.delete();
273 MCRPathEventHelper.fireFileDeleteEvent(path);
274 } catch (RuntimeException e) {
275 throw new IOException("Could not delete: " + mcrPath, e);
276 }
277 }
278
279
280
281
282 @Override
283 public void copy(Path source, Path target, CopyOption... options) throws IOException {
284 if (isSameFile(source, target)) {
285 return;
286 }
287 checkCopyOptions(options);
288 HashSet<CopyOption> copyOptions = Sets.newHashSet(options);
289 boolean createNew = !copyOptions.contains(StandardCopyOption.REPLACE_EXISTING);
290 MCRPath src = MCRFileSystemUtils.checkPathAbsolute(source);
291 MCRPath tgt = MCRFileSystemUtils.checkPathAbsolute(target);
292 MCRStoredNode srcNode = MCRFileSystemUtils.resolvePath(src);
293
294 if (tgt.getNameCount() == 0 && srcNode instanceof MCRDirectory) {
295 MCRDirectory tgtDir = MCRFileSystemUtils.getFileCollection(tgt.getOwner());
296 if (tgtDir != null) {
297 if (tgtDir.hasChildren() && copyOptions.contains(StandardCopyOption.REPLACE_EXISTING)) {
298 throw new DirectoryNotEmptyException(tgt.toString());
299 }
300 } else {
301 MCRObjectID tgtDerId = MCRObjectID.getInstance(tgt.getOwner());
302 org.mycore.datamodel.ifs2.MCRFileStore store = MCRFileSystemUtils.getStore(tgtDerId.getBase());
303 MCRFileCollection tgtCollection = store.create(tgtDerId.getNumberAsInteger());
304 if (copyOptions.contains(StandardCopyOption.COPY_ATTRIBUTES)) {
305 copyDirectoryAttributes((MCRDirectory) srcNode, tgtCollection);
306 }
307 }
308 return;
309 }
310 if (srcNode instanceof MCRFile) {
311 copyFile((MCRFile) srcNode, tgt, copyOptions, createNew);
312 } else if (srcNode instanceof MCRDirectory) {
313 copyDirectory((MCRDirectory) srcNode, tgt, copyOptions);
314 }
315 }
316
317 private static void copyFile(MCRFile srcNode, MCRPath target, HashSet<CopyOption> copyOptions, boolean createNew)
318 throws IOException {
319 MCRFile srcFile = srcNode;
320 boolean fireCreateEvent = createNew || Files.notExists(target);
321 MCRFile targetFile = MCRFileSystemUtils.getMCRFile(target, true, createNew, !fireCreateEvent);
322 targetFile.setContent(srcFile.getContent());
323 if (copyOptions.contains(StandardCopyOption.COPY_ATTRIBUTES)) {
324 copyFileAttributes(srcFile, targetFile);
325 }
326 if (fireCreateEvent) {
327 MCRPathEventHelper.fireFileCreateEvent(target, targetFile.getBasicFileAttributes());
328 } else {
329 MCRPathEventHelper.fireFileUpdateEvent(target, targetFile.getBasicFileAttributes());
330 }
331 }
332
333 private static void copyDirectory(MCRDirectory srcNode, MCRPath target, HashSet<CopyOption> copyOptions)
334 throws IOException {
335 MCRDirectory tgtParentDir = MCRFileSystemUtils.resolvePath(target.getParent());
336 MCRStoredNode child = (MCRStoredNode) tgtParentDir.getChild(target.getFileName().toString());
337 if (child != null) {
338 if (!copyOptions.contains(StandardCopyOption.REPLACE_EXISTING)) {
339 throw new FileAlreadyExistsException(tgtParentDir.toString(), target.getFileName().toString(), null);
340 }
341 if (child instanceof MCRFile) {
342 throw new NotDirectoryException(target.toString());
343 }
344 MCRDirectory tgtDir = (MCRDirectory) child;
345 if (tgtDir.hasChildren() && copyOptions.contains(StandardCopyOption.REPLACE_EXISTING)) {
346 throw new DirectoryNotEmptyException(target.toString());
347 }
348 if (copyOptions.contains(StandardCopyOption.COPY_ATTRIBUTES)) {
349 copyDirectoryAttributes(srcNode, tgtDir);
350 }
351 } else {
352
353 @SuppressWarnings("unused")
354 MCRDirectory tgtDir = tgtParentDir.createDir(target.getFileName().toString());
355 if (copyOptions.contains(StandardCopyOption.COPY_ATTRIBUTES)) {
356 copyDirectoryAttributes(srcNode, tgtDir);
357 }
358 }
359 }
360
361 private static void copyFileAttributes(MCRFile source, MCRFile target)
362 throws IOException {
363 Path targetLocalFile = target.getLocalPath();
364 BasicFileAttributeView targetBasicFileAttributeView = Files.getFileAttributeView(targetLocalFile,
365 BasicFileAttributeView.class);
366 BasicFileAttributes srcAttr = Files.readAttributes(source.getLocalPath(), BasicFileAttributes.class);
367 target.setMD5(source.getMD5());
368 targetBasicFileAttributeView.setTimes(srcAttr.lastModifiedTime(), srcAttr.lastAccessTime(),
369 srcAttr.creationTime());
370 }
371
372 private static void copyDirectoryAttributes(MCRDirectory source, MCRDirectory target)
373 throws IOException {
374 Path tgtLocalPath = target.getLocalPath();
375 Path srcLocalPath = source.getLocalPath();
376 BasicFileAttributes srcAttrs = Files
377 .readAttributes(srcLocalPath, BasicFileAttributes.class);
378 Files.getFileAttributeView(tgtLocalPath, BasicFileAttributeView.class)
379 .setTimes(srcAttrs.lastModifiedTime(), srcAttrs.lastAccessTime(), srcAttrs.creationTime());
380 }
381
382 private void checkCopyOptions(CopyOption[] options) {
383 for (CopyOption option : options) {
384 if (!SUPPORTED_COPY_OPTIONS.contains(option)) {
385 throw new UnsupportedOperationException("Unsupported copy option: " + option);
386 }
387 }
388 }
389
390
391
392
393 @Override
394 public void move(Path source, Path target, CopyOption... options) throws IOException {
395 HashSet<CopyOption> copyOptions = Sets.newHashSet(options);
396 if (copyOptions.contains(StandardCopyOption.ATOMIC_MOVE)) {
397 throw new AtomicMoveNotSupportedException(source.toString(), target.toString(),
398 "ATOMIC_MOVE not supported yet");
399 }
400 if (Files.isDirectory(source)) {
401 MCRPath src = MCRFileSystemUtils.checkPathAbsolute(source);
402 MCRDirectory srcRootDirectory = MCRFileSystemUtils.getFileCollection(src.getOwner());
403 if (srcRootDirectory.hasChildren()) {
404 throw new IOException("Directory is not empty");
405 }
406 }
407 copy(source, target, options);
408 delete(source);
409 }
410
411
412
413
414 @Override
415 public boolean isSameFile(Path path, Path path2) throws IOException {
416 return MCRFileSystemUtils.checkPathAbsolute(path).equals(MCRFileSystemUtils.checkPathAbsolute(path2));
417 }
418
419
420
421
422 @Override
423 public boolean isHidden(Path path) throws IOException {
424 MCRFileSystemUtils.checkPathAbsolute(path);
425 return false;
426 }
427
428
429
430
431 @Override
432 public FileStore getFileStore(Path path) throws IOException {
433 MCRPath mcrPath = MCRFileSystemUtils.checkPathAbsolute(path);
434 MCRStoredNode node = MCRFileSystemUtils.resolvePath(mcrPath);
435 return MCRFileStore.getInstance(node);
436 }
437
438
439
440
441 @Override
442 public void checkAccess(Path path, AccessMode... modes) throws IOException {
443 MCRPath mcrPath = MCRFileSystemUtils.checkPathAbsolute(path);
444 MCRStoredNode node = MCRFileSystemUtils.resolvePath(mcrPath);
445 if (node == null) {
446 throw new NoSuchFileException(mcrPath.toString());
447 }
448 if (node instanceof MCRDirectory) {
449 checkDirectoryAccessModes(modes);
450 } else {
451 checkFile((MCRFile) node, modes);
452 }
453 }
454
455 private void checkDirectoryAccessModes(AccessMode... modes) throws AccessDeniedException {
456 for (AccessMode mode : modes) {
457 switch (mode) {
458 case READ:
459 case WRITE:
460 case EXECUTE:
461 break;
462 default:
463 throw new AccessDeniedException("Unsupported AccessMode: " + mode);
464 }
465 }
466 }
467
468 private void checkFile(MCRFile file, AccessMode... modes) throws AccessDeniedException {
469 for (AccessMode mode : modes) {
470 switch (mode) {
471 case READ:
472 case WRITE:
473 break;
474 case EXECUTE:
475 throw new AccessDeniedException(MCRFileSystemUtils.toPath(file).toString(), null,
476 "Unsupported AccessMode: " + mode);
477 default:
478 throw new AccessDeniedException("Unsupported AccessMode: " + mode);
479 }
480 }
481 }
482
483
484
485
486 @SuppressWarnings("unchecked")
487 @Override
488 public <V extends FileAttributeView> V getFileAttributeView(Path path, Class<V> type, LinkOption... options) {
489 MCRPath mcrPath = MCRFileSystemUtils.checkPathAbsolute(path);
490
491 if (type == BasicFileAttributeView.class) {
492 return (V) new BasicFileAttributeViewImpl(mcrPath);
493 }
494 if (type == MCRMD5AttributeView.class) {
495 return (V) new MD5FileAttributeViewImpl(mcrPath);
496 }
497 return null;
498 }
499
500
501
502
503 @SuppressWarnings("unchecked")
504 @Override
505 public <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption... options)
506 throws IOException {
507 MCRPath mcrPath = MCRFileSystemUtils.checkPathAbsolute(path);
508 MCRStoredNode node = MCRFileSystemUtils.resolvePath(mcrPath);
509
510 if (type == BasicFileAttributes.class || type == MCRFileAttributes.class) {
511 return (A) MCRBasicFileAttributeViewImpl.readAttributes(node);
512 }
513 return null;
514 }
515
516
517
518
519 @Override
520 public Map<String, Object> readAttributes(Path path, String attributes, LinkOption... options) throws IOException {
521 MCRPath mcrPath = MCRFileSystemUtils.checkPathAbsolute(path);
522 String[] s = splitAttrName(attributes);
523 if (s[0].length() == 0) {
524 throw new IllegalArgumentException(attributes);
525 }
526 BasicFileAttributeViewImpl view = null;
527 switch (s[0]) {
528 case "basic":
529 view = new BasicFileAttributeViewImpl(mcrPath);
530 break;
531 case "md5":
532 view = new MD5FileAttributeViewImpl(mcrPath);
533 break;
534 default:
535 throw new UnsupportedOperationException("View '" + s[0] + "' not available");
536 }
537 return view.getAttributeMap(s[1].split(","));
538 }
539
540 private static String[] splitAttrName(String attribute) {
541 String[] s = new String[2];
542 int pos = attribute.indexOf(':');
543 if (pos == -1) {
544 s[0] = "basic";
545 s[1] = attribute;
546 } else {
547 s[0] = attribute.substring(0, pos++);
548 s[1] = (pos == attribute.length()) ? "" : attribute.substring(pos);
549 }
550 return s;
551 }
552
553
554
555
556 @Override
557 public void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException {
558 throw new UnsupportedOperationException("setAttributes is not implemented yet.");
559 }
560
561 public static MCRIFSFileSystem getMCRIFSFileSystem() {
562 return (MCRIFSFileSystem) (FILE_SYSTEM_INSTANCE == null ? MCRAbstractFileSystem.getInstance(SCHEME)
563 : FILE_SYSTEM_INSTANCE);
564 }
565
566 static class BasicFileAttributeViewImpl extends MCRBasicFileAttributeViewImpl {
567 private static final String SIZE_NAME = "size";
568
569 private static final String CREATION_TIME_NAME = "creationTime";
570
571 private static final String LAST_ACCESS_TIME_NAME = "lastAccessTime";
572
573 private static final String LAST_MODIFIED_TIME_NAME = "lastModifiedTime";
574
575 private static final String FILE_KEY_NAME = "fileKey";
576
577 private static final String IS_DIRECTORY_NAME = "isDirectory";
578
579 private static final String IS_REGULAR_FILE_NAME = "isRegularFile";
580
581 private static final String IS_SYMBOLIC_LINK_NAME = "isSymbolicLink";
582
583 private static final String IS_OTHER_NAME = "isOther";
584
585 private static HashSet<String> allowedAttr = Sets.newHashSet("*", SIZE_NAME, CREATION_TIME_NAME,
586 LAST_ACCESS_TIME_NAME, LAST_MODIFIED_TIME_NAME, FILE_KEY_NAME, IS_DIRECTORY_NAME, IS_REGULAR_FILE_NAME,
587 IS_SYMBOLIC_LINK_NAME, IS_OTHER_NAME);
588
589 protected MCRPath path;
590
591 BasicFileAttributeViewImpl(Path path) {
592 this.path = MCRPath.toMCRPath(path);
593 if (!path.isAbsolute()) {
594 throw new InvalidPathException(path.toString(), "'path' must be absolute.");
595 }
596 }
597
598 @Override
599 protected MCRStoredNode resolveNode() throws IOException {
600 return MCRFileSystemUtils.resolvePath(this.path);
601 }
602
603 public Map<String, Object> getAttributeMap(String... attributes) throws IOException {
604 Set<String> allowed = getAllowedAttributes();
605 boolean copyAll = false;
606 for (String attr : attributes) {
607 if (!allowed.contains(attr)) {
608 throw new IllegalArgumentException("'" + attr + "' not recognized");
609 }
610 if ("*".equals(attr)) {
611 copyAll = true;
612 }
613 }
614 Set<String> requested = copyAll ? allowed : Sets.newHashSet(attributes);
615 return buildMap(requested, readAttributes());
616 }
617
618 protected Map<String, Object> buildMap(Set<String> requested, MCRFileAttributes<String> attrs) {
619 HashMap<String, Object> map = new HashMap<>();
620 for (String attr : map.keySet()) {
621 switch (attr) {
622 case SIZE_NAME:
623 map.put(attr, attrs.size());
624 break;
625 case CREATION_TIME_NAME:
626 map.put(attr, attrs.creationTime());
627 break;
628 case LAST_ACCESS_TIME_NAME:
629 map.put(attr, attrs.lastAccessTime());
630 break;
631 case LAST_MODIFIED_TIME_NAME:
632 map.put(attr, attrs.lastModifiedTime());
633 break;
634 case FILE_KEY_NAME:
635 map.put(attr, attrs.fileKey());
636 break;
637 case IS_DIRECTORY_NAME:
638 map.put(attr, attrs.isDirectory());
639 break;
640 case IS_REGULAR_FILE_NAME:
641 map.put(attr, attrs.isRegularFile());
642 break;
643 case IS_SYMBOLIC_LINK_NAME:
644 map.put(attr, attrs.isSymbolicLink());
645 break;
646 case IS_OTHER_NAME:
647 map.put(attr, attrs.isOther());
648 break;
649 default:
650
651 break;
652 }
653 }
654 return map;
655 }
656
657 public void setAttribute(String name, Object value) throws IOException {
658 Set<String> allowed = getAllowedAttributes();
659 if ("*".equals(name) || !allowed.contains(name)) {
660 throw new IllegalArgumentException("'" + name + "' not recognized");
661 }
662 switch (name) {
663 case CREATION_TIME_NAME:
664 this.setTimes(null, null, (FileTime) value);
665 break;
666 case LAST_ACCESS_TIME_NAME:
667 this.setTimes(null, (FileTime) value, null);
668 break;
669 case LAST_MODIFIED_TIME_NAME:
670 this.setTimes((FileTime) value, null, null);
671 break;
672 case SIZE_NAME:
673 case FILE_KEY_NAME:
674 case IS_DIRECTORY_NAME:
675 case IS_REGULAR_FILE_NAME:
676 case IS_SYMBOLIC_LINK_NAME:
677 case IS_OTHER_NAME:
678 throw new IllegalArgumentException("'" + name + "' is a read-only attribute.");
679 default:
680
681 break;
682 }
683
684 }
685
686 protected Set<String> getAllowedAttributes() {
687 return allowedAttr;
688 }
689 }
690
691 private static class MD5FileAttributeViewImpl extends BasicFileAttributeViewImpl implements
692 MCRMD5AttributeView<String> {
693
694 private static String MD5_NAME = "md5";
695
696 private static Set<String> allowedAttr = Sets.union(BasicFileAttributeViewImpl.allowedAttr,
697 Sets.newHashSet(MD5_NAME));
698
699 MD5FileAttributeViewImpl(Path path) {
700 super(path);
701 }
702
703 @Override
704 public MCRFileAttributes<String> readAllAttributes() throws IOException {
705 return readAttributes();
706 }
707
708 @Override
709 public String name() {
710 return "md5";
711 }
712
713 @Override
714 protected Set<String> getAllowedAttributes() {
715 return allowedAttr;
716 }
717
718 @Override
719 protected Map<String, Object> buildMap(Set<String> requested, MCRFileAttributes<String> attrs) {
720 Map<String, Object> buildMap = super.buildMap(requested, attrs);
721 if (requested.contains(MD5_NAME)) {
722 buildMap.put(MD5_NAME, attrs.md5sum());
723 }
724 return buildMap;
725 }
726
727 @Override
728 public void setAttribute(String name, Object value) throws IOException {
729 if (MD5_NAME.equals(name)) {
730 MCRStoredNode node = resolveNode();
731 if (node instanceof MCRDirectory) {
732 throw new IOException("Cannot set md5sum on directories: " + path);
733 }
734 ((MCRFile) node).setMD5((String) value);
735 } else {
736 super.setAttribute(name, value);
737 }
738 }
739
740 }
741
742 }