diff --git a/file-repository-core/pom.xml b/file-repository-core/pom.xml index e618186290713b92c12281bbba6c156bd92b7914..4915a52acd9492c33261fede6b8a0f72c175bf6a 100644 --- a/file-repository-core/pom.xml +++ b/file-repository-core/pom.xml @@ -172,12 +172,6 @@ application-blocks-security 1.5-SNAPSHOT - - com.querydsl - querydsl-jpa - ${querydsl.version} - provided - org.apache.tika tika-core diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/FolderNotEmptyException.java b/file-repository-core/src/main/java/org/genesys/filerepository/FolderNotEmptyException.java new file mode 100644 index 0000000000000000000000000000000000000000..73a070ee89b9eb72e5919020d123829c55585b83 --- /dev/null +++ b/file-repository-core/src/main/java/org/genesys/filerepository/FolderNotEmptyException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Global Crop Diversity Trust + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.genesys.filerepository; + +/** + * The InvalidRepositoryPathException is thrown when Repository is not happy + * with your selected path. + */ +public class FolderNotEmptyException extends FileRepositoryException { + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; + + /** + * Instantiates a new invalid repository path exception. + * + * @param message the message + */ + public FolderNotEmptyException(final String message) { + super(message); + } +} diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/migration/RepositoryUpgrade20180920.java b/file-repository-core/src/main/java/org/genesys/filerepository/migration/RepositoryUpgrade20180920.java new file mode 100644 index 0000000000000000000000000000000000000000..9813c0538658e619bdb68961fd18480c1dfbc617 --- /dev/null +++ b/file-repository-core/src/main/java/org/genesys/filerepository/migration/RepositoryUpgrade20180920.java @@ -0,0 +1,141 @@ +/* + * Copyright 2018 Global Crop Diversity Trust + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.genesys.filerepository.migration; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import org.genesys.filerepository.model.QRepositoryFile; +import org.genesys.filerepository.model.RepositoryFile; +import org.genesys.filerepository.model.RepositoryFolder; +import org.genesys.filerepository.persistence.RepositoryFilePersistence; +import org.genesys.filerepository.service.RepositoryService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.querydsl.jpa.impl.JPAQueryFactory; + +/** + * Creates {@link RepositoryFolder} entries and their parents - Links all + * {@link RepositoryFile} to their parent folders + * + * @author Matija Obreza + */ +@Component +public class RepositoryUpgrade20180920 { + private static final Logger LOG = LoggerFactory.getLogger(RepositoryUpgrade20180920.class); + + /** The tx manager. */ + @Autowired + @Qualifier("transactionManager") + protected PlatformTransactionManager txManager; + + @Autowired + private RepositoryFilePersistence fileRepository; + + @Autowired + private RepositoryService repositoryService; + + @Autowired + private JPAQueryFactory jpaQueryFactory; + + public void doUpgrade() throws Exception { + TransactionTemplate tmpl = new TransactionTemplate(txManager); + tmpl.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus status) { + try { + makeFolders(); + } catch (Throwable e) { + LOG.error("Could not migrate 1.0 to 1.1 model: {}", e.getMessage(), e); + } + } + }); + + tmpl.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus status) { + try { + moveFilesToFolders(); + } catch (Throwable e) { + LOG.error("Could not migrate 1.0 to 1.1 model: {}", e.getMessage(), e); + } + } + }); + } + + /** + * Do the migration. + * + * @throws Exception the exception + */ + void makeFolders() throws Exception { + long count = 0; + + // get distinct paths + List paths = jpaQueryFactory.selectFrom(QRepositoryFile.repositoryFile).select(QRepositoryFile.repositoryFile.path).distinct().orderBy( + QRepositoryFile.repositoryFile.path.asc()).fetch(); + + for (String folderName : paths) { + final Path folderPath = Paths.get(folderName); + RepositoryFolder folder = repositoryService.getFolder(folderPath); + + if (folder == null) { + LOG.warn("Creating repository path={}", folderPath); + folder = repositoryService.ensureFolder(folderPath); + LOG.warn("Created folder={}", folder.getFolderPath()); + count++; + } + } + + if (count == 0) { + LOG.warn("\n\n\t** All repository folders have been created **\n\t You can remove the {} bean.\n\n", this.getClass().getName()); + } + } + + /** + * Do the migration. + * + * @throws Exception the exception + */ + void moveFilesToFolders() throws Exception { + long count = 0; + + for (RepositoryFile repoFile : fileRepository.findAll()) { + if (repoFile.getFolder() == null) { + RepositoryFolder repoFolder = repositoryService.getFolder(Paths.get(repoFile.getPath())); + if (repoFile.getFolder() == null || repoFile.getFolder().getId() != repoFolder.getId()) { + LOG.warn("Upgrading {} to folder={}", repoFile.getPath(), repoFolder.getPath()); + repoFile.setFolder(repoFolder); + fileRepository.save(repoFile); + count++; + } + } + } + + if (count == 0) { + LOG.warn("\n\n\t** All repository files have been moved to proper folders **\n\t You can remove the {} bean.\n\n", this.getClass().getName()); + } + } +} diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/model/ImageGallery.java b/file-repository-core/src/main/java/org/genesys/filerepository/model/ImageGallery.java index 3710f27ef7476e9f29562fddb2799fd2058d5d67..bcda90e5bcdc212872452c71dec48655314a9052 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/model/ImageGallery.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/model/ImageGallery.java @@ -16,6 +16,8 @@ package org.genesys.filerepository.model; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -28,6 +30,7 @@ import javax.persistence.Lob; import javax.persistence.ManyToMany; import javax.persistence.OrderColumn; import javax.persistence.Table; +import javax.persistence.Transient; import org.genesys.blocks.model.AuditedVersionedModel; import org.genesys.blocks.model.Copyable; @@ -78,6 +81,9 @@ public class ImageGallery extends AuditedVersionedModel implements AclAwareModel @OrderColumn(name = "position") private List images; + @Transient + private Path folderPath; + /** * Gets the path. * @@ -175,4 +181,18 @@ public class ImageGallery extends AuditedVersionedModel implements AclAwareModel copy.images = new ArrayList<>(this.images); return copy; } + + /** + * Gets the folder path. + * + * @return the folder path + */ + public Path getFolderPath() { + synchronized (this) { + if (folderPath == null) { + this.folderPath = Paths.get(this.path); + } + } + return this.folderPath; + } } diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryDocument.java b/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryDocument.java index 2677ec9128f284f8afa4a18957f678802eb71895..49179bf173ea2849b762fd2a88dbf703efb8bc7f 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryDocument.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryDocument.java @@ -20,6 +20,7 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Lob; import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; import javax.persistence.Table; import org.genesys.filerepository.metadata.DocumentMetadata; @@ -53,6 +54,7 @@ public class RepositoryDocument extends RepositoryFile implements DocumentMetada */ @Override @PrePersist + @PreUpdate protected void prePersist() { // Don't forget the superclass! super.prePersist(); diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryFile.java b/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryFile.java index c2f9dff9af7378c83c3ded072ae30721a508b383..2d601186e9f8af303d6bc005fa2050ccc228a363 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryFile.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryFile.java @@ -16,11 +16,14 @@ package org.genesys.filerepository.model; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Date; import java.util.UUID; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @@ -28,33 +31,41 @@ import javax.persistence.Index; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.Lob; +import javax.persistence.ManyToOne; import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; -import javax.persistence.Transient; import javax.persistence.UniqueConstraint; import org.apache.commons.lang3.StringUtils; import org.genesys.blocks.model.AuditedVersionedModelWithoutId; import org.genesys.blocks.model.Copyable; import org.genesys.blocks.model.InMemoryIdGenerator; +import org.genesys.blocks.model.SelfCleaning; import org.genesys.blocks.security.model.AclAwareModel; import org.genesys.filerepository.metadata.BaseMetadata; import org.genesys.filerepository.service.BytesStorageService; import org.hibernate.annotations.Type; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.JsonIdentityReference; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonProperty.Access; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; + /** * The RepositoryFile. */ @Entity @Table(name = "repository_file", // indexes - indexes = { @Index(unique = false, columnList = "path", name = "IX_repoFile_path") } + indexes = { @Index(unique = false, columnList = "folder_id", name = "IX_repoFile_path") } // unique - , uniqueConstraints = { @UniqueConstraint(columnNames = { "path", "originalFilename" }) }) + , uniqueConstraints = { @UniqueConstraint(columnNames = { "folder_id", "originalFilename" }) }) @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) -public class RepositoryFile extends AuditedVersionedModelWithoutId implements AclAwareModel, BaseMetadata, Copyable { +public class RepositoryFile extends AuditedVersionedModelWithoutId implements AclAwareModel, BaseMetadata, Copyable, SelfCleaning { /** The Constant serialVersionUID. */ private static final long serialVersionUID = -4816923593950502695L; @@ -70,11 +81,21 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements Ac @Type(type = "uuid-binary") private UUID uuid; - /** The path. */ - // Path in the repository - @Column(nullable = false, length = 250) + /** Path in the repository. */ + @Column(length = 250) private String path; + /** + * The repository folder. + * + * @since 1.1 + */ + @ManyToOne(cascade = {}, fetch = FetchType.LAZY, optional = false) + @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "path") + @JsonIdentityReference(alwaysAsId = true) + @JsonProperty(access = Access.READ_ONLY) + private RepositoryFolder folder; + /** The original filename as provided by the end user. */ @Column(nullable = false, length = 250) private String originalFilename; @@ -90,7 +111,7 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements Ac /** The subject. */ @Column @Lob - @Type(type = "org.hibernate.type.TextType") + @Type(type = "org.hibernate.type.TextType") private String subject; /** The description. */ @@ -158,13 +179,25 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements Ac private int size; /** - * Pre persist. + * Before persist and any update */ @PrePersist + @PreUpdate protected void prePersist() { if (uuid == null) { uuid = UUID.randomUUID(); } + + trimStringsToNull(); + } + + /** + * For repository files, the parent object is always a {@link RepositoryFolder} + * (can't be null). + */ + @Override + public AclAwareModel aclParentObject() { + return this.folder; } /* @@ -184,7 +217,7 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements Ac * @return relative URL to the file resource */ public String getUrl() { - return getStorageFullPath(); + return getStorageFullPath().toString(); } /** @@ -225,11 +258,11 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements Ac * * @return the storage path */ - public String getStoragePath() { + public Path getStoragePath() { if (uuid == null) { return null; } - return "/" + uuid.toString().substring(0, 3); + return Paths.get("/", uuid.toString().substring(0, 3)); } /** @@ -238,8 +271,8 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements Ac * * @return the storage full path */ - public String getStorageFullPath() { - return getStoragePath() + "/" + getFilename(); + public Path getStorageFullPath() { + return getStoragePath().resolve(getFilename()); } /* @@ -544,24 +577,6 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements Ac this.extension = extension; } - /** - * Gets the path. - * - * @return the path - */ - public String getPath() { - return path; - } - - /** - * Sets the path. - * - * @param path the new path - */ - public void setPath(final String path) { - this.path = path; - } - /** * Gets the original url. * @@ -652,19 +667,55 @@ public class RepositoryFile extends AuditedVersionedModelWithoutId implements Ac this.size = size; } + /** + * Gets the folder. + * + * @return the folder + */ + public RepositoryFolder getFolder() { + return folder; + } + + /** + * Sets the folder. + * + * @param folder the new folder + */ + public void setFolder(RepositoryFolder folder) { + this.folder = folder; + } + + /** + * Gets the path. + * + * @return the path + */ + public String getPath() { + return path; + } + + /** + * Sets the path. + * + * @param path the new path + */ + public void setPath(String path) { + this.path = path; + } + /* * (non-Javadoc) * @see org.genesys.blocks.model.Copyable#apply(java.lang.Object) */ @Override public RepositoryFile apply(final RepositoryFile source) { - this.path = StringUtils.defaultIfBlank(source.path, this.path); if (StringUtils.isNotBlank(source.originalFilename)) { // also updates extension setOriginalFilename(source.originalFilename); } this.active = source.active; + this.folder = source.folder; this.accessRights = source.accessRights; this.bibliographicCitation = source.bibliographicCitation; this.contentType = source.contentType; diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryFolder.java b/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryFolder.java new file mode 100644 index 0000000000000000000000000000000000000000..f2a6fe99adb4fa112b3657972c3af2e3e1f4c41e --- /dev/null +++ b/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryFolder.java @@ -0,0 +1,286 @@ +/* + * Copyright 2018 Global Crop Diversity Trust + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.genesys.filerepository.model; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.Lob; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.PrePersist; +import javax.persistence.Table; +import javax.persistence.Transient; + +import org.genesys.blocks.model.UuidModel; +import org.genesys.blocks.security.model.AclAwareModel; +import org.genesys.filerepository.InvalidRepositoryPathException; +import org.genesys.filerepository.service.impl.PathValidator; +import org.hibernate.annotations.Type; + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.JsonIdentityReference; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; + +/** + * Repository Folder represents a location (path) of files in the + * repository. It is immutable and it's path cannot be modified. + * + * @since 1.1-SNAPSHOT + */ +@Entity +@Table(name = "repositoryfolder") +public class RepositoryFolder extends UuidModel implements AclAwareModel { + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = -7947000802758739238L; + + /** + * Reference to parent Folder. Root folders have this set to null. This + * establishes hierarchical structure of folders. + * + * Because paths are immutable, this cannot be updated. + */ + @ManyToOne(cascade = {}, optional = true, fetch = FetchType.LAZY) + @JoinColumn(updatable = false) + @JsonIgnore + private RepositoryFolder parent; + + /** + * List of sub-folders. + */ + @OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = "parent") + @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "path") + @JsonIdentityReference(alwaysAsId = true) + private List children; + + /** List of files in this folder. */ + @OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = "folder") + // @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, + // property = "originalFilename") + // @JsonIdentityReference(alwaysAsId = true) + @JsonIgnore + private List files; + + /** + * The name of the folder within parent Folder. It is immutable and must not be + * updated. + */ + @Column(name = "name", nullable = false, updatable = false) + private String name; + + /** + * Unique path in the repository. It is immutable and must not be updated. It is + * based on the parent Folder path + name. + */ + @Column(name = "path", nullable = false, unique = true, updatable = false) + private String path; + + /** + * A human-friendly folder title, not to be confused with {@link #name} above. + */ + @Column + private String title; + + /** Folder description. */ + @Lob + @Type(type = "org.hibernate.type.TextType") + private String description; + + /** The folder path. */ + @Transient + private Path folderPath; + + /** + * Pre persist. + */ + @PrePersist + protected void prePersist() { + if (uuid == null) { + uuid = UUID.randomUUID(); + } + this.path = this.parent == null ? "/" + this.name : this.parent.getFolderPath().resolve(this.name).normalize().toAbsolutePath().toString(); + } + + /** + * The parent folder is generally the parent object for any folder. + * + * @return the ACL parent object + */ + @Override + public AclAwareModel aclParentObject() { + return this.parent; + } + + /** + * Gets the parent. + * + * @return the parent + */ + public RepositoryFolder getParent() { + return parent; + } + + /** + * Sets the parent. + * + * @param parent the new parent + */ + public void setParent(RepositoryFolder parent) { + this.parent = parent; + } + + /** + * Gets the children. + * + * @return the children + */ + public List getChildren() { + return children; + } + + /** + * Sets the children. + * + * @param children the new children + */ + public void setChildren(List children) { + this.children = children; + } + + /** + * Gets the path. + * + * @return the path + */ + public String getPath() { + return path; + } + + /** + * Sets the path. + * + * @param path the new path + */ + protected void setPath(String path) { + this.path = path; + } + + /** + * Gets the folder name. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Sets the folder name. + * + * @param name the new name + * @throws InvalidRepositoryPathException if name contains illegal characters + */ + public void setName(String name) throws InvalidRepositoryPathException { + PathValidator.checkValidFolderName(name); + this.name = name; + } + + /** + * Gets the title. + * + * @return the title + */ + public String getTitle() { + return title; + } + + /** + * Sets the title. + * + * @param title the new title + */ + public void setTitle(String title) { + this.title = title; + } + + /** + * Gets the description. + * + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * Sets the description. + * + * @param description the new description + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Gets the folder path. + * + * @return the folder path + */ + public Path getFolderPath() { + synchronized (this) { + if (folderPath == null) { + this.folderPath = Paths.get(this.path); + } + } + return this.folderPath; + } + + /** + * Gets the files. + * + * @return the files + */ + public List getFiles() { + return files; + } + + /** + * Sets the files. + * + * @param files the new files + */ + public void setFiles(List files) { + this.files = files; + } + + /* + * (non-Javadoc) + * @see org.genesys.blocks.model.VersionedModel#toString() + */ + @Override + public String toString() { + return "Folder id=" + getId() + " path=" + this.path; + } +} diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryImage.java b/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryImage.java index f380f4834e7cba8ceadfbcbcb97d8c2eb6c449ee..bf1d5fbd10b950516e229bd48459f03cd75a9b17 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryImage.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/model/RepositoryImage.java @@ -21,6 +21,7 @@ import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; import javax.persistence.Table; import org.genesys.filerepository.metadata.ImageMetadata; @@ -57,6 +58,7 @@ public class RepositoryImage extends RepositoryFile implements ImageMetadata { */ @Override @PrePersist + @PreUpdate protected void prePersist() { // Don't forget the superclass! super.prePersist(); diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryDocumentPersistence.java b/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryDocumentPersistence.java index 556cfb6f40bdf7b34e80ea456f5cdf9e43174807..f66ff463766726f1b8d7309895a2c67b707253e5 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryDocumentPersistence.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryDocumentPersistence.java @@ -21,6 +21,7 @@ import java.util.UUID; import org.genesys.filerepository.RepositoryPersistence; import org.genesys.filerepository.model.RepositoryDocument; +import org.genesys.filerepository.model.RepositoryFolder; import org.springframework.stereotype.Repository; // TODO: Auto-generated Javadoc @@ -39,10 +40,10 @@ public interface RepositoryDocumentPersistence extends RepositoryPersistence findByPath(String repositoryPath); + List findByFolder(RepositoryFolder folder); } diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryFilePersistence.java b/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryFilePersistence.java index e49c6eb746bd4d6399d13e6b782cb4e1df05b6a5..c000d95b7fa3fc0b322cf32c046b5494851d1194 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryFilePersistence.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryFilePersistence.java @@ -16,15 +16,14 @@ package org.genesys.filerepository.persistence; -import java.util.Collection; import java.util.List; import java.util.UUID; -import java.util.stream.Stream; import org.genesys.filerepository.RepositoryPersistence; import org.genesys.filerepository.model.RepositoryFile; -import org.springframework.data.domain.Pageable; +import org.genesys.filerepository.model.RepositoryFolder; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.querydsl.QueryDslPredicateExecutor; import org.springframework.stereotype.Repository; // TODO: Auto-generated Javadoc @@ -36,7 +35,7 @@ import org.springframework.stereotype.Repository; * */ @Repository -public interface RepositoryFilePersistence extends RepositoryPersistence { +public interface RepositoryFilePersistence extends RepositoryPersistence, QueryDslPredicateExecutor { /** * Find by uuid. @@ -56,52 +55,6 @@ public interface RepositoryFilePersistence extends RepositoryPersistence findByPath(String repositoryPath); - - /** - * Stream by path. - * - * @param repositoryPath the root repository path (includes all subpaths) - * @return the list - */ - @Query("select rf from RepositoryFile rf where rf.path like ?1%") - Stream streamByBasePath(String repositoryPath); - - - /** - * List repository files at specified paths. - * - * @param paths the paths - * @return the list - */ - @Query("select rf from RepositoryFile rf where rf.path in ?1") - List findByPath(Collection paths); - - /** - * List distinct paths starting with the prefix. - * - * @param prefix the prefix - * @param pageable the pagination - * @return the list - */ - @Query("select distinct(rf.path) from RepositoryFile rf where rf.path like ?1%") - List listDistinctPaths(String prefix, Pageable pageable); - - /** - * List distinct paths starting with the prefix. - * - * @param prefix the prefix - * @return the list of paths - */ - @Query("select distinct(rf.path) from RepositoryFile rf where rf.path like ?1%") - List listDistinctPaths(String prefix); - /** * Find files with missing hashes. * @@ -110,22 +63,21 @@ public interface RepositoryFilePersistence extends RepositoryPersistence findByMissingHashSums(); + /** - * Find repository file by path and originalFilename. + * Count by folder. * - * @param path the path - * @param originalFilename the original filename - * @return the repository file + * @param folder the folder + * @return the int */ - RepositoryFile findByPathAndOriginalFilename(String path, String originalFilename); + long countByFolder(RepositoryFolder folder); /** - * Count files with matching path. + * Find by folder and original filename. * - * @param path Repository path - * @return Number of files at specified path + * @param folder the containing folder + * @param originalFilename the original filename + * @return the repository file */ - @Query("select count(rf) from RepositoryFile rf where rf.path = ?1") - int countByPath(String path); - + RepositoryFile findByFolderAndOriginalFilename(RepositoryFolder folder, String originalFilename); } diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryFolderRepository.java b/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryFolderRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..3c82fc96ed7844abf4c7bee026b1443776996eab --- /dev/null +++ b/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryFolderRepository.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 Global Crop Diversity Trust + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.genesys.filerepository.persistence; + +import java.util.List; +import java.util.UUID; + +import org.genesys.filerepository.RepositoryPersistence; +import org.genesys.filerepository.model.RepositoryFolder; +import org.springframework.data.domain.Pageable; +import org.springframework.data.querydsl.QueryDslPredicateExecutor; +import org.springframework.stereotype.Repository; + +/** + * JPA Repository for {@link RepositoryFolder} + */ +@Repository +public interface RepositoryFolderRepository extends RepositoryPersistence, QueryDslPredicateExecutor { + + /** + * Find by uuid. + * + * @param uuid the uuid + * @return the repository folder with specified UUID + */ + RepositoryFolder findByUuid(UUID uuid); + + /** + * Find by path. + * + * @param repositoryPath the repository path + * @return the {@link RepositoryFolder} at the specified path + */ + RepositoryFolder findByPath(String repositoryPath); + + /** + * Find Folders where path starts with specified prefix. + * + * @param prefix the path + * @return the list of folders starting with prefix + */ + List findByPathStartingWith(String prefix); + + + /** + * Find by path starting with. + * + * @param prefix the prefix + * @param pageable the pageable + * @return the list + */ + List findByPathStartingWith(String prefix, Pageable pageable); +} diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryImagePersistence.java b/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryImagePersistence.java index 011e336062205f6b16866ee9d8d189be66f9ff32..ea4d9410b48826d93bf13853f44892f33422f009 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryImagePersistence.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/persistence/RepositoryImagePersistence.java @@ -20,7 +20,9 @@ import java.util.List; import java.util.UUID; import org.genesys.filerepository.RepositoryPersistence; +import org.genesys.filerepository.model.RepositoryFolder; import org.genesys.filerepository.model.RepositoryImage; +import org.springframework.data.querydsl.QueryDslPredicateExecutor; import org.springframework.stereotype.Repository; // TODO: Auto-generated Javadoc @@ -28,7 +30,7 @@ import org.springframework.stereotype.Repository; * The Interface RepositoryImagePersistence. */ @Repository -public interface RepositoryImagePersistence extends RepositoryPersistence { +public interface RepositoryImagePersistence extends RepositoryPersistence, QueryDslPredicateExecutor { /** * Find by uuid. @@ -48,11 +50,11 @@ public interface RepositoryImagePersistence extends RepositoryPersistence findByPath(String repositoryPath); + List findByFolder(RepositoryFolder folder); } diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/service/BytesStorageService.java b/file-repository-core/src/main/java/org/genesys/filerepository/service/BytesStorageService.java index 0c1a24df1c23ca8a3dc304cc50683b5789f66f13..c16b6068017007024ea1ecf68347558a9cd34a5d 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/service/BytesStorageService.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/service/BytesStorageService.java @@ -17,6 +17,7 @@ package org.genesys.filerepository.service; import java.io.IOException; +import java.nio.file.Path; import java.util.List; import org.genesys.filerepository.InvalidRepositoryPathException; @@ -28,45 +29,41 @@ import org.genesys.filerepository.InvalidRepositoryPathException; public interface BytesStorageService { /** - * Upsert. + * Upsert bytes of the file. * - * @param path the path - * @param filename the filename + * @param bytesFile the bytes file * @param data the data * @throws IOException Signals that an I/O exception has occurred. */ - void upsert(String path, String filename, byte[] data) throws IOException; + void upsert(Path bytesFile, byte[] data) throws IOException; /** * Removes the file with specified filename from repository at the specified * path. * - * @param path the path - * @param filename the filename + * @param bytesFile the bytes file * @throws IOException Signals that an I/O exception has occurred. */ - void remove(String path, String filename) throws IOException; + void remove(Path bytesFile) throws IOException; /** * Gets the file bytes. * - * @param path the path - * @param filename the filename + * @param bytesFile the bytes file * @return the byte[] * @throws IOException Signals that an I/O exception has occurred. */ - byte[] get(String path, String filename) throws IOException; + byte[] get(Path bytesFile) throws IOException; /** * Check if bytes exist at specified location. * - * @param path the path - * @param filename the filename + * @param bytesFile the bytes file * @return true, if successful * @throws IOException when things go wrong on bytes storage level * @throws InvalidRepositoryPathException when path or filename are not valid */ - boolean exists(String path, String filename) throws IOException, InvalidRepositoryPathException; + boolean exists(Path bytesFile) throws IOException, InvalidRepositoryPathException; /** * List all filenames at specified path. Does not include subfolders. @@ -75,6 +72,6 @@ public interface BytesStorageService { * @return the list * @throws InvalidRepositoryPathException when invalid path is provided */ - List listFiles(String path) throws InvalidRepositoryPathException; + List listFiles(Path path) throws InvalidRepositoryPathException; } diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/service/ImageGalleryService.java b/file-repository-core/src/main/java/org/genesys/filerepository/service/ImageGalleryService.java index 8074f5544f69718ce08ea0cba6d896016a0ac5d9..5ef4823dbe404d467c3c3223ee676c28bc190358 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/service/ImageGalleryService.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/service/ImageGalleryService.java @@ -16,6 +16,8 @@ package org.genesys.filerepository.service; +import java.nio.file.Path; + import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.model.ImageGallery; import org.springframework.data.domain.Page; @@ -40,7 +42,7 @@ public interface ImageGalleryService { * @return the ImageGallery or null if no gallery exists at the * specified path. */ - ImageGallery loadImageGallery(String path); + ImageGallery loadImageGallery(Path path); /** * Create a gallery at the specified path if it does not exist. Path of the @@ -51,7 +53,7 @@ public interface ImageGalleryService { * @param description Image gallery description in English. * @return the new ImageGallery or existing gallery at the specified path. */ - ImageGallery createImageGallery(String path, String title, String description); + ImageGallery createImageGallery(Path path, String title, String description); /** * Delete the image gallery, but don't remove the images at that path. @@ -106,6 +108,6 @@ public interface ImageGalleryService { * @param pageable the pageable * @return paginated image gallery data */ - Page listImageGalleries(String prefix, Pageable pageable); + Page listImageGalleries(Path root, Pageable pageable); } diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/service/RepositoryService.java b/file-repository-core/src/main/java/org/genesys/filerepository/service/RepositoryService.java index fb419729032139d5f403f6d15c20b067fecf9a00..3a898a881103c3c5a02390c67309ca4a7d094527 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/service/RepositoryService.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/service/RepositoryService.java @@ -22,18 +22,23 @@ import java.util.List; import java.util.UUID; import java.util.stream.Stream; +import org.genesys.filerepository.FolderNotEmptyException; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; import org.genesys.filerepository.metadata.ImageMetadata; import org.genesys.filerepository.model.RepositoryFile; +import org.genesys.filerepository.model.RepositoryFolder; import org.genesys.filerepository.model.RepositoryImage; -import org.springframework.data.domain.Pageable; // TODO: Auto-generated Javadoc /** * The Interface RepositoryService. */ +/** + * @author Matija Obreza + * + */ public interface RepositoryService { /** @@ -50,7 +55,7 @@ public interface RepositoryService { * exception * @throws IOException when things go wrong on bytes storage level */ - RepositoryFile addFile(String repositoryPath, String originalFilename, String contentType, byte[] bytes, RepositoryFile metaData) throws InvalidRepositoryPathException, + RepositoryFile addFile(Path repositoryPath, String originalFilename, String contentType, byte[] bytes, RepositoryFile metaData) throws InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException; /** @@ -67,7 +72,7 @@ public interface RepositoryService { * exception * @throws IOException when things go wrong on bytes storage level */ - RepositoryImage addImage(String repositoryPath, String originalFilename, String contentType, byte[] bytes, RepositoryImage metaData) throws InvalidRepositoryPathException, + RepositoryImage addImage(Path repositoryPath, String originalFilename, String contentType, byte[] bytes, RepositoryImage metaData) throws InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException; /** @@ -100,7 +105,7 @@ public interface RepositoryService { * @return the file * @throws NoSuchRepositoryFileException the no such repository file exception */ - RepositoryFile getFile(String path, String filename) throws NoSuchRepositoryFileException; + RepositoryFile getFile(Path path, String filename) throws NoSuchRepositoryFileException; /** * Get repository file bytes by its path and filename. @@ -110,7 +115,7 @@ public interface RepositoryService { * @return the file bytes * @throws NoSuchRepositoryFileException the no such repository file exception */ - byte[] getFileBytes(String repositoryPath, String filename) throws NoSuchRepositoryFileException; + byte[] getFileBytes(Path repositoryPath) throws NoSuchRepositoryFileException; /** * Gets the file bytes. @@ -124,18 +129,20 @@ public interface RepositoryService { /** * List all files at the specified repository path. * - * @param repositoryPath the repository path + * @param folderPath the folder path * @return the files + * @throws NoSuchRepositoryFileException */ - List getFiles(String repositoryPath); + List getFiles(Path folderPath); /** * Stream file info at the specified repository path. * * @param repositoryPath the repository path * @return the files + * @throws InvalidRepositoryPathException */ - Stream streamFiles(String repositoryPath); + Stream streamFiles(Path root) throws InvalidRepositoryPathException; /** * Update file metadata. The update is based on the record UUID. @@ -194,7 +201,7 @@ public interface RepositoryService { * @throws NoSuchRepositoryFileException the no such repository file exception * @throws InvalidRepositoryPathException when the new path is invalid */ - RepositoryFile moveFile(RepositoryFile repositoryFile, String newPath) throws NoSuchRepositoryFileException, InvalidRepositoryPathException; + RepositoryFile moveFile(RepositoryFile repositoryFile, Path target) throws NoSuchRepositoryFileException, InvalidRepositoryPathException; /** * Update path and originalFilename of repository file. @@ -206,7 +213,7 @@ public interface RepositoryService { * @throws InvalidRepositoryFileDataException the invalid repository file data * exception */ - RepositoryFile moveAndRenameFile(RepositoryFile repositoryFile, String fullPath) throws InvalidRepositoryPathException, InvalidRepositoryFileDataException; + RepositoryFile moveAndRenameFile(RepositoryFile repositoryFile, Path fullPath) throws InvalidRepositoryPathException, InvalidRepositoryFileDataException; /** * List all {@link RepositoryImage} entries at specified path. @@ -214,28 +221,17 @@ public interface RepositoryService { * @param path the path * @return the list */ - List listImages(String path); - - /** - * List all paths within the prefix, including prefix itself if such paths - * exist. - * - * @param prefix The prefix - * @param pageRequest Pagination - * @return Distinct list of paths in repository starting with prefix - * @throws InvalidRepositoryPathException the invalid repository path exception - */ - List listPaths(String prefix, Pageable pageRequest) throws InvalidRepositoryPathException; + List listImages(Path path); /** - * List all paths within the prefix, including prefix itself if such paths - * exist. + * List all paths within the root Path, including the root folder itself if it + * exists. * * @param prefix the prefix * @return the list * @throws InvalidRepositoryPathException the invalid repository path exception */ - List listPaths(String prefix) throws InvalidRepositoryPathException; + List listPaths(Path root) throws InvalidRepositoryPathException; /** * Update image metadata. The update is based on the record UUID. @@ -258,6 +254,14 @@ public interface RepositoryService { */ RepositoryImage removeImage(RepositoryImage repositoryImage) throws NoSuchRepositoryFileException, IOException; + /** + * Gets the folder by path + * + * @param folderPath the folder path + * @return the folder + */ + RepositoryFolder getFolder(Path folderPath); + /** * Test if repository contains the path. * @@ -272,8 +276,36 @@ public interface RepositoryService { * * @param currentPath the current path * @param newPath the new path + * @return Repository folder of the new path * @throws InvalidRepositoryPathException the invalid repository path exception */ - void renamePath(String currentPath, String newPath) throws InvalidRepositoryPathException; + RepositoryFolder renamePath(Path currentPath, Path newPath) throws InvalidRepositoryPathException; + + /** + * Register a folder at specified path. Creates a new record if path is not + * found. + * + * @param path the folder path + * @return a {@link RepositoryFolder} + * @throws InvalidRepositoryPathException + */ + RepositoryFolder ensureFolder(Path path) throws InvalidRepositoryPathException; + + /** + * Delete an empty folder (no children, no files). + * + * @param string repository path + * @return the deleted repository folder + * @throws FolderNotEmptyException if folder contains sub-folders or files + */ + RepositoryFolder deleteFolder(Path path) throws FolderNotEmptyException; + + /** + * Get subfolders of root + * + * @param root + * @return + */ + List getFolders(Path root); } diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/AbstractImageGalleryAspects.java b/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/AbstractImageGalleryAspects.java index 1477370e8c3e94f4b2462c5e317d87314774695d..35bf16e5bc8253b2fa625d2fce076b534db0934f 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/AbstractImageGalleryAspects.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/AbstractImageGalleryAspects.java @@ -94,7 +94,7 @@ public abstract class AbstractImageGalleryAspects { public Object aroundRepositoryImageDelete(final ProceedingJoinPoint joinPoint, final RepositoryImage repositoryImage) throws Throwable { if (repositoryImage != null) { - LOG.trace("1 image is being deleted path={} originalFilename={}", repositoryImage.getPath(), repositoryImage.getOriginalFilename()); + LOG.trace("1 image is being deleted path={} originalFilename={}", repositoryImage.getFolder(), repositoryImage.getOriginalFilename()); } removeImageFromGallery(repositoryImage); diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/ImageGalleryAspectsImpl.java b/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/ImageGalleryAspectsImpl.java index 2ec2a247a6e9c107fbda090767b538b30cdd8e2b..f1e18475d4e077f14cb18b1bf67f75aab62dba29 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/ImageGalleryAspectsImpl.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/ImageGalleryAspectsImpl.java @@ -83,11 +83,11 @@ public class ImageGalleryAspectsImpl extends AbstractImageGalleryAspects impleme return; } - final ImageGallery imageGallery = imageGalleryService.loadImageGallery(repositoryImage.getPath()); + final ImageGallery imageGallery = imageGalleryService.loadImageGallery(repositoryImage.getFolder().getFolderPath()); if (imageGallery == null) { if (LOG.isDebugEnabled()) { - LOG.debug("No gallery at path={}", repositoryImage.getPath()); + LOG.debug("No gallery at path={}", repositoryImage.getFolder()); } return; } @@ -118,11 +118,11 @@ public class ImageGalleryAspectsImpl extends AbstractImageGalleryAspects impleme return; } - final ImageGallery imageGallery = imageGalleryService.loadImageGallery(repositoryImage.getPath()); + final ImageGallery imageGallery = imageGalleryService.loadImageGallery(repositoryImage.getFolder().getFolderPath()); if (imageGallery == null) { if (LOG.isTraceEnabled()) { - LOG.trace("No gallery at path=" + repositoryImage.getPath()); + LOG.trace("No gallery at path=" + repositoryImage.getFolder()); } return; } diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/MetadataInStorageAspect.java b/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/MetadataInStorageAspect.java index a55b5272d01b77863425fb555f2632c442aa3445..a7de1821b42d477835bce36e8436e8c6f4927a1c 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/MetadataInStorageAspect.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/service/aspect/MetadataInStorageAspect.java @@ -163,13 +163,13 @@ public class MetadataInStorageAspect { if (repositoryFile == null) { return; } - LOG.trace("File was updated path={} originalFilename={}. Writing metadata.json", repositoryFile.getPath(), repositoryFile.getOriginalFilename()); + LOG.trace("File was updated path={} originalFilename={}. Writing metadata.json", repositoryFile.getFolder(), repositoryFile.getOriginalFilename()); try { final String metadataJson = objectWriter.writeValueAsString(repositoryFile); try { - bytesStorageService.upsert(repositoryFile.getStoragePath(), repositoryFile.getMetadataFilename(), metadataJson.getBytes(UTF8)); + bytesStorageService.upsert(repositoryFile.getStoragePath().resolve(repositoryFile.getMetadataFilename()), metadataJson.getBytes(UTF8)); } catch (final IOException e) { if (LOG.isDebugEnabled()) { LOG.debug("Failed to upload metadata bytes", e); @@ -193,10 +193,10 @@ public class MetadataInStorageAspect { return; } - LOG.trace("File was deleted path={} originalFilename={}. Removing metadata.json", repositoryFile.getPath(), repositoryFile.getOriginalFilename()); + LOG.trace("File was deleted path={} originalFilename={}. Removing metadata.json", repositoryFile.getFolder(), repositoryFile.getOriginalFilename()); try { - bytesStorageService.remove(repositoryFile.getStoragePath(), repositoryFile.getMetadataFilename()); + bytesStorageService.remove(repositoryFile.getStoragePath().resolve(repositoryFile.getMetadataFilename())); } catch (final IOException e) { if (LOG.isDebugEnabled()) { LOG.debug("Failed to delete metadata bytes", e); diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/FilesystemStorageServiceImpl.java b/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/FilesystemStorageServiceImpl.java index 64793f33da7cebc9d84eb3225e57b9f9609a93f2..206b5edb1b5fcc132da1c44e9dbf15236aa32620 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/FilesystemStorageServiceImpl.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/FilesystemStorageServiceImpl.java @@ -22,6 +22,8 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -32,6 +34,7 @@ import org.genesys.filerepository.BytesStorageException; import org.genesys.filerepository.service.BytesStorageService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Service; // TODO: Auto-generated Javadoc @@ -41,13 +44,14 @@ import org.springframework.stereotype.Service; * @author mobreza */ @Service("fileSystemStorage") -public class FilesystemStorageServiceImpl implements BytesStorageService { +public class FilesystemStorageServiceImpl implements InitializingBean, BytesStorageService { /** The Constant LOG. */ private final static Logger LOG = LoggerFactory.getLogger(FilesystemStorageServiceImpl.class); /** Repository base directory. */ private File repoDir; + private Path repoPath; /** * Sets the repository base directory. @@ -63,8 +67,10 @@ public class FilesystemStorageServiceImpl implements BytesStorageService { * * @throws BytesStorageException the bytes storage exception */ + @Override public void afterPropertiesSet() throws BytesStorageException { sanityCheck(); + this.repoPath = Paths.get(repoDir.getAbsolutePath()); } /** @@ -72,17 +78,9 @@ public class FilesystemStorageServiceImpl implements BytesStorageService { * * @throws BytesStorageException the bytes storage exception */ - // Do not do any null checks, let it fail. protected void sanityCheck() throws BytesStorageException { if (!repoDir.isDirectory()) { - throw new BytesStorageException("Base path is not a directory"); - } - - // Base directory must contain the file FILEREPOSITORY (so we don't - // create things all over the place) - final File repositoryMarker = new File(repoDir, "FILEREPOSITORY"); - if (!repositoryMarker.exists() || !repositoryMarker.isFile()) { - throw new BytesStorageException("Missing FILEREPOSITORY marker in " + repoDir.getAbsolutePath()); + throw new BytesStorageException("Base path " + repoDir + " is not a directory"); } } @@ -92,9 +90,12 @@ public class FilesystemStorageServiceImpl implements BytesStorageService { * java.lang.String, java.lang.String, byte[]) */ @Override - public void upsert(final String path, final String filename, final byte[] data) throws FileNotFoundException, IOException { - LOG.trace("Trying to upsert path={} filename={}", path, filename); - final File destinationDir = new File(repoDir, path); + public void upsert(Path bytesFile, final byte[] data) throws FileNotFoundException, IOException { + final Path normalPath = bytesFile.normalize().toAbsolutePath(); + final Path destinationFilePath = getDestPath(normalPath); + + LOG.trace("Trying to upsert path={}", normalPath); + final File destinationDir = getDestPath(normalPath).getParent().toFile(); if (!destinationDir.getCanonicalPath().startsWith(repoDir.getCanonicalPath())) { throw new IOException("Not within repository path: " + destinationDir.getAbsolutePath()); @@ -104,7 +105,7 @@ public class FilesystemStorageServiceImpl implements BytesStorageService { throw new IOException("Exists, not a directory: " + destinationDir.getAbsolutePath()); } - final File destinationFile = new File(destinationDir, filename); + final File destinationFile = destinationFilePath.toFile(); if (!destinationFile.getCanonicalPath().startsWith(repoDir.getCanonicalPath())) { throw new IOException("Not within repository path: " + destinationFile.getAbsolutePath()); } @@ -114,15 +115,28 @@ public class FilesystemStorageServiceImpl implements BytesStorageService { } } + /** + * Gets the path where subPath a sub-folder of {@link #repoDir} + * + * @param subPath the normal path + * @return the dest path + */ + public Path getDestPath(Path subPath) { + return Paths.get(repoPath.toString(), subPath.toString()).normalize().toAbsolutePath(); + } + /* * (non-Javadoc) * @see org.genesys.filerepository.service.BytesStorageService#remove( * java.lang.String, java.lang.String) */ @Override - public void remove(final String path, final String filename) throws IOException { - final File destinationDir = new File(repoDir, path); - final File destinationFile = new File(destinationDir, filename); + public void remove(Path bytesFile) throws IOException { + final Path normalPath = bytesFile.normalize().toAbsolutePath(); + final Path destinationFilePath = getDestPath(normalPath); + + final File destinationDir = destinationFilePath.getParent().toFile(); + final File destinationFile = destinationFilePath.toFile(); if (!destinationFile.getCanonicalPath().startsWith(repoDir.getCanonicalPath())) { throw new IOException("Not within repository path: " + destinationFile.getAbsolutePath()); @@ -151,10 +165,13 @@ public class FilesystemStorageServiceImpl implements BytesStorageService { * lang.String, java.lang.String) */ @Override - public byte[] get(final String path, final String filename) throws IOException { - LOG.trace("Retrieving bytes of {} {}", path, filename); - final File destinationDir = new File(repoDir, path); - final File destinationFile = new File(destinationDir, filename); + public byte[] get(Path bytesFile) throws IOException { + final Path normalPath = bytesFile.normalize().toAbsolutePath(); + final Path destinationFilePath = getDestPath(normalPath); + + LOG.trace("Retrieving bytes of {}", normalPath); + + final File destinationFile = destinationFilePath.toFile(); if (!destinationFile.getCanonicalPath().startsWith(repoDir.getCanonicalPath())) { throw new IOException("Not within repository path: " + destinationFile.getAbsolutePath()); @@ -178,11 +195,9 @@ public class FilesystemStorageServiceImpl implements BytesStorageService { * String, java.lang.String) */ @Override - public boolean exists(final String path, final String filename) { - final File destinationDir = new File(repoDir, path); - final File destinationFile = new File(destinationDir, filename); + public boolean exists(final Path bytesFile) { - return destinationFile.exists(); + return getDestPath(bytesFile).toFile().exists(); } /* @@ -192,12 +207,12 @@ public class FilesystemStorageServiceImpl implements BytesStorageService { * String) */ @Override - public List listFiles(final String path) { + public List listFiles(final Path path) { if (LOG.isDebugEnabled()) { LOG.debug("Listing filenames at path=" + path); } - final File destinationDir = new File(repoDir, path); + final File destinationDir = getDestPath(path).toFile(); if (!destinationDir.exists() || !destinationDir.isDirectory()) { LOG.info("Returning empty files list for nonexistent dir={}", destinationDir.getAbsolutePath()); diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/ImageGalleryServiceImpl.java b/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/ImageGalleryServiceImpl.java index 0feb9262adf211627d7943d1768fdfe05ad9033c..e3916a6ddd7a89f6bed23c68a9f2e64e9779b1c9 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/ImageGalleryServiceImpl.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/ImageGalleryServiceImpl.java @@ -17,6 +17,8 @@ package org.genesys.filerepository.service.impl; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -76,8 +78,8 @@ public class ImageGalleryServiceImpl implements ImageGalleryService { */ @Override @PostAuthorize("returnObject == null or hasRole('ADMINISTRATOR') or hasPermission(returnObject, 'read')") - public ImageGallery loadImageGallery(final String path) { - final ImageGallery imageGallery = imageGalleryPersistence.findByPath(path); + public ImageGallery loadImageGallery(final Path path) { + final ImageGallery imageGallery = imageGalleryPersistence.findByPath(path.normalize().toAbsolutePath().toString()); return deepLoad(imageGallery); } @@ -104,10 +106,10 @@ public class ImageGalleryServiceImpl implements ImageGalleryService { @Override @Transactional @PreAuthorize("isAuthenticated()") - public ImageGallery createImageGallery(final String path, final String title, final String description) { + public ImageGallery createImageGallery(final Path path, final String title, final String description) { LOG.debug("Creating ImageGallery at path={}", path); - ImageGallery imageGallery = imageGalleryPersistence.findByPath(path); + ImageGallery imageGallery = imageGalleryPersistence.findByPath(path.normalize().toAbsolutePath().toString()); if (imageGallery != null) { return imageGallery; } else { @@ -115,11 +117,11 @@ public class ImageGalleryServiceImpl implements ImageGalleryService { imageGallery = new ImageGallery(); } - imageGallery.setPath(path); + imageGallery.setPath(path.normalize().toAbsolutePath().toString()); imageGallery.setTitle(title); imageGallery.setDescription(description); - final List images = new ArrayList<>(repositoryService.listImages(imageGallery.getPath())); + final List images = new ArrayList<>(repositoryService.listImages(Paths.get(imageGallery.getPath()))); imageGallery.setImages(images); @@ -141,11 +143,11 @@ public class ImageGalleryServiceImpl implements ImageGalleryService { } for (final RepositoryImage image : imageGallery.getImages()) { - final String imageThumbPath = getFullThumbnailsPath(image); + final Path imageThumbPath = getFullThumbnailsPath(image); bytesStorageService.listFiles(imageThumbPath).forEach(filename -> { try { LOG.debug("Removing _thumb path={} filename={}", THUMB_PATH, filename); - bytesStorageService.remove(imageThumbPath, filename); + bytesStorageService.remove(imageThumbPath.resolve(filename)); } catch (final Exception e) { LOG.error("Failed to remove bytes path=" + imageThumbPath + " filename=" + filename, e); } @@ -161,8 +163,8 @@ public class ImageGalleryServiceImpl implements ImageGalleryService { * @param image the image * @return the full thumbnails path */ - private String getFullThumbnailsPath(final RepositoryImage image) { - return THUMB_PATH + image.getThumbnailPath(); + private Path getFullThumbnailsPath(final RepositoryImage image) { + return Paths.get(THUMB_PATH, image.getThumbnailPath()); } /* @@ -249,18 +251,18 @@ public class ImageGalleryServiceImpl implements ImageGalleryService { 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(getFullThumbnailsPath(repositoryImage), filename)) { + if (!bytesStorageService.exists(getFullThumbnailsPath(repositoryImage).resolve(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.getStoragePath(), repositoryImage.getFilename())); + final byte[] bytesPng = thumbnailGenerator.createThumbnail(width, height, bytesStorageService.get(repositoryImage.getStorageFullPath())); if (LOG.isDebugEnabled()) { LOG.debug("Persisting new thumbnail width={} height={} for image={}", width, height, repositoryImage.getUuid()); } - bytesStorageService.upsert(getFullThumbnailsPath(repositoryImage), filename, bytesPng); + bytesStorageService.upsert(getFullThumbnailsPath(repositoryImage).resolve(filename), bytesPng); } } @@ -306,7 +308,7 @@ public class ImageGalleryServiceImpl implements ImageGalleryService { */ @Override @PostFilter("hasRole('ADMINISTRATOR') or hasPermission(filterObject, 'read')") - public Page listImageGalleries(final String prefix, final Pageable pageable) { - return imageGalleryPersistence.listByPath(prefix, pageable); + public Page listImageGalleries(final Path root, final Pageable pageable) { + return imageGalleryPersistence.listByPath(root.normalize().toAbsolutePath().toString(), pageable); } } diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/PathValidator.java b/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/PathValidator.java index 21f65c5966c536e71e3c9ef1c8797ea919ec9c87..7438f224729768d913cd78e92248b5f61d7d0b31 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/PathValidator.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/PathValidator.java @@ -16,11 +16,13 @@ package org.genesys.filerepository.service.impl; +import java.nio.file.Path; + +import org.apache.commons.lang3.StringUtils; import org.genesys.filerepository.InvalidRepositoryPathException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -// TODO: Auto-generated Javadoc /** * Simple path validator. */ @@ -36,8 +38,18 @@ public class PathValidator { * @return true, if path is valid */ protected static boolean isValidPath(final String path) { - return (path != null) && path.startsWith("/") && (path.equals("/") || !path.endsWith("/")) && !path.contains("//") && !path.contains(" /") && !path.contains("/ ") && !path - .contains("?") && !path.contains("&") && !path.contains("\\"); + return StringUtils.isNotBlank(path) && path.startsWith("/") && (path.equals("/") || !path.endsWith("/")) && !path.contains("//") && !path.contains(" /") && !path.contains( + "/ ") && !path.contains("?") && !path.contains("&") && !path.contains("\\") && !path.endsWith(" "); + } + + /** + * Checks if folder name is valid. + * + * @param path the path + * @return true, if path is valid + */ + protected static boolean isValidFolderName(final String name) { + return StringUtils.isNotBlank(name) && !("..".equals(name) || name.contains("/") || name.contains("?") || name.contains("&") || name.contains("\\")); } /** @@ -53,4 +65,30 @@ public class PathValidator { throw new InvalidRepositoryPathException(path); } } + + /** + * Check valid folder name. + * + * @param name the name + * @throws InvalidRepositoryPathException the invalid repository path exception + */ + public static void checkValidFolderName(String name) throws InvalidRepositoryPathException { + if (!isValidFolderName(name)) { + LOG.warn("Invalid repository name {}", name); + throw new InvalidRepositoryPathException(name); + } + } + + /** + * Check valid path. + * + * @param repositoryPath the repository path + * @throws InvalidRepositoryPathException the invalid repository path exception + */ + public static void checkValidPath(Path repositoryPath) throws InvalidRepositoryPathException { + if (repositoryPath == null) { + throw new InvalidRepositoryPathException("null path not allowed"); + } + checkValidPath(repositoryPath.normalize().toAbsolutePath().toString()); + } } diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/RepositoryServiceImpl.java b/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/RepositoryServiceImpl.java index 2c0af5ed92b94835b10a6852992351c02440dcd4..0622029a624bd0293703c49938ea73e4f4889670 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/RepositoryServiceImpl.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/RepositoryServiceImpl.java @@ -22,23 +22,28 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.UUID; -import java.util.stream.Collectors; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import javax.imageio.ImageIO; import org.apache.commons.codec.digest.DigestUtils; import org.apache.tika.Tika; +import org.genesys.filerepository.FolderNotEmptyException; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; +import org.genesys.filerepository.model.QRepositoryFile; +import org.genesys.filerepository.model.QRepositoryFolder; import org.genesys.filerepository.model.RepositoryFile; +import org.genesys.filerepository.model.RepositoryFolder; import org.genesys.filerepository.model.RepositoryImage; import org.genesys.filerepository.persistence.RepositoryFilePersistence; +import org.genesys.filerepository.persistence.RepositoryFolderRepository; import org.genesys.filerepository.persistence.RepositoryImagePersistence; import org.genesys.filerepository.service.BytesStorageService; import org.genesys.filerepository.service.RepositoryService; @@ -46,16 +51,21 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Pageable; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -// TODO: Auto-generated Javadoc +import com.google.common.collect.Lists; +import com.querydsl.core.types.dsl.BooleanExpression; + /** * The RepositoryServiceImpl implementation. */ +/** + * @author Matija Obreza + * + */ @Service @Transactional(readOnly = true) public class RepositoryServiceImpl implements RepositoryService, InitializingBean { @@ -63,6 +73,10 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea /** The Constant LOG. */ private final static Logger LOG = LoggerFactory.getLogger(RepositoryServiceImpl.class); + /** The folder repository. */ + @Autowired + private RepositoryFolderRepository folderRepository; + /** The repository file persistence. */ @Autowired private RepositoryFilePersistence repositoryFilePersistence; @@ -83,6 +97,13 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea public void afterPropertiesSet() throws Exception { addMissingHashSums(); } + + private T lazyLoad(T repositoryFile) { + if (repositoryFile != null) { + repositoryFile.getFolder().getId(); + } + return repositoryFile; + } /** * Just in case. @@ -94,7 +115,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea LOG.debug("Updating SHA-1 and MD5 for file uuid={}", repositoryFile.getUuid()); } try { - final byte[] bytes = getFileBytes(repositoryFile.getPath(), repositoryFile.getFilename()); + final byte[] bytes = getFileBytes(repositoryFile.getFolder().getFolderPath().resolve(repositoryFile.getFilename())); repositoryFile.setSha1Sum(DigestUtils.sha1Hex(bytes)); repositoryFile.setMd5Sum(DigestUtils.md5Hex(bytes)); repositoryFilePersistence.save(repositoryFile); @@ -113,7 +134,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea @Override @Transactional(rollbackFor = Throwable.class) @PreAuthorize("isAuthenticated()") - public RepositoryFile addFile(final String repositoryPath, final String originalFilename, String contentType, final byte[] bytes, final RepositoryFile metaData) + public RepositoryFile addFile(final Path repositoryPath, final String originalFilename, String contentType, final byte[] bytes, final RepositoryFile metaData) throws InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { PathValidator.checkValidPath(repositoryPath); @@ -141,7 +162,9 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea repositoryFile.setMd5Sum(DigestUtils.md5Hex(bytes)); repositoryFile.setSize(bytes.length); - repositoryFile.setPath(repositoryPath); + RepositoryFolder repositoryFolder = ensureFolder(repositoryPath); + repositoryFile.setFolder(repositoryFolder); + repositoryFile.setOriginalFilename(originalFilename); repositoryFile.setContentType(contentType); @@ -152,7 +175,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea repositoryFile = repositoryFilePersistence.save(repositoryFile); try { - bytesStorageService.upsert(repositoryFile.getStoragePath(), repositoryFile.getFilename(), bytes); + bytesStorageService.upsert(repositoryFile.getStorageFullPath(), bytes); } catch (final IOException e) { if (LOG.isDebugEnabled()) { LOG.debug("Failed to upload bytes", e); @@ -172,7 +195,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea @Override @Transactional(rollbackFor = Throwable.class) @PreAuthorize("isAuthenticated()") - public RepositoryImage addImage(final String repositoryPath, final String originalFilename, String contentType, final byte[] bytes, final RepositoryImage metaData) + public RepositoryImage addImage(final Path repositoryPath, final String originalFilename, String contentType, final byte[] bytes, final RepositoryImage metaData) throws InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { PathValidator.checkValidPath(repositoryPath); @@ -194,7 +217,9 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea repositoryImage.setMd5Sum(DigestUtils.md5Hex(bytes)); repositoryImage.setSize(bytes.length); - repositoryImage.setPath(repositoryPath); + RepositoryFolder repositoryFolder = ensureFolder(repositoryPath); + repositoryImage.setFolder(repositoryFolder); + repositoryImage.setOriginalFilename(originalFilename); repositoryImage.setContentType(contentType); @@ -203,7 +228,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea repositoryImage = repositoryImagePersistence.save(repositoryImage); try { - bytesStorageService.upsert(repositoryImage.getStoragePath(), repositoryImage.getFilename(), bytes); + bytesStorageService.upsert(repositoryImage.getStorageFullPath(), bytes); } catch (final IOException e) { if (LOG.isDebugEnabled()) { LOG.debug("Failed to upload bytes", e); @@ -242,7 +267,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea public RepositoryFile getFile(final UUID fileUuid) throws NoSuchRepositoryFileException { RepositoryFile file = repositoryFilePersistence.findByUuid(fileUuid); if (file != null) { - return file; + return lazyLoad(file); } file = repositoryImagePersistence.findByUuid(fileUuid); @@ -251,9 +276,15 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea throw new NoSuchRepositoryFileException(); } - return file; + return lazyLoad(file); } + /* + * (non-Javadoc) + * @see + * org.genesys.filerepository.service.RepositoryService#getFile(java.util.UUID, + * int) + */ @SuppressWarnings("unchecked") @Override @PostAuthorize("hasRole('ADMINISTRATOR') or hasPermission(returnObject, 'read')") @@ -279,11 +310,17 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea */ @Override @PostAuthorize("hasRole('ADMINISTRATOR') or hasPermission(returnObject, 'read')") - public RepositoryFile getFile(final String path, final String originalFilename) throws NoSuchRepositoryFileException { - final RepositoryFile repositoryFile = repositoryFilePersistence.findByPathAndOriginalFilename(path, originalFilename); + public RepositoryFile getFile(final Path path, final String originalFilename) throws NoSuchRepositoryFileException { + RepositoryFolder folder = folderRepository.findByPath(path.toString()); + if (folder == null) { + throw new NoSuchRepositoryFileException("No file at path=" + path + " originalFilename=" + originalFilename); + } + + final RepositoryFile repositoryFile = repositoryFilePersistence.findByFolderAndOriginalFilename(folder, originalFilename); if (repositoryFile == null) { throw new NoSuchRepositoryFileException("No file at path=" + path + " originalFilename=" + originalFilename); } + return repositoryFile; } @@ -293,11 +330,11 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea * (java.lang.String, java.lang.String) */ @Override - public byte[] getFileBytes(final String storagePath, final String filename) throws NoSuchRepositoryFileException { + public byte[] getFileBytes(final Path filePath) throws NoSuchRepositoryFileException { byte[] data = null; try { - data = bytesStorageService.get(storagePath, filename); + data = bytesStorageService.get(filePath); } catch (final IOException e) { e.printStackTrace(); } @@ -314,25 +351,57 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea @Override @PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#repositoryFile, 'read')") public byte[] getFileBytes(final RepositoryFile repositoryFile) throws IOException { - return bytesStorageService.get(repositoryFile.getStoragePath(), repositoryFile.getFilename()); + return bytesStorageService.get(repositoryFile.getStorageFullPath()); + } + + /* + * (non-Javadoc) + * @see + * org.genesys.filerepository.service.RepositoryService#getFiles(java.nio.file. + * Path) + */ + @Override + public List getFiles(Path folderPath) { + RepositoryFolder folder = getFolder(folderPath); + if (folder == null) { + return Collections.emptyList(); + } + return (List) repositoryFilePersistence.findAll(QRepositoryFile.repositoryFile.folder.eq(folder)); } /* * (non-Javadoc) - * @see org.genesys.filerepository.service.RepositoryService#getFiles( - * java.lang.String) + * @see + * org.genesys.filerepository.service.RepositoryService#getFolders(java.nio.file + * .Path) */ @Override - public List getFiles(final String repositoryPath) { - final List repositoryFiles = new ArrayList<>(); - repositoryFiles.addAll(repositoryFilePersistence.findByPath(repositoryPath)); + public List getFolders(Path root) { + if (root == null || "/".equals(root.normalize().toAbsolutePath().toString())) { + return (List) folderRepository.findAll(QRepositoryFolder.repositoryFolder.parent.isNull()); + } else { + RepositoryFolder parent = getFolder(root); + return parent == null ? Collections.emptyList() : + // Load child folders + (List) folderRepository.findAll(QRepositoryFolder.repositoryFolder.parent.eq(parent)); + } + } - return repositoryFiles; + @Override + public RepositoryFolder getFolder(Path folderPath) { + return folderRepository.findByPath(folderPath.normalize().toAbsolutePath().toString()); } + /* + * (non-Javadoc) + * @see + * org.genesys.filerepository.service.RepositoryService#streamFiles(java.nio. + * file.Path) + */ @Override - public Stream streamFiles(String repositoryPath) { - return repositoryFilePersistence.streamByBasePath(repositoryPath); + public Stream streamFiles(Path root) throws InvalidRepositoryPathException { + BooleanExpression q = QRepositoryFile.repositoryFile.folder.in(listPaths(root)); + return StreamSupport.stream(repositoryFilePersistence.findAll(q).spliterator(), false); } /* @@ -356,7 +425,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea repositoryFile.apply(fileData); repositoryFile = repositoryFilePersistence.save(repositoryFile); - return (T) repositoryFile; + return (T) lazyLoad(repositoryFile); } /* @@ -391,7 +460,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea @PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#repositoryFile, 'write')") public T updateBytes(final T repositoryFile, String contentType, final byte[] bytes) throws NoSuchRepositoryFileException, IOException { T storedFile = getFile(repositoryFile.getUuid(), repositoryFile.getVersion()); - + if (storedFile == null) { throw new NoSuchRepositoryFileException(); } @@ -409,7 +478,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea LOG.debug("updateByes length={} repoFile.size={}", bytes.length, repositoryFile.getSize()); storedFile.setContentType(contentType); - bytesStorageService.upsert(storedFile.getStoragePath(), storedFile.getFilename(), bytes); + bytesStorageService.upsert(storedFile.getStorageFullPath(), bytes); return repositoryFilePersistence.save(storedFile); } @@ -438,7 +507,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea fillImageProperties(storedFile, bytes); - bytesStorageService.upsert(storedFile.getStoragePath(), storedFile.getFilename(), bytes); + bytesStorageService.upsert(storedFile.getStorageFullPath(), bytes); return repositoryImagePersistence.save(storedFile); } @@ -480,7 +549,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea return removeImage((RepositoryImage) repositoryFile); } - bytesStorageService.remove(repositoryFile.getStoragePath(), repositoryFile.getFilename()); + bytesStorageService.remove(repositoryFile.getStorageFullPath()); repositoryFilePersistence.delete(repositoryFile); return repositoryFile; } @@ -499,7 +568,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea throw new NoSuchRepositoryFileException(); } - bytesStorageService.remove(repositoryImage.getStoragePath(), repositoryImage.getFilename()); + bytesStorageService.remove(repositoryImage.getStorageFullPath()); repositoryImagePersistence.delete(repositoryImage); return repositoryImage; } @@ -512,15 +581,19 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea @Override @Transactional @PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#repositoryFile, 'write')") - public RepositoryFile moveFile(final RepositoryFile repositoryFile, final String newPath) throws NoSuchRepositoryFileException, InvalidRepositoryPathException { + public RepositoryFile moveFile(final RepositoryFile repositoryFile, final Path destination) throws NoSuchRepositoryFileException, InvalidRepositoryPathException { + if (destination == null) { + throw new InvalidRepositoryPathException("destination cannot be null"); + } - PathValidator.checkValidPath(newPath); + PathValidator.checkValidPath(destination); if (repositoryFile == null) { throw new NoSuchRepositoryFileException(); } - repositoryFile.setPath(newPath); + RepositoryFolder repositoryFolder = ensureFolder(destination); + repositoryFile.setFolder(repositoryFolder); RepositoryFile file; if (repositoryFile.getContentType().startsWith("image")) { @@ -541,21 +614,21 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea @Override @Transactional @PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#repositoryFile, 'write')") - public RepositoryFile moveAndRenameFile(final RepositoryFile repositoryFile, final String fullPath) throws InvalidRepositoryPathException, InvalidRepositoryFileDataException { + public RepositoryFile moveAndRenameFile(final RepositoryFile repositoryFile, final Path fullPath) throws InvalidRepositoryPathException, InvalidRepositoryFileDataException { if (fullPath == null) { throw new NullPointerException("Full path cannot be null"); } - LOG.info("Moving path={} name={} to {}", repositoryFile.getPath(), repositoryFile.getFilename(), fullPath); + LOG.info("Moving path={} name={} to {}", repositoryFile.getFolder(), repositoryFile.getFilename(), fullPath); - final Path path = Paths.get(fullPath).normalize().toAbsolutePath(); + final Path path = fullPath.normalize().toAbsolutePath(); PathValidator.checkValidPath(path.getParent().toString()); if (path.getFileName().toString().trim().length() == 0) { throw new InvalidRepositoryFileDataException("File name cannot be blank"); } - repositoryFile.setPath(path.getParent().toString()); + repositoryFile.setFolder(ensureFolder(path.getParent())); repositoryFile.setOriginalFilename(path.getFileName().toString()); if (repositoryFile instanceof RepositoryImage) { @@ -588,7 +661,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea result.setExtent(source.getExtent()); result.setLastModifiedDate(source.getLastModifiedDate()); result.setLicense(source.getLicense()); - result.setPath(source.getPath()); + result.setFolder(source.getFolder()); result.setRightsHolder(source.getRightsHolder()); result.setSubject(source.getSubject()); result.setTitle(source.getTitle()); @@ -603,8 +676,8 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea * String) */ @Override - public List listImages(final String repositoryPath) { - return repositoryImagePersistence.findByPath(repositoryPath); + public List listImages(final Path repositoryPath) { + return repositoryImagePersistence.findByFolder(folderRepository.findByPath(repositoryPath.normalize().toAbsolutePath().toString())); } /* @@ -618,16 +691,7 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea final String p = path.normalize().toAbsolutePath().toString(); PathValidator.checkValidPath(p); LOG.trace("Is directory path={}", p); - if (repositoryFilePersistence.countByPath(p) > 0) { - // Exact match - LOG.trace("Yes, hasPath {}", p); - return true; - } else { - // Any files within the specified parent - final List x = repositoryFilePersistence.listDistinctPaths(p); - LOG.trace("Testing hasPath within {}: {}", p, x); - return x.size() > 0; - } + return folderRepository.exists(QRepositoryFolder.repositoryFolder.path.eq(p)); } /* @@ -637,62 +701,123 @@ public class RepositoryServiceImpl implements RepositoryService, InitializingBea * String) */ @Override - public List listPaths(final String prefix, final Pageable pageable) throws InvalidRepositoryPathException { + public List listPaths(final Path prefix) throws InvalidRepositoryPathException { PathValidator.checkValidPath(prefix); + ArrayList folders = new ArrayList<>(); - // note the trailing slash - final String prefixSlash = "/".equals(prefix) ? prefix : prefix + "/"; - LOG.debug("Listing paths under prefix={} page={}", prefix, pageable); + RepositoryFolder rootFolder = folderRepository.findByPath(prefix.normalize().toAbsolutePath().toString()); + if (rootFolder != null) { + folders.add(rootFolder); + addAllSubfolders(rootFolder, folders); + } + return folders; + } - final List paths = repositoryFilePersistence.listDistinctPaths(prefix, pageable).stream().filter(path -> { - return path.startsWith(prefixSlash) || path.equals(prefix); - }).collect(Collectors.toList()); - LOG.trace("Paths under prefix={}: {}", prefix, paths); - return paths; + /** + * Recursively Adds the all subfolders to the list + * + * @param folder the root folder + * @param folders the folders + */ + private void addAllSubfolders(RepositoryFolder folder, ArrayList folders) { + if (folder != null && folder.getChildren() != null) { + for (RepositoryFolder ch : folder.getChildren()) { + folders.add(ch); + addAllSubfolders(ch, folders); + } + } } /* * (non-Javadoc) * @see - * org.genesys.filerepository.service.RepositoryService#listPaths(java.lang. - * String) + * org.genesys.filerepository.service.RepositoryService#renamePath(java.lang. + * String, java.lang.String) */ @Override - public List listPaths(final String prefix) throws InvalidRepositoryPathException { - PathValidator.checkValidPath(prefix); + @Transactional + public RepositoryFolder renamePath(final Path currentPath, final Path newPath) throws InvalidRepositoryPathException { + final Path cPath = currentPath.normalize().toAbsolutePath(); + final Path nPath = newPath.normalize().toAbsolutePath(); + PathValidator.checkValidPath(cPath.toString()); + PathValidator.checkValidPath(nPath.toString()); + + RepositoryFolder target = folderRepository.findByPath(nPath.toString()); + if (target != null) { + throw new InvalidRepositoryPathException("Folder with this name already exists. Path was " + nPath); + } + + for (final RepositoryFolder folder : Lists.reverse(listPaths(currentPath))) { + final Path folderPath = folder.getFolderPath(); + final Path relative = cPath.relativize(folderPath); + + LOG.debug("Base={} rfPath={} relative={} to={}", cPath, folderPath, relative, nPath.resolve(relative)); + + final RepositoryFolder newFolder = ensureFolder(nPath.resolve(relative).toAbsolutePath()); + for (final RepositoryFile repositoryFile : folder.getFiles()) { + repositoryFile.setFolder(newFolder); + repositoryFilePersistence.save(repositoryFile); + } - // note the trailing slash - final String prefixSlash = "/".equals(prefix) ? prefix : prefix + "/"; - LOG.debug("Listing paths under prefix={}", prefix); + LOG.debug("Deleting folder {}", folder); + folderRepository.delete(folder); + } - final List paths = repositoryFilePersistence.listDistinctPaths(prefix).stream().filter(path -> { - return path.startsWith(prefixSlash) || path.equals(prefix); - }).collect(Collectors.toList()); - LOG.trace("Paths under prefix={}: {}", prefix, paths); - return paths; + return folderRepository.findByPath(nPath.toString()); } /* * (non-Javadoc) * @see - * org.genesys.filerepository.service.RepositoryService#renamePath(java.lang. - * String, java.lang.String) + * org.genesys.filerepository.service.RepositoryService#addFolder(java.nio.file. + * Path) */ @Override @Transactional - public void renamePath(final String currentPath, final String newPath) throws InvalidRepositoryPathException { - PathValidator.checkValidPath(currentPath); - PathValidator.checkValidPath(newPath); - final Path cPath = Paths.get(currentPath); - final Path nPath = Paths.get(newPath); + public RepositoryFolder ensureFolder(Path folderPath) throws InvalidRepositoryPathException { + folderPath = folderPath.normalize().toAbsolutePath(); + PathValidator.checkValidPath(folderPath.toString()); + + if ("/".equals(folderPath.toString())) { + // Root folder + return null; + } else { + PathValidator.checkValidFolderName(folderPath.getFileName().toString()); + } + + RepositoryFolder folder = folderRepository.findByPath(folderPath.toString()); + + if (folder == null) { + folder = new RepositoryFolder(); + folder.setName(folderPath.getFileName().toString()); + if (folderPath.getParent() != null) { + folder.setParent(ensureFolder(folderPath.getParent())); + } + folderRepository.save(folder); + } - for (final RepositoryFile repositoryFile : repositoryFilePersistence.findByPath(listPaths(currentPath))) { - final Path rfPath = Paths.get(repositoryFile.getPath()); - final Path relative = cPath.relativize(rfPath); + return folder; + } + + /* + * (non-Javadoc) + * @see + * org.genesys.filerepository.service.RepositoryService#deleteFolder(java.nio. + * file.Path) + */ + @Override + @Transactional + public RepositoryFolder deleteFolder(Path path) throws FolderNotEmptyException { + final Path cPath = path.normalize().toAbsolutePath(); + + RepositoryFolder folder = folderRepository.findByPath(cPath.toString()); + if (folder != null) { + if (folder.getChildren().size() > 0 || folder.getFiles().size() > 0) { + throw new FolderNotEmptyException("Folder " + path.toString() + " is not empty."); + } - LOG.debug("Base={} rfPath={} relative={} to={}", cPath, rfPath, relative, nPath.resolve(relative)); - repositoryFile.setPath(nPath.resolve(relative).toAbsolutePath().toString()); - repositoryFilePersistence.save(repositoryFile); + folderRepository.delete(folder); } + return folder; } } diff --git a/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/S3StorageServiceImpl.java b/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/S3StorageServiceImpl.java index 199b594c0d493a060bf4297095622536eac1bb5f..5e8fc16d8378c64c48302e74920d5a078c3c9ee6 100644 --- a/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/S3StorageServiceImpl.java +++ b/file-repository-core/src/main/java/org/genesys/filerepository/service/impl/S3StorageServiceImpl.java @@ -21,6 +21,8 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -38,8 +40,6 @@ import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; -import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; - import org.apache.commons.lang3.StringUtils; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.service.BytesStorageService; @@ -59,6 +59,8 @@ import org.springframework.stereotype.Service; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; + /** * Amazon S3 storage implementation. */ @@ -110,10 +112,15 @@ public class S3StorageServiceImpl implements BytesStorageService, InitializingBe /** The prefix. */ @Value("${s3.prefix}") private String prefix; + + // We use this handle the prefix + private Path awsBasePath; @Override public void afterPropertiesSet() throws Exception { - LOG.warn("S3 region={} bucket={} prefix={} dummy={}", region, bucket, prefix, getUrl("/dummy", "filename.txt")); + this.awsBasePath = Paths.get(StringUtils.defaultIfBlank(this.prefix, "/")); + + LOG.warn("S3 region={} bucket={} prefix={} dummy={}", region, bucket, prefix, getAwsUrl(Paths.get("/dummy", "filename.txt"))); } /* @@ -122,25 +129,18 @@ public class S3StorageServiceImpl implements BytesStorageService, InitializingBe * (java.lang.String, java.lang.String, byte[]) */ @Override - public void upsert(final String path, final String filename, final byte[] data) throws FileNotFoundException, IOException { - - if (!PathValidator.isValidPath(path)) { - throw new IOException("Path is not valid. Path was " + path); - } - - if (filename == null) { - throw new IOException("File name is null"); - } + public void upsert(final Path bytesFile, final byte[] data) throws FileNotFoundException, IOException { + final Path normalPath = bytesFile.normalize().toAbsolutePath(); if (data == null) { throw new IOException("File bytes are null"); } if (LOG.isDebugEnabled()) { - LOG.debug("Putting to path={} filename={} len={}", path, filename, data.length); + LOG.debug("Putting to path={} len={}", bytesFile, data.length); } - final String url = getUrl(path, filename); + final String url = getAwsUrl(normalPath); try { restTemplate.put(url, data); } catch (final HttpClientErrorException e) { @@ -155,19 +155,13 @@ public class S3StorageServiceImpl implements BytesStorageService, InitializingBe * (java.lang.String, java.lang.String) */ @Override - public void remove(final String path, final String filename) throws IOException { - if (!PathValidator.isValidPath(path)) { - throw new IOException("Path is not valid"); - } - - if (filename == null) { - throw new IOException("File name is null"); - } + public void remove(final Path bytesFile) throws IOException { + final Path normalPath = bytesFile.normalize().toAbsolutePath(); - final String url = getUrl(path, filename); + final String url = getAwsUrl(normalPath); if (LOG.isDebugEnabled()) { - LOG.debug("Deleting from path={} filename={} url={}", path, filename, url); + LOG.debug("Deleting from path={} url={}", normalPath, url); } try { @@ -184,19 +178,13 @@ public class S3StorageServiceImpl implements BytesStorageService, InitializingBe * .lang.String, java.lang.String) */ @Override - public byte[] get(final String path, final String filename) throws IOException { - if (!PathValidator.isValidPath(path)) { - throw new IOException("Path is not valid"); - } - - if (!FilenameValidator.isValidFilename(filename)) { - throw new IOException("File name is not valid: " + filename); - } - + public byte[] get(final Path bytesFile) throws IOException { + final Path normalPath = bytesFile.normalize().toAbsolutePath(); + if (LOG.isDebugEnabled()) { - LOG.debug("Getting bytes path={} filename={}", path, filename); + LOG.debug("Getting bytes path={} filename={}", normalPath.getParent().toString(), normalPath.getFileName().toString()); } - final String url = getUrl(path, filename); + final String url = getAwsUrl(normalPath); try { return restTemplate.getForObject(url, byte[].class); @@ -209,14 +197,14 @@ public class S3StorageServiceImpl implements BytesStorageService, InitializingBe /** * Returns URL for S3 resource. * - * @param path the path + * @param path the normalized absolute path * @param filename the filename * @return the url */ - private String getUrl(final String path, final String filename) { - final String url = String.format("https://%s%s", getHost(), getPath(path) + startWithSlash(filename)); + private String getAwsUrl(final Path bytesFile) { + final String url = String.format("https://%s%s", getHost(), getAwsPath(bytesFile)); if (LOG.isTraceEnabled()) { - LOG.trace("getUrl path={} filename={} result={}", path, filename, url); + LOG.trace("getUrl path={} result={}", bytesFile, url); } return url; } @@ -227,26 +215,8 @@ public class S3StorageServiceImpl implements BytesStorageService, InitializingBe * @param path the path * @return the path */ - private String getPath(final String path) { - String result; - if (StringUtils.isEmpty(prefix)) { - result = startWithSlash(path); - } else { - result = prefix + startWithSlash(path); - } - return startWithSlash(result); - } - - private String startWithSlash(String path) { - if (path == null) - return ""; - - path = path.trim(); - if (path.length() == 0) { - return ""; - } else { - return path.charAt(0) == '/' ? path : "/" + path; - } + private String getAwsPath(final Path path) { + return Paths.get(awsBasePath.toString(), path.toString()).normalize().toAbsolutePath().toString(); } /** @@ -518,17 +488,14 @@ public class S3StorageServiceImpl implements BytesStorageService, InitializingBe * @throws InvalidRepositoryPathException when path or filename are weird */ @Override - public boolean exists(final String path, final String filename) throws IOException, InvalidRepositoryPathException { - PathValidator.checkValidPath(path); - if (!FilenameValidator.isValidFilename(filename)) { - throw new InvalidRepositoryPathException("Filename is not valid: " + filename); - } + public boolean exists(final Path bytesFile) throws IOException, InvalidRepositoryPathException { + final Path normalPath = bytesFile.normalize().toAbsolutePath(); try { if (LOG.isTraceEnabled()) { - LOG.trace("Fetching HEAD for url={}", getUrl(path, filename)); + LOG.trace("Fetching HEAD for url={}", getAwsUrl(normalPath)); } - final HttpHeaders headers = restTemplate.headForHeaders(getUrl(path, filename)); + final HttpHeaders headers = restTemplate.headForHeaders(getAwsUrl(normalPath)); if (LOG.isDebugEnabled()) { headers.forEach((header, values) -> { LOG.debug("{}: {}", header, values); @@ -558,11 +525,11 @@ public class S3StorageServiceImpl implements BytesStorageService, InitializingBe * @throws InvalidRepositoryPathException when path is messed up */ @Override - public List listFiles(final String path) throws InvalidRepositoryPathException { + public List listFiles(final Path path) throws InvalidRepositoryPathException { PathValidator.checkValidPath(path); - final String s3prefix = getPath(path).substring(1); + final String s3prefix = getAwsPath(path).substring(1); LOG.debug("Listing S3 bucket for host={} path={} prefix={}", getHost(), path, s3prefix); try { diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/config/ServiceBeanConfig.java b/file-repository-core/src/test/java/org/genesys/filerepository/config/ServiceBeanConfig.java index 6dadd2e324845e041135e36750a37f003575bddb..3f406c492260645110ec09d5f675d20eb0f1e4a2 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/config/ServiceBeanConfig.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/config/ServiceBeanConfig.java @@ -18,6 +18,7 @@ package org.genesys.filerepository.config; import java.io.File; +import org.apache.commons.io.FileUtils; import org.genesys.filerepository.service.BytesStorageService; import org.genesys.filerepository.service.ImageGalleryService; import org.genesys.filerepository.service.RepositoryService; @@ -30,6 +31,8 @@ import org.genesys.filerepository.service.impl.ImageGalleryServiceImpl; import org.genesys.filerepository.service.impl.RepositoryServiceImpl; import org.genesys.filerepository.service.impl.S3StorageServiceImpl; import org.genesys.filerepository.service.impl.ThumbnailGenerator1; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -45,7 +48,23 @@ import org.springframework.core.io.Resource; @Configuration // Needed for ImageGalleryAspects @EnableAspectJAutoProxy -public class ServiceBeanConfig { +public class ServiceBeanConfig implements InitializingBean, DisposableBean { + + File fileRepositoryFolder; + + @Override + public void afterPropertiesSet() throws Exception { + this.fileRepositoryFolder = new File(FileUtils.getTempDirectory(), "file-repo-" + System.currentTimeMillis()); + assert(this.fileRepositoryFolder.exists() == false); + this.fileRepositoryFolder.mkdirs(); + } + + @Override + public void destroy() throws Exception { + System.err.println("Deleting " + fileRepositoryFolder.getAbsolutePath()); + FileUtils.deleteDirectory(this.fileRepositoryFolder); + assert(this.fileRepositoryFolder.exists() == false); + } /** * Property placeholder configurer. @@ -71,9 +90,8 @@ public class ServiceBeanConfig { */ @Bean(name = "bytesStorageService") public BytesStorageService bytesStorageService() { - final File repoDir = new File("data"); final FilesystemStorageServiceImpl storageService = new FilesystemStorageServiceImpl(); - storageService.setRepositoryBaseDirectory(repoDir); + storageService.setRepositoryBaseDirectory(fileRepositoryFolder); return storageService; } @@ -147,4 +165,5 @@ public class ServiceBeanConfig { public ThumbnailGenerator thumbnailGenerator() { return new ThumbnailGenerator1(); } + } diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryAddTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryAddTest.java index d6fe95dd0b180bd282f276a92ae0a2f8aa9a11d8..5a3361493ab545a8ce8543c4ab76e571ea6002c2 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryAddTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryAddTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2018 Global Crop Diversity Trust + * Copyright 2017 Global Crop Diversity Trust * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,35 +16,27 @@ package org.genesys.filerepository.service; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Random; import org.apache.commons.codec.digest.DigestUtils; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; -import org.genesys.filerepository.config.DatabaseConfig; -import org.genesys.filerepository.config.ServiceBeanConfig; import org.genesys.filerepository.model.RepositoryFile; import org.junit.Test; -import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; // TODO: Auto-generated Javadoc /** * The Class FileRepositoryAddTest. */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { ServiceBeanConfig.class, DatabaseConfig.class }) -public class FileRepositoryAddTest { +public class FileRepositoryAddTest extends RepositoryServiceTest { /** The Constant SOME_BYTES. */ private static final byte[] SOME_BYTES = "filecontents".getBytes(); @@ -53,7 +45,7 @@ public class FileRepositoryAddTest { private static final byte[] EMPTY_BYTES = new byte[0]; /** The Constant PATH. */ - private final static String PATH = "/temp/" + System.currentTimeMillis(); + private final static Path PATH = Paths.get("/temp", "" + System.currentTimeMillis()); /** The Constant DEFAULT_EXT. */ private static final String DEFAULT_EXT = ".txt"; @@ -63,7 +55,7 @@ public class FileRepositoryAddTest { /** The file repo service. */ @Autowired - private RepositoryService fileRepoService; + private RepositoryService repositoryService; /** * Test basic submission to file repository. @@ -71,7 +63,7 @@ public class FileRepositoryAddTest { * @throws InvalidRepositoryPathException the invalid repository path exception * @throws InvalidRepositoryFileDataException the invalid repository file data * exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ @Test public void addFile() throws InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { @@ -79,7 +71,7 @@ public class FileRepositoryAddTest { final String extension = ".txt"; final String originalFilename = "requirements" + extension; - final RepositoryFile repoFile = fileRepoService.addFile(PATH, originalFilename, contentType, SOME_BYTES, null); + final RepositoryFile repoFile = repositoryService.addFile(PATH, originalFilename, contentType, SOME_BYTES, null); assertThat(repoFile.getSize(), is(SOME_BYTES.length)); FileRepositoryTestUtil.checkFile(repoFile, PATH, originalFilename, extension, contentType); @@ -91,11 +83,11 @@ public class FileRepositoryAddTest { * @throws InvalidRepositoryPathException the invalid repository path exception * @throws InvalidRepositoryFileDataException the invalid repository file data * exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ @Test public void addFileWithMetadata() throws InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { - final String path = "/test1/test2"; + final Path path = Paths.get("/test1/test2"); final String contentType = "text/plain;charset=UTF-8"; final String extension = ".txt"; final String originalFilename = "requirements" + extension; @@ -134,7 +126,7 @@ public class FileRepositoryAddTest { fileData.setSubject(subject); fileData.setTitle(title); - final RepositoryFile repoFile = fileRepoService.addFile(path, originalFilename, contentType, SOME_BYTES, fileData); + final RepositoryFile repoFile = repositoryService.addFile(path, originalFilename, contentType, SOME_BYTES, fileData); FileRepositoryTestUtil.checkFile(repoFile, path, originalFilename, extension, contentType); FileRepositoryTestUtil.checkMetadata(repoFile, bibliographicCitation, accessRights, created, creator, description, extent, license, rightsHolder, subject, title); @@ -146,11 +138,11 @@ public class FileRepositoryAddTest { * @throws InvalidRepositoryFileDataException the invalid repository file data * exception * @throws InvalidRepositoryPathException the invalid repository path exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ @Test(expected = InvalidRepositoryFileDataException.class) public void invalidMissingOriginalFilename() throws InvalidRepositoryFileDataException, InvalidRepositoryPathException, IOException { - fileRepoService.addFile("/valid/path", null, "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); + repositoryService.addFile(Paths.get("/valid/path"), null, "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); } /** @@ -159,11 +151,11 @@ public class FileRepositoryAddTest { * @throws InvalidRepositoryFileDataException the invalid repository file data * exception * @throws InvalidRepositoryPathException the invalid repository path exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ @Test public void defaultContentType() throws InvalidRepositoryFileDataException, InvalidRepositoryPathException, IOException { - final RepositoryFile f = fileRepoService.addFile("/valid/path", "orignalFilename.txt", null, FileRepositoryAddTest.EMPTY_BYTES, null); + final RepositoryFile f = repositoryService.addFile(Paths.get("/valid/path"), "orignalFilename.txt", null, FileRepositoryAddTest.EMPTY_BYTES, null); assertThat(f.getContentType(), is("application/octet-stream")); } @@ -173,11 +165,11 @@ public class FileRepositoryAddTest { * @throws InvalidRepositoryFileDataException the invalid repository file data * exception * @throws InvalidRepositoryPathException the invalid repository path exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ @Test(expected = InvalidRepositoryFileDataException.class) public void invalidMissingBytes() throws InvalidRepositoryFileDataException, InvalidRepositoryPathException, IOException { - fileRepoService.addFile("/valid/path", "orignalFilename.txt", "contentType", null, null); + repositoryService.addFile(Paths.get("/valid/path"), "orignalFilename.txt", "contentType", null, null); } /** @@ -187,11 +179,11 @@ public class FileRepositoryAddTest { * @throws InvalidRepositoryPathException the invalid repository path exception * @throws InvalidRepositoryFileDataException the invalid repository file data * exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ @Test(expected = InvalidRepositoryPathException.class) public void invalidAddNullPath() throws NoSuchRepositoryFileException, InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { - fileRepoService.addFile(null, "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); + repositoryService.addFile(null, "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); } /** @@ -201,11 +193,11 @@ public class FileRepositoryAddTest { * @throws InvalidRepositoryPathException the invalid repository path exception * @throws InvalidRepositoryFileDataException the invalid repository file data * exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ @Test(expected = InvalidRepositoryPathException.class) public void invalidAddBlankPath() throws NoSuchRepositoryFileException, InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { - fileRepoService.addFile(" ", "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); + repositoryService.addFile(Paths.get(" "), "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); } /** @@ -215,11 +207,11 @@ public class FileRepositoryAddTest { * @throws InvalidRepositoryPathException the invalid repository path exception * @throws InvalidRepositoryFileDataException the invalid repository file data * exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ - @Test(expected = InvalidRepositoryPathException.class) + @Test // No longer (expected = InvalidRepositoryPathException.class) public void invalidAddDoubleSlashPath() throws NoSuchRepositoryFileException, InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { - fileRepoService.addFile("/double//slash/", "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); + repositoryService.addFile(Paths.get("/double//slash/"), "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); } /** @@ -228,43 +220,29 @@ public class FileRepositoryAddTest { * @throws InvalidRepositoryPathException the invalid repository path exception * @throws InvalidRepositoryFileDataException the invalid repository file data * exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ - @Test(expected = InvalidRepositoryPathException.class) + @Test // no longer (expected = InvalidRepositoryPathException.class) public void invalidAddMissingStartSlash() throws InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { - fileRepoService.addFile("invalidpath/here/", "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); - } - - /** - * Path must end with / test. - * - * @throws NoSuchRepositoryFileException the no such repository file exception - * @throws InvalidRepositoryPathException the invalid repository path exception - * @throws InvalidRepositoryFileDataException the invalid repository file data - * exception - * @throws IOException Signals that an I/O exception has occurred. - */ - @Test(expected = InvalidRepositoryPathException.class) - public void invalidAddMissingEndSlash() throws NoSuchRepositoryFileException, InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { - fileRepoService.addFile("/invalidpath/here/", "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); + repositoryService.addFile(Paths.get("invalidpath/here/"), "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); } /** - * Path can contain spaces. + * Path can contain spaces * * @throws NoSuchRepositoryFileException the no such repository file exception * @throws InvalidRepositoryPathException the invalid repository path exception * @throws InvalidRepositoryFileDataException the invalid repository file data * exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ @Test public void validSpacesInPath() throws NoSuchRepositoryFileException, InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { for (final String validPath : new String[] { "/valid/he re", "/va lid/her e", "/va lid/e", "/va lid/1 e" }) { try { - final RepositoryFile repoFile = fileRepoService.addFile(validPath, "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); - fileRepoService.removeFile(repoFile); + final RepositoryFile repoFile = repositoryService.addFile(Paths.get(validPath), "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); + repositoryService.removeFile(repoFile); } catch (final InvalidRepositoryPathException e) { fail("Repository must allow for path=" + validPath); } @@ -272,41 +250,40 @@ public class FileRepositoryAddTest { } /** - * Path can contain spaces, but not next to /. + * Path can contain spaces, but not next to / * * @throws NoSuchRepositoryFileException the no such repository file exception * @throws InvalidRepositoryPathException the invalid repository path exception * @throws InvalidRepositoryFileDataException the invalid repository file data * exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ @Test(expected = InvalidRepositoryPathException.class) public void invalidSpaceNextToSlashInPath1() throws NoSuchRepositoryFileException, InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { - fileRepoService.addFile("/invalidpath/here /", "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); + repositoryService.addFile(Paths.get("/invalidpath/here /"), "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); } /** - * Path can contain spaces, but not next to /. + * Path can contain spaces, but not next to / * * @throws NoSuchRepositoryFileException the no such repository file exception * @throws InvalidRepositoryPathException the invalid repository path exception * @throws InvalidRepositoryFileDataException the invalid repository file data * exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException */ @Test(expected = InvalidRepositoryPathException.class) public void invalidSpaceNextToSlashInPath2() throws NoSuchRepositoryFileException, InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { - fileRepoService.addFile("/invalidpath/ orhere/", "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); + repositoryService.addFile(Paths.get("/invalidpath/ orhere/"), "originalFilename.txt", "contentType", FileRepositoryAddTest.EMPTY_BYTES, null); } /** - * Check that SHA1 and MD5 sums are generated on add. + * Check that SHA1 and MD5 sums are generated on add * - * @throws InvalidRepositoryPathException the invalid repository path exception - * @throws InvalidRepositoryFileDataException the invalid repository file data - * exception - * @throws NoSuchRepositoryFileException the no such repository file exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws InvalidRepositoryPathException + * @throws InvalidRepositoryFileDataException + * @throws IOException + * @throws NoSuchRepositoryFileException */ @Test public void testSha1AndMd5SumsOnAdd() throws InvalidRepositoryPathException, InvalidRepositoryFileDataException, NoSuchRepositoryFileException, IOException { @@ -316,7 +293,7 @@ public class FileRepositoryAddTest { final Random rnd = new Random(System.currentTimeMillis()); rnd.nextBytes(randomBytes); - final RepositoryFile repositoryFile = fileRepoService.addFile(PATH, DEFAULT_FILENAME, contentType, randomBytes, null); + final RepositoryFile repositoryFile = repositoryService.addFile(PATH, DEFAULT_FILENAME, contentType, randomBytes, null); FileRepositoryTestUtil.checkFile(repositoryFile, PATH, DEFAULT_FILENAME, DEFAULT_EXT, contentType); final String sha1hex = DigestUtils.sha1Hex(randomBytes); @@ -325,30 +302,29 @@ public class FileRepositoryAddTest { assertThat("sha1 does must match", repositoryFile.getSha1Sum(), equalTo(sha1hex)); assertThat("md5 does must match", repositoryFile.getMd5Sum(), equalTo(md5hex)); - fileRepoService.removeFile(repositoryFile); + repositoryService.removeFile(repositoryFile); } /** - * Check that SHA1 and MD5 sums are fixed on update. + * Check that SHA1 and MD5 sums are fixed on update * - * @throws InvalidRepositoryPathException the invalid repository path exception - * @throws InvalidRepositoryFileDataException the invalid repository file data - * exception - * @throws NoSuchRepositoryFileException the no such repository file exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws InvalidRepositoryPathException + * @throws InvalidRepositoryFileDataException + * @throws IOException + * @throws NoSuchRepositoryFileException */ @Test public void testSha1AndMd5SumsOnUpdate() throws InvalidRepositoryPathException, InvalidRepositoryFileDataException, NoSuchRepositoryFileException, IOException { final String contentType = "text/plain;charset=UTF-8"; - RepositoryFile repositoryFile = fileRepoService.addFile(PATH, DEFAULT_FILENAME, contentType, SOME_BYTES, null); + RepositoryFile repositoryFile = repositoryService.addFile(PATH, DEFAULT_FILENAME, contentType, SOME_BYTES, null); FileRepositoryTestUtil.checkFile(repositoryFile, PATH, DEFAULT_FILENAME, DEFAULT_EXT, contentType); final byte[] randomBytes = new byte[100]; final Random rnd = new Random(System.currentTimeMillis()); rnd.nextBytes(randomBytes); - repositoryFile = fileRepoService.updateBytes(repositoryFile, contentType, randomBytes); + repositoryFile = repositoryService.updateBytes(repositoryFile, contentType, randomBytes); FileRepositoryTestUtil.checkFile(repositoryFile, PATH, DEFAULT_FILENAME, DEFAULT_EXT, contentType); final String sha1hex = DigestUtils.sha1Hex(randomBytes); @@ -357,6 +333,6 @@ public class FileRepositoryAddTest { assertThat("sha1 does must match", repositoryFile.getSha1Sum(), equalTo(sha1hex)); assertThat("md5 does must match", repositoryFile.getMd5Sum(), equalTo(md5hex)); - fileRepoService.removeFile(repositoryFile); + repositoryService.removeFile(repositoryFile); } } diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryDirectoryTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryDirectoryTest.java index 263bd34a4f9be79dc45e05bbc53ab5e9ddf39d24..52a004a46f82dec813efbc1c52117d962057864d 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryDirectoryTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryDirectoryTest.java @@ -16,34 +16,28 @@ package org.genesys.filerepository.service; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; -import org.genesys.filerepository.config.DatabaseConfig; -import org.genesys.filerepository.config.ServiceBeanConfig; import org.genesys.filerepository.model.RepositoryFile; +import org.genesys.filerepository.model.RepositoryFolder; import org.junit.Test; -import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.PageRequest; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * Test the folder navigation of the repository. */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { ServiceBeanConfig.class, DatabaseConfig.class }) -public class FileRepositoryDirectoryTest { +public class FileRepositoryDirectoryTest extends RepositoryServiceTest { /** The Constant SOME_BYTES. */ private static final byte[] SOME_BYTES = "filecontents".getBytes(); @@ -52,7 +46,7 @@ public class FileRepositoryDirectoryTest { private final long timestamp = System.currentTimeMillis(); /** The Constant PATH. */ - private final String PATH = "/temp/" + timestamp; + private final Path PATH = Paths.get("/temp/", "" + timestamp); /** The file repo service. */ @Autowired @@ -74,50 +68,47 @@ public class FileRepositoryDirectoryTest { final String originalFilename = "folderfile" + extension; final List repoFiles = new ArrayList<>(20); - repoFiles.add(fileRepoService.addFile(PATH + "aa", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa", 2 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa", 3 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa", 4 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa", 5 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa/dd", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa/dd", 2 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa/dd/ee", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa/dd/ee", 2 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa/dd/ee/gg", originalFilename, contentType, SOME_BYTES, null)); - - repoFiles.add(fileRepoService.addFile(PATH + "bb", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "bb", 2 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "bb", 3 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "bb", 4 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "bb", 5 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "bb/cc", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "bb/cc", 2 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "bb/cc/ee", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "bb/cc/ee", 2 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "bb/cc/ee/ff", originalFilename, contentType, SOME_BYTES, null)); - - List paths = fileRepoService.listPaths(PATH + "aa", new PageRequest(0, 10)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa"), 2 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa"), 3 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa"), 4 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa"), 5 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa/dd"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa/dd"), 2 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa/dd/ee"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa/dd/ee"), 2 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa/dd/ee/gg"), originalFilename, contentType, SOME_BYTES, null)); + + repoFiles.add(fileRepoService.addFile(PATH.resolve("bb"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("bb"), 2 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("bb"), 3 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("bb"), 4 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("bb"), 5 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("bb/cc"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("bb/cc"), 2 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("bb/cc/ee"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("bb/cc/ee"), 2 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("bb/cc/ee/ff"), originalFilename, contentType, SOME_BYTES, null)); + + List paths = fileRepoService.listPaths(PATH.resolve("aa")).stream().map(rf -> rf.getFolderPath()).collect(Collectors.toList()); assertThat("Paths definitely exist", paths, notNullValue()); // paths.stream().forEach(path -> { // System.err.println("Distinct path=" + path); // }); assertThat("Paths definitely exist", paths, hasSize(4)); - assertThat("Paths not in correct order", paths, contains(PATH + "aa", PATH + "aa/dd", PATH + "aa/dd/ee", PATH + "aa/dd/ee/gg")); + assertThat("Paths not in correct order", paths, contains(PATH.resolve("aa"), PATH.resolve("aa/dd"), PATH.resolve("aa/dd/ee"), PATH.resolve("aa/dd/ee/gg"))); - paths = fileRepoService.listPaths(PATH + "bb", new PageRequest(0, 10)); + paths = fileRepoService.listPaths(PATH.resolve("bb")).stream().map(rf -> rf.getFolderPath()).collect(Collectors.toList()); assertThat("Paths definitely exist", paths, notNullValue()); // paths.stream().forEach(path -> { // System.err.println("Distinct path=" + path); // }); assertThat("Paths definitely exist", paths, hasSize(4)); - assertThat("Paths not in correct order", paths, contains(PATH + "bb", PATH + "bb/cc", PATH + "bb/cc/ee", PATH + "bb/cc/ee/ff")); + assertThat("Paths not in correct order", paths, contains(PATH.resolve("bb"), PATH.resolve("bb/cc"), PATH.resolve("bb/cc/ee"), PATH.resolve("bb/cc/ee/ff"))); for (final RepositoryFile repoFile : repoFiles) { fileRepoService.removeFile(repoFile); } - - paths = fileRepoService.listPaths(PATH, new PageRequest(0, 10)); - assertThat("Paths should no longer exist", paths, hasSize(0)); } /** @@ -136,16 +127,16 @@ public class FileRepositoryDirectoryTest { final String originalFilename = "folderfile" + extension; final List repoFiles = new ArrayList<>(20); - repoFiles.add(fileRepoService.addFile(PATH + "aa", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aaa", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aaaa/bb", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aaaa/bbb", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aaaa/cc", 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aaa"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aaaa/bb"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aaaa/bbb"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aaaa/cc"), 1 + originalFilename, contentType, SOME_BYTES, null)); - assertThat(fileRepoService.listPaths(PATH + "aa"), hasSize(1)); - assertThat(fileRepoService.listPaths(PATH + "aaa"), hasSize(1)); - assertThat(fileRepoService.listPaths(PATH + "aaaa"), hasSize(3)); - assertThat(fileRepoService.listPaths(PATH + "aaaa/bb"), hasSize(1)); + assertThat(fileRepoService.listPaths(PATH.resolve("aa")), hasSize(1)); // self + assertThat(fileRepoService.listPaths(PATH.resolve("aaa")), hasSize(1)); // self + assertThat(fileRepoService.listPaths(PATH.resolve("aaaa")), hasSize(4)); // self + 3 + assertThat(fileRepoService.listPaths(PATH.resolve("aaaa/bb")), hasSize(1)); // self for (final RepositoryFile repoFile : repoFiles) { fileRepoService.removeFile(repoFile); @@ -168,33 +159,30 @@ public class FileRepositoryDirectoryTest { final String originalFilename = "folderfile" + extension; final List repoFiles = new ArrayList<>(20); - repoFiles.add(fileRepoService.addFile(PATH + "aa", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa", 2 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa/dd", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa/dd", 2 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa/dd/ee", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa/dd/ee", 2 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa/dd/ee/gg", 1 + originalFilename, contentType, SOME_BYTES, null)); - repoFiles.add(fileRepoService.addFile(PATH + "aa/dd/ee/gg", 2 + originalFilename, contentType, SOME_BYTES, null)); - - List paths = fileRepoService.listPaths(PATH + "aa", new PageRequest(0, 10)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa"), 2 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa/dd"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa/dd"), 2 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa/dd/ee"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa/dd/ee"), 2 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa/dd/ee/gg"), 1 + originalFilename, contentType, SOME_BYTES, null)); + repoFiles.add(fileRepoService.addFile(PATH.resolve("aa/dd/ee/gg"), 2 + originalFilename, contentType, SOME_BYTES, null)); + + List paths = fileRepoService.listPaths(PATH.resolve("aa")); assertThat("Paths definitely exist", paths, notNullValue()); assertThat("Paths definitely exist", paths, hasSize(4)); - assertThat("Paths not in correct order", paths, contains(PATH + "aa", PATH + "aa/dd", PATH + "aa/dd/ee", PATH + "aa/dd/ee/gg")); + assertThat("Paths not in correct order", paths.stream().map(rf -> rf.getFolderPath()).collect(Collectors.toList()), contains(PATH.resolve("aa"), PATH.resolve("aa/dd"), PATH.resolve("aa/dd/ee"), PATH.resolve("aa/dd/ee/gg"))); - fileRepoService.renamePath(PATH + "aa/dd/ee/gg", PATH + "aa/dd/ee/zz"); - assertThat("Paths not renamed correctly", fileRepoService.listPaths(PATH + "aa/dd/ee"), contains(PATH + "aa/dd/ee", PATH + "aa/dd/ee/zz")); - fileRepoService.renamePath(PATH + "aa/dd", PATH + "aa/zz"); - assertThat("Paths not renamed correctly", fileRepoService.listPaths(PATH + "aa/zz"), contains(PATH + "aa/zz", PATH + "aa/zz/ee", PATH + "aa/zz/ee/zz")); + fileRepoService.renamePath(PATH.resolve("aa/dd/ee/gg"), PATH.resolve("aa/dd/ee/zz")); + assertThat("Paths not renamed correctly", fileRepoService.listPaths(PATH.resolve("aa/dd/ee")).stream().map(rf -> rf.getFolderPath()).collect(Collectors.toList()), contains(PATH.resolve("aa/dd/ee"), PATH.resolve("aa/dd/ee/zz"))); + fileRepoService.renamePath(PATH.resolve("aa/dd"), PATH.resolve("aa/zz")); + assertThat("Paths not renamed correctly", fileRepoService.listPaths(PATH.resolve("aa/zz")).stream().map(rf -> rf.getFolderPath()).collect(Collectors.toList()), contains(PATH.resolve("aa/zz"), PATH.resolve("aa/zz/ee"), PATH.resolve("aa/zz/ee/zz"))); - for (final String repositoryPath : fileRepoService.listPaths(PATH + "aa")) { - for (final RepositoryFile repoFile : fileRepoService.getFiles(repositoryPath)) { + for (final RepositoryFolder repositoryFolder : fileRepoService.listPaths(PATH.resolve("aa"))) { + for (final RepositoryFile repoFile : fileRepoService.getFiles(repositoryFolder.getFolderPath())) { fileRepoService.removeFile(repoFile); } } - - paths = fileRepoService.listPaths(PATH, new PageRequest(0, 10)); - assertThat("Paths should no longer exist", paths, hasSize(0)); } } diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryExtensionTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryExtensionTest.java index 9ec35b29fbbd7a3e4524a9aa20a8413c23c0d84d..c9070c3b59d946e73811139ebdca7f7a04c7ba93 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryExtensionTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryExtensionTest.java @@ -17,32 +17,27 @@ package org.genesys.filerepository.service; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; -import org.genesys.filerepository.config.DatabaseConfig; -import org.genesys.filerepository.config.ServiceBeanConfig; import org.genesys.filerepository.model.RepositoryFile; import org.junit.Test; -import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; // TODO: Auto-generated Javadoc /** * The Class FileRepositoryExtensionTest. */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { ServiceBeanConfig.class, DatabaseConfig.class }) -public class FileRepositoryExtensionTest { +public class FileRepositoryExtensionTest extends RepositoryServiceTest { /** The initial content type. */ private final String initialContentType = "text/plain"; /** The initial path. */ - private final String initialPath = "/initial/" + System.currentTimeMillis(); + private final Path initialPath = Paths.get("/initial/", "" + System.currentTimeMillis()); /** The initial extension. */ private final String initialExtension = ".txt"; diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryTestUtil.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryTestUtil.java index 115181d297be3f7261cf8ce740cb23251e569068..d23947c417b8fe082a46d54b622aa3dd06740c72 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryTestUtil.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryTestUtil.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertThat; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Path; import org.apache.commons.io.IOUtils; import org.genesys.filerepository.metadata.ImageMetadata.Orientation; @@ -46,7 +47,7 @@ public class FileRepositoryTestUtil { * @param contentType the content type * @return the repository file */ - static RepositoryFile checkFile(final RepositoryFile repoFile, final String path, final String originalFilename, final String extension, final String contentType) { + static RepositoryFile checkFile(final RepositoryFile repoFile, final Path path, final String originalFilename, final String extension, final String contentType) { assertThat("RepositoryFile cannot be null", repoFile, notNullValue()); assertThat("RepositoryFile#UUID cannot be null", repoFile.getUuid(), notNullValue()); assertThat("RepositoryFile#originalFilename doesn't match", repoFile.getOriginalFilename(), equalTo(originalFilename)); @@ -118,7 +119,7 @@ public class FileRepositoryTestUtil { * @param height the height * @param orientation the orientation */ - public static void checkImage(final RepositoryImage imageData, final String path, final String originalFilename, final String extension, final String contentType, + public static void checkImage(final RepositoryImage imageData, final Path path, final String originalFilename, final String extension, final String contentType, final int width, final int height, final Orientation orientation) { checkFile(imageData, path, originalFilename, extension, contentType); diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryUpdateTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryUpdateTest.java index a60fb9d5b39ae257ec9ba550170fcf1da1bab5e0..42f0c7a13c0801b8be6d38f3a179bbd33eeb0944 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryUpdateTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileRepositoryUpdateTest.java @@ -16,42 +16,34 @@ package org.genesys.filerepository.service; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.assertThat; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; import java.util.UUID; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; -import org.genesys.filerepository.config.DatabaseConfig; -import org.genesys.filerepository.config.ServiceBeanConfig; import org.genesys.filerepository.model.RepositoryFile; -import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; // TODO: Auto-generated Javadoc /** * The Class FileRepositoryUpdateTest. */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { ServiceBeanConfig.class, DatabaseConfig.class }) -public class FileRepositoryUpdateTest { +public class FileRepositoryUpdateTest extends RepositoryServiceTest { /** The initial content type. */ private final String initialContentType = "text/plain"; /** The initial path. */ - private final String initialPath = "/initial/" + System.currentTimeMillis(); + private final Path initialPath = Paths.get("/initial/", ""+ System.currentTimeMillis()); /** The initial extension. */ private final String initialExtension = ".txt"; @@ -59,10 +51,6 @@ public class FileRepositoryUpdateTest { /** The initial original filename. */ private final String initialOriginalFilename = "initial" + initialExtension; - /** The file repo service. */ - @Autowired - private RepositoryService fileRepoService; - /** The file uuid. */ private UUID fileUuid; @@ -74,20 +62,12 @@ public class FileRepositoryUpdateTest { * exception * @throws IOException Signals that an I/O exception has occurred. */ + @Override @Before - public void beforeTest() throws InvalidRepositoryPathException, InvalidRepositoryFileDataException, IOException { - fileUuid = fileRepoService.addFile(initialPath, initialOriginalFilename, initialContentType, "initial".getBytes(), null).getUuid(); - } - - /** - * After test. - * - * @throws NoSuchRepositoryFileException the no such repository file exception - * @throws IOException Signals that an I/O exception has occurred. - */ - @After - public void afterTest() throws NoSuchRepositoryFileException, IOException { - fileRepoService.removeFile(fileRepoService.getFile(fileUuid)); + @Transactional + public void beforeTest() throws Throwable { + super.beforeTest(); + fileUuid = repositoryService.addFile(initialPath, initialOriginalFilename, initialContentType, "initial".getBytes(), null).getUuid(); } /** @@ -97,7 +77,7 @@ public class FileRepositoryUpdateTest { */ @Test(expected = NoSuchRepositoryFileException.class) public void fetchFileNoSuchFile() throws NoSuchRepositoryFileException { - fileRepoService.getFile(UUID.randomUUID()); + repositoryService.getFile(UUID.randomUUID()); } /** @@ -107,17 +87,18 @@ public class FileRepositoryUpdateTest { */ @Test public void fetchFileByUuid() throws NoSuchRepositoryFileException { - final RepositoryFile repoFile = fileRepoService.getFile(fileUuid); + final RepositoryFile repoFile = repositoryService.getFile(fileUuid); FileRepositoryTestUtil.checkFile(repoFile, initialPath, initialOriginalFilename, initialExtension, initialContentType); } /** * Test basic submission to file repository. + * @throws NoSuchRepositoryFileException */ @Test - public void fetchFilesByPath() { - final List repoFiles = fileRepoService.getFiles(initialPath); + public void fetchFilesByPath() throws NoSuchRepositoryFileException { + final List repoFiles = repositoryService.getFiles(initialPath); assertThat("List should have one element", repoFiles.size(), is(1)); @@ -133,12 +114,12 @@ public class FileRepositoryUpdateTest { */ @Test public void originalFilenameChangeUpdatesExtension() throws NoSuchRepositoryFileException { - RepositoryFile repositoryFile = fileRepoService.getFile(fileUuid); + RepositoryFile repositoryFile = repositoryService.getFile(fileUuid); final String extension = ".png"; final String originalFilename = "originalFilename2" + extension; repositoryFile.setOriginalFilename(originalFilename); - repositoryFile = fileRepoService.updateMetadata(repositoryFile); + repositoryFile = repositoryService.updateMetadata(repositoryFile); assertThat("Extension was not updated", repositoryFile.getExtension(), equalTo(extension)); } @@ -149,7 +130,7 @@ public class FileRepositoryUpdateTest { */ @Test public void addMetadataToFile() throws NoSuchRepositoryFileException { - final RepositoryFile repositoryFile = fileRepoService.getFile(fileUuid); + final RepositoryFile repositoryFile = repositoryService.getFile(fileUuid); FileRepositoryTestUtil.checkFile(repositoryFile, initialPath, initialOriginalFilename, initialExtension, initialContentType); FileRepositoryTestUtil.assertMetadataIsBlank(repositoryFile); @@ -181,7 +162,7 @@ public class FileRepositoryUpdateTest { repositoryFile.setSubject(subject); repositoryFile.setTitle(title); - final RepositoryFile repoFile = fileRepoService.updateMetadata(repositoryFile); + final RepositoryFile repoFile = repositoryService.updateMetadata(repositoryFile); // Entity test assertThat("RepositoryFile cannot be null", repoFile, notNullValue()); @@ -200,18 +181,18 @@ public class FileRepositoryUpdateTest { */ @Test public void moveFile() throws NoSuchRepositoryFileException, InvalidRepositoryPathException { - RepositoryFile fileData = fileRepoService.getFile(fileUuid); + RepositoryFile fileData = repositoryService.getFile(fileUuid); FileRepositoryTestUtil.checkFile(fileData, initialPath, initialOriginalFilename, initialExtension, initialContentType); FileRepositoryTestUtil.assertMetadataIsBlank(fileData); // Move - final String newPath = "/new/" + System.currentTimeMillis(); - fileData = fileRepoService.moveFile(fileData, newPath); + final Path newPath = Paths.get("/new/" + System.currentTimeMillis()); + fileData = repositoryService.moveFile(fileData, newPath); FileRepositoryTestUtil.checkFile(fileData, newPath, initialOriginalFilename, initialExtension, initialContentType); // Move back - fileData = fileRepoService.moveFile(fileData, initialPath); + fileData = repositoryService.moveFile(fileData, initialPath); FileRepositoryTestUtil.checkFile(fileData, initialPath, initialOriginalFilename, initialExtension, initialContentType); } @@ -223,8 +204,8 @@ public class FileRepositoryUpdateTest { */ @Test(expected = InvalidRepositoryPathException.class) public void invalidMoveNullPath() throws NoSuchRepositoryFileException, InvalidRepositoryPathException { - RepositoryFile fileData = fileRepoService.getFile(fileUuid); - fileData = fileRepoService.moveFile(fileData, null); + RepositoryFile fileData = repositoryService.getFile(fileUuid); + fileData = repositoryService.moveFile(fileData, null); } /** @@ -235,44 +216,20 @@ public class FileRepositoryUpdateTest { */ @Test(expected = InvalidRepositoryPathException.class) public void invalidMoveBlankPath() throws NoSuchRepositoryFileException, InvalidRepositoryPathException { - RepositoryFile fileData = fileRepoService.getFile(fileUuid); - fileData = fileRepoService.moveFile(fileData, " "); - } - - /** - * Invalid double // in path test. - * - * @throws NoSuchRepositoryFileException the no such repository file exception - * @throws InvalidRepositoryPathException the invalid repository path exception - */ - @Test(expected = InvalidRepositoryPathException.class) - public void invalidMoveDoubleSlashPath() throws NoSuchRepositoryFileException, InvalidRepositoryPathException { - RepositoryFile fileData = fileRepoService.getFile(fileUuid); - fileData = fileRepoService.moveFile(fileData, "/fo//bar"); - } - - /** - * Path must start with / test. - * - * @throws NoSuchRepositoryFileException the no such repository file exception - * @throws InvalidRepositoryPathException the invalid repository path exception - */ - @Test(expected = InvalidRepositoryPathException.class) - public void invalidMoveMissingStartSlash() throws NoSuchRepositoryFileException, InvalidRepositoryPathException { - RepositoryFile fileData = fileRepoService.getFile(fileUuid); - fileData = fileRepoService.moveFile(fileData, "validpath/here"); + RepositoryFile fileData = repositoryService.getFile(fileUuid); + fileData = repositoryService.moveFile(fileData, Paths.get(" ")); } /** - * Path must not end with / test. + * Path must not end with " /" test. * * @throws NoSuchRepositoryFileException the no such repository file exception * @throws InvalidRepositoryPathException the invalid repository path exception */ @Test(expected = InvalidRepositoryPathException.class) public void invalidMoveMissingEndSlash() throws NoSuchRepositoryFileException, InvalidRepositoryPathException { - RepositoryFile fileData = fileRepoService.getFile(fileUuid); - fileData = fileRepoService.moveFile(fileData, "/validpath/here/"); + RepositoryFile fileData = repositoryService.getFile(fileUuid); + fileData = repositoryService.moveFile(fileData, Paths.get("/validpath/here /")); } } diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileSystemStorageTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileSystemStorageTest.java index d75009131a3761b777fe9cc771afc0093510f968..6f7d16bcded58722e23aaeb69d64567390c01f8a 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/FileSystemStorageTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/FileSystemStorageTest.java @@ -16,33 +16,27 @@ package org.genesys.filerepository.service; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.assertThat; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import org.apache.commons.io.FileUtils; import org.genesys.filerepository.BytesStorageException; -import org.genesys.filerepository.config.DatabaseConfig; -import org.genesys.filerepository.config.ServiceBeanConfig; import org.genesys.filerepository.service.impl.FilesystemStorageServiceImpl; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; // TODO: Auto-generated Javadoc /** * The Class FileSystemStorageTest. */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { ServiceBeanConfig.class, DatabaseConfig.class }) -public class FileSystemStorageTest { +public class FileSystemStorageTest extends RepositoryServiceTest { /** The Constant EMPTY_BYTES. */ private static final byte[] EMPTY_BYTES = new byte[0]; @@ -96,25 +90,6 @@ public class FileSystemStorageTest { } } - /** - * Test blank path. - * - * @throws FileNotFoundException the file not found exception - * @throws IOException Signals that an I/O exception has occurred. - */ - @Test - public void testBlankPath() throws FileNotFoundException, IOException { - final File expectedFile = new File(baseDir, "filename1"); - bytesStorage.upsert("", "filename1", EMPTY_BYTES); - - assertThat("File not created", expectedFile.exists(), is(true)); - assertThat("Created file is not a file", expectedFile.isFile(), is(true)); - assertThat("File size does not match", expectedFile.length(), is(0l)); - - bytesStorage.remove("", "filename1"); - assertThat("File still exists", expectedFile.exists(), is(false)); - } - /** * Test slash path. * @@ -123,17 +98,16 @@ public class FileSystemStorageTest { */ @Test public void testSlashPath() throws FileNotFoundException, IOException { - final String path = "/foo/"; - final String filename = "filename1"; + final Path filePath = Paths.get("/foo/", "filename1"); final File expectedFile = new File(baseDir, "foo/filename1"); - bytesStorage.upsert(path, filename, EMPTY_BYTES); + bytesStorage.upsert(filePath, EMPTY_BYTES); assertThat("File not created", expectedFile.exists(), is(true)); assertThat("Created file is not a file", expectedFile.isFile(), is(true)); assertThat("File size does not match", expectedFile.length(), is(0l)); - bytesStorage.remove(path, filename); + bytesStorage.remove(filePath); assertThat("File still exists", expectedFile.exists(), is(false)); } @@ -143,11 +117,11 @@ public class FileSystemStorageTest { * @throws FileNotFoundException the file not found exception * @throws IOException Signals that an I/O exception has occurred. */ - @Test(expected = IOException.class) + @Test public void testEscapePath() throws FileNotFoundException, IOException { - final String path = "/../"; - final String filename = "filename1"; - bytesStorage.upsert(path, filename, EMPTY_BYTES); + final Path filePath = Paths.get("/../", "filename1"); + bytesStorage.upsert(filePath, EMPTY_BYTES); + bytesStorage.remove(filePath); } /** @@ -156,14 +130,14 @@ public class FileSystemStorageTest { * @throws FileNotFoundException the file not found exception * @throws IOException Signals that an I/O exception has occurred. */ - @Test(expected = IOException.class) + @Test public void testEscapePath2() throws FileNotFoundException, IOException { - final String path = "/../../"; - final String filename = "filename1"; + final Path filePath = Paths.get("/../../", "filename1"); // File expectedFile = new File(baseDir, path + filename); // System.err.println("???" + expectedFile.getCanonicalPath()); - bytesStorage.upsert(path, filename, EMPTY_BYTES); + bytesStorage.upsert(filePath, EMPTY_BYTES); + bytesStorage.remove(filePath); } /** @@ -174,17 +148,16 @@ public class FileSystemStorageTest { */ @Test public void testDoubleSlashPath() throws FileNotFoundException, IOException { - final String path = "/foo/bar/"; - final String filename = "filename2"; + final Path filePath = Paths.get("/foo/bar/", "filename2"); final File expectedFile = new File(baseDir, "foo/bar/filename2"); - bytesStorage.upsert(path, filename, EMPTY_BYTES); + bytesStorage.upsert(filePath, EMPTY_BYTES); assertThat("File not created", expectedFile.exists(), is(true)); assertThat("Created file is not a file", expectedFile.isFile(), is(true)); assertThat("File size does not match", expectedFile.length(), is(0l)); - bytesStorage.remove(path, filename); + bytesStorage.remove(filePath); assertThat("File still exists", expectedFile.exists(), is(false)); } @@ -196,11 +169,10 @@ public class FileSystemStorageTest { */ @Test public void testFileContents() throws FileNotFoundException, IOException { - final String path = "/foo/bar/"; - final String filename = "somecontents"; + final Path filePath = Paths.get("/foo/bar/", "somecontents"); final File expectedFile = new File(baseDir, "foo/bar/somecontents"); - bytesStorage.upsert(path, filename, SOME_BYTES); + bytesStorage.upsert(filePath, SOME_BYTES); assertThat("File not created", expectedFile.exists(), is(true)); assertThat("Created file is not a file", expectedFile.isFile(), is(true)); @@ -209,7 +181,7 @@ public class FileSystemStorageTest { final byte[] readBytes = FileUtils.readFileToByteArray(expectedFile); assertThat("Bytes don't match", readBytes, equalTo(SOME_BYTES)); - bytesStorage.remove(path, filename); + bytesStorage.remove(filePath); assertThat("File still exists", expectedFile.exists(), is(false)); } diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/ImageGalleryTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/ImageGalleryTest.java index 5b54e3ec234a257a76cacdb502b9e0b31d359c55..33da90fcad823a968e42912b7626cd76e7529a1d 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/ImageGalleryTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/ImageGalleryTest.java @@ -16,15 +16,12 @@ package org.genesys.filerepository.service; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -32,24 +29,17 @@ import java.util.Random; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; -import org.genesys.filerepository.config.DatabaseConfig; -import org.genesys.filerepository.config.ServiceBeanConfig; import org.genesys.filerepository.model.ImageGallery; import org.genesys.filerepository.model.RepositoryImage; import org.junit.After; import org.junit.Test; -import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; // TODO: Auto-generated Javadoc /** * The Class ImageGalleryTest. */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { ServiceBeanConfig.class, DatabaseConfig.class }) -public class ImageGalleryTest { +public class ImageGalleryTest extends RepositoryServiceTest { /** The Constant DEFAULT_GALLERY_TITLE. */ private static final String DEFAULT_GALLERY_TITLE = "Test Gallery"; @@ -64,7 +54,7 @@ public class ImageGalleryTest { private final long timestamp = System.currentTimeMillis(); /** The initial path. */ - private final String initialPath = "/gallery/" + timestamp; + private final Path initialPath = Paths.get("/gallery/" + timestamp); /** The image gallery service. */ @Autowired @@ -94,7 +84,7 @@ public class ImageGalleryTest { */ @Test public void loadMissingGallery() { - final ImageGallery imageGallery = imageGalleryService.loadImageGallery("no-such-gallery/" + timestamp); + final ImageGallery imageGallery = imageGalleryService.loadImageGallery(Paths.get("no-such-gallery/" + timestamp)); assertThat("Must be null", imageGallery, nullValue()); } @@ -176,10 +166,10 @@ public class ImageGalleryTest { final RepositoryImage repoImage = fileRepoService.addImage(initialPath, image1.getOriginalFilename(), image1.getContentType(), image1.getImageBytes(), null); // Expect the image to be included in the list! - assertThat("Image gallery must include the image!", imageGalleryService.loadImageGallery(imageGallery.getPath()).getImages(), hasSize(1)); - assertThat("Image gallery must include the image!", imageGalleryService.loadImageGallery(imageGallery.getPath()).getImages(), contains(repoImage)); + assertThat("Image gallery must include the image!", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()).getImages(), hasSize(1)); + assertThat("Image gallery must include the image!", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()).getImages(), contains(repoImage)); - imageGalleryService.removeGallery(imageGalleryService.loadImageGallery(imageGallery.getPath())); + imageGalleryService.removeGallery(imageGalleryService.loadImageGallery(imageGallery.getFolderPath())); fileRepoService.removeFile(repoImage); } @@ -202,17 +192,17 @@ public class ImageGalleryTest { final RepositoryImage repoImage1 = (RepositoryImage) fileRepoService.addFile(initialPath, image1.getOriginalFilename(), image1.getContentType(), image1.getImageBytes(), null); // Expect the image to be included in the list! - assertThat("Image gallery must include the image!", imageGalleryService.loadImageGallery(imageGallery.getPath()).getImages(), contains(repoImage1)); + assertThat("Image gallery must include the image!", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()).getImages(), contains(repoImage1)); // Add an image to the gallery path final TestImage image2 = new TestImage("11x10.png", "image/png"); final RepositoryImage repoImage2 = (RepositoryImage) fileRepoService.addFile(initialPath, image2.getOriginalFilename(), image2.getContentType(), image2.getImageBytes(), null); - assertThat("Image gallery must include both images!", imageGalleryService.loadImageGallery(imageGallery.getPath()).getImages(), contains(repoImage1, repoImage2)); + assertThat("Image gallery must include both images!", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()).getImages(), contains(repoImage1, repoImage2)); - imageGalleryService.removeGallery(imageGalleryService.loadImageGallery(imageGallery.getPath())); - // fileRepoService.removeFile(repoImage2); - // fileRepoService.removeFile(repoImage1); + imageGalleryService.removeGallery(imageGalleryService.loadImageGallery(imageGallery.getFolderPath())); + // repositoryService.removeFile(repoImage2); + // repositoryService.removeFile(repoImage1); } /** @@ -237,16 +227,16 @@ public class ImageGalleryTest { final TestImage image2 = new TestImage("11x10.png", "image/png"); final RepositoryImage repoImage2 = fileRepoService.addImage(initialPath, image2.getOriginalFilename(), image2.getContentType(), image2.getImageBytes(), null); - assertThat("Image gallery must include both images!", imageGalleryService.loadImageGallery(imageGallery.getPath()).getImages(), contains(repoImage1, repoImage2)); + assertThat("Image gallery must include both images!", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()).getImages(), contains(repoImage1, repoImage2)); fileRepoService.removeFile(repoImage2); - assertThat("Image gallery must include the image!", imageGalleryService.loadImageGallery(imageGallery.getPath()).getImages(), contains(repoImage1)); + assertThat("Image gallery must include the image!", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()).getImages(), contains(repoImage1)); fileRepoService.removeFile(repoImage1); // Expect the image to be gone from the list! - assertThat("Image gallery must be deleted", imageGalleryService.loadImageGallery(imageGallery.getPath()), is(nullValue())); + assertThat("Image gallery must be deleted", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()), is(nullValue())); } /** @@ -272,26 +262,26 @@ public class ImageGalleryTest { images.add(repoImg); } - imageGallery = imageGalleryService.loadImageGallery(imageGallery.getPath()); + imageGallery = imageGalleryService.loadImageGallery(imageGallery.getFolderPath()); assertThat("Image gallery must have 20 images", imageGallery.getImages(), hasSize(20)); // Remove something in the middle of the gallery fileRepoService.removeImage(images.remove(4)); // Test order - assertThat("Images must be reordered!", imageGalleryService.loadImageGallery(imageGallery.getPath()).getImages(), contains(images.toArray(EMPTY_REPOSITORYIMAGE_ARRAY))); + assertThat("Images must be reordered!", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()).getImages(), contains(images.toArray(EMPTY_REPOSITORYIMAGE_ARRAY))); // Remove something in the start of the gallery fileRepoService.removeFile(images.remove(0)); // Test order - assertThat("Images must be reordered!", imageGalleryService.loadImageGallery(imageGallery.getPath()).getImages(), contains(images.toArray(EMPTY_REPOSITORYIMAGE_ARRAY))); + assertThat("Images must be reordered!", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()).getImages(), contains(images.toArray(EMPTY_REPOSITORYIMAGE_ARRAY))); // Remove something in the end of the gallery fileRepoService.removeFile(images.remove(images.size() - 1)); // Test order - assertThat("Images must be reordered!", imageGalleryService.loadImageGallery(imageGallery.getPath()).getImages(), contains(images.toArray(EMPTY_REPOSITORYIMAGE_ARRAY))); + assertThat("Images must be reordered!", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()).getImages(), contains(images.toArray(EMPTY_REPOSITORYIMAGE_ARRAY))); // Remove randomly until empty final Random rnd = new Random(System.currentTimeMillis()); @@ -300,10 +290,10 @@ public class ImageGalleryTest { fileRepoService.removeFile(images.remove(idx)); if (images.size() == 0) { - assertThat("Image gallery must be deleted", imageGalleryService.loadImageGallery(imageGallery.getPath()), is(nullValue())); + assertThat("Image gallery must be deleted", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()), is(nullValue())); } else { // Test order - assertThat("Images must be reordered!", imageGalleryService.loadImageGallery(imageGallery.getPath()).getImages(), contains(images.toArray(EMPTY_REPOSITORYIMAGE_ARRAY))); + assertThat("Images must be reordered!", imageGalleryService.loadImageGallery(imageGallery.getFolderPath()).getImages(), contains(images.toArray(EMPTY_REPOSITORYIMAGE_ARRAY))); } } } @@ -328,7 +318,7 @@ public class ImageGalleryTest { final TestImage image2 = new TestImage("11x10.png", "image/png"); final RepositoryImage repoImage2 = fileRepoService.addImage(initialPath, image2.getOriginalFilename(), image2.getContentType(), image2.getImageBytes(), null); - imageGallery = imageGalleryService.loadImageGallery(imageGallery.getPath()); + imageGallery = imageGalleryService.loadImageGallery(imageGallery.getFolderPath()); assertThat("Image gallery must include both images!", imageGallery.getImages(), contains(repoImage1, repoImage2)); @@ -367,7 +357,7 @@ public class ImageGalleryTest { ImageGallery imageGallery = imageGalleryService.createImageGallery(initialPath, DEFAULT_GALLERY_TITLE, DEFAULT_GALLERY_DESCRIPTION); - imageGallery = imageGalleryService.loadImageGallery(imageGallery.getPath()); + imageGallery = imageGalleryService.loadImageGallery(imageGallery.getFolderPath()); assertThat("Image gallery must include both images!", imageGallery.getImages(), contains(repoImage1, repoImage2)); diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/ImageGalleryThumbnailsTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/ImageGalleryThumbnailsTest.java index 0c33241e24fcf29220b651639ab0ca58a74acff9..1fdd7e4d6c5515ddc051fbca877950e2bc9219fb 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/ImageGalleryThumbnailsTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/ImageGalleryThumbnailsTest.java @@ -16,14 +16,15 @@ package org.genesys.filerepository.service; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.UUID; import javax.imageio.ImageIO; @@ -31,25 +32,19 @@ import javax.imageio.ImageIO; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; -import org.genesys.filerepository.config.DatabaseConfig; -import org.genesys.filerepository.config.ServiceBeanConfig; import org.genesys.filerepository.model.ImageGallery; import org.genesys.filerepository.model.RepositoryImage; import org.genesys.filerepository.service.impl.ImageGalleryServiceImpl; import org.junit.After; import org.junit.Test; -import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; // TODO: Auto-generated Javadoc /** * The Class ImageGalleryTest. */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { ServiceBeanConfig.class, DatabaseConfig.class }) -public class ImageGalleryThumbnailsTest { +public class ImageGalleryThumbnailsTest extends RepositoryServiceTest { /** The Constant DEFAULT_GALLERY_TITLE. */ private static final String DEFAULT_GALLERY_TITLE = "Test Gallery"; @@ -61,7 +56,7 @@ public class ImageGalleryThumbnailsTest { private final long timestamp = System.currentTimeMillis(); /** The initial path. */ - private final String initialPath = "/gallery/" + timestamp; + private final Path initialPath = Paths.get("/gallery/" + timestamp); /** The image gallery service. */ @Autowired @@ -78,12 +73,14 @@ public class ImageGalleryThumbnailsTest { * @throws IOException Signals that an I/O exception has occurred. * @throws InvalidRepositoryPathException the invalid repository path exception */ + @Transactional @After - public void afterTest() throws NoSuchRepositoryFileException, IOException, InvalidRepositoryPathException { + public void afterTest() throws Throwable { final ImageGallery imageGallery = imageGalleryService.loadImageGallery(initialPath); if (imageGallery != null) { imageGalleryService.removeGallery(imageGallery); } + super.afterTest(); } /** @@ -121,7 +118,7 @@ public class ImageGalleryThumbnailsTest { imageGalleryService.ensureThumbnails(imageGallery, 100, 200); - final byte[] thumbBytes1 = fileRepoService.getFileBytes(ImageGalleryService.THUMB_PATH + repoImage1.getThumbnailPath(), "100x200" + ".png"); + final byte[] thumbBytes1 = fileRepoService.getFileBytes(Paths.get(ImageGalleryService.THUMB_PATH, repoImage1.getThumbnailPath(), "100x200" + ".png")); assertThat("Thumbnail must not be null", thumbBytes1, notNullValue()); try (InputStream is = new ByteArrayInputStream(thumbBytes1)) { diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/MetadataTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/MetadataTest.java index 01cce614c5479bf55185f68849ad5633261de4f6..92d44aabb132664a6ae53c4d5590bf794fc3dd11 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/MetadataTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/MetadataTest.java @@ -16,41 +16,35 @@ package org.genesys.filerepository.service; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; import java.io.IOException; - -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; +import java.nio.file.Path; +import java.nio.file.Paths; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; -import org.genesys.filerepository.config.DatabaseConfig; -import org.genesys.filerepository.config.ServiceBeanConfig; import org.genesys.filerepository.model.RepositoryImage; import org.junit.After; import org.junit.Test; -import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; /** * Repository metadata tests. */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { ServiceBeanConfig.class, DatabaseConfig.class }) -public class MetadataTest { +public class MetadataTest extends RepositoryServiceTest { /** The timestamp. */ private final long timestamp = System.currentTimeMillis(); /** The initial path. */ - private final String initialPath = "/images/" + timestamp; + private final Path initialPath = Paths.get("/images/" + timestamp); private final ObjectMapper objectMapper; @@ -68,10 +62,13 @@ public class MetadataTest { /** * After test. + * @throws Throwable */ + @Override @After - public void afterTest() { - + @Transactional + public void afterTest() throws Throwable { + super.afterTest(); } /** @@ -89,7 +86,7 @@ public class MetadataTest { RepositoryImage repoImage1 = repositoryService.addImage(initialPath, image1.getOriginalFilename(), image1.getContentType(), image1.getImageBytes(), null); assertThat(repoImage1.getUuid(), not(nullValue())); - byte[] metadata = bytesStorageService.get(repoImage1.getStoragePath(), repoImage1.getMetadataFilename()); + byte[] metadata = bytesStorageService.get(repoImage1.getStoragePath().resolve(repoImage1.getMetadataFilename())); assertThat("Metadata .json not found", metadata, not(nullValue())); RepositoryImage meta = objectMapper.readValue(metadata, RepositoryImage.class); @@ -102,12 +99,12 @@ public class MetadataTest { repoImage1.setOriginalFilename("test.png"); repoImage1 = repositoryService.updateMetadata(repoImage1); - metadata = bytesStorageService.get(repoImage1.getStoragePath(), repoImage1.getMetadataFilename()); + metadata = bytesStorageService.get(repoImage1.getStoragePath().resolve(repoImage1.getMetadataFilename())); meta = objectMapper.readValue(metadata, RepositoryImage.class); assertThat(meta.getOriginalFilename(), is(repoImage1.getOriginalFilename())); repositoryService.removeFile(repoImage1); - metadata = bytesStorageService.get(repoImage1.getStoragePath(), repoImage1.getMetadataFilename()); + metadata = bytesStorageService.get(repoImage1.getStoragePath().resolve(repoImage1.getMetadataFilename())); assertThat(metadata, is(nullValue())); } } diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryFolderTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryFolderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..629587acd292ec5aa552fc329dd6d2ea6b7d5f4d --- /dev/null +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryFolderTest.java @@ -0,0 +1,141 @@ +/* + * Copyright 2017 Global Crop Diversity Trust + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.genesys.filerepository.service; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import org.genesys.filerepository.FolderNotEmptyException; +import org.genesys.filerepository.InvalidRepositoryPathException; +import org.genesys.filerepository.model.RepositoryFolder; +import org.junit.Test; + +// TODO: Auto-generated Javadoc +/** + * The Class FileRepositoryAddTest. + */ +public class RepositoryFolderTest extends RepositoryServiceTest { + + @Test + public void slashFolderIsNull() throws InvalidRepositoryPathException { + RepositoryFolder folder = repositoryService.ensureFolder(ROOT); + assertThat(folder, nullValue()); + } + + @Test + public void addRootFolder() throws InvalidRepositoryPathException { + Path path = Paths.get("/aaa"); + RepositoryFolder folder = repositoryService.ensureFolder(path); + assertThat(folder, notNullValue()); + assertThat(folder.getName(), is(path.getFileName().toString())); + assertThat(folder.getParent(), nullValue()); + assertThat(folder.getPath(), is(path.toString())); + } + + @Test + public void addRootFolderTwice() throws InvalidRepositoryPathException { + Path path = Paths.get("/aaa"); + RepositoryFolder folder = repositoryService.ensureFolder(path); + assertThat(folder, notNullValue()); + RepositoryFolder folder2 = repositoryService.ensureFolder(path); + assertThat(folder2, notNullValue()); + + assertThat(folder.getUuid(), is(folder2.getUuid())); + } + + @Test + public void addDeepFolder() throws InvalidRepositoryPathException { + Path path = Paths.get("/bbbb/cccc/dddd/eeee"); + RepositoryFolder folder = repositoryService.ensureFolder(path); + assertThat(folder, notNullValue()); + assertThat(folder.getName(), is(path.getFileName().toString())); + assertThat(folder.getPath(), is(path.toString())); + + assertThat(folder.getParent(), notNullValue()); + assertThat(folder.getParent().getName(), is(path.getParent().getFileName().toString())); + assertThat(folder.getParent().getPath(), is(path.getParent().toString())); + assertThat(folder.getParent().getParent(), notNullValue()); + } + + @Test + public void listFolders() throws InvalidRepositoryPathException { + Path path = Paths.get("/bbbb/cccc/dddd/eeee"); + RepositoryFolder folder = repositoryService.ensureFolder(path); + assertThat(folder, notNullValue()); + + List folders = repositoryService.listPaths(Paths.get("/bbbb")); + assertThat(folders, hasSize(4)); + } + + @Test + public void renamePath() throws InvalidRepositoryPathException { + Path path = Paths.get("/bbbb/cccc/dddd/eeee"); + RepositoryFolder folder = repositoryService.ensureFolder(path); + // repositoryService.listPaths("/").forEach(f -> System.err.println("0 " + f)); + assertThat(folder, notNullValue()); + + Path newPath = path.getParent().resolve("ffff"); + RepositoryFolder renamed = repositoryService.renamePath(path, newPath); + // repositoryService.listPaths("/").forEach(f -> System.err.println("1 " + f)); + assertThat(renamed, notNullValue()); + assertThat(renamed.getPath(), is(newPath.toString())); + assertThat(renamed.getFolderPath().getParent(), equalTo(path.getParent())); + + newPath = path.getRoot().resolve("xxxx"); + renamed = repositoryService.renamePath(renamed.getFolderPath(), newPath); + // repositoryService.listPaths("/").forEach(f -> System.err.println("2 " + f)); + assertThat(renamed, notNullValue()); + assertThat(renamed.getPath(), is(newPath.toString())); + assertThat(renamed.getFolderPath().getParent(), is(ROOT)); + } + + @Test(expected = InvalidRepositoryPathException.class) + public void failRenamePathToExisting() throws InvalidRepositoryPathException { + Path path = Paths.get("/bbbb/cccc/dddd/eeee"); + RepositoryFolder folder = repositoryService.ensureFolder(path); + assertThat(folder, notNullValue()); + repositoryService.listPaths(ROOT).forEach(f -> System.err.println("0 " + f)); + + Path newPath = path.getRoot().resolve("bbbb"); + repositoryService.renamePath(path, newPath); + } + + @Test(expected = InvalidRepositoryPathException.class) + public void failRenamePathToExisting2() throws InvalidRepositoryPathException { + Path path = Paths.get("/bbbb/cccc/dddd/eeee"); + RepositoryFolder folder = repositoryService.ensureFolder(path); + assertThat(folder, notNullValue()); + repositoryService.listPaths(ROOT).forEach(f -> System.err.println("0 " + f)); + + Path newPath = path.getParent().getParent().resolve("dddd"); + repositoryService.renamePath(path, newPath); + } + + @Test + public void deleteEmptyFolder() throws InvalidRepositoryPathException, FolderNotEmptyException { + Path path = Paths.get("/bbbb/cccc/dddd/eeee"); + RepositoryFolder folder = repositoryService.ensureFolder(path); + assertThat(folder, notNullValue()); + + RepositoryFolder deleted = repositoryService.deleteFolder(path); + assertThat(deleted, notNullValue()); + } +} diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryImageAddTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryImageAddTest.java index 4dbf8154f281feb25a897c85a137eb3103b20fd7..9ec214784b2415f19cb9043708eb981d5a84c854 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryImageAddTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryImageAddTest.java @@ -16,11 +16,12 @@ package org.genesys.filerepository.service; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.not; -import static org.junit.Assert.assertThat; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; @@ -47,7 +48,7 @@ public class RepositoryImageAddTest { private final String initialContentType = "image/png"; /** The initial path. */ - private final String initialPath = "/initial/" + System.currentTimeMillis(); + private final Path initialPath = Paths.get("/initial/" + System.currentTimeMillis()); /** The initial extension. */ private final String initialExtension = ".png"; diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryImageUpdateTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryImageUpdateTest.java index c0ac005c4d2ee63e4f4415206be824c8258c9e78..1704c46240de85f14c0de8fa35d61bcea387ea54 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryImageUpdateTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryImageUpdateTest.java @@ -17,36 +17,31 @@ package org.genesys.filerepository.service; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.UUID; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; -import org.genesys.filerepository.config.DatabaseConfig; -import org.genesys.filerepository.config.ServiceBeanConfig; import org.genesys.filerepository.metadata.ImageMetadata.Orientation; import org.genesys.filerepository.model.RepositoryImage; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; // TODO: Auto-generated Javadoc /** * The Class RepositoryImageUpdateTest. */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { ServiceBeanConfig.class, DatabaseConfig.class }) -public class RepositoryImageUpdateTest { +public class RepositoryImageUpdateTest extends RepositoryServiceTest { /** The initial content type. */ private final String initialContentType = "image/png"; /** The initial path. */ - private final String initialPath = "/initial/" + System.currentTimeMillis(); + private final Path initialPath = Paths.get("/initial/" + System.currentTimeMillis()); /** The initial extension. */ private final String initialExtension = ".png"; @@ -77,17 +72,6 @@ public class RepositoryImageUpdateTest { fileUuid = fileRepoService.addImage(initialPath, initialOriginalFilename, initialContentType, EMPTY_BYTES, null).getUuid(); } - /** - * After test. - * - * @throws NoSuchRepositoryFileException the no such repository file exception - * @throws IOException Signals that an I/O exception has occurred. - */ - @After - public void afterTest() throws NoSuchRepositoryFileException, IOException { - fileRepoService.removeFile(fileRepoService.getFile(fileUuid)); - } - /** * Test many update image data. * diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryServiceTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9bccf66cc454ab2e46bad4749e8465a24df9b764 --- /dev/null +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/RepositoryServiceTest.java @@ -0,0 +1,72 @@ +package org.genesys.filerepository.service; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import org.genesys.filerepository.config.DatabaseConfig; +import org.genesys.filerepository.config.ServiceBeanConfig; +import org.genesys.filerepository.model.RepositoryFolder; +import org.genesys.filerepository.persistence.RepositoryFilePersistence; +import org.genesys.filerepository.persistence.RepositoryFolderRepository; +import org.junit.After; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { ServiceBeanConfig.class, DatabaseConfig.class }) +public abstract class RepositoryServiceTest { + + protected static final Path ROOT = Paths.get("/"); + + /** The file repo service. */ + @Autowired + protected RepositoryService repositoryService; + + @Autowired + protected RepositoryFilePersistence fileRepository; + + @Autowired + protected RepositoryFolderRepository folderRepository; + + @Before + @Transactional + public void beforeTest() throws Throwable { + fileRepository.deleteAll(); + deleteFolders(folderRepository.findAll()); + + assertThat(fileRepository.count(), is(0l)); + assertThat(folderRepository.count(), is(0l)); + } + + private void deleteFolders(List toDelete) { + List pending = new ArrayList(); + for (RepositoryFolder folder : toDelete) { + try { + folderRepository.delete(folder); + System.err.println("Folder deleted " + folder); + } catch (Throwable e) { + System.err.println("Folder NOT deleted " + folder); + pending.add(folder); + } + } + if (pending.size() > 0) { + deleteFolders(pending); + } + } + + @After + @Transactional + public void afterTest() throws Throwable { + + } + +} diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/S3StorageServiceTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/S3StorageServiceTest.java index 2c90fc9793d25330ec0934f6850bd2546d6be7a8..7671fa59b80f28a3719adbf67b45a27274bd74cc 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/S3StorageServiceTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/S3StorageServiceTest.java @@ -16,22 +16,18 @@ package org.genesys.filerepository.service; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; -import com.fasterxml.jackson.core.JsonProcessingException; - import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.config.DatabaseConfig; import org.genesys.filerepository.config.ServiceBeanConfig; @@ -49,6 +45,8 @@ import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import com.fasterxml.jackson.core.JsonProcessingException; + // TODO: Auto-generated Javadoc /** * The Class S3StorageServiceTest. @@ -87,13 +85,14 @@ public class S3StorageServiceTest { */ @Test public void testAddFile() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.upsert(PATH, FILENAME, SOME_BYTES); + Path filePath = Paths.get(PATH, FILENAME); + bytesStorageService.upsert(filePath, SOME_BYTES); - final byte[] response = bytesStorageService.get(PATH, FILENAME); + final byte[] response = bytesStorageService.get(filePath); assertThat("File bytes length is different", response.length, is(SOME_BYTES.length)); assertArrayEquals("File bytes don't match", SOME_BYTES, response); - bytesStorageService.remove(PATH, FILENAME); + bytesStorageService.remove(filePath); } /** @@ -119,22 +118,22 @@ public class S3StorageServiceTest { + "accept;host;x-amz-content-sha256;x-amz-date\n" + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; byte[] a = canonicalRequest.getBytes(); - byte[] b = new byte[] { 0x47, 0x45, 0x54, 0x0a, 0x2f, 0x0a, 0x64, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x3d, 0x25, 0x32, 0x46, 0x26, 0x70, 0x72, 0x65, 0x66, 0x69, - 0x78, 0x3d, 0x6d, 0x6f, 0x62, 0x72, 0x65, 0x7a, 0x61, 0x25, 0x32, 0x46, 0x74, 0x65, 0x6d, 0x70, 0x25, 0x32, 0x46, 0x31, 0x35, 0x30, 0x38, 0x30, 0x39, 0x36, 0x32, 0x30, - 0x33, 0x30, 0x32, 0x36, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x6d, 0x6c, 0x2c, - 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x6d, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x2c, - 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x2a, 0x2b, 0x78, 0x6d, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2f, 0x2a, 0x2b, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x3a, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x79, 0x73, 0x2d, 0x73, 0x61, 0x6e, 0x64, - 0x62, 0x6f, 0x78, 0x2d, 0x72, 0x65, 0x70, 0x6f, 0x2e, 0x73, 0x33, 0x2d, 0x65, 0x75, 0x2d, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x2d, 0x31, 0x2e, 0x61, 0x6d, 0x61, - 0x7a, 0x6f, 0x6e, 0x61, 0x77, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x78, 0x2d, 0x61, 0x6d, 0x7a, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x68, 0x61, - 0x32, 0x35, 0x36, 0x3a, 0x65, 0x33, 0x62, 0x30, 0x63, 0x34, 0x34, 0x32, 0x39, 0x38, 0x66, 0x63, 0x31, 0x63, 0x31, 0x34, 0x39, 0x61, 0x66, 0x62, 0x66, 0x34, 0x63, 0x38, - 0x39, 0x39, 0x36, 0x66, 0x62, 0x39, 0x32, 0x34, 0x32, 0x37, 0x61, 0x65, 0x34, 0x31, 0x65, 0x34, 0x36, 0x34, 0x39, 0x62, 0x39, 0x33, 0x34, 0x63, 0x61, 0x34, 0x39, 0x35, - 0x39, 0x39, 0x31, 0x62, 0x37, 0x38, 0x35, 0x32, 0x62, 0x38, 0x35, 0x35, 0x0a, 0x78, 0x2d, 0x61, 0x6d, 0x7a, 0x2d, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x32, 0x30, 0x31, 0x37, - 0x31, 0x30, 0x31, 0x35, 0x54, 0x31, 0x39, 0x33, 0x36, 0x34, 0x38, 0x5a, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3b, 0x68, 0x6f, 0x73, 0x74, 0x3b, 0x78, 0x2d, - 0x61, 0x6d, 0x7a, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x3b, 0x78, 0x2d, 0x61, 0x6d, 0x7a, 0x2d, 0x64, 0x61, 0x74, - 0x65, 0x0a, 0x65, 0x33, 0x62, 0x30, 0x63, 0x34, 0x34, 0x32, 0x39, 0x38, 0x66, 0x63, 0x31, 0x63, 0x31, 0x34, 0x39, 0x61, 0x66, 0x62, 0x66, 0x34, 0x63, 0x38, 0x39, 0x39, - 0x36, 0x66, 0x62, 0x39, 0x32, 0x34, 0x32, 0x37, 0x61, 0x65, 0x34, 0x31, 0x65, 0x34, 0x36, 0x34, 0x39, 0x62, 0x39, 0x33, 0x34, 0x63, 0x61, 0x34, 0x39, 0x35, 0x39, 0x39, - 0x31, 0x62, 0x37, 0x38, 0x35, 0x32, 0x62, 0x38, 0x35, 0x35 }; + byte[] b = new byte[] { 0x47, 0x45, 0x54, 0x0a, 0x2f, 0x0a, 0x64, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x3d, 0x25, 0x32, 0x46, 0x26, 0x70, 0x72, 0x65, 0x66, + 0x69, 0x78, 0x3d, 0x6d, 0x6f, 0x62, 0x72, 0x65, 0x7a, 0x61, 0x25, 0x32, 0x46, 0x74, 0x65, 0x6d, 0x70, 0x25, 0x32, 0x46, 0x31, 0x35, 0x30, 0x38, 0x30, 0x39, 0x36, + 0x32, 0x30, 0x33, 0x30, 0x32, 0x36, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, + 0x6d, 0x6c, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x78, 0x6d, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, + 0x73, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x2a, 0x2b, 0x78, 0x6d, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x2a, 0x2b, 0x6a, 0x73, 0x6f, 0x6e, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x3a, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x79, + 0x73, 0x2d, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2d, 0x72, 0x65, 0x70, 0x6f, 0x2e, 0x73, 0x33, 0x2d, 0x65, 0x75, 0x2d, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, + 0x6c, 0x2d, 0x31, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x61, 0x77, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x0a, 0x78, 0x2d, 0x61, 0x6d, 0x7a, 0x2d, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x3a, 0x65, 0x33, 0x62, 0x30, 0x63, 0x34, 0x34, 0x32, 0x39, 0x38, 0x66, 0x63, 0x31, 0x63, 0x31, + 0x34, 0x39, 0x61, 0x66, 0x62, 0x66, 0x34, 0x63, 0x38, 0x39, 0x39, 0x36, 0x66, 0x62, 0x39, 0x32, 0x34, 0x32, 0x37, 0x61, 0x65, 0x34, 0x31, 0x65, 0x34, 0x36, 0x34, + 0x39, 0x62, 0x39, 0x33, 0x34, 0x63, 0x61, 0x34, 0x39, 0x35, 0x39, 0x39, 0x31, 0x62, 0x37, 0x38, 0x35, 0x32, 0x62, 0x38, 0x35, 0x35, 0x0a, 0x78, 0x2d, 0x61, 0x6d, + 0x7a, 0x2d, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x32, 0x30, 0x31, 0x37, 0x31, 0x30, 0x31, 0x35, 0x54, 0x31, 0x39, 0x33, 0x36, 0x34, 0x38, 0x5a, 0x0a, 0x0a, 0x61, 0x63, + 0x63, 0x65, 0x70, 0x74, 0x3b, 0x68, 0x6f, 0x73, 0x74, 0x3b, 0x78, 0x2d, 0x61, 0x6d, 0x7a, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x68, 0x61, + 0x32, 0x35, 0x36, 0x3b, 0x78, 0x2d, 0x61, 0x6d, 0x7a, 0x2d, 0x64, 0x61, 0x74, 0x65, 0x0a, 0x65, 0x33, 0x62, 0x30, 0x63, 0x34, 0x34, 0x32, 0x39, 0x38, 0x66, 0x63, + 0x31, 0x63, 0x31, 0x34, 0x39, 0x61, 0x66, 0x62, 0x66, 0x34, 0x63, 0x38, 0x39, 0x39, 0x36, 0x66, 0x62, 0x39, 0x32, 0x34, 0x32, 0x37, 0x61, 0x65, 0x34, 0x31, 0x65, + 0x34, 0x36, 0x34, 0x39, 0x62, 0x39, 0x33, 0x34, 0x63, 0x61, 0x34, 0x39, 0x35, 0x39, 0x39, 0x31, 0x62, 0x37, 0x38, 0x35, 0x32, 0x62, 0x38, 0x35, 0x35 }; assertThat(a.length, is(b.length)); assertThat(canonicalRequest, is(new String(b))); @@ -194,17 +193,18 @@ public class S3StorageServiceTest { */ @Test public void testList() throws IOException, InvalidKeyException, NoSuchAlgorithmException, InvalidRepositoryPathException { + Path basePath = Paths.get(PATH); for (int i = 1; i <= 20; i++) { - bytesStorageService.upsert(PATH, i + FILENAME, SOME_BYTES); + bytesStorageService.upsert(basePath.resolve(i + FILENAME), SOME_BYTES); } - final List x = bytesStorageService.listFiles(PATH); + final List x = bytesStorageService.listFiles(basePath); assertThat("List must not be null", x, notNullValue()); assertThat("Size doesn't match", x, hasSize(20)); for (final String filename : x) { LOG.debug("filename={}", filename); - bytesStorageService.remove(PATH, filename); + bytesStorageService.remove(basePath.resolve(filename)); } } @@ -218,12 +218,14 @@ public class S3StorageServiceTest { */ @Test public void testRemoveFile() throws IOException, InvalidKeyException, NoSuchAlgorithmException, InvalidRepositoryPathException { - bytesStorageService.upsert(PATH, FILENAME, SOME_BYTES); - assertThat(bytesStorageService.exists(PATH, FILENAME), is(true)); + Path filePath = Paths.get(PATH, FILENAME); - bytesStorageService.remove(PATH, FILENAME); + bytesStorageService.upsert(filePath, SOME_BYTES); + assertThat(bytesStorageService.exists(filePath), is(true)); - assertThat(bytesStorageService.exists(PATH, FILENAME), is(false)); + bytesStorageService.remove(filePath); + + assertThat(bytesStorageService.exists(filePath), is(false)); } /** @@ -235,18 +237,20 @@ public class S3StorageServiceTest { */ @Test public void testUpdateFile() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.upsert(PATH, FILENAME, SOME_BYTES); + Path filePath = Paths.get(PATH, FILENAME); + + bytesStorageService.upsert(filePath, SOME_BYTES); - byte[] response = bytesStorageService.get(PATH, FILENAME); + byte[] response = bytesStorageService.get(filePath); assertArrayEquals("File bytes don't match", SOME_BYTES, response); final byte[] bytes = new byte[] { 1, 2, 3 }; - bytesStorageService.upsert(PATH, FILENAME, bytes); + bytesStorageService.upsert(filePath, bytes); - response = bytesStorageService.get(PATH, FILENAME); + response = bytesStorageService.get(filePath); assertArrayEquals("File bytes don't match", bytes, response); - bytesStorageService.remove(PATH, FILENAME); + bytesStorageService.remove(filePath); } /** @@ -258,7 +262,8 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidUpsertNullBytes() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.upsert(PATH, FILENAME, null); + Path filePath = Paths.get(PATH, FILENAME); + bytesStorageService.upsert(filePath, null); } /** @@ -270,7 +275,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidUpsertWithoutFirstSlash() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.upsert("test/", FILENAME, SOME_BYTES); + bytesStorageService.upsert(Paths.get("test/", FILENAME), SOME_BYTES); } /** @@ -282,7 +287,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidUpsertWithLastSlash() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.upsert("/test/", FILENAME, SOME_BYTES); + bytesStorageService.upsert(Paths.get("/test/", FILENAME), SOME_BYTES); } /** @@ -294,7 +299,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidUpsertWithDoubleSlash() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.upsert("/test//test/", FILENAME, SOME_BYTES); + bytesStorageService.upsert(Paths.get("/test//test/", FILENAME), SOME_BYTES); } /** @@ -306,7 +311,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidUpsertNullPath() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.upsert(null, FILENAME, SOME_BYTES); + bytesStorageService.upsert(Paths.get(null, FILENAME), SOME_BYTES); } /** @@ -318,7 +323,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidUpsertBlankPath() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.upsert(" ", FILENAME, SOME_BYTES); + bytesStorageService.upsert(Paths.get(" ", FILENAME), SOME_BYTES); } /** @@ -330,7 +335,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidUpsertNullFilename() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.upsert("/test/", null, SOME_BYTES); + bytesStorageService.upsert(Paths.get("/test/", null), SOME_BYTES); } /** @@ -342,7 +347,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidRemoveWithoutFirstSlash() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.remove("test/", FILENAME); + bytesStorageService.remove(Paths.get("test/", FILENAME)); } /** @@ -354,7 +359,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidRemoveWithLastSlash() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.remove("/test/", FILENAME); + bytesStorageService.remove(Paths.get("/test/", FILENAME)); } /** @@ -366,7 +371,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidRemoveWithDoubleSlash() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.remove("/test//test/", FILENAME); + bytesStorageService.remove(Paths.get("/test//test/", FILENAME)); } /** @@ -378,7 +383,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidRemoveNullPath() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.remove(null, FILENAME); + bytesStorageService.remove(Paths.get(null, FILENAME)); } /** @@ -390,7 +395,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidRemoveBlankPath() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.remove(" ", FILENAME); + bytesStorageService.remove(Paths.get(" ", FILENAME)); } /** @@ -402,7 +407,7 @@ public class S3StorageServiceTest { */ @Test(expected = IOException.class) public void invalidRemoveNullFilename() throws IOException, InvalidKeyException, NoSuchAlgorithmException { - bytesStorageService.remove("/test/", null); + bytesStorageService.remove(Paths.get("/test/", null)); } /** @@ -413,7 +418,8 @@ public class S3StorageServiceTest { */ @Test public void testExistsWithoutExceptions() throws IOException, InvalidRepositoryPathException { - assertThat("File should not exist", bytesStorageService.exists(PATH, "file-should-not-exist"), is(false)); + Path filePath = Paths.get(PATH, "file-should-not-exist"); + assertThat("File should not exist", bytesStorageService.exists(filePath), is(false)); } /** @@ -424,16 +430,18 @@ public class S3StorageServiceTest { */ @Test public void testExistsNoYesNo() throws IOException, InvalidRepositoryPathException { - assertThat("File should not exist", bytesStorageService.exists(PATH, FILENAME), is(false)); + Path filePath = Paths.get(PATH, FILENAME); - bytesStorageService.upsert(PATH, FILENAME, SOME_BYTES); - final byte[] response = bytesStorageService.get(PATH, FILENAME); + assertThat("File should not exist", bytesStorageService.exists(filePath), is(false)); + + bytesStorageService.upsert(filePath, SOME_BYTES); + final byte[] response = bytesStorageService.get(filePath); assertThat("File bytes length is different", response.length, is(SOME_BYTES.length)); assertArrayEquals("File bytes don't match", SOME_BYTES, response); - assertThat("File must exist", bytesStorageService.exists(PATH, FILENAME), is(true)); + assertThat("File must exist", bytesStorageService.exists(filePath), is(true)); - bytesStorageService.remove(PATH, FILENAME); - assertThat("File must not exist", bytesStorageService.exists(PATH, FILENAME), is(false)); + bytesStorageService.remove(filePath); + assertThat("File must not exist", bytesStorageService.exists(filePath), is(false)); } /** @@ -444,16 +452,17 @@ public class S3StorageServiceTest { */ @Test public void testSpaceInPath() throws IOException, InvalidRepositoryPathException { - final String pathWithSpace = PATH + "IRGC 11111/"; - - bytesStorageService.upsert(pathWithSpace, FILENAME, SOME_BYTES); - assertThat("File must exist", bytesStorageService.exists(pathWithSpace, FILENAME), is(true)); + final Path pathWithSpace = Paths.get(PATH, "IRGC 11111/"); + Path fileName = pathWithSpace.resolve(FILENAME); + + bytesStorageService.upsert(fileName, SOME_BYTES); + assertThat("File must exist", bytesStorageService.exists(fileName), is(true)); final List x = bytesStorageService.listFiles(pathWithSpace); assertThat("Size doesn't match", x, hasSize(1)); assertThat("File must not be missing from the list", x, contains(FILENAME)); - bytesStorageService.remove(pathWithSpace, FILENAME); - assertThat("File must not exist", bytesStorageService.exists(pathWithSpace, FILENAME), is(false)); + bytesStorageService.remove(fileName); + assertThat("File must not exist", bytesStorageService.exists(fileName), is(false)); } } diff --git a/file-repository-core/src/test/java/org/genesys/filerepository/service/VirusScannerTest.java b/file-repository-core/src/test/java/org/genesys/filerepository/service/VirusScannerTest.java index 8a12bbda04f3b43764b27649dda96b2197b4ae38..d269c71444c476139e741ee3cd3bb5865c871853 100644 --- a/file-repository-core/src/test/java/org/genesys/filerepository/service/VirusScannerTest.java +++ b/file-repository-core/src/test/java/org/genesys/filerepository/service/VirusScannerTest.java @@ -18,12 +18,15 @@ package org.genesys.filerepository.service; import java.io.File; import java.io.IOException; +import java.nio.file.Paths; +import org.apache.commons.io.FileUtils; import org.genesys.filerepository.service.aspect.VirusScanAspect; import org.genesys.filerepository.service.impl.ClamAVScanner; import org.genesys.filerepository.service.impl.FilesystemStorageServiceImpl; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -51,10 +54,11 @@ public class VirusScannerTest { */ @Configuration @EnableAspectJAutoProxy - public static class Config { + public static class Config implements DisposableBean { private static final String CLAMD_PORT = "CLAMD_PORT"; private static final String CLAMD_HOSTNAME = "CLAMD_HOSTNAME"; + private File fileRepositoryFolder; /** * Bytes storage service. @@ -63,13 +67,23 @@ public class VirusScannerTest { */ @Bean(name = "bytesStorageService") public BytesStorageService bytesStorageService() { - final File repoDir = new File("data"); + this.fileRepositoryFolder = new File(FileUtils.getTempDirectory(), "file-repo-" + System.currentTimeMillis()); + assert(this.fileRepositoryFolder.exists() == false); + this.fileRepositoryFolder.mkdirs(); + final FilesystemStorageServiceImpl storageService = new FilesystemStorageServiceImpl(); - storageService.setRepositoryBaseDirectory(repoDir); + storageService.setRepositoryBaseDirectory(this.fileRepositoryFolder); return storageService; } + @Override + public void destroy() throws Exception { + System.err.println("Deleting " + fileRepositoryFolder.getAbsolutePath()); + FileUtils.deleteDirectory(this.fileRepositoryFolder); + assert(this.fileRepositoryFolder.exists() == false); + } + /** * Virus scan aspect. * @@ -166,7 +180,7 @@ public class VirusScannerTest { @Test(expected = IOException.class) public void testVirusScannerStandardVirus2() throws IOException { if (virusScanner != null) { - bytesStorageService.upsert("test", "file", EICAR_TEST); + bytesStorageService.upsert(Paths.get("test", "file"), EICAR_TEST); } else { throw new IOException("Scanner not available, so fake it!"); } diff --git a/file-repository-core/src/test/resources/log4j.properties b/file-repository-core/src/test/resources/log4j.properties index e0eec68ccdfc4cb7c98859d7ed4dd8b2db8da68f..fbb35f4f0748318ea66373d5340bf175c6926131 100644 --- a/file-repository-core/src/test/resources/log4j.properties +++ b/file-repository-core/src/test/resources/log4j.properties @@ -26,3 +26,6 @@ log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %t %5p %c{1}:%L - %m log4j.rootLogger=warn, stdout log4j.category.org.genesys.filerepository=debug + +# Internal Hibernate logging is at ERROR +log4j.category.org.hibernate.engine.jdbc=fatal diff --git a/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFileSystemFactory.java b/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFileSystemFactory.java index f4b2fc1c157fabe8ee311891dd8e7abe1552be0e..50bbdad0276dd8eac9b9e54c2d8011d0c20c7c4c 100644 --- a/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFileSystemFactory.java +++ b/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFileSystemFactory.java @@ -22,9 +22,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import org.apache.ftpserver.ftplet.AuthenticationFailedException; @@ -33,6 +31,7 @@ import org.apache.ftpserver.ftplet.FileSystemView; import org.apache.ftpserver.ftplet.FtpException; import org.apache.ftpserver.ftplet.FtpFile; import org.apache.ftpserver.ftplet.User; +import org.genesys.filerepository.FolderNotEmptyException; import org.genesys.filerepository.InvalidRepositoryFileDataException; import org.genesys.filerepository.InvalidRepositoryPathException; import org.genesys.filerepository.NoSuchRepositoryFileException; @@ -62,7 +61,6 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ @Autowired(required = true) private TemporaryBytesManager bytesManager; - /** * File. * @@ -88,7 +86,7 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ @Override public boolean mkdir() { - // TODO Auto-generated method stub + LOG.debug("MKDIR on file not possible"); return false; } @@ -109,9 +107,9 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ @Override public boolean move(final FtpFile destination) { return FtpRunAs.asFtpUser(session.user, () -> { - LOG.info("Move file={} to dest={}", this.getAbsolutePath(), destination.getAbsolutePath()); + LOG.info("Move file={} to dest={}", this.getAbsolutePath(), Paths.get(destination.getAbsolutePath())); try { - repositoryService.moveAndRenameFile(repositoryFile, destination.getAbsolutePath()); + repositoryService.moveAndRenameFile(repositoryFile, Paths.get(destination.getAbsolutePath())); return true; } catch (InvalidRepositoryPathException | InvalidRepositoryFileDataException e) { LOG.warn("Error moving file: {}", e.getMessage()); @@ -148,8 +146,8 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ * @param session the session * @return the repository ftp directory */ - private RepositoryFtpDirectory directory(final String path, final RepositoryFileSystemView session) { - LOG.trace("Making RepositoryFtpDirectory path={}", path); + private RepositoryFtpDirectory directory(final Path path, final RepositoryFileSystemView session) { + LOG.trace("Viewing RepositoryFtpDirectory path={}", path); final RepositoryFtpDirectory rfd = new RepositoryFtpDirectory(path) { @Override @@ -157,7 +155,7 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ return FtpRunAs.asFtpUser(session.user, () -> { LOG.info("Move directory={} to dest={}", this.getAbsolutePath(), destination.getAbsolutePath()); try { - repositoryService.renamePath(this.getAbsolutePath(), destination.getAbsolutePath()); + repositoryService.renamePath(Paths.get(this.getAbsolutePath()), Paths.get(destination.getAbsolutePath())); return true; } catch (final InvalidRepositoryPathException e) { LOG.error("Failed to rename directory", e); @@ -169,8 +167,15 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ @Override public boolean mkdir() { LOG.info("Mkdir directory={}", this.getAbsolutePath()); - // TODO Auto-generated method stub - return false; + try { + return FtpRunAs.asFtpUser(session.user, () -> { + repositoryService.ensureFolder(path); + return true; + }); + } catch (InvalidRepositoryPathException e) { + LOG.error("{}", e.getMessage(), e); + return false; + } } @Override @@ -179,53 +184,20 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ return _listFiles(); }); } - + private List _listFiles() { - final String currentPath = getAbsolutePath(); - LOG.debug("Listing files in path={}", currentPath); + final Path root = path.normalize().toAbsolutePath(); + LOG.debug("Listing files in path={}", root); final ArrayList all = new ArrayList<>(); - final Path root = Paths.get(currentPath); + all.addAll(repositoryService.getFolders(root).stream().peek(rf -> { + // System.err.println("repoFolder " + rf.getPath()); + }).map(rf -> directory(rf.getFolderPath(), session)).collect(Collectors.toList())); - all.addAll(repositoryService.getFiles(currentPath).stream().peek(rf -> { - // System.err.println("repoFile " + rf.getPath() + " " + - // rf.getOriginalFilename()); + all.addAll(repositoryService.getFiles(root).stream().peek(rf -> { + // System.err.println("repoFile " + rf.getStorageFullPath()); }).map(rf -> file(rf, session)).collect(Collectors.toList())); - try { - all.addAll(repositoryService.listPaths(currentPath).stream() - // remove from temporaryDir if exists in the repository - .peek(path -> { - session.temporaryDirs.remove(path); - }) - // filter out current path - .filter(path -> !currentPath.equals(path)) - // get the first subfolder name within currentPath - .map(path -> { - final Path foo = Paths.get(path.substring(currentPath.length())); - LOG.trace("Sub cp=" + currentPath + " p=" + path + " x=" + foo.getName(0)); - return foo.getName(0).toString(); - }) - // remove duplicates and make directories - .distinct().map(path -> directory(path, session)).collect(Collectors.toList())); - } catch (final InvalidRepositoryPathException e) { - LOG.warn("Error listing paths for {}: {}", currentPath, e.getMessage()); - } - - all.addAll(session.temporaryDirs.stream().filter(path -> path.startsWith(currentPath) && !path.equals(currentPath)) - // we have full paths as string, filter the ones that are direct children - .map(path -> { - final Path relativized = root.relativize(Paths.get(path)); - LOG.trace("Rel={} rel[0]={} root.resolve={}", relativized.toString(), relativized.getName(0), root.resolve(relativized.getName(0)).normalize().toString()); - return root.resolve(relativized.getName(0)).normalize().toString(); - }) - // unique - .distinct().peek(p -> { - LOG.debug("Temporary folder={}", p); - }) - // map to RepositoryFtpDirectory - .map(path -> directory(path, session)).collect(Collectors.toList())); - // Distinct sorted list of everything return Collections.unmodifiableList(all.stream().distinct().sorted((a, b) -> { return a.getName().compareTo(b.getName()); @@ -249,19 +221,19 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ @Override public boolean delete() { return FtpRunAs.asFtpUser(session.user, () -> { - LOG.info("Delete this={}", getAbsolutePath()); - if (session.hasTempDir(getAbsolutePath())) { - session.removeTempDir(getAbsolutePath()); + LOG.info("Delete this={}", path); + try { + repositoryService.deleteFolder(path); return true; + } catch (FolderNotEmptyException e) { + return false; } - LOG.warn("Not deleting repository folder={}", getAbsolutePath()); - return false; }); } @Override public boolean changeWorkingDirectory(final String dir) { - final String normalized = Paths.get(getAbsolutePath()).resolve(dir).normalize().toAbsolutePath().toString(); + final Path normalized = Paths.get(getAbsolutePath()).resolve(dir).normalize().toAbsolutePath(); LOG.info("CWD this={} dir={} normalized={}", getAbsolutePath(), dir, normalized); this.cwd(normalized); // TODO Check if such path exists? @@ -271,7 +243,7 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ return rfd; } - + /* * (non-Javadoc) * @see @@ -281,7 +253,7 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ @Override public FileSystemView createFileSystemView(final User user) throws FtpException { LOG.info("Creating new repository view for {}", user.getName()); - + RepositoryFileSystemView userView = new RepositoryFileSystemView((FtpUser) user) { @Override @@ -289,67 +261,76 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ LOG.debug("getFile file={} for user={}", file, username); final Path path = file.startsWith("/") ? Paths.get(file).normalize() : Paths.get(cwd.getAbsolutePath(), file).normalize(); LOG.trace("Resolved normalized={}", path.toString()); - LOG.trace("Temporary dirs: {}", temporaryDirs); - - if (temporaryDirs.stream().filter(longpath -> longpath.startsWith(path.toString())).findFirst().isPresent()) { - LOG.trace("dir={} is a temporary session-bound directory", path); - return directory(path.toString(), this); - } try { + return isDirectory(path) ? - // directory - directory(path.toString(), this) + // directory + directory(path, this) // or file - : file(FtpRunAs.asFtpUser(user, () -> repositoryService.getFile( - path.getParent().toString(), - path.getFileName().toString())), this); + : file(FtpRunAs.asFtpUser(user, () -> repositoryService.getFile(path.getParent(), path.getFileName().toString())), this); } catch (final AuthenticationException e) { LOG.warn("Authentication problem {}", e.getMessage(), e); throw new AuthenticationFailedException(e.getMessage()); - } catch (final NoSuchRepositoryFileException e) { + } catch (NoSuchRepositoryFileException e) { + LOG.warn("No such file {}", file); - LOG.debug("Making new CanBeAnythingFile path={} name={}", path.getParent().toString(), path.getFileName().toString()); return new CanBeAnythingFile(path.getParent(), path.getFileName().toString()) { @Override public boolean mkdir() { - this.dir = true; - LOG.info("Mkdir path={}", this.getAbsolutePath()); - temporaryDirs.add(this.getAbsolutePath()); - return true; + LOG.debug("MKDIR {}", path); + try { + FtpRunAs.asFtpUser(user, () -> repositoryService.ensureFolder(path)); + return true; + } catch (InvalidRepositoryPathException e) { + LOG.warn("{}", e.getMessage(), e); + return false; + } } @Override public boolean delete() { - final Set matches = temporaryDirs.stream().filter(longpath -> longpath.startsWith(getAbsolutePath())).collect(Collectors.toSet()); - LOG.debug("Removing session-bound directories {}", matches); - temporaryDirs.removeAll(matches); - return true; - }; + return false; + } @Override - public OutputStream createOutputStream(final long offset) throws IOException { - LOG.info("Creating output stream for new file={} at offset={}", getAbsolutePath(), offset); - assert (offset == 0l); - return bytesManager.newFile(user, Paths.get(getAbsolutePath())); + public OutputStream createOutputStream(long offset) throws IOException { + LOG.debug("STOR {}", path); + if (path.getParent() != null) { + LOG.debug("MKDIR {}", path.getParent()); + try { + FtpRunAs.asFtpUser(user, () -> repositoryService.ensureFolder(path.getParent())); + return bytesManager.newFile(user, path); + } catch (InvalidRepositoryPathException e) { + LOG.warn("{}", e.getMessage(), e); + throw new IOException(e.getMessage(), e); + } + } else { + throw new IOException("Cannot store files to /"); + } } }; } } - private boolean isDirectory(final Path path) { + private boolean isDirectory(final Path path) throws FtpException { + if (path.toString().equals("/")) { + return true; + } + try { - return path.toString().equals("/") || repositoryService.hasPath(path) || temporaryDirs.stream().filter(longpath -> longpath.equals(path.toString())).findFirst().isPresent(); + LOG.trace("isDirectory " + path); + return repositoryService.hasPath(path); } catch (final InvalidRepositoryPathException e) { LOG.debug("Invalid repository path {}: {}", path, e.getMessage()); - return temporaryDirs.stream().filter(longpath -> longpath.equals(path.toString())).findFirst().isPresent(); + throw new FtpException(e.getMessage(), e); } } }; - + return userView; // AspectJProxyFactory factory = new AspectJProxyFactory(userView); // factory.addAspect(new FtpSpringSecurityAspect((FtpUser) user)); @@ -378,13 +359,10 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ protected String username; /** The cwd. */ - protected RepositoryFtpDirectory cwd = directory("/", this); + protected RepositoryFtpDirectory cwd = directory(Paths.get("/"), this); /** The home dir. */ - protected RepositoryFtpDirectory homeDir = directory("/", this); - - /** The temporary dirs. */ - protected Set temporaryDirs = new HashSet<>(); + protected RepositoryFtpDirectory homeDir = directory(Paths.get("/"), this); /** * Instantiates a new repository file system view. @@ -396,17 +374,6 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ username = user.getName(); } - /** - * Removes the temp dir. - * - * @param absolutePath the absolute path - */ - public void removeTempDir(final String absolutePath) { - final Set matches = temporaryDirs.stream().filter(longpath -> longpath.startsWith(absolutePath)).collect(Collectors.toSet()); - LOG.debug("Removing session-bound directories {}", matches); - temporaryDirs.removeAll(matches); - } - /* * (non-Javadoc) * @see org.apache.ftpserver.ftplet.FileSystemView#isRandomAccessible() @@ -457,15 +424,5 @@ public class RepositoryFileSystemFactory implements FileSystemFactory, Initializ LOG.debug("CWD dir={} for user={}", dir, username); return this.cwd.changeWorkingDirectory(dir); } - - /** - * Checks for temp dir. - * - * @param absolutePath the absolute path - * @return true, if successful - */ - public boolean hasTempDir(final String absolutePath) { - return temporaryDirs.stream().filter(longpath -> longpath.startsWith(absolutePath)).findFirst().isPresent(); - } } } diff --git a/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFtpDirectory.java b/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFtpDirectory.java index 6e1704ba1066f935561f1cf4ccc836580cba6a1b..33e0dac568c2eaac2bdfce54fb17fa3361f2bb3e 100644 --- a/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFtpDirectory.java +++ b/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFtpDirectory.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import org.apache.ftpserver.ftplet.FtpFile; @@ -39,7 +38,7 @@ public abstract class RepositoryFtpDirectory implements FtpFile { * * @param path the path */ - public RepositoryFtpDirectory(final String path) { + public RepositoryFtpDirectory(final Path path) { assert (path != null); cwd(path); } @@ -49,8 +48,8 @@ public abstract class RepositoryFtpDirectory implements FtpFile { * * @param path the path */ - protected void cwd(final String path) { - this.path = Paths.get(path).normalize().toAbsolutePath(); + protected void cwd(final Path path) { + this.path = path.normalize().toAbsolutePath(); } /* diff --git a/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFtpFile.java b/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFtpFile.java index 01666426180d0e1a02f81c3ec3a4374bc3bcb0b4..cb68c86a11669b121fb1fa78f44c5a4b47f4ade6 100644 --- a/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFtpFile.java +++ b/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/RepositoryFtpFile.java @@ -49,7 +49,7 @@ public abstract class RepositoryFtpFile implements FtpFile { */ @Override public String getAbsolutePath() { - return this.repositoryFile.getPath() + this.repositoryFile.getOriginalFilename(); + return this.repositoryFile.getFolder().getPath() + this.repositoryFile.getOriginalFilename(); } /* diff --git a/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/TemporaryBytesManager.java b/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/TemporaryBytesManager.java index 1be5891ee36145c59bdb280c89deacf0d4eb363f..ae015a19a96992b63cb7caf43b4bd2b4a266e4cd 100644 --- a/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/TemporaryBytesManager.java +++ b/file-repository-ftpserver/src/main/java/org/genesys/filerepository/service/ftp/TemporaryBytesManager.java @@ -70,7 +70,7 @@ public class TemporaryBytesManager { * @throws IOException Signals that an I/O exception has occurred. */ public OutputStream newFile(FtpUser user, final Path path) throws IOException { - final String parent = path.getParent().toString(); + final Path parent = path.getParent(); final String filename = path.getFileName().toString(); LOG.info("Creating new path={} parent={} filename={}", path, parent, filename); @@ -210,7 +210,7 @@ public class TemporaryBytesManager { LOG.warn("Error synchronizing new file with repository: {}", e.getMessage()); throw new IOException(e); } - LOG.info("Synchronized file={} with repository path={} originalFilename={}", tempFile.getAbsolutePath(), repositoryFile.getPath(), repositoryFile.getOriginalFilename()); + LOG.info("Synchronized file={} with repository path={} originalFilename={}", tempFile.getAbsolutePath(), repositoryFile.getFolder().getPath(), repositoryFile.getOriginalFilename()); return null; }); } diff --git a/file-repository-ftpserver/src/test/java/org/genesys/filerepository/service/ftp/FtpServerTest.java b/file-repository-ftpserver/src/test/java/org/genesys/filerepository/service/ftp/FtpServerTest.java index a3c5436d30e51a7b1cf23e1365de4b736448c0cf..175151f812713772d0e96e8d0b7abf2811fdf446 100644 --- a/file-repository-ftpserver/src/test/java/org/genesys/filerepository/service/ftp/FtpServerTest.java +++ b/file-repository-ftpserver/src/test/java/org/genesys/filerepository/service/ftp/FtpServerTest.java @@ -199,6 +199,7 @@ public class FtpServerTest { ftp.makeDirectory("test1"); FTPFile[] files = ftp.listFiles(); assertThat(files, notNullValue()); + Arrays.stream(files).forEach(f -> LOG.debug("Got file {}", f)); assertThat(Arrays.stream(files).map(file -> file.getName()).collect(Collectors.toList()), hasItems("test1")); assertThat(Arrays.stream(files).map(file -> file.isDirectory()).collect(Collectors.toList()), hasItems(true)); @@ -222,11 +223,9 @@ public class FtpServerTest { * @throws IOException Signals that an I/O exception has occurred. */ public void debugListFiles(final FTPClient ftp) throws IOException { - if (LOG.isDebugEnabled()) { - Arrays.stream(ftp.listFiles()).forEach(file -> { - LOG.debug("list> " + file); - }); - } + Arrays.stream(ftp.listFiles()).forEach(file -> { + LOG.debug("list> {}", file); + }); } /** @@ -257,6 +256,8 @@ public class FtpServerTest { debugListFiles(ftp); final FTPFile[] files = ftp.listFiles(); + LOG.debug("Listing thingies"); + debugListFiles(ftp); assertThat(files, notNullValue()); assertThat(Arrays.stream(files).map(file -> file.getName()).collect(Collectors.toList()), hasItems("test1", "test2", "test3")); assertThat(Arrays.stream(files).map(file -> file.isDirectory()).collect(Collectors.toList()), hasItems(true, true, true)); @@ -266,8 +267,9 @@ public class FtpServerTest { assertThat(ftp.removeDirectory("/test1"), is(true)); assertThat(ftp.removeDirectory("/test2"), is(true)); assertThat(Arrays.stream(ftp.listFiles()).map(file -> file.getName()).collect(Collectors.toList()), hasItems("test3")); - assertThat(ftp.removeDirectory("test3"), is(true)); - assertThat(ftp.listFiles().length, is(0)); + assertThat(ftp.removeDirectory("test3"), is(false)); + debugListFiles(ftp); + assertThat(ftp.listFiles().length, is(1)); } finally { ftp.disconnect(); @@ -328,6 +330,9 @@ public class FtpServerTest { ftp.setFileTransferMode(FTP.ASCII_FILE_TYPE); + ftp.cwd("folder"); + assertThat(ftp.printWorkingDirectory(), is("/folder")); + try (InputStream local = new ByteArrayInputStream(TEST_FILE_CONTENTS.getBytes())) { assertThat(ftp.storeFile("file", local), is(true)); } @@ -390,7 +395,7 @@ public class FtpServerTest { assertThat(ftp.changeWorkingDirectory(dir), is(true)); debugListFiles(ftp); final char nextDir = dir == "/" ? 'a' : (char) (dir.substring(dir.length() - 1, dir.length()).charAt(0) + 1); - // System.err.println("Curr=" + dir + " next=" + nextDir); + LOG.trace("Curr={} next={}", dir, nextDir); assertThat(Arrays.stream(ftp.listFiles()).map(file -> file.getName()).collect(Collectors.toList()), hasItems("" + nextDir)); } @@ -423,6 +428,8 @@ public class FtpServerTest { assertThat(ftp.printWorkingDirectory(), is("/")); ftp.setFileTransferMode(FTP.ASCII_FILE_TYPE); + ftp.cwd("folder"); + assertThat(ftp.printWorkingDirectory(), is("/folder")); try (InputStream local = new ByteArrayInputStream(TEST_FILE_CONTENTS.getBytes())) { assertThat(ftp.storeFile("rewrite", local), is(true)); @@ -479,13 +486,15 @@ public class FtpServerTest { assertThat(ftp.printWorkingDirectory(), is("/")); ftp.setFileTransferMode(FTP.ASCII_FILE_TYPE); + ftp.cwd("folder"); + assertThat(ftp.printWorkingDirectory(), is("/folder")); try (InputStream local = new ByteArrayInputStream(TEST_FILE_CONTENTS.getBytes())) { assertThat(ftp.storeFile("append.txt", local), is(true)); } final FTPFile[] files = ftp.listFiles(); - System.err.println(Arrays.asList(files)); + LOG.trace("Listing: {}", Arrays.asList(files)); assertThat(Arrays.asList(files).stream().map(file -> file.getName()).collect(Collectors.toList()), contains("append.txt")); final FTPFile theFile = files[0]; @@ -567,14 +576,6 @@ public class FtpServerTest { assertThat(ftp.changeWorkingDirectory("/a/b1/c"), is(true)); assertThat(ftp.listFiles().length, is(0)); - assertThat(ftp.changeWorkingDirectory("/"), is(true)); - Arrays.stream(ftp.listDirectories()).forEach(dir -> { - try { - ftp.removeDirectory(dir.getName()); - } catch (final IOException e) { - } - }); - assertThat(ftp.listFiles().length, is(0)); } finally { ftp.disconnect(); diff --git a/file-repository-ftpserver/src/test/resources/log4j.properties b/file-repository-ftpserver/src/test/resources/log4j.properties index b460580722da884ad328bb4404603b518cb806da..1def964199049f4a6450dd64696cc7444388832c 100644 --- a/file-repository-ftpserver/src/test/resources/log4j.properties +++ b/file-repository-ftpserver/src/test/resources/log4j.properties @@ -25,6 +25,6 @@ log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %t %5p %c{1}:%L - %m ### set log levels - for more verbose logging change 'info' to 'debug' ### log4j.rootLogger=error, stdout -log4j.category.org.genesys.filerepository=debug +log4j.category.org.genesys.filerepository=trace log4j.category.org.apache.ftpserver=debug log4j.category.org.apache.commons.net=info diff --git a/pom.xml b/pom.xml index 4602a74ef195f7260d1430f1092a44e96cd50d60..f484dca06ddbbd062e36d39c5e9347dbcde208cb 100644 --- a/pom.xml +++ b/pom.xml @@ -1,21 +1,15 @@ - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - - + 4.0.0 org.genesys-pgr file-repository @@ -119,6 +113,13 @@ + + com.querydsl + querydsl-jpa + ${querydsl.version} + provided + + junit @@ -230,7 +231,8 @@ - + false false @@ -245,7 +247,7 @@ true true true - true + false