NIHVIVO-160 These belong in the 'src' directory, not in the 'test' directory.
This commit is contained in:
parent
197aa2f4f9
commit
734067f22a
9 changed files with 551 additions and 315 deletions
|
@ -0,0 +1,63 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.filestorage;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface for the File Storage system.
|
||||||
|
*/
|
||||||
|
public interface FileStorage {
|
||||||
|
/**
|
||||||
|
* The default implementation will use this key to ask
|
||||||
|
* {@link ConfigurationProperties} for the file storage base directory.
|
||||||
|
*/
|
||||||
|
String PROPERTY_FILE_STORAGE_BASE_DIR = "upload.directory";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation will use this key to ask
|
||||||
|
* {@link ConfigurationProperties} for the default URI namespace.
|
||||||
|
*/
|
||||||
|
String PROPERTY_DEFAULT_NAMESPACE = "Vitro.defaultNamespace";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the bytes from this stream as a file with the specified ID and
|
||||||
|
* filename. If the file already exists, it is over-written.
|
||||||
|
*
|
||||||
|
* @throws FileAlreadyExistsException
|
||||||
|
* if a file already exists with this ID but with a different
|
||||||
|
* filename.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void createFile(String id, String filename, InputStream bytes)
|
||||||
|
throws FileAlreadyExistsException, IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a file exists with this ID, get its name.
|
||||||
|
*
|
||||||
|
* @return The name of the file (un-encoded) if it exists, or
|
||||||
|
* <code>null</code> if it does not.
|
||||||
|
*/
|
||||||
|
String getFilename(String id) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the contents of the file with this ID and this filename.
|
||||||
|
*
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
* if there is no file that matches this ID and filename.
|
||||||
|
*/
|
||||||
|
byte[] getfile(String id, String filename) throws FileNotFoundException,
|
||||||
|
IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a file exists with this ID, it will be deleted, regardless of the file
|
||||||
|
* name. If no such file exists, no action is taken, no exception is thrown.
|
||||||
|
*
|
||||||
|
* @return <code>true<code> if a file existed, <code>false</code> otherwise.
|
||||||
|
*/
|
||||||
|
boolean deleteFile(String id) throws IOException;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.filestorage;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance of {@link FileStorage} -- either the default
|
||||||
|
* implementation, or one specified by a system property.
|
||||||
|
*/
|
||||||
|
public class FileStorageFactory {
|
||||||
|
/**
|
||||||
|
* If this system property is set, it will be taken as the name of the
|
||||||
|
* implementing class.
|
||||||
|
*/
|
||||||
|
public static final String PROPERTY_IMPLEMETATION_CLASSNAME = FileStorage.class
|
||||||
|
.getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Get an instance of {@link FileStorage}. By default, this will be an
|
||||||
|
* instance of {@link FileStorageImpl}.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* If the System Property named by
|
||||||
|
* {#SYSTEM_PROPERTY_IMPLEMETATION_CLASSNAME} is set, it must contain the
|
||||||
|
* name of the implementation class, which must be a sub-class of
|
||||||
|
* {@link FileStorage}, and must have a public, no-argument constructor.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public static FileStorage getFileStorage() throws IOException {
|
||||||
|
String className = System.getProperty(PROPERTY_IMPLEMETATION_CLASSNAME);
|
||||||
|
if (className == null) {
|
||||||
|
return new FileStorageImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName(className);
|
||||||
|
Object instance = clazz.newInstance();
|
||||||
|
return FileStorage.class.cast(instance);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Can't create a FileStorage instance", e);
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Can't create a FileStorage instance", e);
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Can't create a FileStorage instance", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Can't create a FileStorage instance", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.filestorage;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
public class FileStorageHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String id2Path(String id) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new RuntimeException("FileStorageHelper.id2Path() not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param filename
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String encodeName(String filename) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new RuntimeException("FileStorageHelper.encodeName() not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param rootDir
|
||||||
|
* @param id
|
||||||
|
* @param filename
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static File getFullPath(File rootDir, String id, String filename) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new RuntimeException("FileStorageHelper.getFullPath() not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param rootDir
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static File getPathToIdDirectory(File rootDir, String id) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new RuntimeException("FileStorageHelper.getPathToIdDirectory() not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String decodeName(String name) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new RuntimeException("FileStorageHelper.decodeName() not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,359 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.filestorage;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default implementation of {@link FileStorage}.
|
||||||
|
*/
|
||||||
|
public class FileStorageImpl implements FileStorage {
|
||||||
|
|
||||||
|
private final File baseDir;
|
||||||
|
private final File rootDir;
|
||||||
|
private final File namespaceFile;
|
||||||
|
private final Map<Character, String> namespacesMap;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Constructors and helper methods.
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the configuration properties to create an instance.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if the configuration property for the base directory is
|
||||||
|
* missing, or if it doesn't point to an existing, writeable
|
||||||
|
* directory.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if the configuration property for the default namespace is
|
||||||
|
* missing, or if it isn't in the expected form.
|
||||||
|
*/
|
||||||
|
FileStorageImpl() throws IOException {
|
||||||
|
this(figureBaseDir(), figureFileNamespace());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the arguments to create an instance. If the base directory is empty,
|
||||||
|
* initialize it. Otherwise, check that it was initialized to the same
|
||||||
|
* namespaces.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* if the configuration property doesn't point to an existing,
|
||||||
|
* writeable directory.
|
||||||
|
*/
|
||||||
|
FileStorageImpl(File baseDir, Collection<String> namespaces)
|
||||||
|
throws IOException {
|
||||||
|
checkBaseDirValid(baseDir);
|
||||||
|
checkNamespacesValid(namespaces);
|
||||||
|
|
||||||
|
this.baseDir = baseDir;
|
||||||
|
this.rootDir = new File(baseDir, "file_storage_root");
|
||||||
|
|
||||||
|
this.namespaceFile = new File(baseDir,
|
||||||
|
"file_storage_namespaces.properties");
|
||||||
|
|
||||||
|
if (rootDir.exists() && namespaceFile.exists()) {
|
||||||
|
this.namespacesMap = confirmNamespaces(namespaces);
|
||||||
|
} else if (!rootDir.exists() && !namespaceFile.exists()) {
|
||||||
|
this.namespacesMap = mapNamespaces(namespaces);
|
||||||
|
initializeStorage();
|
||||||
|
} else if (rootDir.exists()) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Storage directory '' has been partially initialized. '"
|
||||||
|
+ rootDir.getPath() + "' exists, but '"
|
||||||
|
+ namespaceFile.getPath() + "' does not.");
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Storage directory '' has been partially initialized. '"
|
||||||
|
+ namespaceFile.getPath() + "' exists, but '"
|
||||||
|
+ rootDir.getPath() + "' does not.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkNamespacesValid(Collection<String> namespaces) {
|
||||||
|
if (namespaces == null) {
|
||||||
|
throw new NullPointerException("namespaces may not be null.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 'baseDir' must point to an existing, writeable directory.
|
||||||
|
*/
|
||||||
|
private void checkBaseDirValid(File baseDir) {
|
||||||
|
if (baseDir == null) {
|
||||||
|
throw new NullPointerException("baseDir may not be null.");
|
||||||
|
}
|
||||||
|
if (!baseDir.exists()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"File upload directory does not exist: '"
|
||||||
|
+ baseDir.getPath() + "'");
|
||||||
|
}
|
||||||
|
if (!baseDir.isDirectory()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"File upload directory is not a directory: '"
|
||||||
|
+ baseDir.getPath() + "'");
|
||||||
|
}
|
||||||
|
if (!baseDir.canWrite()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"File upload directory is not writeable: '"
|
||||||
|
+ baseDir.getPath() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configuration property for the file storage base directory, and
|
||||||
|
* check that it points to an existing, writeable directory.
|
||||||
|
*
|
||||||
|
* For use by the constructor in implementations of {@link FileStorage}.
|
||||||
|
*/
|
||||||
|
static File figureBaseDir() {
|
||||||
|
String baseDirPath = ConfigurationProperties
|
||||||
|
.getProperty(PROPERTY_FILE_STORAGE_BASE_DIR);
|
||||||
|
if (baseDirPath == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Configuration properties must contain a value for '"
|
||||||
|
+ PROPERTY_FILE_STORAGE_BASE_DIR + "'");
|
||||||
|
}
|
||||||
|
return new File(baseDirPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configuration property for the default namespace, and derive the
|
||||||
|
* file namespace from it. The default namespace is assumed to be in this
|
||||||
|
* form: <code>http://vivo.mydomain.edu/individual/</code>
|
||||||
|
*
|
||||||
|
* For use by the constructor in implementations of {@link FileStorage}.
|
||||||
|
*
|
||||||
|
* @returns the file namespace is assumed to be in this form:
|
||||||
|
* <code>http://vivo.mydomain.edu/file/</code>
|
||||||
|
*/
|
||||||
|
static Collection<String> figureFileNamespace() {
|
||||||
|
String defaultNamespace = ConfigurationProperties
|
||||||
|
.getProperty(PROPERTY_DEFAULT_NAMESPACE);
|
||||||
|
if (defaultNamespace == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Configuration properties must contain a value for '"
|
||||||
|
+ PROPERTY_DEFAULT_NAMESPACE + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
String defaultSuffix = "/individual/";
|
||||||
|
String fileSuffix = "/file/";
|
||||||
|
|
||||||
|
if (!defaultNamespace.endsWith(defaultSuffix)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Default namespace does not match the expected form: '"
|
||||||
|
+ defaultNamespace + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
int hostLength = defaultNamespace.length() - defaultSuffix.length();
|
||||||
|
String fileNamespace = defaultNamespace.substring(0, hostLength)
|
||||||
|
+ fileSuffix;
|
||||||
|
return Collections.singleton(fileNamespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign arbitrary prefixes to these namespaces.
|
||||||
|
*/
|
||||||
|
private Map<Character, String> mapNamespaces(Collection<String> namespaces) {
|
||||||
|
Map<Character, String> map = new HashMap<Character, String>();
|
||||||
|
|
||||||
|
char prefixChar = 'a';
|
||||||
|
for (String namespace : namespaces) {
|
||||||
|
map.put(prefixChar, namespace);
|
||||||
|
prefixChar++;
|
||||||
|
if (prefixChar > 'z') {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Can't handle more than 26 namespaces.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the root directory and the namespaces file. Write the namespaces
|
||||||
|
* map to the namespaces file.
|
||||||
|
*/
|
||||||
|
private void initializeStorage() throws IOException {
|
||||||
|
boolean created = this.rootDir.mkdir();
|
||||||
|
if (!created) {
|
||||||
|
throw new IOException("Failed to create root directory '"
|
||||||
|
+ this.rootDir + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new PrintWriter(this.namespaceFile);
|
||||||
|
for (Entry<Character, String> entry : this.namespacesMap.entrySet()) {
|
||||||
|
writer.println(entry.getKey() + " = " + entry.getValue());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (writer != null) {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm that the namespaces file contains mappings for these namespaces,
|
||||||
|
* and only these namespaces.
|
||||||
|
*/
|
||||||
|
private Map<Character, String> confirmNamespaces(
|
||||||
|
Collection<String> namespaces) throws IOException {
|
||||||
|
Map<Character, String> map;
|
||||||
|
try {
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.load(new FileReader(this.namespaceFile));
|
||||||
|
map = new HashMap<Character, String>();
|
||||||
|
for (Object key : props.keySet()) {
|
||||||
|
char keyChar = key.toString().charAt(0);
|
||||||
|
map.put(keyChar, (String) props.get(key));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IOException("Problem loading the namespace file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> requestedNamespaces = new HashSet<String>(namespaces);
|
||||||
|
Set<String> previousNamespaces = new HashSet<String>(map.values());
|
||||||
|
if (!requestedNamespaces.equals(previousNamespaces)) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"File storage was previously initialized with a "
|
||||||
|
+ "different set of namespaces than are found "
|
||||||
|
+ "in the current request. Previous: "
|
||||||
|
+ previousNamespaces + ", Requested: "
|
||||||
|
+ requestedNamespaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Public methods
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void createFile(String id, String filename, InputStream bytes)
|
||||||
|
throws FileAlreadyExistsException, IOException {
|
||||||
|
String existingFilename = getFilename(id);
|
||||||
|
if ((existingFilename != null) && (!filename.equals(existingFilename))) {
|
||||||
|
throw new FileAlreadyExistsException(id, existingFilename, filename);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = FileStorageHelper.getFullPath(this.rootDir, id, filename);
|
||||||
|
|
||||||
|
OutputStream out = null;
|
||||||
|
try {
|
||||||
|
out = new BufferedOutputStream(new FileOutputStream(file));
|
||||||
|
InputStream in = new BufferedInputStream(bytes);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int howMany;
|
||||||
|
while (-1 != (howMany = in.read(buffer))) {
|
||||||
|
out.write(buffer, 0, howMany);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (out != null) {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean deleteFile(String id) throws IOException {
|
||||||
|
String existingFilename = getFilename(id);
|
||||||
|
if (existingFilename == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = FileStorageHelper.getFullPath(this.rootDir, id,
|
||||||
|
existingFilename);
|
||||||
|
|
||||||
|
file.delete();
|
||||||
|
if (file.exists()) {
|
||||||
|
throw new IOException("Failed to delete file with ID '" + id
|
||||||
|
+ "', file location '" + file + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* <p>
|
||||||
|
* For a non-null result, a directory must exist for the ID, and it must
|
||||||
|
* contain a file (it may or may not contain other directories).
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getFilename(String id) throws IOException {
|
||||||
|
File dir = FileStorageHelper.getPathToIdDirectory(this.rootDir, id);
|
||||||
|
|
||||||
|
if ((!dir.exists()) || (!dir.isDirectory())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
File[] files = dir.listFiles(new FileFilter() {
|
||||||
|
public boolean accept(File pathname) {
|
||||||
|
return pathname.isFile();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (files.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (files.length > 1) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"More than one file associated with ID: '" + id
|
||||||
|
+ "', directory location '" + dir + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return FileStorageHelper.decodeName(files[0].getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public byte[] getfile(String id, String filename)
|
||||||
|
throws FileNotFoundException, IOException {
|
||||||
|
// gets the bytes from the file
|
||||||
|
// throws FileNotFoundException if the file does not exist
|
||||||
|
// throws IOException
|
||||||
|
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new RuntimeException("FileStorage.getfile() not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* The code in this package implements the Vitro file-storage system.
|
* The code in this package implements the Vitro file-storage system.
|
||||||
|
@ -24,7 +26,7 @@
|
||||||
* but is different in several respects:
|
* but is different in several respects:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>
|
* <li>
|
||||||
* Each “object” will consist only of a single file,
|
* Each "object" will consist only of a single file,
|
||||||
* causing the entire issue of object encapsulation to be moot.
|
* causing the entire issue of object encapsulation to be moot.
|
||||||
* </li>
|
* </li>
|
||||||
* <li>
|
* <li>
|
||||||
|
@ -77,6 +79,16 @@
|
||||||
* would be converted to this:
|
* would be converted to this:
|
||||||
* <pre>a~n3424/myPhoto.jpg</pre>
|
* <pre>a~n3424/myPhoto.jpg</pre>
|
||||||
* </p>
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The namespaces and their assigned prefixes are stored in a properties file
|
||||||
|
* when the structure is initialized. When the structure is re-opened, the
|
||||||
|
* file is read to find the correct prefixes. The file
|
||||||
|
* might look like this:
|
||||||
|
* <pre>
|
||||||
|
* a = http://the.first.namespace/
|
||||||
|
* b = http://the.second.namespace/
|
||||||
|
* </pre>
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* <h1>ID encoding</h1>
|
* <h1>ID encoding</h1>
|
||||||
*
|
*
|
||||||
|
@ -91,10 +103,6 @@
|
||||||
* to be required, since few files are named with the special characters.
|
* to be required, since few files are named with the special characters.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p></p>
|
|
||||||
* <p></p>
|
|
||||||
* <p></p>
|
|
||||||
* <p></p>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.utils.filestorage;
|
package edu.cornell.mannlib.vitro.webapp.utils.filestorage;
|
|
@ -1,108 +0,0 @@
|
||||||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.utils.filestorage;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.ConfigurationProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The "interface" for the File Storage system. All methods are abstract except
|
|
||||||
* for the factory method.
|
|
||||||
*/
|
|
||||||
public abstract class FileStorage {
|
|
||||||
/**
|
|
||||||
* If this system property is set, it will be taken as the name of the
|
|
||||||
* implementing class.
|
|
||||||
*/
|
|
||||||
public static final String PROPERTY_IMPLEMETATION_CLASSNAME = FileStorage.class
|
|
||||||
.getName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default implementation will use this key to ask
|
|
||||||
* {@link ConfigurationProperties} for the file storage base directory.
|
|
||||||
*/
|
|
||||||
public static final String PROPERTY_FILE_STORAGE_BASE_DIR = "upload.directory";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default implementation will use this key to ask
|
|
||||||
* {@link ConfigurationProperties} for the default URI namespace.
|
|
||||||
*/
|
|
||||||
public static final String PROPERTY_DEFAULT_NAMESPACE = "Vitro.defaultNamespace";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Get an instance of {@link FileStorage}. By default, this will be an
|
|
||||||
* instance of {@link FileStorageImpl}.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* If the System Property named by
|
|
||||||
* {#SYSTEM_PROPERTY_IMPLEMETATION_CLASSNAME} is set, it must contain the
|
|
||||||
* name of the implementation class, which must be a sub-class of
|
|
||||||
* {@link FileStorage}, and must have a public, no-argument constructor.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public static FileStorage getInstance() {
|
|
||||||
String className = System.getProperty(PROPERTY_IMPLEMETATION_CLASSNAME);
|
|
||||||
if (className == null) {
|
|
||||||
return new FileStorageImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Class<?> clazz = Class.forName(className);
|
|
||||||
Object instance = clazz.newInstance();
|
|
||||||
return FileStorage.class.cast(instance);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Can't create a FileStorage instance", e);
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Can't create a FileStorage instance", e);
|
|
||||||
} catch (InstantiationException e) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Can't create a FileStorage instance", e);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Can't create a FileStorage instance", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store the bytes from this stream as a file with the specified ID and
|
|
||||||
* filename. If the file already exists, it is over-written.
|
|
||||||
*
|
|
||||||
* @throws FileAlreadyExistsException
|
|
||||||
* if a file already exists with this ID but with a different
|
|
||||||
* filename.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public abstract void createFile(String id, String filename,
|
|
||||||
InputStream bytes) throws FileAlreadyExistsException, IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If a file exists with this ID, get its name.
|
|
||||||
*
|
|
||||||
* @return The name of the file (un-encoded) if it exists, or
|
|
||||||
* <code>null</code> if it does not.
|
|
||||||
*/
|
|
||||||
public abstract String getFilename(String id) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the contents of the file with this ID and this filename.
|
|
||||||
*
|
|
||||||
* @throws FileNotFoundException
|
|
||||||
* if there is no file that matches this ID and filename.
|
|
||||||
*/
|
|
||||||
public abstract byte[] getfile(String id, String filename)
|
|
||||||
throws FileNotFoundException, IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If a file exists with this ID, it will be deleted, regardless of the file
|
|
||||||
* name. If no such file exists, no action is taken, no exception is thrown.
|
|
||||||
*
|
|
||||||
* @return <code>true<code> if a file existed, <code>false</code> otherwise.
|
|
||||||
*/
|
|
||||||
public abstract boolean deleteFile(String id) throws IOException;
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.utils.filestorage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*/
|
|
||||||
public class FileStorageHelper {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,192 +0,0 @@
|
||||||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.utils.filestorage;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.ConfigurationProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default implementation of {@link FileStorage}.
|
|
||||||
*/
|
|
||||||
public class FileStorageImpl extends FileStorage {
|
|
||||||
|
|
||||||
// static FileStorage getInstance()
|
|
||||||
// gets baseDir and namespaces from ConfigurationProperties
|
|
||||||
// gets instance class from system properties
|
|
||||||
// throws IllegalStateException if requires properties are missing
|
|
||||||
// throws IOException
|
|
||||||
//
|
|
||||||
// void createFile(String id, String filename, InputStream bytes)
|
|
||||||
// stores the bytes as a file with this name under this id
|
|
||||||
// if the file already exists, over-writes it
|
|
||||||
// throws FileAlreadyExistsException if a file already exists under this id
|
|
||||||
// with a different name
|
|
||||||
// throws IOException
|
|
||||||
//
|
|
||||||
// String getfilename(String id)
|
|
||||||
// returns the name of the file at this ID, or null if there is none.
|
|
||||||
// throws IOException
|
|
||||||
//
|
|
||||||
// byte[] getFile(String id, String filename)
|
|
||||||
// gets the bytes from the file
|
|
||||||
// throws FileNotFoundException if the file does not exist
|
|
||||||
// throws IOException
|
|
||||||
//
|
|
||||||
// boolean deleteFile(String id)
|
|
||||||
// removes the file at this id, returns true
|
|
||||||
// if no such file, takes no action, returns false
|
|
||||||
// throws IOException
|
|
||||||
//
|
|
||||||
// FileStorageImpl
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the configuration properties to create an instance.
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException
|
|
||||||
* if the configuration property for the base directory is
|
|
||||||
* missing, or if it doesn't point to an existing, writeable
|
|
||||||
* directory.
|
|
||||||
* @throws IllegalArgumentException
|
|
||||||
* if the configuration property for the default namespace is
|
|
||||||
* missing, or if it isn't in the expected form.
|
|
||||||
*/
|
|
||||||
FileStorageImpl() {
|
|
||||||
this(figureBaseDir(), figureFileNamespace());
|
|
||||||
}
|
|
||||||
|
|
||||||
// package-level constructor(File baseDir, Collection<String> namespaces),
|
|
||||||
// gets properties from arguments
|
|
||||||
// if baseDir is not initialized with file_storage_root and
|
|
||||||
// file_storage_prefixMap, do it.
|
|
||||||
// otherwise check for correctness and consistency
|
|
||||||
// throws IllegalStateException if partially initialized
|
|
||||||
// throws IllegalStateException if already initialized and namespaces don't
|
|
||||||
// match
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the arguments to create an instance. If the base directory is empty,
|
|
||||||
* initialize it. Otherwise, check that it was initialized to the same
|
|
||||||
* namespaces.
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException
|
|
||||||
* if the configuration property doesn't point to an existing,
|
|
||||||
* writeable directory.
|
|
||||||
*/
|
|
||||||
FileStorageImpl(File baseDir, Collection<String> namespaces) {
|
|
||||||
if (baseDir == null) {
|
|
||||||
throw new NullPointerException("baseDir may not be null.");
|
|
||||||
}
|
|
||||||
if (namespaces == null) {
|
|
||||||
throw new NullPointerException("namespaces may not be null.");
|
|
||||||
}
|
|
||||||
if (!baseDir.exists()) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"File upload directory does not exist: '"
|
|
||||||
+ baseDir.getPath() + "'");
|
|
||||||
}
|
|
||||||
if (!baseDir.isDirectory()) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"File upload directory is not a directory: '"
|
|
||||||
+ baseDir.getPath() + "'");
|
|
||||||
}
|
|
||||||
if (!baseDir.canWrite()) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"File upload directory is not writeable: '"
|
|
||||||
+ baseDir.getPath() + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the configuration property for the file storage base directory, and
|
|
||||||
* check that it points to an existing, writeable directory.
|
|
||||||
*/
|
|
||||||
private static File figureBaseDir() {
|
|
||||||
String baseDirPath = ConfigurationProperties
|
|
||||||
.getProperty(PROPERTY_FILE_STORAGE_BASE_DIR);
|
|
||||||
if (baseDirPath == null) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Configuration properties must contain a value for '"
|
|
||||||
+ PROPERTY_FILE_STORAGE_BASE_DIR + "'");
|
|
||||||
}
|
|
||||||
return new File(baseDirPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the configuration property for the default namespace, and derive the
|
|
||||||
* file namespace from it. The default namespace is assumed to be in this
|
|
||||||
* form: <code>http://vivo.mydomain.edu/individual/</code>
|
|
||||||
*
|
|
||||||
* @returns the file namespace is assumed to be in this form:
|
|
||||||
* <code>http://vivo.mydomain.edu/file/</code>
|
|
||||||
*/
|
|
||||||
private static Collection<String> figureFileNamespace() {
|
|
||||||
String defaultNamespace = ConfigurationProperties
|
|
||||||
.getProperty(PROPERTY_DEFAULT_NAMESPACE);
|
|
||||||
if (defaultNamespace == null) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Configuration properties must contain a value for '"
|
|
||||||
+ PROPERTY_DEFAULT_NAMESPACE + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
String defaultSuffix = "/individual/";
|
|
||||||
String fileSuffix = "/file/";
|
|
||||||
|
|
||||||
if (!defaultNamespace.endsWith(defaultSuffix)) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Default namespace does not match the expected form: '"
|
|
||||||
+ defaultNamespace + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
int hostLength = defaultNamespace.length() - defaultSuffix.length();
|
|
||||||
String fileNamespace = defaultNamespace.substring(0, hostLength)
|
|
||||||
+ fileSuffix;
|
|
||||||
return Collections.singleton(fileNamespace);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void createFile(String id, String filename, InputStream bytes)
|
|
||||||
throws FileAlreadyExistsException, IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
throw new RuntimeException("FileStorage.createFile() not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean deleteFile(String id) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
throw new RuntimeException("FileStorage.deleteFile() not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getFilename(String id) throws IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
throw new RuntimeException("FileStorage.getFilename() not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public byte[] getfile(String id, String filename)
|
|
||||||
throws FileNotFoundException, IOException {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
throw new RuntimeException("FileStorage.getfile() not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue