CCM NG: NIOFileSystemAdapter (Fallback for CcmFiles)

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4642 8810af33-2d31-482b-a856-94f89814c4df

Former-commit-id: b84f43235f
pull/2/head
jensp 2017-03-24 11:00:35 +00:00
parent 980ba6661a
commit d2e157e481
10 changed files with 487 additions and 126 deletions

View File

@ -23,7 +23,10 @@ import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.List;
import javax.enterprise.inject.Instance;
import javax.faces.bean.RequestScoped;
import javax.inject.Inject;
/**
* This class provides access to the file (local) system. If available an
@ -46,6 +49,9 @@ import javax.faces.bean.RequestScoped;
@RequestScoped
public class CcmFiles {
@Inject
private Instance<FileSystemAdapter> fileSystemAdapters;
/**
* Creates a {@link Reader} for the provided {@code path}.
*

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2017 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.files;
import org.libreccm.configuration.Configuration;
import org.libreccm.configuration.Setting;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Configuration(descBundle
= "org.libreccm.files.CcmFilesConfiguration.properties",
titleKey = "title",
descKey = "description")
public class CcmFilesConfiguration {
@Setting()
private String dataPath;
public String getDataPath() {
return dataPath;
}
public void setDataPath(final String dataPath) {
this.dataPath = dataPath;
}
}

View File

@ -20,36 +20,43 @@ package org.libreccm.files;
/**
* Thrown if a non empty directory is not deleted recursively.
*
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class DirectoryNotEmptyException extends Exception {
private static final long serialVersionUID = -8515711805034123260L;
/**
* Creates a new instance of <code>DirectoryNotEmptyException</code> without
* detail message.
*/
DirectoryNotEmptyException() {
super();
private static final String MESSAGE_TEMPLATE
= "The directory '%s' is not empty.";
DirectoryNotEmptyException(final String path) {
super(String.format(MESSAGE_TEMPLATE, path));
}
/**
* Constructs an instance of <code>DirectoryNotEmptyException</code> with
* the specified detail message.
*
* @param msg the detail message.
*/
DirectoryNotEmptyException(final String msg) {
super(msg);
}
DirectoryNotEmptyException(final Exception ex) {
super(ex);
}
DirectoryNotEmptyException(final String msg, final Exception ex) {
super(msg, ex);
// /**
// * Creates a new instance of <code>DirectoryNotEmptyException</code> without
// * detail message.
// */
// DirectoryNotEmptyException() {
// super();
// }
//
// /**
// * Constructs an instance of <code>DirectoryNotEmptyException</code> with
// * the specified detail message.
// *
// * @param msg the detail message.
// */
// DirectoryNotEmptyException(final String msg) {
// super(msg);
// }
//
// DirectoryNotEmptyException(final Exception ex) {
// super(ex);
// }
//
DirectoryNotEmptyException(final String path, final Exception ex) {
super(String.format(MESSAGE_TEMPLATE, path), ex);
}
}

View File

@ -28,29 +28,24 @@ public class FileAccessException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Creates a new instance of <code>FileAccessException</code> without detail
* message.
*/
FileAccessException() {
super();
private static final String MESSAGE_TEMPLATE = "Error accessing file '%s'.";
// /**
// * Creates a new instance of <code>FileAccessException</code> without detail
// * message.
// */
// FileAccessException() {
// super();
// }
FileAccessException(final String path) {
super(String.format(MESSAGE_TEMPLATE, path));
}
/**
* Constructs an instance of <code>FileAccessException</code> with the
* specified detail message.
*
* @param msg the detail message.
*/
FileAccessException(final String msg) {
super(msg);
// FileAccessException(final Exception ex) {
// super(ex);
// }
FileAccessException(final String path, final Exception ex) {
super(String.format(MESSAGE_TEMPLATE, path), ex);
}
FileAccessException(final Exception ex) {
super(ex);
}
FileAccessException(final String msg, final Exception ex) {
super(msg, ex);
}
}

View File

@ -27,30 +27,27 @@ package org.libreccm.files;
public class FileAlreadyExistsException extends Exception {
private static final long serialVersionUID = 2237027823060973043L;
private static final String MESSAGE_TEMPLATE = "The file '%s' already exists.";
/**
* Creates a new instance of <code>FileAlreadyExistsException</code> without
* detail message.
*/
FileAlreadyExistsException() {
super();
// /**
// * Creates a new instance of <code>FileAlreadyExistsException</code> without
// * detail message.
// */
// FileAlreadyExistsException() {
// super();
// }
FileAlreadyExistsException(final String path) {
super(String.format(MESSAGE_TEMPLATE, path));
}
/**
* Constructs an instance of <code>FileAlreadyExistsException</code> with
* the specified detail message.
*
* @param msg the detail message.
*/
FileAlreadyExistsException(final String msg) {
super(msg);
}
// FileAlreadyExistsException(final Exception ex) {
// super(ex);
// }
FileAlreadyExistsException(final Exception ex) {
super(ex);
}
FileAlreadyExistsException(final String msg, final Exception ex) {
super(msg, ex);
FileAlreadyExistsException(final String path, final Exception ex) {
super(String.format(MESSAGE_TEMPLATE, path), ex);
}
}

View File

@ -27,29 +27,25 @@ package org.libreccm.files;
public class FileDoesNotExistException extends Exception {
private static final long serialVersionUID = 1L;
private static final String MESSAGE_TEMPLATE = "The file '%s' does not exist.";
/**
* Creates a new instance of <code>FileDoesNotExistException</code> without
* detail message.
*/
FileDoesNotExistException() {
// /**
// * Creates a new instance of <code>FileDoesNotExistException</code> without
// * detail message.
// */
// FileDoesNotExistException() {
// }
FileDoesNotExistException(final String path) {
super(String.format(MESSAGE_TEMPLATE, path));
}
/**
* Constructs an instance of <code>FileDoesNotExistException</code> with the
* specified detail message.
*
* @param msg the detail message.
*/
FileDoesNotExistException(String msg) {
super(msg);
}
// FileDoesNotExistException(final Exception ex) {
// super(ex);
// }
FileDoesNotExistException(final Exception ex) {
super(ex);
}
FileDoesNotExistException(final String msg, final Exception ex) {
super(msg, ex);
FileDoesNotExistException(final String path, final Exception ex) {
super(String.format(MESSAGE_TEMPLATE, path), ex);
}
}

View File

@ -232,6 +232,9 @@ public interface FileSystemAdapter {
* exceptions occurs.
* @throws FileDoesNotExistException If the requested file does not
* exist.
* @throws DirectoryNotEmptyException If the directory is not empty
* <em>and</em> {@code recursively}
* is set to {@code false}.
* @throws InsufficientPermissionsException If the user which runs the
* application server does not have
* the permission to access the
@ -240,6 +243,7 @@ public interface FileSystemAdapter {
void deleteFile(String path, boolean recursively)
throws FileAccessException,
FileDoesNotExistException,
DirectoryNotEmptyException,
InsufficientPermissionsException;
}

View File

@ -27,30 +27,27 @@ package org.libreccm.files;
public class InsufficientPermissionsException extends Exception {
private static final long serialVersionUID = -7496839503615573013L;
private static final String MESSAGE_TEMPLATE = "Insufficient permissions for accessing file '%s'.";
/**
* Creates a new instance of <code>InsufficientPermissionsException</code>
* without detail message.
*/
InsufficientPermissionsException() {
super();
// /**
// * Creates a new instance of <code>InsufficientPermissionsException</code>
// * without detail message.
// */
// InsufficientPermissionsException() {
// super();
// }
InsufficientPermissionsException(final String path) {
super(String.format(MESSAGE_TEMPLATE, path));
}
/**
* Constructs an instance of <code>InsufficientPermissionsException</code>
* with the specified detail message.
*
* @param msg the detail message.
*/
InsufficientPermissionsException(final String msg) {
super(msg);
}
// InsufficientPermissionsException(final Exception ex) {
// super(ex);
// }
InsufficientPermissionsException(final Exception ex) {
super(ex);
}
InsufficientPermissionsException(final String msg, final Exception ex) {
super(msg, ex);
InsufficientPermissionsException(final String path, final Exception ex) {
super(String.format(MESSAGE_TEMPLATE, path), ex);
}
}

View File

@ -0,0 +1,317 @@
/*
* Copyright (C) 2017 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.files;
import org.libreccm.configuration.ConfigurationManager;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
/**
* This implementation of the {@link FileSystemAdapter} interface is used by
* {@link CcmFiles} as a fallback if no other implementations are available.
*
* This adapter uses the classes from the {@code java.nio} for accessing the
* file system directly. Using this adapter is not recommended. Operations may
* fail due to security constraints of the application server if this adapter is
* used.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class NIOFileSystemAdapter implements FileSystemAdapter {
@Inject
private ConfigurationManager confManager;
private String dataPath;
@PostConstruct
private void init() {
final CcmFilesConfiguration filesConf = confManager.findConfiguration(
CcmFilesConfiguration.class);
dataPath = filesConf.getDataPath();
}
@Override
public boolean isConfigured() {
return dataPath != null && !dataPath.isEmpty();
}
@Override
public Reader createReader(final String path)
throws FileDoesNotExistException,
FileAccessException,
InsufficientPermissionsException {
final Path nioPath = Paths.get(path);
if (!Files.exists(nioPath)) {
throw new FileDoesNotExistException(path);
}
if (!Files.isReadable(nioPath)) {
throw new InsufficientPermissionsException(path);
}
final FileReader fileReader;
try {
fileReader = new FileReader(nioPath.toFile());
} catch (FileNotFoundException ex) {
throw new FileDoesNotExistException(path, ex);
}
return fileReader;
}
@Override
public Writer createWriter(final String path)
throws FileAccessException,
InsufficientPermissionsException {
final Path nioPath = Paths.get(path);
if (!Files.exists(nioPath)) {
try {
Files.createFile(nioPath);
} catch (IOException ex) {
throw new FileAccessException(path, ex);
}
}
if (!Files.isWritable(nioPath)) {
throw new InsufficientPermissionsException(path);
}
final FileWriter fileWriter;
try {
fileWriter = new FileWriter(nioPath.toFile());
} catch (IOException ex) {
throw new FileAccessException(path, ex);
}
return fileWriter;
}
@Override
public InputStream createInputStream(final String path) throws
FileDoesNotExistException,
FileAccessException,
InsufficientPermissionsException {
final Path nioPath = Paths.get(path);
if (!Files.exists(nioPath)) {
throw new FileDoesNotExistException(path);
}
if (!Files.isReadable(nioPath)) {
throw new InsufficientPermissionsException(path);
}
final FileInputStream fileInputStream;
try {
fileInputStream = new FileInputStream(nioPath.toFile());
} catch (FileNotFoundException ex) {
throw new FileDoesNotExistException(path, ex);
}
return fileInputStream;
}
@Override
public OutputStream createOutputStream(final String path) throws
FileAccessException,
InsufficientPermissionsException {
final Path nioPath = Paths.get(path);
if (!Files.exists(nioPath)) {
try {
Files.createFile(nioPath);
} catch (IOException ex) {
throw new FileAccessException(path, ex);
}
}
if (!Files.isWritable(nioPath)) {
throw new InsufficientPermissionsException(path);
}
final FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(nioPath.toFile());
} catch (FileNotFoundException ex) {
throw new FileAccessException(path, ex);
}
return fileOutputStream;
}
@Override
public boolean existsFile(final String path)
throws FileAccessException,
InsufficientPermissionsException {
final Path nioPath = Paths.get(path);
return Files.exists(nioPath);
}
@Override
public boolean isDirectory(final String path) throws FileAccessException,
FileDoesNotExistException,
InsufficientPermissionsException {
final Path nioPath = Paths.get(path);
return Files.isDirectory(nioPath);
}
@Override
public void createDirectory(final String path)
throws FileAccessException,
FileAlreadyExistsException,
InsufficientPermissionsException {
final Path nioPath = Paths.get(path);
if (Files.exists(nioPath)) {
throw new FileAlreadyExistsException(path);
}
try {
Files.createDirectories(nioPath);
} catch (IOException ex) {
throw new FileAccessException(path, ex);
}
}
@Override
public List<String> listFiles(final String path)
throws FileAccessException,
FileDoesNotExistException,
InsufficientPermissionsException {
final Path nioPath = Paths.get(path);
if (!Files.isDirectory(nioPath)) {
throw new FileAccessException(path);
}
final Stream<Path> paths;
try {
paths = Files.list(nioPath);
} catch (IOException ex) {
throw new FileAccessException(path, ex);
}
return paths
.map(filePath -> filePath.getFileName().toString())
.collect(Collectors.toList());
}
@Override
public void deleteFile(final String path)
throws FileAccessException,
FileDoesNotExistException,
DirectoryNotEmptyException,
InsufficientPermissionsException {
final Path nioPath = Paths.get(path);
if (!Files.isWritable(nioPath)) {
throw new InsufficientPermissionsException(path);
}
try {
if (Files.isDirectory(nioPath) && Files.list(nioPath).count() > 0) {
throw new DirectoryNotEmptyException(path);
}
} catch (IOException ex) {
throw new FileAccessException(path, ex);
}
try {
Files.deleteIfExists(nioPath);
} catch (IOException ex) {
throw new FileAccessException(path, ex);
}
}
@Override
public void deleteFile(final String path, final boolean recursively)
throws FileAccessException,
FileDoesNotExistException,
DirectoryNotEmptyException,
InsufficientPermissionsException {
final Path nioPath = Paths.get(path);
if (!Files.isWritable(nioPath)) {
throw new InsufficientPermissionsException(path);
}
try {
if (Files.isDirectory(nioPath) && Files.list(nioPath).count() > 0) {
throw new DirectoryNotEmptyException(path);
}
} catch (IOException ex) {
throw new FileAccessException(path, ex);
}
if (recursively && Files.isDirectory(nioPath)) {
final List<String> files;
try {
files = Files
.list(nioPath)
.map(file -> file.toString())
.collect(Collectors.toList());
} catch (IOException ex) {
throw new FileAccessException(path, ex);
}
for (final String file : files) {
deleteFile(file, recursively);
}
} else {
deleteFile(path);
}
}
}

View File

@ -28,29 +28,26 @@ public class NoDirectoryException extends Exception {
private static final long serialVersionUID = -5811387600385322767L;
/**
* Creates a new instance of <code>NoDirectoryException</code> without
* detail message.
*/
NoDirectoryException() {
super();
}
private static final String MESSAGE_TEMPLATE = "The file '%s' is not a directory.";
// /**
// * Creates a new instance of <code>NoDirectoryException</code> without
// * detail message.
// */
// NoDirectoryException() {
// super();
// }
/**
* Constructs an instance of <code>NoDirectoryException</code> with the
* specified detail message.
*
* @param msg the detail message.
*/
NoDirectoryException(final String msg) {
super(msg);
NoDirectoryException(final String path) {
super(String.format(MESSAGE_TEMPLATE, path));
}
NoDirectoryException(final Exception ex) {
super(ex);
}
// NoDirectoryException(final Exception ex) {
// super(ex);
// }
NoDirectoryException(final String msg, final Exception ex) {
super(msg, ex);
NoDirectoryException(final String path, final Exception ex) {
super(String.format(MESSAGE_TEMPLATE, path), ex);
}
}