package org.peerbox.app.manager.file; import java.math.BigInteger; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.hive2hive.core.api.interfaces.IFileConfiguration; import org.hive2hive.core.exceptions.NoPeerConnectionException; import org.hive2hive.core.exceptions.NoSessionException; import org.hive2hive.core.file.FileUtil; import org.hive2hive.core.model.PermissionType; import org.hive2hive.core.processes.files.list.FileNode; import org.hive2hive.core.processes.files.recover.IVersionSelector; import org.hive2hive.processframework.exceptions.InvalidProcessStateException; import org.hive2hive.processframework.exceptions.ProcessExecutionException; import org.hive2hive.processframework.interfaces.IProcessComponent; import org.peerbox.app.config.UserConfig; import org.peerbox.app.manager.AbstractManager; import org.peerbox.app.manager.ProcessHandle; import org.peerbox.app.manager.node.INodeManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.inject.Inject; import com.google.inject.Singleton; /** * The file manager wraps the H2H file manager (see {@link org.hive2hive.core.api.interfaces.IFileManager}). * In general, process handles are returned containing the process component returned by H2H. * The process, however, is not started yet. Thus, clients must either call execute or executeAsync. * * @author albrecht * */ @Singleton public class FileManager extends AbstractManager implements IFileManager { private static final Logger logger = LoggerFactory.getLogger(FileManager.class); private final UserConfig userConfig; @Inject public FileManager(final INodeManager nodeManager, final UserConfig userConfig) { super(nodeManager, null); this.userConfig = userConfig; } private Path getRootPath() { return userConfig.getRootPath(); } @Override public ProcessHandle<Void> add(final Path file) throws NoSessionException, NoPeerConnectionException { logger.debug("ADD - {}", file); IProcessComponent<Void> component = getH2HFileManager().createAddProcess(file.toFile()); ProcessHandle<Void> handle = new ProcessHandle<Void>(component); return handle; } @Override public ProcessHandle<Void> update(final Path file) throws NoSessionException, NoPeerConnectionException { logger.debug("UPDATE - {}", file); IProcessComponent<Void> component = getH2HFileManager().createUpdateProcess(file.toFile()); ProcessHandle<Void> handle = new ProcessHandle<Void>(component); return handle; } @Override public ProcessHandle<Void> delete(final Path file) throws NoSessionException, NoPeerConnectionException { logger.debug("DELETE - {}", file); IProcessComponent<Void> component = getH2HFileManager().createDeleteProcess(file.toFile()); ProcessHandle<Void> handle = new ProcessHandle<Void>(component); return handle; } @Override public ProcessHandle<Void> move(final Path source, final Path destination) throws NoSessionException, NoPeerConnectionException { logger.debug("MOVE - from: {}, to: {}", source, destination); IProcessComponent<Void> component = getH2HFileManager().createMoveProcess(source.toFile(), destination.toFile()); ProcessHandle<Void> handle = new ProcessHandle<Void>(component); return handle; } @Override public ProcessHandle<Void> download(final Path file) throws NoSessionException, NoPeerConnectionException { logger.debug("DOWNLOAD - {}", file); IProcessComponent<Void> component = getH2HFileManager().createDownloadProcess(file.toFile()); ProcessHandle<Void> handle = new ProcessHandle<Void>(component); return handle; } @Override public ProcessHandle<Void> recover(final Path file, final IVersionSelector versionSelector) throws NoSessionException, NoPeerConnectionException, IllegalArgumentException { logger.debug("RECOVER - {}", file); IProcessComponent<Void> component = getH2HFileManager().createRecoverProcess(file.toFile(), versionSelector); ProcessHandle<Void> handle = new ProcessHandle<Void>(component); return handle; } @Override public ProcessHandle<Void> share(final Path folder, final String userId, final PermissionType permission) throws IllegalArgumentException, NoSessionException, NoPeerConnectionException, InvalidProcessStateException, ProcessExecutionException { logger.debug("SHARE - User: '{}', Permission: '{}', Folder: '{}'", userId, permission.name(), folder); IProcessComponent<Void> component = getH2HFileManager().createShareProcess(folder.toFile(), userId, permission); ProcessHandle<Void> handle = new ProcessHandle<Void>(component); return handle; } @Override public ProcessHandle<FileNode> listFiles() throws NoPeerConnectionException, NoSessionException { IProcessComponent<FileNode> component = getH2HFileManager().createFileListProcess(); ProcessHandle<FileNode> handle = new ProcessHandle<FileNode>(component); return handle; } @Override public boolean existsRemote(final Path path) { FileNode item = null; FileNode list = null; try { list = listFiles().execute(); item = getFileNodeByPath(list, path); } catch (NoPeerConnectionException | NoSessionException | InvalidProcessStateException | ProcessExecutionException e) { item = null; logger.warn("Could not check existsRemote - Exception: {}", e.getMessage(), e); } return item != null ? true : false; } /** * Searches a FileNode given a path. * * @param index the file index, e.g. the root node * @param path the path for which the node should be searched * @return the file node corresponding to the given path or null if none exists */ private FileNode getFileNodeByPath(final FileNode index, final Path path) { Path current = path; List<String> pathItems = new ArrayList<>(); while (current != null && !getRootPath().equals(current)) { pathItems.add(current.getFileName().toString()); current = current.getParent(); } Collections.reverse(pathItems); FileNode currentNode = index; for (String pathItem : pathItems) { FileNode child = getChildByName(currentNode.getChildren(), pathItem); if (child == null) { return null; } currentNode = child; if(child.isFile()) { break; // cannot go further down the tree } } // it may be the case that we did not consider all pathItems if(currentNode.getFile().toPath().equals(path)) { return currentNode; } else { return null; } } /** * Searches a child node in a list with a given name * * @param children list of child nodes * @param name the name to search * @return the FileNode or null if none exists */ private FileNode getChildByName(final List<FileNode> children, final String name) { for (FileNode child : children) { if (child.getName().equalsIgnoreCase(name)) { return child; } } return null; } @Override public boolean isSmallFile(final Path path) { IFileConfiguration fileConfig = getFileConfiguration(); BigInteger max = fileConfig.getMaxFileSize(); BigInteger size = BigInteger.valueOf(FileUtil.getFileSize(path.toFile())); return size.compareTo(max) == -1; } @Override public boolean isLargeFile(final Path path) { return !isSmallFile(path); } }