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:
jeb228 2010-07-14 20:28:29 +00:00
parent 39ffb7c433
commit 4246a4385c
5 changed files with 489 additions and 192 deletions

View file

@ -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.
*/

View file

@ -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();
}
}

View file

@ -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.
// ----------------------------------------------------------------------

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}