NIHVIVO-785 When the main image is uploaded, it is stored in the session, not on the Individual, until the thumbnail is cropped -- then both the main image and the thumbnail are stored on the Individual.
This commit is contained in:
parent
39ffb7c433
commit
4246a4385c
5 changed files with 489 additions and 192 deletions
|
@ -29,6 +29,7 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.FileModelHelper;
|
|||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileServingHelper;
|
||||
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.uploadrequest.FileUploadServletRequest;
|
||||
import freemarker.template.Configuration;
|
||||
|
||||
|
@ -281,37 +282,22 @@ public class ImageUploadController extends FreeMarkerHttpServlet {
|
|||
ImageUploadHelper helper = new ImageUploadHelper(fileStorage, vreq
|
||||
.getFullWebappDaoFactory());
|
||||
|
||||
// Did they provide a file to upload? If not, show an error.
|
||||
FileItem fileItem;
|
||||
try {
|
||||
fileItem = helper.validateImageFromRequest(vreq);
|
||||
// Did they provide a file to upload? If not, show an error.
|
||||
FileItem fileItem = helper.validateImageFromRequest(vreq);
|
||||
|
||||
// Put it in the file system, and store a reference in the session.
|
||||
FileInfo fileInfo = helper.storeNewImage(fileItem, vreq);
|
||||
|
||||
// How big is the new image? If not big enough, show an error.
|
||||
Dimensions size = helper.getNewImageSize(fileInfo);
|
||||
|
||||
// Go to the cropping page.
|
||||
return showCropImagePage(vreq, entity, fileInfo
|
||||
.getBytestreamAliasUrl(), size);
|
||||
} catch (UserMistakeException e) {
|
||||
return showErrorMessage(vreq, entity, e.getMessage());
|
||||
}
|
||||
|
||||
// Remove the old main image (if any) and store the new one.
|
||||
helper.removeExistingImage(entity);
|
||||
helper.storeMainImageFile(entity, fileItem);
|
||||
|
||||
// The entity Individual is stale - get another one;
|
||||
String entityUri = entity.getURI();
|
||||
entity = vreq.getFullWebappDaoFactory().getIndividualDao()
|
||||
.getIndividualByURI(entityUri);
|
||||
|
||||
Dimensions mainImageSize = helper.getMainImageSize(entity);
|
||||
|
||||
if ((mainImageSize.height < THUMBNAIL_HEIGHT)
|
||||
|| (mainImageSize.width < THUMBNAIL_WIDTH)) {
|
||||
String message = "The uploaded image should be at least "
|
||||
+ THUMBNAIL_HEIGHT + " pixels high and " + THUMBNAIL_WIDTH
|
||||
+ " pixels wide.";
|
||||
return showErrorMessage(vreq, entity, message);
|
||||
}
|
||||
|
||||
// Go to the cropping page.
|
||||
return showCropImagePage(vreq, entity, getMainImageUrl(entity),
|
||||
mainImageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -338,13 +324,18 @@ public class ImageUploadController extends FreeMarkerHttpServlet {
|
|||
ImageUploadHelper helper = new ImageUploadHelper(fileStorage, vreq
|
||||
.getFullWebappDaoFactory());
|
||||
|
||||
validateMainImage(entity);
|
||||
CropRectangle crop = validateCropCoordinates(vreq);
|
||||
try {
|
||||
CropRectangle crop = validateCropCoordinates(vreq);
|
||||
FileInfo newImage = helper.getNewImageInfo(vreq);
|
||||
FileInfo thumbnail = helper.generateThumbnail(crop, newImage);
|
||||
|
||||
helper.removeExistingThumbnail(entity);
|
||||
helper.generateThumbnailAndStore(entity, crop);
|
||||
helper.removeExistingImage(entity);
|
||||
helper.storeImageFiles(entity, newImage, thumbnail);
|
||||
|
||||
return showExitPage(vreq, entity);
|
||||
return showExitPage(vreq, entity);
|
||||
} catch (UserMistakeException e) {
|
||||
return showErrorMessage(vreq, entity, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -379,17 +370,6 @@ public class ImageUploadController extends FreeMarkerHttpServlet {
|
|||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* We can't do a thumbnail if there is no main image.
|
||||
*/
|
||||
private void validateMainImage(Individual entity) {
|
||||
if (entity.getMainImageUri() == null) {
|
||||
throw new IllegalStateException("Can't store a thumbnail "
|
||||
+ "on an individual with no main image: '"
|
||||
+ showEntity(entity) + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Did we get the cropping coordinates?
|
||||
*/
|
||||
|
@ -552,19 +532,6 @@ public class ImageUploadController extends FreeMarkerHttpServlet {
|
|||
return UrlBuilder.getPath(URL_HERE, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an entity for display in a message.
|
||||
*/
|
||||
private String showEntity(Individual entity) {
|
||||
if (entity == null) {
|
||||
return String.valueOf(null);
|
||||
} else if (entity.getName() == null) {
|
||||
return "'no name' (" + entity.getURI() + ")";
|
||||
} else {
|
||||
return "'" + entity.getName() + "' (" + entity.getURI() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the entity's name for display as part of the page title.
|
||||
*/
|
||||
|
|
|
@ -31,13 +31,16 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.CropRectangle;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.Dimensions;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.UserMistakeException;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileModelHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.TempFileHolder;
|
||||
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.uploadrequest.FileUploadServletRequest;
|
||||
|
||||
/**
|
||||
|
@ -46,6 +49,12 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServ
|
|||
public class ImageUploadHelper {
|
||||
private static final Log log = LogFactory.getLog(ImageUploadHelper.class);
|
||||
|
||||
/**
|
||||
* When they upload a new image, store it as this session attribute until
|
||||
* we're ready to attach it to the Individual.
|
||||
*/
|
||||
public static final String ATTRIBUTE_TEMP_FILE = "ImageUploadHelper.tempFile";
|
||||
|
||||
/**
|
||||
* If the main image is larger than this, it will be displayed at reduced
|
||||
* scale.
|
||||
|
@ -65,10 +74,12 @@ public class ImageUploadHelper {
|
|||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
private final WebappDaoFactory webAppDaoFactory;
|
||||
private final FileModelHelper fileModelHelper;
|
||||
private final FileStorage fileStorage;
|
||||
|
||||
ImageUploadHelper(FileStorage fileStorage, WebappDaoFactory webAppDaoFactory) {
|
||||
this.webAppDaoFactory = webAppDaoFactory;
|
||||
this.fileModelHelper = new FileModelHelper(webAppDaoFactory);
|
||||
this.fileStorage = fileStorage;
|
||||
}
|
||||
|
@ -118,12 +129,158 @@ public class ImageUploadHelper {
|
|||
String mimeType = getMimeType(file);
|
||||
if (!RECOGNIZED_FILE_TYPES.containsValue(mimeType)) {
|
||||
throw new UserMistakeException("'" + filename
|
||||
+ "' is not a recognized image file type. Please upload JPEG, GIF, or PNG files only.");
|
||||
+ "' is not a recognized image file type. "
|
||||
+ "Please upload JPEG, GIF, or PNG files only.");
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* The user has uploaded a new main image, but we're not ready to assign it
|
||||
* to them.
|
||||
*
|
||||
* Put it into the file storage system, and attach it as a temp file on the
|
||||
* session until we need it.
|
||||
*/
|
||||
FileInfo storeNewImage(FileItem fileItem, VitroRequest vreq) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = fileItem.getInputStream();
|
||||
String mimeType = getMimeType(fileItem);
|
||||
String filename = getSimpleFilename(fileItem);
|
||||
WebappDaoFactory wadf = vreq.getWebappDaoFactory();
|
||||
|
||||
FileInfo fileInfo = FileModelHelper.createFile(fileStorage, wadf,
|
||||
filename, mimeType, inputStream);
|
||||
|
||||
TempFileHolder.attach(vreq.getSession(), ATTRIBUTE_TEMP_FILE,
|
||||
fileInfo);
|
||||
|
||||
return fileInfo;
|
||||
} catch (FileAlreadyExistsException e) {
|
||||
throw new IllegalStateException("Can't create the new image file.",
|
||||
e);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Can't create the new image file.",
|
||||
e);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out how big this image is.
|
||||
*
|
||||
* @throws UserMistakeException
|
||||
* if the image is smaller than a thumbnail.
|
||||
*/
|
||||
Dimensions getNewImageSize(FileInfo fileInfo) throws UserMistakeException {
|
||||
String uri = fileInfo.getBytestreamUri();
|
||||
String filename = fileInfo.getFilename();
|
||||
|
||||
InputStream stream = null;
|
||||
try {
|
||||
stream = fileStorage.getInputStream(uri, filename);
|
||||
BufferedImage i = ImageIO.read(stream);
|
||||
Dimensions size = new Dimensions(i.getWidth(), i.getHeight());
|
||||
log.debug("new image size is " + size);
|
||||
|
||||
if ((size.height < THUMBNAIL_HEIGHT)
|
||||
|| (size.width < THUMBNAIL_WIDTH)) {
|
||||
throw new UserMistakeException(
|
||||
"The uploaded image should be at least "
|
||||
+ THUMBNAIL_HEIGHT + " pixels high and "
|
||||
+ THUMBNAIL_WIDTH + " pixels wide.");
|
||||
}
|
||||
|
||||
return size;
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new IllegalStateException("File not found: " + fileInfo, e);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Can't read image file: "
|
||||
+ fileInfo, e);
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the info for the new image, from where we stored it in the session.
|
||||
*
|
||||
* @throws UserMistakeException
|
||||
* if it isn't there.
|
||||
*/
|
||||
FileInfo getNewImageInfo(VitroRequest vreq) throws UserMistakeException {
|
||||
FileInfo fileInfo = TempFileHolder.remove(vreq.getSession(),
|
||||
ATTRIBUTE_TEMP_FILE);
|
||||
|
||||
if (fileInfo == null) {
|
||||
throw new UserMistakeException(
|
||||
"There is no image file to be cropped.");
|
||||
}
|
||||
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crop the main image to create the thumbnail, and put it into the file
|
||||
* storage system.
|
||||
*/
|
||||
FileInfo generateThumbnail(CropRectangle crop, FileInfo newImage) {
|
||||
InputStream mainStream = null;
|
||||
InputStream thumbStream = null;
|
||||
try {
|
||||
String mainBytestreamUri = newImage.getBytestreamUri();
|
||||
String mainFilename = newImage.getFilename();
|
||||
mainStream = fileStorage.getInputStream(mainBytestreamUri,
|
||||
mainFilename);
|
||||
|
||||
thumbStream = scaleImageForThumbnail(mainStream, crop);
|
||||
|
||||
String mimeType = RECOGNIZED_FILE_TYPES.get(".jpg");
|
||||
String filename = createThumbnailFilename(mainFilename);
|
||||
|
||||
FileInfo fileInfo = FileModelHelper.createFile(fileStorage,
|
||||
webAppDaoFactory, filename, mimeType, thumbStream);
|
||||
log.debug("Created thumbnail: " + fileInfo);
|
||||
return fileInfo;
|
||||
} catch (FileAlreadyExistsException e) {
|
||||
throw new IllegalStateException("Can't create the thumbnail file: "
|
||||
+ e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Can't create the thumbnail file",
|
||||
e);
|
||||
} finally {
|
||||
if (mainStream != null) {
|
||||
try {
|
||||
mainStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (thumbStream != null) {
|
||||
try {
|
||||
thumbStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If this entity already had a main image, remove the connection. If the
|
||||
* image and the thumbnail are no longer used by anyone, remove them from
|
||||
|
@ -154,47 +311,6 @@ public class ImageUploadHelper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store this image in the model and in the file storage system, and set it
|
||||
* as the main image for this person.
|
||||
*/
|
||||
void storeMainImageFile(Individual person, FileItem imageFileItem) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = imageFileItem.getInputStream();
|
||||
String mimeType = getMimeType(imageFileItem);
|
||||
String filename = getSimpleFilename(imageFileItem);
|
||||
|
||||
// Create the file individuals in the model
|
||||
Individual byteStream = fileModelHelper
|
||||
.createByteStreamIndividual();
|
||||
Individual file = fileModelHelper.createFileIndividual(mimeType,
|
||||
filename, byteStream);
|
||||
|
||||
// Store the file in the FileStorage system.
|
||||
fileStorage.createFile(byteStream.getURI(), filename, inputStream);
|
||||
|
||||
// Set the file as the main image for the person.
|
||||
fileModelHelper.setAsMainImageOnEntity(person, file);
|
||||
} catch (FileAlreadyExistsException e) {
|
||||
throw new IllegalStateException(
|
||||
"Can't create the main image file for '" + person.getName()
|
||||
+ "' (" + person.getURI() + ")" + e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(
|
||||
"Can't create the main image file for '" + person.getName()
|
||||
+ "' (" + person.getURI() + ")", e);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the entity already has a thumbnail, remove it. If there are no other
|
||||
* references to the thumbnail, delete it from the model and from the file
|
||||
|
@ -227,64 +343,12 @@ public class ImageUploadHelper {
|
|||
}
|
||||
|
||||
/**
|
||||
* Generate a thumbnail from the main image from it, store it in the model
|
||||
* and in the file storage system, and set it as the thumbnail on the main
|
||||
* image.
|
||||
* Store the image on the entity, and the thumbnail on the image.
|
||||
*/
|
||||
void generateThumbnailAndStore(Individual person,
|
||||
ImageUploadController.CropRectangle crop) {
|
||||
String mainBytestreamUri = FileModelHelper
|
||||
.getMainImageBytestreamUri(person);
|
||||
String mainFilename = FileModelHelper.getMainImageFilename(person);
|
||||
if (mainBytestreamUri == null) {
|
||||
log.warn("Tried to generate a thumbnail on '" + person.getURI()
|
||||
+ "', but there was no main image.");
|
||||
return;
|
||||
}
|
||||
|
||||
InputStream mainInputStream = null;
|
||||
InputStream thumbInputStream = null;
|
||||
try {
|
||||
mainInputStream = fileStorage.getInputStream(mainBytestreamUri,
|
||||
mainFilename);
|
||||
thumbInputStream = scaleImageForThumbnail(mainInputStream, crop);
|
||||
String mimeType = RECOGNIZED_FILE_TYPES.get(".jpg");
|
||||
String filename = createThumbnailFilename(mainFilename);
|
||||
|
||||
// Create the file individuals in the model
|
||||
Individual byteStream = fileModelHelper
|
||||
.createByteStreamIndividual();
|
||||
Individual file = fileModelHelper.createFileIndividual(mimeType,
|
||||
filename, byteStream);
|
||||
|
||||
// Store the file in the FileStorage system.
|
||||
fileStorage.createFile(byteStream.getURI(), filename,
|
||||
thumbInputStream);
|
||||
|
||||
// Set the file as the thumbnail on the main image for the person.
|
||||
fileModelHelper.setThumbnailOnIndividual(person, file);
|
||||
} catch (FileAlreadyExistsException e) {
|
||||
throw new IllegalStateException("Can't create the thumbnail file: "
|
||||
+ e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Can't create the thumbnail file",
|
||||
e);
|
||||
} finally {
|
||||
if (mainInputStream != null) {
|
||||
try {
|
||||
mainInputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (thumbInputStream != null) {
|
||||
try {
|
||||
thumbInputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
void storeImageFiles(Individual entity, FileInfo newImage,
|
||||
FileInfo thumbnail) {
|
||||
FileModelHelper.setImagesOnEntity(webAppDaoFactory, entity, newImage,
|
||||
thumbnail);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -398,42 +462,4 @@ public class ImageUploadHelper {
|
|||
return crop.unscale(displayScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out how big the main image is.
|
||||
*/
|
||||
Dimensions getMainImageSize(Individual entity) {
|
||||
String uri = FileModelHelper.getMainImageBytestreamUri(entity);
|
||||
String filename = FileModelHelper.getMainImageFilename(entity);
|
||||
InputStream stream = null;
|
||||
try {
|
||||
stream = fileStorage.getInputStream(uri, filename);
|
||||
BufferedImage i = ImageIO.read(stream);
|
||||
Dimensions size = new Dimensions(i.getWidth(), i.getHeight());
|
||||
log.debug("main image size is " + size);
|
||||
return size;
|
||||
} catch (FileNotFoundException e) {
|
||||
log.error(
|
||||
"No main image file for '" + showUri(entity) + "'; name='"
|
||||
+ filename + "', bytestreamUri='" + uri + "'", e);
|
||||
return new Dimensions(0, 0);
|
||||
} catch (IOException e) {
|
||||
log.error(
|
||||
"Can't read main image file for '" + showUri(entity)
|
||||
+ "'; name='" + filename + "', bytestreamUri='"
|
||||
+ uri + "'", e);
|
||||
return new Dimensions(0, 0);
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String showUri(Individual entity) {
|
||||
return (entity == null) ? "null" : entity.getURI();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
@ -19,6 +21,9 @@ 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;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
@ -30,10 +35,66 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
|||
* a parameter holds all necessary references for the operation. Other methods
|
||||
* require an instance, which is initialized with a {@link WebappDaoFactory}.
|
||||
* </p>
|
||||
* <p>
|
||||
* TODO: This should be based around FileInfo and ImageInfo, as much as
|
||||
* possible.
|
||||
* </p>
|
||||
*/
|
||||
public class FileModelHelper {
|
||||
private static final Log log = LogFactory.getLog(FileModelHelper.class);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Methods based around FileInfo
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public static FileInfo createFile(FileStorage fileStorage,
|
||||
WebappDaoFactory wadf, String filename, String mimeType,
|
||||
InputStream inputStream) throws FileAlreadyExistsException,
|
||||
IOException {
|
||||
FileModelHelper fmh = new FileModelHelper(wadf);
|
||||
|
||||
// Create the file individuals in the model
|
||||
Individual byteStream = fmh.createByteStreamIndividual();
|
||||
String bytestreamUri = byteStream.getURI();
|
||||
Individual file = fmh.createFileIndividual(mimeType, filename,
|
||||
byteStream);
|
||||
String fileUri = file.getURI();
|
||||
|
||||
// Store the file in the FileStorage system.
|
||||
fileStorage.createFile(bytestreamUri, filename, inputStream);
|
||||
|
||||
// Figure out the alias URL
|
||||
String aliasUrl = FileServingHelper.getBytestreamAliasUrl(
|
||||
bytestreamUri, filename);
|
||||
|
||||
// And wrap it all up in a tidy little package.
|
||||
return new FileInfo.Builder().setFilename(filename).setMimeType(
|
||||
mimeType).setUri(fileUri).setBytestreamUri(bytestreamUri)
|
||||
.setBytestreamAliasUrl(aliasUrl).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Record this image file and thumbnail on this entity. NOTE: after this
|
||||
* update, the entity object is stale.
|
||||
*/
|
||||
public static void setImagesOnEntity(WebappDaoFactory wadf,
|
||||
Individual entity, FileInfo mainInfo, FileInfo thumbInfo) {
|
||||
IndividualDao individualDao = wadf.getIndividualDao();
|
||||
|
||||
// Add the thumbnail file to the main image file.
|
||||
ObjectPropertyStatementDao opsd = wadf.getObjectPropertyStatementDao();
|
||||
opsd.insertNewObjectPropertyStatement(new ObjectPropertyStatementImpl(
|
||||
mainInfo.getUri(), VitroVocabulary.FS_THUMBNAIL_IMAGE,
|
||||
thumbInfo.getUri()));
|
||||
|
||||
// Add the main image file to the entity.
|
||||
entity.setMainImageUri(mainInfo.getUri());
|
||||
individualDao.updateIndividual(entity);
|
||||
|
||||
log.debug("Set images on '" + entity.getURI() + "': main=" + mainInfo
|
||||
+ ", thumb=" + thumbInfo);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Static methods -- the Individual holds all necessary references.
|
||||
// ----------------------------------------------------------------------
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
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;
|
||||
|
||||
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.filestorage.model.FileInfo;
|
||||
|
||||
/**
|
||||
* Attaches an uploaded file to the session with a listener, so the file will be
|
||||
* deleted if
|
||||
* <ul>
|
||||
* <li>The session times out.</li>
|
||||
* <li>The session is invalidated.</li>
|
||||
* <li>The server is shut down.</li>
|
||||
* <li>Another file is attached to the session with the same attribute name.</li>
|
||||
* </ul>
|
||||
* To see that the file isn't deleted, remove it from the session with a call to
|
||||
* {@link TempFileHolder#remove(HttpSession, String) remove}.
|
||||
*/
|
||||
public class TempFileHolder implements HttpSessionBindingListener {
|
||||
private static final Log log = LogFactory.getLog(TempFileHolder.class);
|
||||
|
||||
/**
|
||||
* Create a {@link TempFileHolder} holding the given {@link FileInfo}, and
|
||||
* attach it to the session with the given attribute name.
|
||||
*
|
||||
* If an attribute with this name already exists, it is replaced.
|
||||
*/
|
||||
public static void attach(HttpSession session, String attributeName,
|
||||
FileInfo fileInfo) {
|
||||
if (session == null) {
|
||||
throw new NullPointerException("session may not be null.");
|
||||
}
|
||||
if (attributeName == null) {
|
||||
throw new NullPointerException("attributeName may not be null.");
|
||||
}
|
||||
if (fileInfo == null) {
|
||||
throw new NullPointerException("fileInfo may not be null.");
|
||||
}
|
||||
log.debug("attach this file: " + fileInfo);
|
||||
session.setAttribute(attributeName, new TempFileHolder(fileInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link TempFileHolder} which is stored as an attribute on this
|
||||
* session, extract the {@link FileInfo} from it, and remove it from the
|
||||
* session.
|
||||
*
|
||||
* If there is no such attribute, of if it is not a {@link TempFileHolder},
|
||||
* return null.
|
||||
*/
|
||||
public static FileInfo remove(HttpSession session, String attributeName) {
|
||||
if (session == null) {
|
||||
throw new NullPointerException("session may not be null.");
|
||||
}
|
||||
if (attributeName == null) {
|
||||
throw new NullPointerException("attributeName may not be null.");
|
||||
}
|
||||
Object attribute = session.getAttribute(attributeName);
|
||||
if (attribute instanceof TempFileHolder) {
|
||||
FileInfo fileInfo = ((TempFileHolder) attribute).extractFileInfo();
|
||||
session.removeAttribute(attributeName);
|
||||
log.debug("remove this file: " + fileInfo);
|
||||
return fileInfo;
|
||||
} else if (attribute == null) {
|
||||
return null;
|
||||
} else {
|
||||
session.removeAttribute(attributeName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private FileInfo fileInfo;
|
||||
|
||||
private TempFileHolder(FileInfo fileInfo) {
|
||||
if (fileInfo == null) {
|
||||
throw new NullPointerException("fileInfo may not be null.");
|
||||
}
|
||||
this.fileInfo = fileInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link FileInfo} payload, and removes it so the file won't be
|
||||
* deleted when the value is unbound.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private FileInfo extractFileInfo() {
|
||||
FileInfo result = this.fileInfo;
|
||||
this.fileInfo = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* When attached to the session, do nothing.
|
||||
*
|
||||
* @see HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)
|
||||
*/
|
||||
@Override
|
||||
public void valueBound(HttpSessionBindingEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* When removed from the session, if the {@link #fileInfo} is not empty,
|
||||
* delete the file. If you had wanted this file, you should have called
|
||||
* {@link #remove(HttpSession, String) remove}.
|
||||
*
|
||||
* @see HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)
|
||||
*/
|
||||
@Override
|
||||
public void valueUnbound(HttpSessionBindingEvent event) {
|
||||
if (fileInfo == null) {
|
||||
log.trace("No file info.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileInfo.getBytestreamUri() == null) {
|
||||
log.warn("File info has no URI?");
|
||||
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;
|
||||
}
|
||||
|
||||
try {
|
||||
fs.deleteFile(fileInfo.getBytestreamUri());
|
||||
log.debug("Deleted file " + fileInfo);
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to delete temp file from session: " + event, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.model;
|
||||
|
||||
/**
|
||||
* An immutable packet of information about an uploaded file, with a builder
|
||||
* class to permit incremental construction.
|
||||
*/
|
||||
public class FileInfo {
|
||||
private final String uri;
|
||||
private final String filename;
|
||||
private final String mimeType;
|
||||
private final String bytestreamUri;
|
||||
private final String bytestreamAliasUrl;
|
||||
|
||||
private FileInfo(Builder builder) {
|
||||
this.uri = builder.uri;
|
||||
this.filename = builder.filename;
|
||||
this.mimeType = builder.mimeType;
|
||||
this.bytestreamUri = builder.bytestreamUri;
|
||||
this.bytestreamAliasUrl = builder.bytestreamAliasUrl;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public String getMimeType() {
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
public String getBytestreamUri() {
|
||||
return bytestreamUri;
|
||||
}
|
||||
|
||||
public String getBytestreamAliasUrl() {
|
||||
return bytestreamAliasUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FileInfo[uri=" + uri + ", filename=" + filename + ", mimeType="
|
||||
+ mimeType + ", bytestreamUri=" + bytestreamUri + ", aliasUrl="
|
||||
+ bytestreamAliasUrl + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder class allows us to supply the values one at a time, and then
|
||||
* freeze them into an immutable object.
|
||||
*/
|
||||
public static class Builder {
|
||||
private String uri;
|
||||
private String filename;
|
||||
private String mimeType;
|
||||
private String bytestreamUri;
|
||||
private String bytestreamAliasUrl;
|
||||
|
||||
public Builder setUri(String uri) {
|
||||
this.uri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFilename(String filename) {
|
||||
this.filename = filename;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMimeType(String mimeType) {
|
||||
this.mimeType = mimeType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBytestreamUri(String bytestreamUri) {
|
||||
this.bytestreamUri = bytestreamUri;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBytestreamAliasUrl(String bytestreamAliasUrl) {
|
||||
this.bytestreamAliasUrl = bytestreamAliasUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FileInfo build() {
|
||||
return new FileInfo(this);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue