package ru.kkey.core; import java.io.IOException; import java.nio.file.AccessDeniedException; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * Data source for file system navigation * * @author anstarovoyt */ public class FSSource implements Source { public static final SourceFactory FACTORY = new SourceFactory() { @Override public Source create(String path) { return new FSSource(path); } }; volatile Path currentPath; private final ReadWriteLock lock = new ReentrantReadWriteLock(); public FSSource(Path path) { if (!Files.exists(path) || !Files.isDirectory(path)) { throw new RuntimeException("Incorrect path"); } this.currentPath = path; } public FSSource(String defaultPath) { this(Paths.get(defaultPath).toAbsolutePath()); } @Override public void destroy() { } @Override public byte[] getFile(FileItem item) { try { return Utils.readInputSteamToByteArray(Files.newInputStream(geFileMap().get(item))); } catch (AccessDeniedException e) { throw new RuntimeException("Access denied error"); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } } @Override public Source getSourceFor(FileItem item) { Path path = geFileMap().get(item); if (ZipSource.isZip(path)) { return new ZipSource(path.toString()); } return null; } @Override public FileItem goBack() { lock.writeLock().lock(); try { Path parent = currentPath.getParent(); Path prev = currentPath; if (null != parent && !parent.equals(prev)) { currentPath = parent; return pathToFileItem(prev); } return null; } finally { lock.writeLock().unlock(); } } @Override public void goInto(FileItem item) { lock.writeLock().lock(); try { Map<FileItem, Path> fileItemFileMap = geFileMap(); Path file = fileItemFileMap.get(item); if (Files.isDirectory(file)) { currentPath = file; } } finally { lock.writeLock().unlock(); } } @Override public List<FileItem> listFiles() { Map<FileItem, Path> fileItemFileMap = geFileMap(); ArrayList<FileItem> list = new ArrayList<>(fileItemFileMap.keySet()); Collections.sort(list); return list; } private Map<FileItem, Path> geFileMap() { lock.readLock().lock(); try { if (!Files.exists(currentPath)) { throw new RuntimeException("Path doesn't exist"); } List<Path> files = new ArrayList<>(); //file.listFiles returns incorrect name DirectoryStream<Path> paths = Files.newDirectoryStream(currentPath); for (Path path : paths) { files.add(path); } Map<FileItem, Path> result = new HashMap<>(); for (Path file : files) { FileItem key = pathToFileItem(file); result.put(key, file); } return result; } catch (AccessDeniedException e) { throw new RuntimeException("Access denied error"); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } finally { lock.readLock().unlock(); } } private FileItem pathToFileItem(Path file) { Path fileName = file.getFileName(); String stringName = fileName == null ? "" : fileName.toString(); FileItem key = new FileItem(stringName, Files.isDirectory(file)); return key; } }