Java tutorial
/* * * 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 */ }