de.pksoftware.springstrap.fs.service.LocalFileSystemService.java Source code

Java tutorial

Introduction

Here is the source code for de.pksoftware.springstrap.fs.service.LocalFileSystemService.java

Source

/*
 * 
 * Springstrap
 *
 * @author Jan Philipp Knller <info@pksoftware.de>
 * 
 * Homepage: http://ui5strap.com/springstrap
 *
 * Copyright (c) 2013-2014 Jan Philipp Knller <info@pksoftware.de>
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * Released under Apache2 license: http://www.apache.org/licenses/LICENSE-2.0.txt
 * 
 */

package de.pksoftware.springstrap.fs.service;

import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.servlet.ServletContext;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;

import de.pksoftware.springstrap.fs.exception.BadConfigurationException;
import de.pksoftware.springstrap.fs.exception.FSIOException;
import de.pksoftware.springstrap.fs.exception.FileServiceException;
import de.pksoftware.springstrap.fs.exception.ItemAlreadyExistException;
import de.pksoftware.springstrap.fs.exception.ItemNotVisibleException;
import de.pksoftware.springstrap.fs.exception.NoSuchItemException;
import de.pksoftware.springstrap.fs.exception.NotAFolderException;
import de.pksoftware.springstrap.fs.exception.InvalidBucketException;
import de.pksoftware.springstrap.fs.exception.InvalidPathException;
import de.pksoftware.springstrap.fs.exception.NoSuchFolderException;
import de.pksoftware.springstrap.fs.exception.NoSuchFileException;
import de.pksoftware.springstrap.fs.exception.NotAFileException;

@Service
public class LocalFileSystemService implements ILocalFileSystemService, IResourceProvider {

    private static final Logger logger = LoggerFactory.getLogger(LocalFileSystemService.class);

    protected Map<ItemVisibility, File> visibilityMapping;

    protected String urlPrefix = null;
    protected String rootDirectory = null;

    @Autowired
    protected ServletContext servletContext;

    protected AntPathMatcher antPathMatcher;

    public LocalFileSystemService() {
        antPathMatcher = new AntPathMatcher();

        visibilityMapping = new HashMap<ItemVisibility, File>();
    }

    /**
     * Initializes this LocalFileSystemService.
     */
    @PostConstruct
    protected void init() {
        if (null == rootDirectory) {
            logger.warn("Root Directory is not set.");
        } else {
            File fileSystemRoot = new File(rootDirectory);

            if (!fileSystemRoot.exists()) {
                throw new RuntimeException("Root Directory does not exists: " + rootDirectory);
            }

            // Check Private Root
            File privateRoot = new File(fileSystemRoot, ItemVisibility.PRIVATE.getFolder() + "/");

            if (!privateRoot.exists()) {
                privateRoot.mkdir();
            }

            // Check Protected Root
            File protectedRoot = new File(fileSystemRoot, ItemVisibility.PROTECTED.getFolder() + "/");

            if (!protectedRoot.exists()) {
                protectedRoot.mkdir();
            }

            // Check Public Root
            File publicRoot = new File(fileSystemRoot, ItemVisibility.PUBLIC.getFolder() + "/");

            if (!publicRoot.exists()) {
                publicRoot.mkdir();
            }

            visibilityMapping.put(ItemVisibility.PRIVATE, privateRoot);
            visibilityMapping.put(ItemVisibility.PROTECTED, protectedRoot);
            visibilityMapping.put(ItemVisibility.PUBLIC, publicRoot);
        }
    }

    /**
     * Gets the URL Prefix for this FileSystemService.
     * 
     * @return
     */
    @Override
    public String getUrlPrefix() {
        return urlPrefix;
    }

    /**
     * Sets the URL Prefix for this FileSystemService.
     * 
     * @param urlPrefix
     */
    @Override
    public void setUrlPrefix(String urlPrefix) {
        if (!urlPrefix.startsWith("/")) {
            urlPrefix = "/" + urlPrefix;
        }

        if (!urlPrefix.endsWith("/")) {
            urlPrefix += "/";
        }

        this.urlPrefix = urlPrefix;
    }

    /**
     * Gets the Root Directory for this LocalFileSystemService.
     * 
     * @return
     */
    @Override
    public String getRootDirectory() {
        return rootDirectory;
    }

    /**
     * Sets the Root Directory for this LocalFileSystemService.
     * 
     * @param rootDirectory
     */
    @Override
    public void setRootDirectory(String rootDirectory) {
        if (!rootDirectory.endsWith("/")) {
            rootDirectory += "/";
        }

        this.rootDirectory = rootDirectory;
    }

