VIVO-848 Move the FileStorage system behind an interface
Add it to the Application framework, and do some cleanup.
This commit is contained in:
parent
c751ecdc6d
commit
6e5bbaeef8
24 changed files with 232 additions and 260 deletions
|
@ -6,12 +6,16 @@ import javax.servlet.ServletContext;
|
|||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.impl.FileStorageImplWrapper;
|
||||
import edu.cornell.mannlib.vitro.webapp.imageprocessor.jai.JaiImageProcessor;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.Application;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine;
|
||||
import edu.cornell.mannlib.vitro.webapp.searchengine.SearchEngineWrapper;
|
||||
import edu.cornell.mannlib.vitro.webapp.searchengine.solr.SolrSearchEngine;
|
||||
import edu.cornell.mannlib.vitro.webapp.startup.ComponentStartupStatusImpl;
|
||||
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
||||
|
||||
/**
|
||||
|
@ -25,6 +29,7 @@ public class ApplicationImpl implements Application {
|
|||
private final ServletContext ctx;
|
||||
private SearchEngine searchEngine;
|
||||
private ImageProcessor imageProcessor;
|
||||
private FileStorage fileStorage;
|
||||
|
||||
public ApplicationImpl(ServletContext ctx) {
|
||||
this.ctx = ctx;
|
||||
|
@ -44,6 +49,7 @@ public class ApplicationImpl implements Application {
|
|||
this.searchEngine = searchEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageProcessor getImageProcessor() {
|
||||
return imageProcessor;
|
||||
}
|
||||
|
@ -52,11 +58,21 @@ public class ApplicationImpl implements Application {
|
|||
this.imageProcessor = imageProcessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileStorage getFileStorage() {
|
||||
return fileStorage;
|
||||
}
|
||||
|
||||
public void setFileStorage(FileStorage fileStorage) {
|
||||
this.fileStorage = fileStorage;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// The Setup class.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public static class Setup implements ServletContextListener {
|
||||
private ApplicationImpl application;
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
|
@ -64,14 +80,26 @@ public class ApplicationImpl implements Application {
|
|||
StartupStatus ss = StartupStatus.getBean(ctx);
|
||||
|
||||
try {
|
||||
ApplicationImpl application = new ApplicationImpl(ctx);
|
||||
application = new ApplicationImpl(ctx);
|
||||
|
||||
ComponentStartupStatus css = new ComponentStartupStatusImpl(
|
||||
this, ss);
|
||||
|
||||
SearchEngine searchEngine = new SearchEngineWrapper(
|
||||
new SolrSearchEngine());
|
||||
searchEngine.startup(application, css);
|
||||
application.setSearchEngine(searchEngine);
|
||||
ss.info(this, "Started the searchEngine: " + searchEngine);
|
||||
|
||||
ImageProcessor imageProcessor = new JaiImageProcessor();
|
||||
imageProcessor.startup(application, css);
|
||||
application.setImageProcessor(imageProcessor);
|
||||
ss.info(this, "Started the ImageProcessor: " + searchEngine);
|
||||
|
||||
FileStorage fileStorage = new FileStorageImplWrapper();
|
||||
fileStorage.startup(application, css);
|
||||
application.setFileStorage(fileStorage);
|
||||
ss.info(this, "Started the FileStorage system: " + searchEngine);
|
||||
|
||||
ApplicationUtils.setInstance(application);
|
||||
ss.info(this, "Appliation is configured.");
|
||||
|
@ -82,7 +110,9 @@ public class ApplicationImpl implements Application {
|
|||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
// Nothing to tear down.
|
||||
application.getFileStorage().shutdown(application);
|
||||
application.getImageProcessor().shutdown(application);
|
||||
application.getSearchEngine().shutdown(application);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
|
|||
import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest.UNAUTHORIZED;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.UnavailableException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AddObjectPropertyStatement;
|
||||
|
@ -27,11 +27,10 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.For
|
|||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.model.ImageInfo;
|
||||
import edu.cornell.mannlib.vitro.webapp.i18n.I18n;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor.CropRectangle;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor.Dimensions;
|
||||
import edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil;
|
||||
|
@ -115,23 +114,7 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
|||
@Override
|
||||
public void init() throws ServletException {
|
||||
super.init();
|
||||
Object o = getServletContext().getAttribute(
|
||||
FileStorageSetup.ATTRIBUTE_NAME);
|
||||
if (o instanceof FileStorage) {
|
||||
fileStorage = (FileStorage) o;
|
||||
} else if (o == null) {
|
||||
throw new UnavailableException(this.getClass().getSimpleName()
|
||||
+ " could not initialize. Attribute '"
|
||||
+ FileStorageSetup.ATTRIBUTE_NAME
|
||||
+ "' was not set in the servlet context.");
|
||||
} else {
|
||||
throw new UnavailableException(this.getClass().getSimpleName()
|
||||
+ " could not initialize. Attribute '"
|
||||
+ FileStorageSetup.ATTRIBUTE_NAME
|
||||
+ "' in the servlet context contained an instance of '"
|
||||
+ o.getClass().getName() + "' instead of '"
|
||||
+ FileStorage.class.getName() + "'");
|
||||
}
|
||||
fileStorage = ApplicationUtils.instance().getFileStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,9 +28,9 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadControl
|
|||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.TempFileHolder;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.UploadedFileHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileAlreadyExistsException;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileAlreadyExistsException;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor.CropRectangle;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor.Dimensions;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor.ImageProcessorException;
|
||||
|
|
|
@ -11,7 +11,6 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||
|
||||
/**
|
||||
* Static methods to help when serving uploaded files.
|
||||
|
@ -19,6 +18,8 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
|||
public class FileServingHelper {
|
||||
private static final Log log = LogFactory.getLog(FileServingHelper.class);
|
||||
|
||||
public static final String PROPERTY_DEFAULT_NAMESPACE = "Vitro.defaultNamespace";
|
||||
|
||||
private static final String DEFAULT_PATH = "/individual/";
|
||||
private static final String FILE_PATH = "/file/";
|
||||
private static boolean warned; // Only issue the warning once.
|
||||
|
@ -29,11 +30,11 @@ public class FileServingHelper {
|
|||
*/
|
||||
private static String getDefaultNamespace(ServletContext ctx) {
|
||||
String defaultNamespace = ConfigurationProperties.getBean(ctx)
|
||||
.getProperty(FileStorageSetup.PROPERTY_DEFAULT_NAMESPACE);
|
||||
.getProperty(PROPERTY_DEFAULT_NAMESPACE);
|
||||
if (defaultNamespace == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Configuration properties must contain a value for '"
|
||||
+ FileStorageSetup.PROPERTY_DEFAULT_NAMESPACE + "'");
|
||||
+ PROPERTY_DEFAULT_NAMESPACE + "'");
|
||||
}
|
||||
|
||||
if (!defaultNamespace.endsWith(DEFAULT_PATH)) {
|
||||
|
|
|
@ -4,7 +4,6 @@ package edu.cornell.mannlib.vitro.webapp.filestorage;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpSessionBindingEvent;
|
||||
import javax.servlet.http.HttpSessionBindingListener;
|
||||
|
@ -12,9 +11,9 @@ import javax.servlet.http.HttpSessionBindingListener;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
|
||||
/**
|
||||
* Attaches an uploaded file to the session with a listener, so the file will be
|
||||
|
@ -109,6 +108,7 @@ public class TempFileHolder implements HttpSessionBindingListener {
|
|||
*/
|
||||
@Override
|
||||
public void valueBound(HttpSessionBindingEvent event) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,17 +130,7 @@ public class TempFileHolder implements HttpSessionBindingListener {
|
|||
return;
|
||||
}
|
||||
|
||||
HttpSession session = event.getSession();
|
||||
ServletContext servletContext = session.getServletContext();
|
||||
|
||||
FileStorage fs = (FileStorage) servletContext
|
||||
.getAttribute(FileStorageSetup.ATTRIBUTE_NAME);
|
||||
if (fs == null) {
|
||||
log.error("Servlet context does not contain file storage at '"
|
||||
+ FileStorageSetup.ATTRIBUTE_NAME + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
FileStorage fs = ApplicationUtils.instance().getFileStorage();
|
||||
try {
|
||||
fs.deleteFile(fileInfo.getBytestreamUri());
|
||||
log.debug("Deleted file " + fileInfo);
|
||||
|
|
|
@ -22,10 +22,10 @@ import edu.cornell.mannlib.vitro.webapp.dao.InsertException;
|
|||
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileAlreadyExistsException;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.model.ImageInfo;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileAlreadyExistsException;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
|
||||
/**
|
||||
* A helper object to handle the mundane details of dealing with uploaded files
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.backend;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
||||
|
||||
/**
|
||||
* Initializes the file storage system, and stores a reference in the servlet
|
||||
* context.
|
||||
*/
|
||||
public class FileStorageSetup implements ServletContextListener {
|
||||
private static final Log log = LogFactory.getLog(FileStorageSetup.class);
|
||||
|
||||
/**
|
||||
* The implementation of the {@link FileStorage} system will be stored in
|
||||
* the {@link ServletContext} as an attribute with this name.
|
||||
*/
|
||||
public static final String ATTRIBUTE_NAME = FileStorage.class.getName();
|
||||
|
||||
/**
|
||||
* The default implementation will use this key to ask
|
||||
* {@link ConfigurationProperties} for the vivo home directory. The file
|
||||
* storage base directory is in a subdirectory below this one.
|
||||
*/
|
||||
public static final String PROPERTY_VITRO_HOME_DIR = "vitro.home";
|
||||
public static final String FILE_STORAGE_SUBDIRECTORY = "uploads";
|
||||
|
||||
/**
|
||||
* 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";
|
||||
|
||||
/**
|
||||
* Create an implementation of {@link FileStorage} and store it in the
|
||||
* {@link ServletContext}, as an attribute named according to
|
||||
* {@link #ATTRIBUTE_NAME}.
|
||||
*/
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
ServletContext ctx = sce.getServletContext();
|
||||
StartupStatus ss = StartupStatus.getBean(ctx);
|
||||
|
||||
try {
|
||||
File baseDirectory = figureBaseDir(sce);
|
||||
Collection<String> fileNamespace = confirmDefaultNamespace(sce);
|
||||
FileStorage fs = new FileStorageImpl(baseDirectory, fileNamespace);
|
||||
|
||||
ctx.setAttribute(ATTRIBUTE_NAME, fs);
|
||||
} catch (Exception e) {
|
||||
log.fatal("Failed to initialize the file system.", e);
|
||||
ss.fatal(this, "Failed to initialize the file system.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
private File figureBaseDir(ServletContextEvent sce) throws IOException {
|
||||
String homeDirPath = ConfigurationProperties.getBean(sce).getProperty(
|
||||
PROPERTY_VITRO_HOME_DIR);
|
||||
if (homeDirPath == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Configuration properties must contain a value for '"
|
||||
+ PROPERTY_VITRO_HOME_DIR + "'");
|
||||
}
|
||||
|
||||
File homeDir = new File(homeDirPath);
|
||||
if (!homeDir.exists()) {
|
||||
throw new IllegalStateException("Vitro home directory '"
|
||||
+ homeDir.getAbsolutePath() + "' does not exist.");
|
||||
}
|
||||
|
||||
File baseDir = new File(homeDir, FILE_STORAGE_SUBDIRECTORY);
|
||||
if (!baseDir.exists()) {
|
||||
boolean created = baseDir.mkdir();
|
||||
if (!created) {
|
||||
throw new IOException("Unable to create uploads directory at '"
|
||||
+ baseDir + "'");
|
||||
}
|
||||
}
|
||||
return baseDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration property for the default namespace. For use by the
|
||||
* constructor in implementations of {@link FileStorage}.
|
||||
*
|
||||
* @returns a collection containing the default namespace.
|
||||
*/
|
||||
private Collection<String> confirmDefaultNamespace(ServletContextEvent sce) {
|
||||
String defaultNamespace = ConfigurationProperties.getBean(sce)
|
||||
.getProperty(PROPERTY_DEFAULT_NAMESPACE);
|
||||
if (defaultNamespace == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Configuration properties must contain a value for '"
|
||||
+ PROPERTY_DEFAULT_NAMESPACE + "'");
|
||||
}
|
||||
|
||||
return Collections.singleton(defaultNamespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.backend;
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.impl;
|
||||
|
||||
import static edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage.SHORTY_LENGTH;
|
||||
import static edu.cornell.mannlib.vitro.webapp.filestorage.impl.FileStorageImpl.SHORTY_LENGTH;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
|
@ -1,6 +1,6 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.backend;
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.impl;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
|
@ -24,10 +24,29 @@ import java.util.Properties;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileAlreadyExistsException;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
|
||||
/**
|
||||
* The default implementation of {@link FileStorage}.
|
||||
*/
|
||||
public class FileStorageImpl implements FileStorage {
|
||||
public class FileStorageImpl {
|
||||
/**
|
||||
* The name of the root directory, within the base directory.
|
||||
*/
|
||||
public static final String FILE_STORAGE_ROOT = "file_storage_root";
|
||||
|
||||
/**
|
||||
* The name of the file in the base directory that holds the namespace map.
|
||||
*/
|
||||
public static final String FILE_STORAGE_NAMESPACES_PROPERTIES = "file_storage_namespaces.properties";
|
||||
|
||||
/**
|
||||
* How often to we insert path separator characters?
|
||||
*/
|
||||
public static final int SHORTY_LENGTH = 3;
|
||||
|
||||
|
||||
private static final Log log = LogFactory.getLog(FileStorageImpl.class);
|
||||
|
||||
private final File baseDir;
|
||||
|
@ -240,7 +259,6 @@ public class FileStorageImpl implements FileStorage {
|
|||
* directories to put it in.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void createFile(String id, String filename, InputStream bytes)
|
||||
throws FileAlreadyExistsException, IOException {
|
||||
String existingFilename = getFilename(id);
|
||||
|
@ -291,7 +309,6 @@ public class FileStorageImpl implements FileStorage {
|
|||
* will be deleted. This repeats, up to (but not including) the root
|
||||
* directory.
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteFile(String id) throws IOException {
|
||||
String existingFilename = getFilename(id);
|
||||
if (existingFilename == null) {
|
||||
|
@ -356,14 +373,12 @@ public class FileStorageImpl implements FileStorage {
|
|||
}
|
||||
|
||||
/**
|
||||
* {@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 {
|
||||
public String getFilename(String id) {
|
||||
File dir = FileStorageHelper.getPathToIdDirectory(id,
|
||||
this.namespacesMap, this.rootDir);
|
||||
log.debug("ID '" + id + "' translates to this directory path: '" + dir
|
||||
|
@ -374,6 +389,7 @@ public class FileStorageImpl implements FileStorage {
|
|||
}
|
||||
|
||||
File[] files = dir.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
return pathname.isFile();
|
||||
}
|
||||
|
@ -395,7 +411,6 @@ public class FileStorageImpl implements FileStorage {
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public InputStream getInputStream(String id, String filename)
|
||||
throws IOException {
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.impl;
|
||||
|
||||
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 javax.servlet.ServletContext;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.Application;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileAlreadyExistsException;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
|
||||
/**
|
||||
* A thin wrapper around the existing FileStorageImpl. Handles the setup.
|
||||
*/
|
||||
public class FileStorageImplWrapper implements FileStorage {
|
||||
public static final String PROPERTY_DEFAULT_NAMESPACE = "Vitro.defaultNamespace";
|
||||
public static final String PROPERTY_VITRO_HOME_DIR = "vitro.home";
|
||||
public static final String FILE_STORAGE_SUBDIRECTORY = "uploads";
|
||||
|
||||
private FileStorageImpl fs;
|
||||
|
||||
/**
|
||||
* Create an instance of FileStorageImpl, based on the values in runtime.properties.
|
||||
*/
|
||||
@Override
|
||||
public void startup(Application application, ComponentStartupStatus ss) {
|
||||
ServletContext ctx = application.getServletContext();
|
||||
|
||||
try {
|
||||
File baseDirectory = figureBaseDir(ctx);
|
||||
Collection<String> fileNamespace = confirmDefaultNamespace(ctx);
|
||||
fs = new FileStorageImpl(baseDirectory, fileNamespace);
|
||||
} catch (Exception e) {
|
||||
ss.fatal("Failed to initialize the file system.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration property for the file storage base directory, and
|
||||
* check that it points to an existing, writeable directory.
|
||||
*/
|
||||
private File figureBaseDir(ServletContext ctx) throws IOException {
|
||||
String homeDirPath = ConfigurationProperties.getBean(ctx).getProperty(
|
||||
PROPERTY_VITRO_HOME_DIR);
|
||||
if (homeDirPath == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Configuration properties must contain a value for '"
|
||||
+ PROPERTY_VITRO_HOME_DIR + "'");
|
||||
}
|
||||
|
||||
File homeDir = new File(homeDirPath);
|
||||
if (!homeDir.exists()) {
|
||||
throw new IllegalStateException("Vitro home directory '"
|
||||
+ homeDir.getAbsolutePath() + "' does not exist.");
|
||||
}
|
||||
|
||||
File baseDir = new File(homeDir, FILE_STORAGE_SUBDIRECTORY);
|
||||
if (!baseDir.exists()) {
|
||||
boolean created = baseDir.mkdir();
|
||||
if (!created) {
|
||||
throw new IOException("Unable to create uploads directory at '"
|
||||
+ baseDir + "'");
|
||||
}
|
||||
}
|
||||
return baseDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration property for the default namespace.
|
||||
*/
|
||||
private Collection<String> confirmDefaultNamespace(ServletContext ctx) {
|
||||
String defaultNamespace = ConfigurationProperties.getBean(ctx)
|
||||
.getProperty(PROPERTY_DEFAULT_NAMESPACE);
|
||||
if (defaultNamespace == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Configuration properties must contain a value for '"
|
||||
+ PROPERTY_DEFAULT_NAMESPACE + "'");
|
||||
}
|
||||
|
||||
return Collections.singleton(defaultNamespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown(Application application) {
|
||||
// Nothing to shut down.
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Delegated methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void createFile(String id, String filename, InputStream bytes)
|
||||
throws FileAlreadyExistsException, IOException {
|
||||
fs.createFile(id, filename, bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilename(String id) throws IOException {
|
||||
return fs.getFilename(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream(String id, String filename)
|
||||
throws FileNotFoundException, IOException {
|
||||
return fs.getInputStream(id, filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteFile(String id) throws IOException {
|
||||
return fs.deleteFile(id);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.backend;
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.impl;
|
||||
|
||||
/**
|
||||
* Indicates that an object ID contains an invalid character.
|
|
@ -1,6 +1,6 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.backend;
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.impl;
|
||||
|
||||
/**
|
||||
* Indicates a PairTree path ("ppath" or "relative path") that is not correctly
|
|
@ -273,10 +273,10 @@ but is different in several respects:
|
|||
<p>
|
||||
By the way, almost all of this is implemented in
|
||||
<pre>
|
||||
edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageHelper
|
||||
edu.cornell.mannlib.vitro.webapp.filestorage.impl.FileStorageHelper
|
||||
</pre>
|
||||
and illustrated in
|
||||
<pre>
|
||||
edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageHelperTest
|
||||
edu.cornell.mannlib.vitro.webapp.filestorage.impl.FileStorageHelperTest
|
||||
</pre>
|
||||
</p>
|
|
@ -12,19 +12,18 @@ import java.net.URLDecoder;
|
|||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.UnavailableException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
@ -59,16 +58,8 @@ public class FileServingServlet extends VitroHttpServlet {
|
|||
*/
|
||||
@Override
|
||||
public void init() throws ServletException {
|
||||
Object o = getServletContext().getAttribute(
|
||||
FileStorageSetup.ATTRIBUTE_NAME);
|
||||
if (o instanceof FileStorage) {
|
||||
fileStorage = (FileStorage) o;
|
||||
} else {
|
||||
throw new UnavailableException(
|
||||
"The ServletContext did not hold a FileStorage object at '"
|
||||
+ FileStorageSetup.ATTRIBUTE_NAME
|
||||
+ "'; found this instead: " + o);
|
||||
}
|
||||
super.init();
|
||||
fileStorage = ApplicationUtils.instance().getFileStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -220,10 +211,6 @@ public class FileServingServlet extends VitroHttpServlet {
|
|||
public FileServingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public FileServingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package edu.cornell.mannlib.vitro.webapp.modules;
|
|||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine;
|
||||
|
||||
|
@ -17,6 +18,8 @@ public interface Application {
|
|||
|
||||
ImageProcessor getImageProcessor();
|
||||
|
||||
FileStorage getFileStorage();
|
||||
|
||||
public interface Component {
|
||||
enum LifecycleState {
|
||||
NEW, ACTIVE, STOPPED
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.backend;
|
||||
package edu.cornell.mannlib.vitro.webapp.modules.fileStorage;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -1,30 +1,17 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.backend;
|
||||
package edu.cornell.mannlib.vitro.webapp.modules.fileStorage;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.Application;
|
||||
|
||||
/**
|
||||
* The interface for the File Storage system.
|
||||
*/
|
||||
public interface FileStorage {
|
||||
/**
|
||||
* The name of the root directory, within the base directory.
|
||||
*/
|
||||
public static final String FILE_STORAGE_ROOT = "file_storage_root";
|
||||
|
||||
/**
|
||||
* The name of the file in the base directory that holds the namespace map.
|
||||
*/
|
||||
public static final String FILE_STORAGE_NAMESPACES_PROPERTIES = "file_storage_namespaces.properties";
|
||||
|
||||
/**
|
||||
* How often to we insert path separator characters?
|
||||
*/
|
||||
int SHORTY_LENGTH = 3;
|
||||
|
||||
public interface FileStorage extends Application.Module {
|
||||
/**
|
||||
* Store the bytes from this stream as a file with the specified ID and
|
||||
* filename. If the file already exists, it is over-written.
|
|
@ -1,32 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.searchengine;
|
||||
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.Application;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus;
|
||||
import edu.cornell.mannlib.vitro.webapp.startup.ComponentStartupStatusImpl;
|
||||
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
||||
|
||||
/**
|
||||
* Whatever search engine we have, start it up and shut it down.
|
||||
*/
|
||||
public class SearchEngineSetup implements ServletContextListener {
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
Application application = ApplicationUtils.instance();
|
||||
StartupStatus ss = StartupStatus.getBean(sce.getServletContext());
|
||||
ComponentStartupStatus css = new ComponentStartupStatusImpl(this, ss);
|
||||
application.getSearchEngine().startup(application, css);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
Application application = ApplicationUtils.instance();
|
||||
application.getSearchEngine().shutdown(application);
|
||||
}
|
||||
|
||||
}
|
|
@ -96,7 +96,7 @@ public class SearchEngineWrapper implements SearchEngine {
|
|||
try {
|
||||
throw new IllegalStateException();
|
||||
} catch (Exception e) {
|
||||
log.warn("startup called when state was " + lifecycleState, e);
|
||||
log.warn("shutdown called when state was " + lifecycleState, e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import stubs.edu.cornell.mannlib.vitro.webapp.config.ConfigurationPropertiesStub
|
|||
import stubs.javax.servlet.ServletContextStub;
|
||||
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||
|
||||
/**
|
||||
*/
|
||||
|
@ -35,7 +34,7 @@ public class FileServingHelperTest extends AbstractTestClass {
|
|||
ctx = new ServletContextStub();
|
||||
|
||||
ConfigurationPropertiesStub props = new ConfigurationPropertiesStub();
|
||||
props.setProperty(FileStorageSetup.PROPERTY_DEFAULT_NAMESPACE,
|
||||
props.setProperty(FileServingHelper.PROPERTY_DEFAULT_NAMESPACE,
|
||||
DEFAULT_NAMESPACE);
|
||||
props.setBean(ctx);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.backend;
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.impl;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.backend;
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.impl;
|
||||
|
||||
import static edu.cornell.mannlib.vitro.webapp.filestorage.impl.FileStorageImpl.FILE_STORAGE_NAMESPACES_PROPERTIES;
|
||||
import static edu.cornell.mannlib.vitro.webapp.filestorage.impl.FileStorageImpl.FILE_STORAGE_ROOT;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -26,6 +28,7 @@ import org.junit.BeforeClass;
|
|||
import org.junit.Test;
|
||||
|
||||
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileAlreadyExistsException;
|
||||
|
||||
/**
|
||||
* Test the FileStorage methods. The zero-argument constructor was tested in
|
||||
|
@ -55,26 +58,29 @@ public class FileStorageImplTest extends AbstractTestClass {
|
|||
// tests
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void baseDirDoesntExist() throws IOException {
|
||||
File baseDir = new File(tempDir, "doesntExist");
|
||||
new FileStorageImpl(baseDir, EMPTY_NAMESPACES);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void partialInitializationRoot() throws IOException {
|
||||
File baseDir = new File(tempDir, "partialWithRoot");
|
||||
baseDir.mkdir();
|
||||
new File(baseDir, FileStorage.FILE_STORAGE_ROOT).mkdir();
|
||||
new File(baseDir, FILE_STORAGE_ROOT).mkdir();
|
||||
|
||||
new FileStorageImpl(baseDir, EMPTY_NAMESPACES);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void partialInitializationNamespaces() throws IOException {
|
||||
File baseDir = new File(tempDir, "partialWithNamespaces");
|
||||
baseDir.mkdir();
|
||||
new File(baseDir, FileStorage.FILE_STORAGE_NAMESPACES_PROPERTIES)
|
||||
new File(baseDir, FILE_STORAGE_NAMESPACES_PROPERTIES)
|
||||
.createNewFile();
|
||||
|
||||
new FileStorageImpl(baseDir, EMPTY_NAMESPACES);
|
||||
|
@ -276,7 +282,7 @@ public class FileStorageImplTest extends AbstractTestClass {
|
|||
*/
|
||||
private void assertFileContents(FileStorageImpl fs, String id,
|
||||
String filename, String expectedContents) throws IOException {
|
||||
File rootDir = new File(fs.getBaseDir(), FileStorage.FILE_STORAGE_ROOT);
|
||||
File rootDir = new File(fs.getBaseDir(), FILE_STORAGE_ROOT);
|
||||
File path = FileStorageHelper.getFullPath(rootDir, id, filename,
|
||||
fs.getNamespaces());
|
||||
|
|
@ -8,6 +8,7 @@ import javax.servlet.ServletContext;
|
|||
|
||||
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.Application;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor;
|
||||
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine;
|
||||
|
||||
|
@ -66,4 +67,11 @@ public class ApplicationStub implements Application {
|
|||
"ApplicationStub.getImageProcessor() not implemented.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileStorage getFileStorage() {
|
||||
throw new RuntimeException(
|
||||
"ApplicationStub.getFileStorage() not implemented.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,8 +28,6 @@ edu.cornell.mannlib.vitro.webapp.servlet.setup.rdfsetup.RDFSetup
|
|||
edu.cornell.mannlib.vitro.webapp.servlet.setup.ConfigurationModelsSetup
|
||||
edu.cornell.mannlib.vitro.webapp.servlet.setup.ContentModelSetup
|
||||
|
||||
edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup
|
||||
|
||||
edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil$Setup
|
||||
|
||||
# Some permissions were removed in release 1.7
|
||||
|
@ -65,7 +63,6 @@ edu.cornell.mannlib.vitro.webapp.i18n.selection.LocaleSelectionSetup
|
|||
|
||||
# The search indexer uses a "public" permission, so the PropertyRestrictionPolicyHelper
|
||||
# and the PermissionRegistry must already be set up.
|
||||
edu.cornell.mannlib.vitro.webapp.searchengine.SearchEngineSetup
|
||||
edu.cornell.mannlib.vitro.webapp.searchindex.SearchIndexerSetup
|
||||
|
||||
edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerSetup
|
||||
|
|
Loading…
Add table
Reference in a new issue