Commit e5941740 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch '16-bytes-persistence' into 'master'

Resolve "Bytes persistence"

Closes #16

See merge request !12
parents 5ce70bc3 d1a40352
/*
* Copyright 2016 Global Crop Diversity Trust, www.croptrust.org
* Copyright 2017 Global Crop Diversity Trust, www.croptrust.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -39,8 +39,8 @@ import org.genesys.blocks.model.Copyable;
import org.genesys.blocks.model.EntityId;
import org.genesys.blocks.model.InMemoryIdGenerator;
import org.genesys.filerepository.metadata.BaseMetadata;
import org.genesys.filerepository.service.BytesStorageService;
// TODO: Auto-generated Javadoc
/**
* The Class RepositoryFile.
*/
......@@ -157,7 +157,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getIdentifier()
*/
// TODO See if we can have a setter instead of this formula.
......@@ -180,7 +179,7 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
}
/**
* Gets the filename.
* Gets the filename as used by {@link BytesStorageService}.
*
* @return the filename
*/
......@@ -199,6 +198,29 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
return sb.toString();
}
/**
* Get the path of the file used by {@link BytesStorageService}
*
* @return
*/
@Transient
public String getStoragePath() {
if (uuid == null) {
return null;
}
return "/" + uuid.toString().substring(0, 3);
}
/**
* Get the full path to the file as used by {@link BytesStorageService}. This is the concatenation of {@link #getStoragePath()} and {@link #getFilename()}.
*
* @return
*/
@Transient
public String getStorageFullPath() {
return getStoragePath() + "/" + getFilename();
}
@Override
public Long getId() {
return id;
......@@ -228,7 +250,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getTitle()
*/
@Override
......@@ -247,7 +268,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getSubject()
*/
@Override
......@@ -266,7 +286,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getDescription()
*/
@Override
......@@ -285,7 +304,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getCreator()
*/
@Override
......@@ -304,7 +322,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getCreated()
*/
@Override
......@@ -323,7 +340,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getRightsHolder( )
*/
@Override
......@@ -342,7 +358,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getAccessRights( )
*/
@Override
......@@ -361,7 +376,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getLicense()
*/
@Override
......@@ -380,7 +394,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getFormat()
*/
@Override
......@@ -408,7 +421,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getExtent()
*/
@Override
......@@ -427,7 +439,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata# getBibliographicCitation()
*/
@Override
......@@ -446,7 +457,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getDateSubmitted ()
*/
@Override
......@@ -456,7 +466,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.BaseMetadata#getModified()
*/
@Override
......@@ -644,7 +653,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
......@@ -657,7 +665,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements En
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
......
/*
* Copyright 2016 Global Crop Diversity Trust, www.croptrust.org
* Copyright 2017 Global Crop Diversity Trust, www.croptrust.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -22,13 +22,13 @@ import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.genesys.filerepository.metadata.ImageMetadata;
// TODO: Auto-generated Javadoc
/**
* An {@link RepositoryImage} is an graphics file in one of the supported image formats (PNG and JPG). It extends the
* {@link RepositoryFile} by including image-specific metadata defined in {@link ImageMetadata}.
* An {@link RepositoryImage} is an graphics file in one of the supported image formats (PNG and JPG). It extends the {@link RepositoryFile} by including
* image-specific metadata defined in {@link ImageMetadata}.
*
* @author mobreza
*/
......@@ -51,10 +51,8 @@ public class RepositoryImage extends RepositoryFile implements ImageMetadata {
@Enumerated(EnumType.ORDINAL)
private Orientation orientation;
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.model.RepositoryFile#prePersist()
*/
@Override
......@@ -67,7 +65,6 @@ public class RepositoryImage extends RepositoryFile implements ImageMetadata {
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.ImageMetadata#getWidth()
*/
@Override
......@@ -87,7 +84,6 @@ public class RepositoryImage extends RepositoryFile implements ImageMetadata {
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.metadata.ImageMetadata#getHeight()
*/
@Override
......@@ -140,4 +136,14 @@ public class RepositoryImage extends RepositoryFile implements ImageMetadata {
return this;
}
/**
* Get the path where thumbnails of this image are stored.
*
* @return Thumbnails path
*/
@Transient
public String getThumbnailPath() {
return getStoragePath() + "/" + getUuid();
}
}
/*
* Copyright 2016 Global Crop Diversity Trust, www.croptrust.org
* Copyright 2017 Global Crop Diversity Trust, www.croptrust.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -16,18 +16,18 @@
package org.genesys.filerepository.service;
import org.genesys.filerepository.InvalidRepositoryPathException;
import org.genesys.filerepository.model.ImageGallery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
// TODO: Auto-generated Javadoc
/**
* The Interface ImageGalleryService.
* The ImageGalleryService.
*/
public interface ImageGalleryService {
/** The Constant THUMB_PATH. */
public static final String THUMB_PATH = "_thumb/";
public static final String THUMB_PATH = "/_thumbs";
/** The Constant THUMB_EXT. */
public static final String THUMB_EXT = ".png";
......@@ -54,8 +54,9 @@ public interface ImageGalleryService {
* Delete the image gallery, but don't remove the images at that path.
*
* @param imageGallery the image gallery
* @throws InvalidRepositoryPathException
*/
void removeGallery(ImageGallery imageGallery);
void removeGallery(ImageGallery imageGallery) throws InvalidRepositoryPathException;
/**
* Update image gallery blah-blahs.
......
......@@ -67,7 +67,6 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.service.ImageGalleryService#loadImageGallery(java.lang.String)
*/
@Override
......@@ -92,7 +91,6 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.service.ImageGalleryService#createImageGallery(java.lang.String, java.lang.String, java.lang.String)
*/
@Override
......@@ -117,49 +115,39 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.service.ImageGalleryService#removeGallery(org.genesys.filerepository. model.ImageGallery)
*/
@Override
@Transactional
public void removeGallery(final ImageGallery imageGallery) {
public void removeGallery(final ImageGallery imageGallery) throws InvalidRepositoryPathException {
if (LOG.isDebugEnabled()) {
LOG.debug("Deleting ImageGallery with id=" + imageGallery.getId());
}
// Remove _thumbs
final String thumbPath = imageGallery.getPath() + THUMB_PATH;
try {
bytesStorageService.listFiles(thumbPath).forEach(filename -> {
for (RepositoryImage image : imageGallery.getImages()) {
String imageThumbPath = getFullThumbnailsPath(image);
bytesStorageService.listFiles(imageThumbPath).forEach(filename -> {
try {
LOG.debug("Removing _thumb path={} filename={}", thumbPath, filename);
bytesStorageService.remove(thumbPath, filename);
LOG.debug("Removing _thumb path={} filename={}", THUMB_PATH, filename);
bytesStorageService.remove(imageThumbPath, filename);
} catch (final Exception e) {
LOG.error("Failed to remove bytes path=" + thumbPath + " filename=" + filename, e);
LOG.error("Failed to remove bytes path=" + imageThumbPath + " filename=" + filename, e);
}
});
} catch (final InvalidRepositoryPathException e) {
// Shouldn't have a gallery with invalid path, but hell
}
imageGalleryPersistence.delete(imageGallery);
}
// // Delete images at the path
// repositoryService.listImages(imageGallery.getPath()).forEach(repositoryImage
// -> {
// LOG.debug("Deleting image from path={} foo={}",
// imageGallery.getPath(), repositoryImage);
// try {
// repositoryService.removeFile(repositoryImage);
// } catch (Exception e) {
// LOG.error("Failed to remove gallery image image=" + repositoryImage);
// }
// });
/**
* Path to /_thumbs/{UUID#short}/{UUID}
*/
private String getFullThumbnailsPath(RepositoryImage image) {
return THUMB_PATH + image.getThumbnailPath();
}
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.service.ImageGalleryService#updateImageGalery(org.genesys2.server. filerepository.model.ImageGallery, java.lang.String,
* java.lang.String)
*/
......@@ -177,7 +165,6 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.service.ImageGalleryService#saveImageOrder(org.genesys.filerepository. model.ImageGallery)
*/
@Override
......@@ -192,8 +179,8 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
}
/**
* For each image in the gallery, generate a PNG thumbnail at maximum width x maximum height as specified. Save bytes to {@link BytesStorageService} directly, not through
* {@link RepositoryService}.
* For each image in the gallery, generate a PNG thumbnail at maximum width x maximum height as specified. Save bytes to {@link BytesStorageService} directly,
* not through {@link RepositoryService}.
*
* Throws NotAnImageException if original bytes are not of an image,
*
......@@ -212,13 +199,11 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
return;
}
final String thumbPath = imageGallery2.getPath() + THUMB_PATH;
imageGallery2.getImages().forEach(repositoryImage -> {
try {
ensureThumbnail(thumbPath, width, height, repositoryImage);
ensureThumbnail(width, height, repositoryImage);
} catch (final NullPointerException e) {
LOG.error("Error generating thumbnail for image={} message={}", repositoryImage, e.getMessage());
LOG.error("Error generating thumbnail for image={} message={}", repositoryImage, e.getMessage(), e);
} catch (final Exception e) {
LOG.error("Error generating thumbnail for " + repositoryImage, e);
}
......@@ -227,29 +212,29 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
/**
* Ensure thumbnail.
*
* @param thumbPath the thumb path
* @param width the width
* @param height the height
* @param repositoryImage the repository image
*
* @throws IOException Signals that an I/O exception has occurred.
* @throws InvalidRepositoryPathException if path is messed up
*/
private void ensureThumbnail(final String thumbPath, final Integer width, final Integer height, final RepositoryImage repositoryImage) throws IOException, InvalidRepositoryPathException {
private void ensureThumbnail(final Integer width, final Integer height, final RepositoryImage repositoryImage) throws IOException,
InvalidRepositoryPathException {
final String filename = getThumbnailFilename(width, height, repositoryImage.getUuid());
if (!bytesStorageService.exists(thumbPath, filename)) {
if (!bytesStorageService.exists(getFullThumbnailsPath(repositoryImage), filename)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Generating new thumbnail width={} height={} for image={}", width, height, repositoryImage.getUuid());
}
final byte[] bytesPng = thumbnailGenerator.createThumbnail(width, height, bytesStorageService.get(repositoryImage.getPath(), repositoryImage.getFilename()));
final byte[] bytesPng = thumbnailGenerator.createThumbnail(width, height, bytesStorageService.get(repositoryImage.getStoragePath(), repositoryImage.getFilename()));
if (LOG.isDebugEnabled()) {
LOG.debug("Persisting new thumbnail width={} height={} for image={}", width, height, repositoryImage.getUuid());
}
bytesStorageService.upsert(thumbPath, filename, bytesPng);
bytesStorageService.upsert(getFullThumbnailsPath(repositoryImage), filename, bytesPng);
}
}
......@@ -263,6 +248,7 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
*/
public static final String getThumbnailFilename(final Integer width, final Integer height, final UUID uuid) {
final StringBuffer sb = new StringBuffer();
if (width != null) {
sb.append(width);
}
......@@ -270,7 +256,7 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
if (height != null) {
sb.append(height);
}
sb.append("_").append(uuid).append(".png");
sb.append(".png");
return sb.toString();
}
......@@ -287,7 +273,6 @@ public class ImageGalleryServiceImpl implements ImageGalleryService {
/*
* (non-Javadoc)
*
* @see org.genesys.filerepository.service.ImageGalleryService#listImageGalleries(java.lang.String, org.springframework.data.domain.Pageable)
*/
@Override
......
/*
* Copyright 2016 Global Crop Diversity Trust, www.croptrust.org
* Copyright 2017 Global Crop Diversity Trust, www.croptrust.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -134,7 +134,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
repositoryFile = repositoryFilePersistence.save(repositoryFile);
try {
bytesStorageService.upsert(repositoryFile.getPath(), repositoryFile.getFilename(), bytes);
bytesStorageService.upsert(repositoryFile.getStoragePath(), repositoryFile.getFilename(), bytes);
} catch (final IOException e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Failed to upload bytes", e);
......@@ -184,7 +184,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
repositoryImage = repositoryImagePersistence.save(repositoryImage);
try {
bytesStorageService.upsert(repositoryImage.getPath(), repositoryImage.getFilename(), bytes);
bytesStorageService.upsert(repositoryImage.getStoragePath(), repositoryImage.getFilename(), bytes);
} catch (final IOException e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Failed to upload bytes", e);
......@@ -248,11 +248,11 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
* @see org.genesys.filerepository.service.RepositoryService#getFileBytes (java.lang.String, java.lang.String)
*/
@Override
public byte[] getFileBytes(final String repositoryPath, final String filename) throws NoSuchRepositoryFileException {
public byte[] getFileBytes(final String storagePath, final String filename) throws NoSuchRepositoryFileException {
byte[] data = null;
try {
data = bytesStorageService.get(repositoryPath, filename);
data = bytesStorageService.get(storagePath, filename);
} catch (final IOException e) {
e.printStackTrace();
}
......@@ -262,7 +262,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
@Override
public byte[] getFileBytes(RepositoryFile repositoryFile) throws IOException {
return bytesStorageService.get(repositoryFile.getPath(), repositoryFile.getFilename());
return bytesStorageService.get(repositoryFile.getStoragePath(), repositoryFile.getFilename());
}
/*
......@@ -347,7 +347,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
LOG.debug("updateByes length={} repoFile.size={}", bytes.length, repositoryFile.getSize());
repositoryFile.setContentType(contentType);
bytesStorageService.upsert(repositoryFile.getPath(), repositoryFile.getFilename(), bytes);
bytesStorageService.upsert(repositoryFile.getStoragePath(), repositoryFile.getFilename(), bytes);
return repositoryFilePersistence.save(repositoryFile);
}
......@@ -374,7 +374,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
fillImageProperties(repositoryImage, bytes);
bytesStorageService.upsert(repositoryImage.getPath(), repositoryImage.getFilename(), bytes);
bytesStorageService.upsert(repositoryImage.getStoragePath(), repositoryImage.getFilename(), bytes);
return repositoryImagePersistence.save(repositoryImage);
}
......@@ -409,7 +409,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
return removeImage((RepositoryImage) repositoryFile);
}
bytesStorageService.remove(repositoryFile.getPath(), repositoryFile.getFilename());
bytesStorageService.remove(repositoryFile.getStoragePath(), repositoryFile.getFilename());
repositoryFilePersistence.delete(repositoryFile);
return repositoryFile;
}
......@@ -421,7 +421,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea
throw new NoSuchRepositoryFileException();
}
bytesStorageService.remove(repositoryImage.getPath(), repositoryImage.getFilename());
bytesStorageService.remove(repositoryImage.getStoragePath(), repositoryImage.getFilename());
repositoryImagePersistence.delete(repositoryImage);
return repositoryImage;
}
......
......@@ -74,9 +74,10 @@ public class ImageGalleryTest {
*
* @throws NoSuchRepositoryFileException the no such repository file exception
* @throws IOException Signals that an I/O exception has occurred.
* @throws InvalidRepositoryPathException
*/
@After
public void afterTest() throws NoSuchRepositoryFileException, IOException {
public void afterTest() throws NoSuchRepositoryFileException, IOException, InvalidRepositoryPathException {
final ImageGallery imageGallery = imageGalleryService.loadImageGallery(initialPath);
if (imageGallery != null) {
imageGalleryService.removeGallery(imageGallery);
......@@ -108,9 +109,10 @@ public class ImageGalleryTest {
/**
* Delete gallery.
* @throws InvalidRepositoryPathException
*/
@Test
public void deleteGallery() {
public void deleteGallery() throws InvalidRepositoryPathException {
final ImageGallery imageGallery = imageGalleryService.createImageGallery(initialPath, DEFAULT_GALLERY_TITLE, DEFAULT_GALLERY_DESCRIPTION);
ImageGallery loadedGallery = imageGalleryService.loadImageGallery(initialPath);
......
......@@ -75,9 +75,10 @@ public class ImageGalleryThumbnailsTest {
*
* @throws NoSuchRepositoryFileException the no such repository file exception
* @throws IOException Signals that an I/O exception has occurred.
* @throws InvalidRepositoryPathException
*/
@After
public void afterTest() throws NoSuchRepositoryFileException, IOException {
public void afterTest() throws NoSuchRepositoryFileException, IOException, InvalidRepositoryPathException {
final ImageGallery imageGallery = imageGalleryService.loadImageGallery(initialPath);
if (imageGallery != null) {
imageGalleryService.removeGallery(imageGallery);
......@@ -90,14 +91,14 @@ public class ImageGalleryThumbnailsTest {
@Test
public void testNames() {
final UUID uuid = UUID.randomUUID();
assertThat("Thumbnail filename is not as expected", ImageGalleryServiceImpl.getThumbnailFilename(1, 1, uuid), equalTo("1x1_" + uuid + ImageGalleryService.THUMB_EXT));
assertThat("Thumbnail filename is not as expected", ImageGalleryServiceImpl.getThumbnailFilename(2, 1, uuid), equalTo("2x1_" + uuid + ImageGalleryService.THUMB_EXT));
assertThat("Thumbnail filename is not as expected", ImageGalleryServiceImpl.getThumbnailFilename(1, 2, uuid), equalTo("1x2_" + uuid + ImageGalleryService.THUMB_EXT));
assertThat("Thumbnail filename is not as expected", ImageGalleryServiceImpl.getThumbnailFilename(null, 2, uuid), equalTo("x2_" + uuid + ImageGalleryService.THUMB_EXT));
assertThat("Thumbnail filename is not as expected", ImageGalleryServiceImpl.getThumbnailFilename(3, null, uuid), equalTo("3x_" + uuid + ImageGalleryService.THUMB_EXT));
assertThat("Thumbnail filename is not as expected", ImageGalleryServiceImpl.getThumbnailFilename(1, 1, uuid), equalTo("1x1" + ImageGalleryService.THUMB_EXT));
assertThat("Thumbnail filename is not as expected", ImageGalleryServiceImpl.getThumbnailFilename(2, 1, uuid), equalTo("2x1" + ImageGalleryService.THUMB_EXT));
assertThat("Thumbnail filename is not as expected", ImageGalleryServiceImpl.getThumbnailFilename(1, 2, uuid), equalTo("1x2" + ImageGalleryService.THUMB_EXT));
assertThat("Thumbnail filename is not as expected", ImageGalleryServiceImpl.getThumbnailFilename(null, 2, uuid), equalTo("x2" + ImageGalleryService.THUMB_EXT));
assertThat("Thumbnail filename is not as expected", ImageGalleryServiceImpl.getThumbnailFilename(3, null, uuid), equalTo("3x" + ImageGalleryService.THUMB_EXT));
// FIXME Should this fail?
assertThat("Thumbnail filename is not as expected", ImageGalleryServiceImpl.getThumbnailFilename(null, null, uuid), equalTo("x_" + uuid + ImageGalleryService.THUMB_EXT));
assert