    /**
     * Adds the Resource Handlers for this FileSystemService.
     * 
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        File publicRoot = (File) visibilityMapping.get(ItemVisibility.PUBLIC);

        if (null != publicRoot) {
            registry.addResourceHandler(urlPrefix + "**").addResourceLocations(publicRoot.toURI().toString());
        }
    }

    /*
     * START Base
     */

    /**
     * 
     * @param visibility
     * @param bucket
     * @return
     */
    protected File getBucketRoot(ItemVisibility visibility, FileSystemBucket bucket) {
        File visRoot = visibilityMapping.get(visibility);
        if (null == visRoot) {
            throw new BadConfigurationException(
                    "Cannot read directory '" + visibility.getFolder() + "' - check your configuration.");
        }

        String bucketName = FileSystemUtils.validateBucket(bucket);

        File bucketRoot = new File(visRoot, bucketName);

        if (!bucketRoot.exists()) {
            bucketRoot.mkdirs();
        }

        return bucketRoot;
    }

    /**
     * 
     * @param visibility
     * @param bucket
     * @param path
     * @return
     */
    protected File getItem(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath path) {
        String pathString = FileSystemUtils.validateScopedPath(path);

        return new File(getBucketRoot(visibility, bucket), pathString);
    }

    /**
     * 
     */
    @Override
    public void deleteItem(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath path)
            throws NoSuchItemException, FSIOException {
        String pathString = FileSystemUtils.validateScopedPath(path);

        File itemToDelete = new File(getBucketRoot(visibility, bucket), pathString);

        if (!itemToDelete.exists()) {
            throw new NoSuchItemException(bucket, path);
        }

        try {
            FileUtils.forceDelete(itemToDelete);
        } catch (IOException e) {
            throw new FSIOException(bucket, path, "deleteItem", e);
        }
    }

    protected void readFolderItems(File directory, FileItem directoryItem, boolean recursive,
            String dirRelativePath, String[] excludeAntPattern) throws NoSuchFolderException, NotAFolderException {
        Assert.isTrue(directory.isDirectory());

        File[] files = directory.listFiles();
        Arrays.sort(files);

        for (final File fileEntry : files) {
            String fileName = fileEntry.getName();

            if (fileName.startsWith(".")) {
                continue;
            }

            String fileRelativePath = dirRelativePath + fileName;

            boolean excludeFile = false;
            for (String antPattern : excludeAntPattern) {
                //logger.info("Testing {} against {}", antPattern, fileInternalAbsolutePath);
                if (antPathMatcher.match(antPattern, fileRelativePath)) {
                    excludeFile = true;
                    break;
                }
            }

            if (excludeFile) {
                continue;
            }

            FileItem fileItem = new FileItem();
            fileItem.setParent(directoryItem);
            fileItem.setIsFolder(fileEntry.isDirectory());
            fileItem.setName(fileName);
            fileItem.setSize(fileEntry.length());

            if (recursive && fileEntry.isDirectory()) {
                readFolderItems(fileEntry, fileItem, recursive, fileRelativePath + "/", excludeAntPattern);
            }

            directoryItem.addChild(fileItem);
        }
    }

    /**
     * 
     */
    @Override
    public FileItem listFolder(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath path,
            boolean recursive, boolean createIfNotExist, String[] excludeAntPattern)
            throws NoSuchFolderException, NotAFolderException {
        File folder = getItem(visibility, bucket, path);

        if (!folder.exists()) {
            if (createIfNotExist) {
                logger.info("Creating folder '{}'", path);
                folder.mkdirs();
            } else {
                throw new NoSuchFolderException(bucket, path);
            }
        } else if (folder.isFile()) {
            throw new NotAFolderException(bucket, path);
        }

        // TODO Check if parent is bucket root
        File parent = folder.getParentFile();
        Assert.notNull(parent);
        Assert.isTrue(parent.isDirectory());

        FileItem parentItem = new FileItem();
        parentItem.setName(parent.getName());
        parentItem.setSize(0);
        parentItem.setIsFolder(true);

        FileItem directoryItem = new FileItem();
        directoryItem.setParent(parentItem);
        directoryItem.setIsFolder(true);
        directoryItem.setName(folder.getName());

        readFolderItems(folder, directoryItem, recursive, "", excludeAntPattern);

        return directoryItem;
    }

    @Override
    public void createFolder(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath path)
            throws NotAFolderException, FSIOException {
        File folder = getItem(visibility, bucket, path);

        if (folder.exists()) {
            if (!folder.isDirectory()) {
                throw new NotAFolderException(bucket, path);
            }

            return;
        } else {
            folder.mkdirs();
        }
    }

