Package ef.impl.volume

Source Code of ef.impl.volume.FsVolume$FileHolder

package ef.impl.volume;

import ef.api.*;
import ef.api.Error;
import ef.impl.archive.ArchiveType;
import ef.impl.archive.Archiver;
import ef.impl.image.ImageHelper;
import ef.impl.misc.MimeUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* User: sduchenko
* Date: 18.04.13
* Time: 13:34
*/
public class FsVolume implements Volume {

    private final PathHashConverter hashConverter;
    private final FsConfig config;
    private final File rootFile;

    public FsVolume(PathHashConverter hashConverter, FsConfig config) {
        this.hashConverter = hashConverter;
        this.config = config;
        this.rootFile = new File(config.getRootPath());
    }

    @Override
    public String id() {
        return config.getVolumeId();
    }

    @Override
    public FileEntry root() {
        SimpleFileEntry entry = buildEntry(rootFile, null);
        entry.setVolumeId(config.getVolumeId());
        entry.setDirs(true);
        return entry;
    }

    @Override
    public FileEntry get(String target) {
        FileHolder holder = getRequiredFile(target);

        if(isRoot(holder)){
            return root();
        }

        FileHolder parent = getRequiredParent(holder);
        return buildEntry(holder, parent.hash);
    }

    @Override
    public String readText(String target) {
        FileHolder holder = getRequiredFile(target);
        try {
            return FileUtils.readFileToString(holder.file, config.getDefaultTextFileEncoding());
        } catch (IOException e) {
            throw new ErrException(e, Error.errRead);
        }
    }

    @Override
    public FileData read(String target) {
        FileHolder holder = getRequiredFile(target);
        assertFile(holder);

        FileEntry entry = buildEntry(holder, null);
        FileInputStream fis;
        try {
            fis = new FileInputStream(holder.file);
        } catch (FileNotFoundException e) {
            throw new ErrException(e, Error.errRead, holder.file.getName());
        }

        return new SimpleFileData(entry, fis);
    }

    @Override
    public void writeText(String target, String text) {
        FileHolder holder = getRequiredFile(target);

        if(holder.file.isDirectory() || !holder.file.canWrite()){
            throw new ErrException(Error.errWrite);
        }

        try {
            FileUtils.writeStringToFile(holder.file, text, config.getDefaultTextFileEncoding());
        } catch (IOException e) {
            throw new ErrException(e, Error.errWrite);
        }
    }

    @Override
    public void remove(String target) {
        FileHolder holder = getRequiredFile(target);
        try {
            FileUtils.forceDelete(holder.file);
        } catch (IOException e) {
            throw new ErrException(e, Error.errRm);
        }
    }

    @Override
    public FileEntry upload(String targetDir, String fileName, InputStream is) {
        FileHolder dir = getRequiredFile(targetDir);
        assertDir(dir);

        String path = dir.path + File.separator + fileName;
        File file = new File(path);

        if(file.exists()){
            throw new ErrException(Error.errExists);
        }

        OutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            IOUtils.copy(is, fos);
        } catch (IOException e) {
            throw new ErrException(e, Error.errUpload);
        } finally {
            try {
                if(fos != null){
                    fos.close();
                }
            } catch (IOException ignored) {}
        }

