Skip to content

Commit

Permalink
Refactor SubmodelRepository FileHandling Methods into SubmodelService (
Browse files Browse the repository at this point in the history
#244)

* Move FileRepository interface/implementations to Common

* Add file handling methods to SubmodelService API

* Move file related tests from RepositorySuite to ServiceSuite

* Refactor SubmodelRepo to use file handling logic from Service

* Fix name typo in MongoDBFileRepository

* Implement /attachment endpoints to the SubmodelServiceHttpController

* Modify injection method of FileRepository in SubmodelServiceFactory
  • Loading branch information
mateusmolina-iese committed Apr 4, 2024
1 parent b62012a commit 7863c28
Show file tree
Hide file tree
Showing 44 changed files with 1,042 additions and 564 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.ConceptDescriptionInMemoryBackendProvider;
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.ConceptDescriptionRepository;
import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingIdentifierException;
import org.eclipse.digitaltwin.basyx.core.filerepository.InMemoryFileRepository;
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelInMemoryBackendProvider;
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
Expand Down Expand Up @@ -77,7 +78,7 @@ public class AasEnvironmentLoaderTest {

@Before
public void setUp() {
submodelRepository = Mockito.spy(new CrudSubmodelRepository(new SubmodelInMemoryBackendProvider(), new InMemorySubmodelServiceFactory()));
submodelRepository = Mockito.spy(new CrudSubmodelRepository(new SubmodelInMemoryBackendProvider(), new InMemorySubmodelServiceFactory(new InMemoryFileRepository())));
aasRepository = Mockito.spy(new CrudAasRepository(new AasInMemoryBackendProvider(), new InMemoryAasServiceFactory()));
conceptDescriptionRepository = Mockito.spy(new CrudConceptDescriptionRepository(new ConceptDescriptionInMemoryBackendProvider()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.eclipse.digitaltwin.basyx.aasservice.backend.InMemoryAasServiceFactory;
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.ConceptDescriptionInMemoryBackendProvider;
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.ConceptDescriptionRepository;
import org.eclipse.digitaltwin.basyx.core.filerepository.InMemoryFileRepository;
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelInMemoryBackendProvider;
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
Expand Down Expand Up @@ -62,7 +63,7 @@ public class TestAASEnvironmentSerialization {

@Before
public void setup() {
submodelRepository = new SimpleSubmodelRepositoryFactory(new SubmodelInMemoryBackendProvider(), new InMemorySubmodelServiceFactory()).create();
submodelRepository = new SimpleSubmodelRepositoryFactory(new SubmodelInMemoryBackendProvider(), new InMemorySubmodelServiceFactory(new InMemoryFileRepository())).create();
aasRepository = new SimpleAasRepositoryFactory(new AasInMemoryBackendProvider(), new InMemoryAasServiceFactory()).create();
conceptDescriptionRepository = new SimpleConceptDescriptionRepositoryFactory(new ConceptDescriptionInMemoryBackendProvider(), createDummyConceptDescriptions(), "cdRepo").create();

Expand Down
25 changes: 25 additions & 0 deletions basyx.common/basyx.filerepository-backend-inmemory/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.common</artifactId>
<version>${revision}</version>
</parent>
<artifactId>basyx.filerepository-backend-inmemory</artifactId>
<dependencies>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.filerepository-backend</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.submodelrepository;
package org.eclipse.digitaltwin.basyx.core.filerepository;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
Expand All @@ -37,39 +37,41 @@
import org.apache.commons.io.IOUtils;
import org.eclipse.digitaltwin.basyx.core.exceptions.FileDoesNotExistException;
import org.eclipse.digitaltwin.basyx.core.exceptions.FileHandlingException;
import org.eclipse.digitaltwin.basyx.core.file.FileMetadata;
import org.eclipse.digitaltwin.basyx.core.file.FileRepository;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;

/**
* An InMemory implementation of the {@link FileRepository}
*
* @author danish
*/
public class InMemorySubmodelFileRepository implements FileRepository {
@Component
@ConditionalOnExpression("'${basyx.backend}'.equals('InMemory')")
public class InMemoryFileRepository implements FileRepository {

private static final String TEMP_DIRECTORY_PREFIX = "basyx-temp";
private String tmpDirectory = getTemporaryDirectoryPath();

@Override
public String save(FileMetadata fileMetadata) throws FileHandlingException {
String filePath = createFilePath(fileMetadata.getFileName());

java.io.File targetFile = new java.io.File(filePath);

try (FileOutputStream outStream = new FileOutputStream(targetFile)) {
IOUtils.copy(fileMetadata.getFileContent(), outStream);
} catch (IOException e) {
throw new FileHandlingException(fileMetadata.getFileName());
}

fileMetadata.setFileName(filePath);

return filePath;
}

@Override
public InputStream find(String fileId) throws FileDoesNotExistException {

try {
return new FileInputStream(fileId);
} catch (FileNotFoundException e) {
Expand All @@ -79,47 +81,47 @@ public InputStream find(String fileId) throws FileDoesNotExistException {

@Override
public void delete(String fileId) throws FileDoesNotExistException {

if (!exists(fileId))
throw new FileDoesNotExistException();

java.io.File tmpFile = new java.io.File(fileId);

tmpFile.delete();
}

@Override
public boolean exists(String fileId) {

if (fileId.isBlank() || !isFilePathValid(fileId))
return false;

return Files.exists(Paths.get(fileId));
}

private boolean isFilePathValid(String filePath) {

try {
Paths.get(filePath);
} catch (InvalidPathException | NullPointerException ex) {
return false;
}

return true;
}

private String getTemporaryDirectoryPath() {
String tempDirectoryPath = "";

try {
tempDirectoryPath = Files.createTempDirectory(TEMP_DIRECTORY_PREFIX).toAbsolutePath().toString();
} catch (IOException e) {
throw new RuntimeException(String.format("Unable to create the temporary directory with prefix: %s", TEMP_DIRECTORY_PREFIX));
}

return tempDirectoryPath;
}

private String createFilePath(String fileName) {
return tmpDirectory + "/" + fileName;
}
Expand Down
21 changes: 21 additions & 0 deletions basyx.common/basyx.filerepository-backend-mongodb/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.common</artifactId>
<version>${revision}</version>
</parent>
<artifactId>basyx.filerepository-backend-mongodb</artifactId>
<dependencies>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.filerepository-backend</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.mongodbcore</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.submodelrepository;
package org.eclipse.digitaltwin.basyx.core.filerepository;

import java.io.IOException;
import java.io.InputStream;
Expand All @@ -34,32 +34,44 @@
import org.bson.types.ObjectId;
import org.eclipse.digitaltwin.basyx.core.exceptions.FileDoesNotExistException;
import org.eclipse.digitaltwin.basyx.core.exceptions.FileHandlingException;
import org.eclipse.digitaltwin.basyx.core.file.FileMetadata;
import org.eclipse.digitaltwin.basyx.core.file.FileRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Component;

import com.mongodb.client.gridfs.model.GridFSFile;

import org.springframework.data.mongodb.core.query.Query;

/**
* A MongoDB implementation of the {@link FileRepository}
*
* @author danish
*/
public class MongoDBSubmodelFileRepository implements FileRepository {
@Component
@ConditionalOnExpression("'${basyx.backend}'.equals('MongoDB')")
public class MongoDBFileRepository implements FileRepository {

private static final String MONGO_ID = "_id";
private static final String GRIDFS_ID_DELIMITER = "#";
private static final String TEMP_DIR_PREFIX = "basyx-temp";

private GridFsTemplate gridFsTemplate;

public MongoDBSubmodelFileRepository(GridFsTemplate gridFsTemplate) {
@Autowired
public MongoDBFileRepository(MongoTemplate mongoTemplate) {
this(buildDefaultGridFsTemplate(mongoTemplate));
}

public MongoDBFileRepository(GridFsTemplate gridFsTemplate) {
this.gridFsTemplate = gridFsTemplate;
}

public static GridFsTemplate buildDefaultGridFsTemplate(MongoTemplate mongoTemplate) {
return new GridFsTemplate(mongoTemplate.getMongoDatabaseFactory(), mongoTemplate.getConverter());
}

@Override
public String save(FileMetadata fileMetadata) throws FileHandlingException {
ObjectId id = gridFsTemplate.store(fileMetadata.getFileContent(), fileMetadata.getFileName(), fileMetadata.getContentType());
Expand All @@ -76,7 +88,7 @@ public InputStream find(String fileId) throws FileDoesNotExistException {

if (!exists(fileId))
throw new FileDoesNotExistException();

String mongoDBfileId = getFileId(fileId);

GridFSFile file = getFile(mongoDBfileId);
Expand All @@ -89,38 +101,38 @@ public void delete(String fileId) throws FileDoesNotExistException {

if (!exists(fileId))
throw new FileDoesNotExistException();

String mongoDBfileId = getFileId(fileId);

gridFsTemplate.delete(new Query(Criteria.where(MONGO_ID).is(mongoDBfileId)));
}

@Override
public boolean exists(String fileId) {

String mongoDBfileId = getFileId(fileId);

if (mongoDBfileId.isBlank())
return false;

GridFSFile gridFSFile = getFile(mongoDBfileId);

return gridFSFile != null;
}

private String getFileId(String value) {

if (value.isBlank())
return "";

String fileName = Paths.get(value).getFileName().toString();

try {
return fileName.substring(0, fileName.indexOf(GRIDFS_ID_DELIMITER));
} catch (IndexOutOfBoundsException e) {
return "";
}

}

private GridFSFile getFile(String mongoDBfileId) {
Expand All @@ -138,22 +150,22 @@ private InputStream getGridFsFileAsInputStream(GridFSFile file) {
}

private String createFilePath(String id, String fileName) {

Path tempDir = createTempDirectory(TEMP_DIR_PREFIX);

String temporaryDirectoryPath = tempDir.toAbsolutePath().toString();

return temporaryDirectoryPath + "/" + id + GRIDFS_ID_DELIMITER + fileName;
}

private Path createTempDirectory(String prefix) {

try {
return Files.createTempDirectory(prefix);
} catch (IOException e) {
throw new FileHandlingException("Exception occurred while creating temporary directory with prefix '" + TEMP_DIR_PREFIX + "'." + e.getMessage());
}

}

}
16 changes: 16 additions & 0 deletions basyx.common/basyx.filerepository-backend/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.common</artifactId>
<version>${revision}</version>
</parent>
<artifactId>basyx.filerepository-backend</artifactId>
<name>BaSyx File Repository Backend</name>
<dependencies>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.core</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.core.file;
package org.eclipse.digitaltwin.basyx.core.filerepository;

import java.io.InputStream;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.core.file;
package org.eclipse.digitaltwin.basyx.core.filerepository;

import java.io.InputStream;

Expand Down
3 changes: 3 additions & 0 deletions basyx.common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,8 @@
<module>basyx.mongocore</module>
<module>basyx.authorization</module>
<module>basyx.client</module>
<module>basyx.filerepository-backend</module>
<module>basyx.filerepository-backend-inmemory</module>
<module>basyx.filerepository-backend-mongodb</module>
</modules>
</project>
Loading

0 comments on commit 7863c28

Please sign in to comment.