    @Override
    public void copyFolder(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath srcPath,
            IFileSystemPath destPath, String[] excludeAntPattern)
            throws NotAFolderException, FSIOException, NoSuchFolderException {
        File srcFolder = getItem(visibility, bucket, srcPath);

        if (!srcFolder.exists()) {
            throw new NoSuchFolderException(bucket, srcPath);
        }

        if (!srcFolder.isDirectory()) {
            throw new NotAFolderException(bucket, srcPath);
        }

        File destFolder = getItem(visibility, bucket, destPath);

        if (destFolder.exists() && !destFolder.isDirectory()) {
            throw new NotAFolderException(bucket, destPath);
        }

        try {
            FileUtils.copyDirectory(srcFolder, destFolder, new FileFilter() {

                @Override
                public boolean accept(File pathname) {
                    for (String antPattern : excludeAntPattern) {
                        String absAntPattern = srcFolder.getAbsolutePath() + "/" + antPattern;

                        //logger.info("Testing {} against {}", absAntPattern, pathname.getAbsolutePath());

                        if (antPathMatcher.match(absAntPattern, pathname.getAbsolutePath())) {
                            return false;
                        }
                    }

                    return true;
                }

            });
        } catch (IOException e) {
            throw new FSIOException(bucket, srcPath, "copyFolder", e);
        }

    }

    /**
     * 
     * @param visibility
     * @param bucket
     * @param path
     * @throws InvalidPathException
     * @throws InvalidBucketException
     * @throws BadConfigurationException
     * @throws NoSuchFolderException
     * @throws NotAFolderException
     * @throws FSIOException
     */
    @Override
    public void deleteFolder(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath path)
            throws NoSuchFolderException, NotAFolderException, FSIOException {
        File directory = getItem(visibility, bucket, path);

        if (!directory.exists()) {
            throw new NoSuchFolderException(bucket, path);
        }

        if (directory.isFile()) {
            throw new NotAFolderException(bucket, path);
        }

        try {
            FileUtils.deleteDirectory(directory);
        } catch (IOException e) {
            throw new FSIOException(bucket, path, "deleteDirectory", e);
        }
    }

    /**
     * Returns whether a file exists inside the Bucket's public directory.
     * 
     * @throws BadConfigurationException
     */
    @Override
    public boolean existFile(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath path) {
        return getItem(visibility, bucket, path).exists();
    }

    /**
     * 
     * @param visibility
     * @param bucket
     * @param path
     * @throws InvalidPathException
     * @throws InvalidBucketException
     * @throws BadConfigurationException
     * @throws NotAFileException
     * @throws FSIOException
     * @throws NoSuchFileException
     */
    @Override
    public void deleteFile(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath path)
            throws NotAFileException, FSIOException, NoSuchFileException {
        File file = getItem(visibility, bucket, path);

        if (!file.exists()) {
            throw new NoSuchFileException(bucket, path);
        }

        if (file.isDirectory()) {
            throw new NotAFileException(bucket, path);
        }

        if (!file.delete()) {
            throw new FSIOException(bucket, path, "deleteFile");
        }
    }

    @Override
    public void copyFile(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath src,
            IFileSystemPath dest) throws NoSuchFileException, NotAFileException, FSIOException {
        File srcFile = getItem(visibility, bucket, src);

        if (!srcFile.exists()) {
            throw new NoSuchFileException(bucket, src);
        }

        if (srcFile.isDirectory()) {
            throw new NotAFileException(bucket, src);
        }

        File destFile = getItem(visibility, bucket, dest);

        if (destFile.exists() && destFile.isDirectory()) {
            throw new NotAFileException(bucket, dest);
        }

        try {
            FileUtils.copyFile(srcFile, destFile);
        } catch (IOException e) {
            logger.error("Could not copy file from {} to {}", srcFile, destFile);
            throw new FSIOException(bucket, src, "copyFile", e);
        }
    }

    @Override
    public void moveFile(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath src,
            IFileSystemPath dest) throws NoSuchFileException, NotAFileException, FSIOException {
        File srcFile = getItem(visibility, bucket, src);

        if (!srcFile.exists()) {
            throw new NoSuchFileException(bucket, src);
        }

        if (srcFile.isDirectory()) {
            throw new NotAFileException(bucket, src);
        }

        File destFile = getItem(visibility, bucket, dest);

        if (destFile.exists() && destFile.isDirectory()) {
            throw new NotAFileException(bucket, dest);
        }

        try {
            FileUtils.moveFile(srcFile, destFile);
        } catch (IOException e) {
            logger.error("Could not move file from {} to {}", srcFile, destFile);
            throw new FSIOException(bucket, src, "moveFile", e);
        }
    }