        return buildEntry(file, targetDir);
    }

    @Override
    public List<FileEntry> list(String targetDir) {
        FileHolder dir = getRequiredFile(targetDir);
        assertDir(dir);
        File[] files = listFiles(dir.file);
        List<FileEntry> list = new ArrayList<FileEntry>(files.length);
        for(File file: files){
            SimpleFileEntry entry = buildEntry(file, targetDir);
            entry.setDirs(file.isDirectory() && isHaveSubFolders(file));
            list.add(entry);
        }
        return list;
    }

    @Override
    public List<FileEntry> parents(String targetDir) {
        FileHolder dir = getRequiredFile(targetDir);
        assertDir(dir);

        List<FileEntry> list = new ArrayList<FileEntry>();

        if(isRoot(dir)){
            return list;
        }

        FileHolder current = getRequiredParent(dir);

        int level = 0;
        while (true){
            // add dirs on same level
            File[] files = listFiles(current.file);
            for(File file: files){
                if(file.isDirectory()){
                    SimpleFileEntry entry = buildEntry(file, current.hash);
                    entry.setDirs(level > 0 || isHaveSubFolders(file));
                    list.add(entry);
                }
            }

            if(isRoot(current)){
                break;
            }

            current = getRequiredParent(current);
            level++;
        }

        return list;
    }

    @Override
    public List<FileEntry> tree(String targetDir) {
        FileHolder dir = getRequiredFile(targetDir);
        assertDir(dir);

        List<FileEntry> list = new ArrayList<FileEntry>();
        File[] files = listFiles(dir.file);
        for(File file: files){
            if(file.isDirectory()){
                SimpleFileEntry entry = buildEntry(file, dir.hash);
                entry.setDirs(isHaveSubFolders(file));
                list.add(entry);
            }
        }

        return list;
    }

    private File[] listFiles(File file) {
        File[] files = file.listFiles();
        if(files == null){
            throw new ErrException(Error.errAccess);
        }
        return files;
    }

    private boolean isHaveSubFolders(File file){
        File[] files = file.listFiles();

        if(files == null){
            return false;
        }

        for(File sub: files){
            if(sub.isDirectory()){
                return true;
            }
        }

        return false;
    }

    @Override
    public FileEntry mkDir(String targetDir, String dirName) {
        FileHolder holder = getRequiredFile(targetDir);
        assertDir(holder);
        File newFile = new File(holder.path+File.separator+dirName);
        if(!newFile.mkdir()){
            throw new ErrException(Error.errMkdir);
        }
        return buildEntry(newFile, targetDir);
    }

    @Override
    public FileEntry mkFile(String targetDir, String fileName) {
        FileHolder holder = getRequiredFile(targetDir);
        assertDir(holder);

        File newFile = new File(holder.path+File.separator+fileName);

        boolean created;
        try {
            created = newFile.createNewFile();
        } catch (IOException e) {
            throw new ErrException(e, Error.errMkfile);
        }

        if(!created){
            throw new ErrException(Error.errMkfile);
        }

        return buildEntry(newFile, targetDir);
    }

    @Override
    public FileEntry rename(String target, String fileName) {
        FileHolder holder = getRequiredFile(target);
        assertNotRoot(holder);
        FileHolder parent = getRequiredParent(holder);

        String newFileName = parent.path + File.separator + fileName;
        File newFile = new File(newFileName);

        if(newFile.exists()){
            throw new ErrException(Error.errExists);
        }

        if(!holder.file.renameTo(newFile)){
            throw new ErrException(Error.errRename);
        }

        return buildEntry(newFile, parent.hash);
    }

    @Override
    public FileEntry copy(String target, String targetDir) {
        FileHolder dirHolder = getRequiredFile(targetDir);
        FileHolder holder = getRequiredFile(target);

        assertDir(dirHolder);

        String name = holder.file.getName();
        String path = dirHolder.path + File.separator + name;
        File file = new File(path);

        if(file.exists()){
            throw new ErrException(Error.errExists);
        }

        try {
            if(holder.file.isDirectory()){
                FileUtils.copyDirectoryToDirectory(holder.file, dirHolder.file);
            }else{
                FileUtils.copyFileToDirectory(holder.file, dirHolder.file);
            }
        } catch (IOException e) {
            throw new ErrException(e, Error.errCopy);
        }

        if(!file.exists()){
            throw new ErrException(Error.errCopy);
        }

        return buildEntry(file, dirHolder.hash);
    }

    @Override
    public FileEntry move(String target, String targetDir) {
        FileHolder dirHolder = getRequiredFile(targetDir);
        FileHolder holder = getRequiredFile(target);

        assertDir(dirHolder);

        String name = holder.file.getName();
        String path = dirHolder.path + File.separator + name;
        File file = new File(path);

        if(file.exists()){
            throw new ErrException(Error.errExists);
        }

        try {
            if(holder.file.isDirectory()){
                FileUtils.moveDirectoryToDirectory(holder.file, dirHolder.file, true);
            }else{
                FileUtils.moveFileToDirectory(holder.file, dirHolder.file, true);
            }
        } catch (IOException e) {
            throw new ErrException(e, Error.errMove);
        }

        if(!file.exists()){
            throw new ErrException(Error.errMove);
        }

        return buildEntry(file, targetDir);
    }

    @Override
    public FileEntry duplicate(String target) {
        FileHolder holder = getRequiredFile(target);
        FileHolder parent = getRequiredParent(holder);
        File newFile  = getDuplicateName(holder, parent);

        try {
            if(holder.file.isDirectory()){
                FileUtils.copyDirectory(holder.file, newFile);
            }else{
                FileUtils.copyFile(holder.file, newFile);
            }
        } catch (IOException e) {
            throw new ErrException(Error.errCopy);
        }

        if(!newFile.exists()){
            throw new ErrException(Error.errCopy);
        }

        return buildEntry(newFile, parent.hash);
    }


    @Override
    public FileEntry archive(String mimeType, String[] targets) {
        ArchiveType type;
        try {
            type = ArchiveType.fromMime(mimeType);
        } catch (Exception e) {
            throw new ErrException(e, Error.errArcType);
        }
        List<FileHolder> holders = getRequiredFiles(targets);
        FileHolder parent = getRequiredParent(holders.get(0));
        File archiveFile = getNewArchiveFile(parent.path + File.separator + parent.file.getName(), type.getFileExt());

        List<File> files = new ArrayList<File>();
        for(FileHolder holder: holders){
            files.add(holder.file);
        }

        try {
            Archiver.createArchive(type, files, archiveFile);
        } catch (Exception e) {
            throw new ErrException(e, Error.errArchive);
        }

        return buildEntry(archiveFile, parent.hash);
    }

    @Override
    public FileEntry extract(String target) {
        FileHolder holder = getRequiredFile(target);
        FileHolder parent = getRequiredParent(holder);
        assertFile(holder);
        String ext = FilenameUtils.getExtension(holder.path);
        ArchiveType type;
        try {
            type = ArchiveType.fromFileExt(ext);
        } catch (Exception e) {
            throw new ErrException(Error.errArcType);
        }

        String name = FilenameUtils.getBaseName(holder.file.getName());
        name = getBaseName(name);
        File dstDir = getNewDir(parent.file, name);

        if(!dstDir.mkdir()){
            throw new ErrException(Error.errExists, name);
        }

        try {
            Archiver.extractArchive(type, holder.file, dstDir);
        } catch (IOException e) {
            throw new ErrException(e, Error.errExtract);
        }

        SimpleFileEntry entry = buildEntry(dstDir, parent.hash);
        entry.setDirs(isHaveSubFolders(dstDir));
        return entry;
    }

    @Override
    public FileEntry resizeImage(String target, long newWidth, long newHeight) {
        FileHolder holder = getRequiredFile(target);
        try {
            ImageHelper.resize(holder.file, newWidth, newHeight);
        } catch (IOException e) {
            throw new ErrException(e, Error.errResize);
        }
        return buildEntry(holder, getRequiredParent(holder).hash);
    }

    @Override
    public FileEntry rotateImage(String target, long newWidth, long newHeight, long degree) {
        FileHolder holder = getRequiredFile(target);
        try {
            ImageHelper.rotate(holder.file, degree);
        } catch (IOException e) {
            throw new ErrException(e, Error.errResize);
        }
        return buildEntry(holder, getRequiredParent(holder).hash);
    }

    @Override
    public FileEntry cropImage(String target, long newWidth, long newHeight, long x, long y) {
        FileHolder holder = getRequiredFile(target);
        try {
            ImageHelper.crop(holder.file, newWidth, newHeight, x, y);
        } catch (IOException e) {
            throw new ErrException(e, Error.errResize);
        }
        return buildEntry(holder, getRequiredParent(holder).hash);
    }

    private static final Pattern BASE_NAME_PATTERN = Pattern.compile("^(.*)\\(\\d+\\)$");
    private String getBaseName(String name) {
        Matcher matcher = BASE_NAME_PATTERN.matcher(name);
        return matcher.matches() ? matcher.group(1) : name;
    }

    private File getNewDir(File parent, String name) {
        int num = 0;
        while(num++<MAX_STEPS){
            File file = new File(parent, num==0 ? name : name+"("+num+")");
            if(!file.exists()){
                return file;
            }
        }
        throw new ErrException(Error.errExists, name);
    }

    private static final int MAX_STEPS = 100;
    private File getNewArchiveFile(String parentPath, String ext){
        String newName =  parentPath+ "." + ext;
        File archiveFile = new File(newName);

        if(!archiveFile.exists()){
            return archiveFile;
        }

        int num = 0;
        while(++num<MAX_STEPS){
            newName = parentPath + "(" + num + ")." + ext;
            archiveFile = new File(newName);
            if(!archiveFile.exists()){
                return archiveFile;
            }
        }

        throw new ErrException(Error.errExists);
    }

    private Pattern FILE_COPY_PATTERN = Pattern.compile("^(.*) copy (\\d+)(.*)?$", Pattern.CASE_INSENSITIVE);
    private Pattern FILE_EXT_PATTERN = Pattern.compile("^(.*)(\\.[^\\.]*)$", Pattern.CASE_INSENSITIVE);
    private File getDuplicateName(FileHolder holder, FileHolder parent) {
        String name = holder.file.getName();
        Matcher matcher = FILE_COPY_PATTERN.matcher(name);
        String baseName;
        int num = 0;
        String ext = "";

        if(!matcher.matches()){
            if(holder.file.isDirectory()){
                baseName = name;
            }else{
                matcher = FILE_EXT_PATTERN.matcher(name);
                if(matcher.matches()){
                    baseName = matcher.group(1);
                    ext = matcher.group(2);
                }else{
                    baseName = name;
                }
            }
        }else {
            baseName = matcher.group(1);
            num = Integer.valueOf(matcher.group(2));
            ext = matcher.groupCount() == 3 ? matcher.group(3) : "";
        }

        baseName = baseName + " copy ";
        int step = 100;
        while(step-->0){
            name = parent.path + File.separator + baseName + (++num) + ext;
            File file = new File(name);
            if(!file.exists()){
                return file;
            }
        }

        throw new ErrException(Error.errUnknown);
    }

    private List<FileHolder> getRequiredFiles(String[] hashes){
        List<FileHolder> holders = new ArrayList<FileHolder>();
        for(String hash: hashes){
            holders.add(getRequiredFile(hash));
        }
        return holders;
    }

    private FileHolder getRequiredFile(String hash){
        String path = hashConverter.hashToPath(hash);
        File file = new File(path);

        if(!file.exists()){
            throw new ErrException(Error.errFileNotFound);
        }

        FileHolder holder = new FileHolder();
        holder.file = file;
        holder.hash = hash;
        holder.path = path;

        return holder;
    }

    private FileHolder getRequiredParent(FileHolder holder){
        File parent = holder.file.getParentFile();

        if(parent == null){
            throw new ErrException(Error.errFolderNotFound);
        }

        FileHolder parentHolder = new FileHolder();
        parentHolder.file = parent;
        parentHolder.path = getFilePath(parent);
        parentHolder.hash = hashConverter.pathToHash(parentHolder.path);

        return parentHolder;
    }

    private void assertDir(FileHolder holder){
        if(!holder.file.isDirectory()) {
            throw new ErrException(Error.errNotFolder, holder.file.getName());
        }
    }

    private void assertFile(FileHolder holder){
        if(holder.file.isDirectory()) {
            throw new ErrException(Error.errNotFile, holder.file.getName());
        }
    }

    private void assertNotRoot(FileHolder holder){
        if(isRoot(holder)){
            throw new ErrException(Error.errAccess, holder.file.getName());
        }
    }

    private boolean isRoot(FileHolder holder){
        return holder.path.equalsIgnoreCase(config.getRootPath()) || holder.path.length() <= config.getRootPath().length();
    }

    private static class FileHolder {
        String path;
        String hash;
        File file;
    }

    private SimpleFileEntry buildEntry(FileHolder holder, String pHash){
        SimpleFileEntry entry = new SimpleFileEntry();
        File file = holder.file;
        entry.setMime(MimeUtil.getMime(file));
        entry.setHash(holder.hash);
        entry.setName(file.getName());
        entry.setSize(file.length());
        entry.setLocked(false);
        entry.setRead(file.canRead());
        entry.setWrite(file.canWrite());
        entry.setPhash(pHash);
        entry.setDirs(false);
        entry.setTs(file.lastModified());
        return entry;
    }

    private SimpleFileEntry buildEntry(File file, String pHash){
        FileHolder holder = new FileHolder();
        holder.file = file;
        holder.hash = hashConverter.pathToHash(getFilePath(file));
        return buildEntry(holder, pHash);
    }

    private String getFilePath(File file){
        try {
            return file.getCanonicalPath();
        } catch (IOException e) {
            throw new ErrException(e);
        }
    }
}
TOP

Related Classes of ef.impl.volume.FsVolume$FileHolder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.