    /**
     * 
     * @param bucket
     * @param path
     * @return
     * @throws InvalidPathException
     * @throws InvalidBucketException
     * @throws BadConfigurationException
     * @throws FSIOException
     * @throws NoSuchFileException
     * @throws NotAFileException
     * @throws NoSuchItemException
     */
    @Override
    public FileItem readFile(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath path,
            boolean allowFolders) throws FSIOException, NotAFileException, NoSuchItemException {
        File file = getItem(visibility, bucket, path);

        if (!file.exists()) {
            throw new NoSuchItemException(bucket, path);
        }

        // TODO Check if parent is bucket root
        File parent = file.getParentFile();
        Assert.notNull(parent);
        Assert.isTrue(parent.isDirectory());

        FileItem parentItem = new FileItem();
        parentItem.setName(parent.getName());
        parentItem.setSize(0);
        parentItem.setIsFolder(true);

        FileItem fileItem = new FileItem();
        fileItem.setParent(parentItem);
        fileItem.setName(file.getName());
        fileItem.setSize(file.length());
        fileItem.setIsFolder(file.isDirectory());

        if (file.isDirectory()) {
            if (allowFolders) {
                return fileItem;
            } else {
                throw new NotAFileException(bucket, path);
            }
        }

        byte[] encoded;

        try {
            encoded = Files.readAllBytes(Paths.get(file.getAbsolutePath()));
        } catch (IOException e) {
            throw new FSIOException(bucket, path, "readFile", e);
        }

        fileItem.setContent(encoded);

        return fileItem;
    }

    /**
     * 
     * @param file
     * @param bucket
     * @param path
     * @param data
     * @param createIfNotExist
     * @throws InvalidPathException
     * @throws FSIOException
     * @throws InvalidBucketException
     * @throws BadConfigurationException
     * @throws NoSuchFileException
     * @throws NotAFileException
     * @throws ItemAlreadyExistException
     */
    @Override
    public void writeFile(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath path, byte[] data,
            boolean createIfNotExist, boolean overrideIfExist)
            throws FSIOException, NoSuchFileException, NotAFileException, ItemAlreadyExistException {
        File file = getItem(visibility, bucket, path);

        if (!file.exists()) {
            if (createIfNotExist) {
                // Create parent folders if needed
                File parentFolder = file.getParentFile();
                Assert.notNull(parentFolder);
                if (!parentFolder.exists()) {
                    parentFolder.mkdirs();
                }
            } else {
                throw new NoSuchFileException(bucket, path);
            }
        } else {
            if (overrideIfExist) {
                if (file.isDirectory()) {
                    throw new NotAFileException(bucket, path);
                }
            } else {
                throw new ItemAlreadyExistException(bucket, path);
            }
        }

        OutputStream stream = null;
        try {
            stream = new FileOutputStream(file);
            stream.write(data);
        } catch (IOException ioex) {
            throw new FSIOException(bucket, path, "writeFile", ioex);
        } finally {
            if (null != stream) {
                try {
                    stream.close();
                } catch (IOException e) {
                    throw new FSIOException(bucket, path, "writeFile", e);
                }
            }
        }
    }

    /**
     * Returns an URL to a file inside the Bucket's public directory.
     * 
     * @throws ItemNotVisibleException
     */
    @Override
    public String getItemURL(ItemVisibility vis, FileSystemBucket bucket, IFileSystemPath path)
            throws ItemNotVisibleException {
        if (null == urlPrefix) {
            throw new BadConfigurationException("URL fragment 'urlPrefix' cannot be null!");
        }

        if (vis != ItemVisibility.PUBLIC) {
            throw new ItemNotVisibleException(bucket, path);
        }

        String bucketName = FileSystemUtils.validateBucket(bucket);

        String pathString = FileSystemUtils.validateScopedPath(path);

        return servletContext.getContextPath() + urlPrefix + bucketName + "/" + pathString;
    }

    @Override
    public File getLocalFile(ItemVisibility visibility, FileSystemBucket bucket, IFileSystemPath path)
            throws FileServiceException {
        File file = getItem(visibility, bucket, path);

        if (!file.exists()) {
            throw new NoSuchItemException(bucket, path);
        }

        return file;
    }

    /*
     * END Base
     */
}