diff --git a/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/AasEnvironmentLoaderTest.java b/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/AasEnvironmentLoaderTest.java index 02bebe59d..639f9adfc 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/AasEnvironmentLoaderTest.java +++ b/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/AasEnvironmentLoaderTest.java @@ -79,7 +79,7 @@ public class AasEnvironmentLoaderTest { @Before public void setUp() { submodelRepository = Mockito.spy(new CrudSubmodelRepository(new SubmodelInMemoryBackendProvider(), new InMemorySubmodelServiceFactory(new InMemoryFileRepository()))); - aasRepository = Mockito.spy(new CrudAasRepository(new AasInMemoryBackendProvider(), new InMemoryAasServiceFactory())); + aasRepository = Mockito.spy(new CrudAasRepository(new AasInMemoryBackendProvider(), new InMemoryAasServiceFactory(new InMemoryFileRepository()))); conceptDescriptionRepository = Mockito.spy(new CrudConceptDescriptionRepository(new ConceptDescriptionInMemoryBackendProvider())); } diff --git a/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/TestAASEnvironmentSerialization.java b/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/TestAASEnvironmentSerialization.java index e672c2902..9072f09fc 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/TestAASEnvironmentSerialization.java +++ b/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/TestAASEnvironmentSerialization.java @@ -1,3 +1,28 @@ +/******************************************************************************* + * Copyright (C) 2024 the Eclipse BaSyx Authors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * SPDX-License-Identifier: MIT + ******************************************************************************/ + package org.eclipse.digitaltwin.basyx.aasenvironment; import static org.junit.Assert.assertFalse; @@ -64,7 +89,7 @@ public class TestAASEnvironmentSerialization { @Before public void setup() { submodelRepository = new SimpleSubmodelRepositoryFactory(new SubmodelInMemoryBackendProvider(), new InMemorySubmodelServiceFactory(new InMemoryFileRepository())).create(); - aasRepository = new SimpleAasRepositoryFactory(new AasInMemoryBackendProvider(), new InMemoryAasServiceFactory()).create(); + aasRepository = new SimpleAasRepositoryFactory(new AasInMemoryBackendProvider(), new InMemoryAasServiceFactory(new InMemoryFileRepository())).create(); conceptDescriptionRepository = new SimpleConceptDescriptionRepositoryFactory(new ConceptDescriptionInMemoryBackendProvider(), createDummyConceptDescriptions(), "cdRepo").create(); for (Submodel submodel : createDummySubmodels()) { diff --git a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/pom.xml b/basyx.aasrepository/basyx.aasrepository-backend-inmemory/pom.xml index a260ae8aa..3f6b3a9b8 100644 --- a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/pom.xml +++ b/basyx.aasrepository/basyx.aasrepository-backend-inmemory/pom.xml @@ -48,5 +48,9 @@ org.springframework.boot spring-boot-starter + + org.eclipse.digitaltwin.basyx + basyx.filerepository-backend-inmemory + \ No newline at end of file diff --git a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/TestInMemoryAasRepository.java b/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/TestInMemoryAasRepository.java index 48c2d1f73..52ab6054d 100644 --- a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/TestInMemoryAasRepository.java +++ b/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/TestInMemoryAasRepository.java @@ -34,6 +34,7 @@ import org.eclipse.digitaltwin.basyx.aasrepository.backend.CrudAasRepository; import org.eclipse.digitaltwin.basyx.aasrepository.backend.SimpleAasRepositoryFactory; import org.eclipse.digitaltwin.basyx.aasservice.backend.InMemoryAasServiceFactory; +import org.eclipse.digitaltwin.basyx.core.filerepository.InMemoryFileRepository; import org.junit.Test; /** @@ -49,12 +50,12 @@ public class TestInMemoryAasRepository extends AasRepositorySuite { @Override protected AasRepository getAasRepository() { - return new SimpleAasRepositoryFactory(backendProvider, new InMemoryAasServiceFactory()).create(); + return new SimpleAasRepositoryFactory(backendProvider, new InMemoryAasServiceFactory(new InMemoryFileRepository())).create(); } @Test public void getConfiguredInMemoryAasRepositoryName() { - AasRepository repo = new CrudAasRepository(backendProvider, new InMemoryAasServiceFactory(), CONFIGURED_AAS_REPO_NAME); + AasRepository repo = new CrudAasRepository(backendProvider, new InMemoryAasServiceFactory(new InMemoryFileRepository()), CONFIGURED_AAS_REPO_NAME); assertEquals(CONFIGURED_AAS_REPO_NAME, repo.getName()); } diff --git a/basyx.aasrepository/basyx.aasrepository-backend-mongodb/pom.xml b/basyx.aasrepository/basyx.aasrepository-backend-mongodb/pom.xml index cf6103c56..5ebbb4d7e 100644 --- a/basyx.aasrepository/basyx.aasrepository-backend-mongodb/pom.xml +++ b/basyx.aasrepository/basyx.aasrepository-backend-mongodb/pom.xml @@ -58,5 +58,9 @@ commons-io commons-io + + org.eclipse.digitaltwin.basyx + basyx.filerepository-backend-mongodb + diff --git a/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/mongodb/AasMongoDBRepositoryConfiguration.java b/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/mongodb/AasMongoDBRepositoryConfiguration.java index f6308c5e0..6a6eb6371 100644 --- a/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/mongodb/AasMongoDBRepositoryConfiguration.java +++ b/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/mongodb/AasMongoDBRepositoryConfiguration.java @@ -28,6 +28,7 @@ import org.eclipse.digitaltwin.basyx.aasservice.AasServiceFactory; import org.eclipse.digitaltwin.basyx.aasservice.backend.InMemoryAasServiceFactory; +import org.eclipse.digitaltwin.basyx.core.filerepository.FileRepository; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -46,7 +47,7 @@ @ConditionalOnExpression("'${basyx.backend}'.equals('MongoDB')") public class AasMongoDBRepositoryConfiguration { @Bean - public AasServiceFactory getAasServiceFactory() { - return new InMemoryAasServiceFactory(); + public AasServiceFactory getAasServiceFactory(FileRepository fileRepository) { + return new InMemoryAasServiceFactory(fileRepository); } } diff --git a/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/mongodb/TestMongoDBAasRepository.java b/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/mongodb/TestMongoDBAasRepository.java index 2bca5ee5c..06352d885 100644 --- a/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/mongodb/TestMongoDBAasRepository.java +++ b/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/mongodb/TestMongoDBAasRepository.java @@ -41,8 +41,10 @@ import org.eclipse.digitaltwin.basyx.aasservice.backend.InMemoryAasServiceFactory; import org.eclipse.digitaltwin.basyx.common.mongocore.BasyxMongoMappingContext; import org.eclipse.digitaltwin.basyx.common.mongocore.MongoDBUtilities; +import org.eclipse.digitaltwin.basyx.core.filerepository.MongoDBFileRepository; import org.junit.Test; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.gridfs.GridFsTemplate; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; @@ -59,13 +61,15 @@ public class TestMongoDBAasRepository extends AasRepositorySuite { private static final String COLLECTION = "testAasCollection"; private static final String CONFIGURED_AAS_REPO_NAME = "configured-aas-repo-name"; - private MongoTemplate mongoTemplate = createMongoTemplate(); + private static MongoTemplate mongoTemplate = createMongoTemplate(); + + private static GridFsTemplate gridFsTemplate = configureDefaultGridFsTemplate(mongoTemplate); @Override protected AasRepository getAasRepository() { MongoDBUtilities.clearCollection(mongoTemplate, COLLECTION); AasBackendProvider aasBackendProvider = new AasMongoDBBackendProvider(new BasyxMongoMappingContext(), COLLECTION, mongoTemplate); - AasRepositoryFactory aasRepositoryFactory = new SimpleAasRepositoryFactory(aasBackendProvider, new InMemoryAasServiceFactory()); + AasRepositoryFactory aasRepositoryFactory = new SimpleAasRepositoryFactory(aasBackendProvider, new InMemoryAasServiceFactory(new MongoDBFileRepository(gridFsTemplate))); return aasRepositoryFactory.create(); } @@ -96,7 +100,7 @@ public void updatedAasIsPersisted() { @Test public void getConfiguredMongoDBAasRepositoryName() { - AasRepository repo = new CrudAasRepository(new AasMongoDBBackendProvider(new BasyxMongoMappingContext(), COLLECTION, mongoTemplate), new InMemoryAasServiceFactory(), CONFIGURED_AAS_REPO_NAME); + AasRepository repo = new CrudAasRepository(new AasMongoDBBackendProvider(new BasyxMongoMappingContext(), COLLECTION, mongoTemplate), new InMemoryAasServiceFactory(new MongoDBFileRepository(gridFsTemplate)), CONFIGURED_AAS_REPO_NAME); assertEquals(CONFIGURED_AAS_REPO_NAME, repo.getName()); } @@ -112,7 +116,7 @@ private AssetAdministrationShell createDummyShellOnRepo(AasRepository aasReposit return expectedShell; } - private MongoTemplate createMongoTemplate() { + private static MongoTemplate createMongoTemplate() { String connectionURL = "mongodb://mongoAdmin:mongoPassword@localhost:27017/"; MongoClient client = MongoClients.create(connectionURL); @@ -120,4 +124,7 @@ private MongoTemplate createMongoTemplate() { return new MongoTemplate(client, "BaSyxTestDb"); } + private static GridFsTemplate configureDefaultGridFsTemplate(MongoTemplate mongoTemplate) { + return new GridFsTemplate(mongoTemplate.getMongoDatabaseFactory(), mongoTemplate.getConverter()); + } } diff --git a/basyx.aasrepository/basyx.aasrepository-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/AASThumbnailHandler.java b/basyx.aasrepository/basyx.aasrepository-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/AASThumbnailHandler.java deleted file mode 100644 index a751d9af4..000000000 --- a/basyx.aasrepository/basyx.aasrepository-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/AASThumbnailHandler.java +++ /dev/null @@ -1,117 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2023 the Eclipse BaSyx Authors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * SPDX-License-Identifier: MIT - ******************************************************************************/ - -package org.eclipse.digitaltwin.basyx.aasrepository.backend; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.InvalidPathException; -import java.nio.file.Paths; - -import org.apache.commons.io.IOUtils; -import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation; -import org.eclipse.digitaltwin.aas4j.v3.model.Resource; -import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultResource; -import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; -import org.eclipse.digitaltwin.basyx.core.exceptions.FileDoesNotExistException; -import org.eclipse.digitaltwin.basyx.core.exceptions.FileHandlingException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AASThumbnailHandler { - - private static Logger logger = LoggerFactory.getLogger(AASThumbnailHandler.class); - - public static void updateThumbnail(AasRepository aasRepo, String aasId, String contentType, String filePath) { - AssetInformation assetInfor = aasRepo.getAssetInformation(aasId); - assetInfor.getDefaultThumbnail().setContentType(contentType); - assetInfor.getDefaultThumbnail().setPath(filePath); - aasRepo.setAssetInformation(aasId, assetInfor); - } - - public static void setNewThumbnail(AasRepository aasRepo, String aasId, String contentType, String filePath) { - Resource resource = new DefaultResource(); - resource.setContentType(contentType); - resource.setPath(filePath); - AssetInformation assetInfor = aasRepo.getAssetInformation(aasId); - assetInfor.setDefaultThumbnail(resource); - aasRepo.setAssetInformation(aasId, assetInfor); - } - - public static void throwIfFileDoesNotExist(String aasId, Resource resource) { - if (resource == null) - throw new FileDoesNotExistException(aasId); - - String filePath = resource.getPath(); - throwIfFilePathIsNotValid(aasId, filePath); - } - - public static String createFilePath(String tmpDirectory, String aasId, String fileName) { - return tmpDirectory + "/" + aasId + "-" + "Thumbnail" + "-" + fileName; - } - - public static void createFileAtSpecifiedPath(String fileName, InputStream inputStream, String filePath) { - java.io.File targetFile = new java.io.File(filePath); - - try (FileOutputStream outStream = new FileOutputStream(targetFile)) { - IOUtils.copy(inputStream, outStream); - } catch (IOException e) { - throw new FileHandlingException(fileName); - } - } - - public static void deleteExistingFile(String path) { - if (path == null || path.isEmpty()) - return; - - try { - Files.deleteIfExists(Paths.get(path, "")); - } catch (IOException e) { - logger.error("Unable to delete the file having path '{}'", path); - } - } - - public static String getTemporaryDirectoryPath() { - String tempDirectoryPath = ""; - try { - tempDirectoryPath = Files.createTempDirectory("basyx-temp-thumbnail").toAbsolutePath().toString(); - } catch (IOException e) { - logger.error("Unable to create file in the temporary path."); - } - return tempDirectoryPath; - } - - private static void throwIfFilePathIsNotValid(String aasId, String filePath) { - if (filePath.isEmpty()) - throw new FileDoesNotExistException(aasId); - try { - Paths.get(filePath); - } catch (InvalidPathException | NullPointerException ex) { - throw new FileDoesNotExistException(aasId); - } - } -} diff --git a/basyx.aasrepository/basyx.aasrepository-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/CrudAasRepository.java b/basyx.aasrepository/basyx.aasrepository-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/CrudAasRepository.java index 89d54960d..f78c7e045 100644 --- a/basyx.aasrepository/basyx.aasrepository-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/CrudAasRepository.java +++ b/basyx.aasrepository/basyx.aasrepository-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/CrudAasRepository.java @@ -34,7 +34,6 @@ import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation; import org.eclipse.digitaltwin.aas4j.v3.model.Reference; -import org.eclipse.digitaltwin.aas4j.v3.model.Resource; import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; import org.eclipse.digitaltwin.basyx.aasservice.AasService; import org.eclipse.digitaltwin.basyx.aasservice.AasServiceFactory; @@ -162,34 +161,25 @@ public String getName() { @Override public File getThumbnail(String aasId) { - Resource resource = getAssetInformation(aasId).getDefaultThumbnail(); - - AASThumbnailHandler.throwIfFileDoesNotExist(aasId, resource); - String filePath = resource.getPath(); - return new File(filePath); + return getAasServiceOrThrow(aasId).getThumbnail(); } @Override public void setThumbnail(String aasId, String fileName, String contentType, InputStream inputStream) { - Resource thumbnail = getAssetInformation(aasId).getDefaultThumbnail(); + AasService aasService = getAasServiceOrThrow(aasId); - if (thumbnail != null) { - updateThumbnailFile(aasId, fileName, contentType, inputStream, thumbnail); - return; - } + aasService.setThumbnail(fileName, contentType, inputStream); - String filePath = createFile(aasId, fileName, inputStream); - AASThumbnailHandler.setNewThumbnail(this, aasId, contentType, filePath); + updateAas(aasId, aasService.getAAS()); } @Override public void deleteThumbnail(String aasId) { - Resource thumbnail = getAssetInformation(aasId).getDefaultThumbnail(); - AASThumbnailHandler.throwIfFileDoesNotExist(aasId, thumbnail); + AasService aasService = getAasServiceOrThrow(aasId); - deleteThumbnailFile(thumbnail); + aasService.deleteThumbnail(); - updateThumbnailInAssetInformation(aasId); + updateAas(aasId, aasService.getAAS()); } private AasService getAasServiceOrThrow(String aasId) { @@ -220,31 +210,4 @@ private void throwIfAasDoesNotExist(String aasId) { if (!aasBackend.existsById(aasId)) throw new ElementDoesNotExistException(aasId); } - - private void updateThumbnailInAssetInformation(String aasId) { - AssetInformation assetInfor = getAssetInformation(aasId); - assetInfor.getDefaultThumbnail().setContentType(""); - assetInfor.getDefaultThumbnail().setPath(""); - setAssetInformation(aasId, assetInfor); - } - - private void deleteThumbnailFile(Resource thumbnail) { - String filePath = thumbnail.getPath(); - java.io.File tmpFile = new java.io.File(filePath); - tmpFile.delete(); - } - - private void updateThumbnailFile(String aasId, String fileName, String contentType, InputStream inputStream, Resource thumbnail) { - String path = thumbnail.getPath(); - AASThumbnailHandler.deleteExistingFile(path); - String filePath = createFile(aasId, fileName, inputStream); - AASThumbnailHandler.updateThumbnail(this, aasId, contentType, filePath); - } - - private String createFile(String aasId, String fileName, InputStream inputStream) { - String filePath = AASThumbnailHandler.createFilePath(AASThumbnailHandler.getTemporaryDirectoryPath(), aasId, fileName); - AASThumbnailHandler.createFileAtSpecifiedPath(fileName, inputStream, filePath); - return filePath; - } - } diff --git a/basyx.aasrepository/basyx.aasrepository-client/pom.xml b/basyx.aasrepository/basyx.aasrepository-client/pom.xml index 189bed0ae..52ec3a222 100644 --- a/basyx.aasrepository/basyx.aasrepository-client/pom.xml +++ b/basyx.aasrepository/basyx.aasrepository-client/pom.xml @@ -1,4 +1,4 @@ - 4.0.0 diff --git a/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositoryAasServiceWrapper.java b/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositoryAasServiceWrapper.java index 352c0099e..f8d0c21f5 100644 --- a/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositoryAasServiceWrapper.java +++ b/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositoryAasServiceWrapper.java @@ -25,6 +25,8 @@ package org.eclipse.digitaltwin.basyx.aasrepository; +import java.io.File; +import java.io.InputStream; import java.util.List; import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; @@ -81,4 +83,20 @@ public AssetInformation getAssetInformation() { return repoApi.getAssetInformation(aasId); } + @Override + public File getThumbnail() { + return repoApi.getThumbnail(aasId); + } + + @Override + public void setThumbnail(String fileName, String contentType, InputStream inputStream) { + repoApi.setThumbnail(aasId, fileName, contentType, inputStream); + + } + + @Override + public void deleteThumbnail() { + repoApi.deleteThumbnail(aasId); + } + } diff --git a/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java b/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java index 53f7b1e39..e6af8282e 100644 --- a/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java +++ b/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java @@ -27,20 +27,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; -import org.apache.commons.io.FileUtils; import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation; import org.eclipse.digitaltwin.aas4j.v3.model.Reference; @@ -49,13 +41,11 @@ import org.eclipse.digitaltwin.basyx.aasservice.AasServiceSuite; import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingIdentifierException; import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException; -import org.eclipse.digitaltwin.basyx.core.exceptions.FileDoesNotExistException; import org.eclipse.digitaltwin.basyx.core.exceptions.IdentificationMismatchException; import org.eclipse.digitaltwin.basyx.core.exceptions.MissingIdentifierException; import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult; import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; import org.junit.Test; -import org.springframework.core.io.ClassPathResource; /** * Testsuite for implementations of the AasRepository interface @@ -68,9 +58,6 @@ public abstract class AasRepositorySuite extends AasServiceSuite { private static final String AAS_EMPTY_ID = " "; private static final String AAS_NULL_ID = null; - private static final String THUMBNAIL_FILE_PATH_1 = "BaSyx-Logo-1.png"; - private static final String THUMBNAIL_FILE_PATH_2 = "BaSyx-Logo-2.png"; - protected abstract AasRepository getAasRepository(); protected AasRepository getAasRepository(Collection shells) { @@ -253,87 +240,6 @@ public void getPaginatedAssetAdministrationShellIterating() { assertEquals(expected, retrieved); } - @Test - public void updateThumbnail() throws FileNotFoundException, IOException { - AssetAdministrationShell aas = DummyAasFactory.createAasWithAssetInformation(); - AasRepository aasRepo = getAasRepository(Collections.singleton(aas)); - - // Set the thumbnail of the AAS for the first time - aasRepo.setThumbnail(aas.getId(), THUMBNAIL_FILE_PATH_1, "", getInputStreamOfFileFromClasspath(THUMBNAIL_FILE_PATH_1)); - - // Set the thumbnail of the AAS for the second time with a new figure - aasRepo.setThumbnail(aas.getId(), THUMBNAIL_FILE_PATH_2, "", getInputStreamOfFileFromClasspath(THUMBNAIL_FILE_PATH_2)); - - File retrievedThumbnail = aasRepo.getThumbnail(aas.getId()); - - assertEquals(readFile("src/test/resources/" + THUMBNAIL_FILE_PATH_2, Charset.defaultCharset()), new String(FileUtils.readFileToByteArray(retrievedThumbnail), Charset.defaultCharset())); - - } - - @Test - public void setThumbnail() throws FileNotFoundException, IOException { - AssetAdministrationShell aas = DummyAasFactory.createAasWithAssetInformation(); - AasRepository aasRepo = getAasRepository(Collections.singleton(aas)); - - aasRepo.setThumbnail(aas.getId(), THUMBNAIL_FILE_PATH_1, "", getInputStreamOfFileFromClasspath(THUMBNAIL_FILE_PATH_1)); - - File retrievedThumbnail = aasRepo.getThumbnail(aas.getId()); - - assertEquals(readFile("src/test/resources/" + THUMBNAIL_FILE_PATH_1, Charset.defaultCharset()), new String(FileUtils.readFileToByteArray(retrievedThumbnail), Charset.defaultCharset())); - - } - - @Test - public void getThumbnail() throws IOException { - AssetAdministrationShell aas = DummyAasFactory.createAasWithAssetInformation(); - AasRepository aasRepo = getAasRepository(Collections.singleton(aas)); - - aasRepo.setThumbnail(aas.getId(), THUMBNAIL_FILE_PATH_1, "", getInputStreamOfFileFromClasspath(THUMBNAIL_FILE_PATH_1)); - - File retrievedThumbnail = aasRepo.getThumbnail(aas.getId()); - - assertEquals(readFile("src/test/resources/" + THUMBNAIL_FILE_PATH_1, Charset.defaultCharset()), new String(FileUtils.readFileToByteArray(retrievedThumbnail), Charset.defaultCharset())); - } - - @Test(expected = FileDoesNotExistException.class) - public void getNonExistingThumbnail() { - AssetAdministrationShell aas = DummyAasFactory.createAasWithAssetInformation(); - AasRepository aasRepo = getAasRepository(Collections.singleton(aas)); - - aasRepo.getThumbnail(aas.getId()); - } - - @Test(expected = FileDoesNotExistException.class) - public void deleteThumbnail() throws FileNotFoundException, IOException { - AssetAdministrationShell aas = DummyAasFactory.createAasWithAssetInformation(); - AasRepository aasRepo = getAasRepository(Collections.singleton(aas)); - - aasRepo.setThumbnail(aas.getId(), THUMBNAIL_FILE_PATH_1, "", getInputStreamOfFileFromClasspath(THUMBNAIL_FILE_PATH_1)); - aasRepo.deleteThumbnail(aas.getId()); - - aasRepo.getThumbnail(aas.getId()); - } - - @Test(expected = FileDoesNotExistException.class) - public void deleteNonExistingThumbnail() throws IOException { - AssetAdministrationShell aas = DummyAasFactory.createAasWithAssetInformation(); - AasRepository aasRepo = getAasRepository(Collections.singleton(aas)); - - aasRepo.deleteThumbnail(aas.getId()); - } - - private static String readFile(String path, Charset encoding) throws IOException { - byte[] encoded = Files.readAllBytes(Paths.get(path)); - - return new String(encoded, encoding); - } - - private InputStream getInputStreamOfFileFromClasspath(String fileName) throws FileNotFoundException, IOException { - ClassPathResource classPathResource = new ClassPathResource(fileName); - - return classPathResource.getInputStream(); - } - @Override public AasService getAasService(AssetAdministrationShell shell) { return new AasRepositoryAasServiceWrapper(getAasRepository(), shell); diff --git a/basyx.aasrepository/basyx.aasrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/mqtt/TestMqttV2AASAggregatorObserver.java b/basyx.aasrepository/basyx.aasrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/mqtt/TestMqttV2AASAggregatorObserver.java index d17b64c5c..785bd0e33 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/mqtt/TestMqttV2AASAggregatorObserver.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/mqtt/TestMqttV2AASAggregatorObserver.java @@ -45,6 +45,7 @@ import org.eclipse.digitaltwin.basyx.common.mqttcore.encoding.Base64URLEncoder; import org.eclipse.digitaltwin.basyx.common.mqttcore.encoding.URLEncoder; import org.eclipse.digitaltwin.basyx.common.mqttcore.listener.MqttTestListener; +import org.eclipse.digitaltwin.basyx.core.filerepository.InMemoryFileRepository; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttSecurityException; @@ -136,7 +137,7 @@ private AssetAdministrationShell createAasDummy(String aasId) { } private static AasRepository createMqttAasRepository(MqttClient client) { - AasRepositoryFactory repoFactory = new SimpleAasRepositoryFactory(new AasInMemoryBackendProvider(), new InMemoryAasServiceFactory()); + AasRepositoryFactory repoFactory = new SimpleAasRepositoryFactory(new AasInMemoryBackendProvider(), new InMemoryAasServiceFactory(new InMemoryFileRepository())); return new MqttAasRepositoryFactory(repoFactory, client, new MqttAasRepositoryTopicFactory(new URLEncoder())).create(); } diff --git a/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/testconfig/DummyAasRepositoryConfig.java b/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/testconfig/DummyAasRepositoryConfig.java index 89d995b6d..d6a40f48e 100644 --- a/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/testconfig/DummyAasRepositoryConfig.java +++ b/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/testconfig/DummyAasRepositoryConfig.java @@ -29,6 +29,7 @@ import org.eclipse.digitaltwin.basyx.aasrepository.backend.SimpleAasRepositoryFactory; import org.eclipse.digitaltwin.basyx.aasrepository.backend.inmemory.AasInMemoryBackendProvider; import org.eclipse.digitaltwin.basyx.aasservice.backend.InMemoryAasServiceFactory; +import org.eclipse.digitaltwin.basyx.core.filerepository.InMemoryFileRepository; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -46,6 +47,6 @@ public class DummyAasRepositoryConfig { @Bean @ConditionalOnMissingBean public AasRepository createAasRepository() { - return new SimpleAasRepositoryFactory(new AasInMemoryBackendProvider(), new InMemoryAasServiceFactory()).create(); + return new SimpleAasRepositoryFactory(new AasInMemoryBackendProvider(), new InMemoryAasServiceFactory(new InMemoryFileRepository())).create(); } } diff --git a/basyx.aasservice/basyx.aasservice-backend-inmemory/pom.xml b/basyx.aasservice/basyx.aasservice-backend-inmemory/pom.xml index 403781db5..51430de95 100644 --- a/basyx.aasservice/basyx.aasservice-backend-inmemory/pom.xml +++ b/basyx.aasservice/basyx.aasservice-backend-inmemory/pom.xml @@ -29,5 +29,9 @@ org.springframework.boot spring-boot-starter + + org.eclipse.digitaltwin.basyx + basyx.filerepository-backend-inmemory + \ No newline at end of file diff --git a/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasService.java b/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasService.java index 5c8f84a6e..56ade886c 100644 --- a/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasService.java +++ b/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasService.java @@ -24,6 +24,11 @@ ******************************************************************************/ package org.eclipse.digitaltwin.basyx.aasservice.backend; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.List; import java.util.TreeMap; import java.util.function.Function; @@ -34,8 +39,14 @@ import org.eclipse.digitaltwin.aas4j.v3.model.Key; import org.eclipse.digitaltwin.aas4j.v3.model.KeyTypes; import org.eclipse.digitaltwin.aas4j.v3.model.Reference; +import org.eclipse.digitaltwin.aas4j.v3.model.Resource; +import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultResource; import org.eclipse.digitaltwin.basyx.aasservice.AasService; import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException; +import org.eclipse.digitaltwin.basyx.core.exceptions.FileDoesNotExistException; +import org.eclipse.digitaltwin.basyx.core.exceptions.FileHandlingException; +import org.eclipse.digitaltwin.basyx.core.filerepository.FileMetadata; +import org.eclipse.digitaltwin.basyx.core.filerepository.FileRepository; import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult; import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; import org.eclipse.digitaltwin.basyx.core.pagination.PaginationSupport; @@ -43,19 +54,22 @@ /** * Implements the AasService as in-memory variant * - * @author schnicke + * @author schnicke, mateusmolina * */ public class InMemoryAasService implements AasService { private AssetAdministrationShell aas; + private final FileRepository fileRepository; + /** * Creates the InMemory AasService containing the passed AAS * * @param aas */ - public InMemoryAasService(AssetAdministrationShell aas) { + public InMemoryAasService(AssetAdministrationShell aas, FileRepository fileRepository) { this.aas = aas; + this.fileRepository = fileRepository; } @Override @@ -129,5 +143,68 @@ private Function extractSubmodelID() { return ""; // Return an empty string if no ID is found }; } - + + @Override + public File getThumbnail() { + Resource resource = getAssetInformation().getDefaultThumbnail(); + + try { + return getResourceContent(resource); + } catch (NullPointerException e) { + throw new FileDoesNotExistException(); + } catch (IOException e) { + throw new FileHandlingException("Exception occurred while creating file from the InputStream." + e.getMessage()); + } + } + + @Override + public void setThumbnail(String fileName, String contentType, InputStream inputStream) { + String filePath = fileRepository.save(new FileMetadata(fileName, contentType, inputStream)); + + setAssetInformation(configureAssetInformationThumbnail(getAssetInformation(), contentType, filePath)); + } + + @Override + public void deleteThumbnail() { + try { + String thumbnailPath = getAssetInformation().getDefaultThumbnail().getPath(); + fileRepository.delete(thumbnailPath); + } catch (NullPointerException e) { + throw new FileDoesNotExistException(); + } finally { + setAssetInformation(configureAssetInformationThumbnail(getAssetInformation(), "", "")); + } + + } + + private void createOutputStream(String filePath, byte[] content) throws IOException { + + try (OutputStream outputStream = new FileOutputStream(filePath)) { + outputStream.write(content); + } catch (IOException e) { + throw new FileHandlingException("Exception occurred while creating OutputStream from byte[]." + e.getMessage()); + } + + } + + private static AssetInformation configureAssetInformationThumbnail(AssetInformation assetInformation, String contentType, String filePath) { + Resource resource = new DefaultResource(); + resource.setContentType(contentType); + resource.setPath(filePath); + assetInformation.setDefaultThumbnail(resource); + return assetInformation; + } + + private File getResourceContent(Resource resource) throws IOException { + String filePath = resource.getPath(); + + InputStream fileIs = fileRepository.find(filePath); + byte[] content = fileIs.readAllBytes(); + fileIs.close(); + + createOutputStream(filePath, content); + + return new java.io.File(filePath); + } + } diff --git a/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasServiceFactory.java b/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasServiceFactory.java index 9fff48156..8ec5e822a 100644 --- a/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasServiceFactory.java +++ b/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasServiceFactory.java @@ -27,6 +27,7 @@ import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; import org.eclipse.digitaltwin.basyx.aasservice.AasService; import org.eclipse.digitaltwin.basyx.aasservice.AasServiceFactory; +import org.eclipse.digitaltwin.basyx.core.filerepository.FileRepository; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; @@ -39,8 +40,14 @@ @Component public class InMemoryAasServiceFactory implements AasServiceFactory { + private final FileRepository fileRepository; + + public InMemoryAasServiceFactory(FileRepository fileRepository) { + this.fileRepository = fileRepository; + } + @Override public AasService create(AssetAdministrationShell aas) { - return new InMemoryAasService(aas); + return new InMemoryAasService(aas, fileRepository); } } diff --git a/basyx.aasservice/basyx.aasservice-backend-inmemory/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/TestInMemoryAasService.java b/basyx.aasservice/basyx.aasservice-backend-inmemory/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/TestInMemoryAasService.java index 84bcab9d8..e385e3152 100644 --- a/basyx.aasservice/basyx.aasservice-backend-inmemory/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/TestInMemoryAasService.java +++ b/basyx.aasservice/basyx.aasservice-backend-inmemory/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/TestInMemoryAasService.java @@ -28,12 +28,13 @@ import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; import org.eclipse.digitaltwin.basyx.aasservice.backend.InMemoryAasServiceFactory; +import org.eclipse.digitaltwin.basyx.core.filerepository.InMemoryFileRepository; public class TestInMemoryAasService extends AasServiceSuite { @Override protected AasService getAasService(AssetAdministrationShell shell) { - return new InMemoryAasServiceFactory().create(shell); + return new InMemoryAasServiceFactory(new InMemoryFileRepository()).create(shell); } } diff --git a/basyx.aasservice/basyx.aasservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/client/ConnectedAasService.java b/basyx.aasservice/basyx.aasservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/client/ConnectedAasService.java index 78eda1d17..7c4114cd5 100644 --- a/basyx.aasservice/basyx.aasservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/client/ConnectedAasService.java +++ b/basyx.aasservice/basyx.aasservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/client/ConnectedAasService.java @@ -26,6 +26,8 @@ package org.eclipse.digitaltwin.basyx.aasservice.client; +import java.io.File; +import java.io.InputStream; import java.util.List; import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; @@ -35,6 +37,7 @@ import org.eclipse.digitaltwin.basyx.aasservice.client.internal.AssetAdministrationShellServiceApi; import org.eclipse.digitaltwin.basyx.client.internal.ApiException; import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException; +import org.eclipse.digitaltwin.basyx.core.exceptions.FeatureNotImplementedException; import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult; import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; import org.springframework.http.HttpStatus; @@ -122,4 +125,21 @@ private RuntimeException mapAasAccess(ApiException e) { return e; } + + @Override + public File getThumbnail() { + throw new FeatureNotImplementedException(); + } + + @Override + public void setThumbnail(String fileName, String contentType, InputStream inputStream) { + throw new FeatureNotImplementedException(); + + } + + @Override + public void deleteThumbnail() { + throw new FeatureNotImplementedException(); + + } } diff --git a/basyx.aasservice/basyx.aasservice-client/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/client/TestConnectedAasService.java b/basyx.aasservice/basyx.aasservice-client/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/client/TestConnectedAasService.java index a121b4cf6..4d62e9f01 100644 --- a/basyx.aasservice/basyx.aasservice-client/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/client/TestConnectedAasService.java +++ b/basyx.aasservice/basyx.aasservice-client/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/client/TestConnectedAasService.java @@ -25,11 +25,15 @@ package org.eclipse.digitaltwin.basyx.aasservice.client; +import java.io.FileNotFoundException; +import java.io.IOException; + import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; import org.eclipse.digitaltwin.basyx.aasrepository.http.DummyAasRepositoryComponent; import org.eclipse.digitaltwin.basyx.aasservice.AasService; import org.eclipse.digitaltwin.basyx.aasservice.AasServiceSuite; +import org.eclipse.digitaltwin.basyx.core.exceptions.FileDoesNotExistException; import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier; import org.junit.After; @@ -70,4 +74,36 @@ protected AasService getAasService(AssetAdministrationShell shell) { } + @Override + public void updateThumbnail() throws FileNotFoundException, IOException { + // TODO test not implemented + } + + @Override + public void setThumbnail() throws FileNotFoundException, IOException { + // TODO test not implemented + } + + @Override + public void getThumbnail() throws IOException { + // TODO test not implemented + } + + @Override + public void getNonExistingThumbnail() { + // TODO test not implemented + throw new FileDoesNotExistException(); + } + + @Override + public void deleteThumbnail() throws FileNotFoundException, IOException { + // TODO test not implemented + throw new FileDoesNotExistException(); + } + + @Override + public void deleteNonExistingThumbnail() throws IOException { + // TODO test not implemented + throw new FileDoesNotExistException(); + } } diff --git a/basyx.aasservice/basyx.aasservice-core/pom.xml b/basyx.aasservice/basyx.aasservice-core/pom.xml index d8ae60729..2a02adead 100644 --- a/basyx.aasservice/basyx.aasservice-core/pom.xml +++ b/basyx.aasservice/basyx.aasservice-core/pom.xml @@ -22,5 +22,10 @@ org.eclipse.digitaltwin.aas4j aas4j-model + + commons-io + commons-io + test + \ No newline at end of file diff --git a/basyx.aasservice/basyx.aasservice-core/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/AasService.java b/basyx.aasservice/basyx.aasservice-core/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/AasService.java index fcf4371d8..c0b6783cd 100644 --- a/basyx.aasservice/basyx.aasservice-core/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/AasService.java +++ b/basyx.aasservice/basyx.aasservice-core/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/AasService.java @@ -24,6 +24,8 @@ ******************************************************************************/ package org.eclipse.digitaltwin.basyx.aasservice; +import java.io.File; +import java.io.InputStream; import java.util.List; import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; @@ -35,7 +37,7 @@ /** * Specifies the overall AasService API * - * @author schnicke + * @author schnicke, mateusmolina * */ public interface AasService { @@ -75,4 +77,29 @@ public interface AasService { * @return the Asset-Information of the AAS */ public AssetInformation getAssetInformation(); + + /** + * Get Thumbnail of the specific aas + * + * @return the file of the thumbnail + */ + public File getThumbnail(); + + /** + * Set Thumbnail of the AAS + * + * @param fileName + * name of the thumbnail file with extension + * @param contentType + * content type of the file + * @param inputStream + * inputstream of the thumbnail file + */ + public void setThumbnail(String fileName, String contentType, InputStream inputStream); + + /** + * Delete the thumbnail file of the AAS + * + */ + public void deleteThumbnail(); } diff --git a/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java b/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java index b97625208..94c63d149 100644 --- a/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java +++ b/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java @@ -29,9 +29,19 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import javax.imageio.ImageIO; + +import org.apache.commons.io.IOUtils; import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation; import org.eclipse.digitaltwin.aas4j.v3.model.AssetKind; @@ -45,6 +55,7 @@ import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultReference; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodel; import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException; +import org.eclipse.digitaltwin.basyx.core.exceptions.FileDoesNotExistException; import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult; import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; import org.junit.Test; @@ -52,7 +63,7 @@ /** * Testsuite for implementations of the AasService interface * - * @author schnicke + * @author schnicke, mateusmolina * */ public abstract class AasServiceSuite { @@ -145,6 +156,74 @@ public void getPaginatedSubmodelReferencesPaginated() { paginatedReferences.getResult().stream().findFirst().get()); } + @Test + public void updateThumbnail() throws FileNotFoundException, IOException { + AssetAdministrationShell shell = DummyAssetAdministrationShellFactory.createWithDefaultThumbnail(); + AasService aasService = getAasService(shell); + + aasService.setThumbnail("dummyImgA.jpeg", "", createDummyImageIS_A()); + + InputStream actualThumbnailIs = new FileInputStream(aasService.getThumbnail()); + + InputStream expectedThumbnail = createDummyImageIS_A(); + + assertTrue(IOUtils.contentEquals(expectedThumbnail, actualThumbnailIs)); + } + + @Test + public void setThumbnail() throws FileNotFoundException, IOException { + AssetAdministrationShell shell = DummyAssetAdministrationShellFactory.create(); + AasService aasService = getAasService(shell); + + aasService.setThumbnail("dummyImgA.jpeg", "", createDummyImageIS_A()); + + InputStream actualThumbnailIs = new FileInputStream(aasService.getThumbnail()); + + InputStream expectedThumbnail = createDummyImageIS_A(); + + assertTrue(IOUtils.contentEquals(expectedThumbnail, actualThumbnailIs)); + } + + @Test + public void getThumbnail() throws IOException { + AssetAdministrationShell shell = DummyAssetAdministrationShellFactory.create(); + AasService aasService = getAasService(shell); + + aasService.setThumbnail("dummyImgA.jpeg", "", createDummyImageIS_A()); + + InputStream actualThumbnailIs = new FileInputStream(aasService.getThumbnail()); + + InputStream expectedThumbnail = createDummyImageIS_A(); + + assertTrue(IOUtils.contentEquals(expectedThumbnail, actualThumbnailIs)); + } + + @Test(expected = FileDoesNotExistException.class) + public void getNonExistingThumbnail() { + AssetAdministrationShell shell = DummyAssetAdministrationShellFactory.create(); + AasService aasService = getAasService(shell); + + aasService.getThumbnail(); + } + + @Test(expected = FileDoesNotExistException.class) + public void deleteThumbnail() throws FileNotFoundException, IOException { + AssetAdministrationShell shell = DummyAssetAdministrationShellFactory.createWithDefaultThumbnail(); + AasService aasService = getAasService(shell); + + aasService.deleteThumbnail(); + + aasService.getThumbnail(); + } + + @Test(expected = FileDoesNotExistException.class) + public void deleteNonExistingThumbnail() throws IOException { + AssetAdministrationShell shell = DummyAssetAdministrationShellFactory.create(); + AasService aasService = getAasService(shell); + + aasService.deleteThumbnail(); + } + private AssetInformation createDummyAssetInformation() { AssetInformation assetInfo = new DefaultAssetInformation.Builder().assetKind(AssetKind.INSTANCE) .globalAssetId("assetIDTestKey") @@ -176,4 +255,19 @@ private List createDummyReferences() { return referenceList; } + private static InputStream createDummyImageIS_A() throws IOException { + return createDummyImageIS(0x000000); + } + + private static InputStream createDummyImageIS(int color) throws IOException { + BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); + + image.setRGB(0, 0, 0x000000); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "jpeg", baos); + + byte[] imageData = baos.toByteArray(); + return new ByteArrayInputStream(imageData); + } } diff --git a/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/DummyAssetAdministrationShellFactory.java b/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/DummyAssetAdministrationShellFactory.java index 89706f770..6193c7713 100644 --- a/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/DummyAssetAdministrationShellFactory.java +++ b/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/DummyAssetAdministrationShellFactory.java @@ -7,10 +7,12 @@ import org.eclipse.digitaltwin.aas4j.v3.model.AssetKind; import org.eclipse.digitaltwin.aas4j.v3.model.KeyTypes; import org.eclipse.digitaltwin.aas4j.v3.model.Reference; +import org.eclipse.digitaltwin.aas4j.v3.model.Resource; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAssetAdministrationShell; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAssetInformation; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultKey; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultReference; +import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultResource; /** * Class containing a Dummy Shell for Unit testing @@ -30,6 +32,11 @@ public static AssetAdministrationShell create() { .build(); } + public static AssetAdministrationShell createWithDefaultThumbnail() { + return new DefaultAssetAdministrationShell.Builder().id("arbitrary") + .assetInformation(new DefaultAssetInformation.Builder().assetKind(AssetKind.INSTANCE).globalAssetId(SUBMODEL_ID).defaultThumbnail(buildDummyThumbnailResource()).build()).build(); + } + /** * Add the Dummy SubmodelReference to the given aas * @@ -45,4 +52,9 @@ private static Reference buildDummyReference() { return new DefaultReference.Builder() .keys(new DefaultKey.Builder().type(KeyTypes.SUBMODEL).value(SUBMODEL_ID).build()).build(); } + + private static Resource buildDummyThumbnailResource() { + return new DefaultResource.Builder().path("").contentType("").build(); + } + } diff --git a/basyx.aasservice/basyx.aasservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/MqttAasService.java b/basyx.aasservice/basyx.aasservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/MqttAasService.java index 448bb1c10..17dcdd0e3 100644 --- a/basyx.aasservice/basyx.aasservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/MqttAasService.java +++ b/basyx.aasservice/basyx.aasservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/MqttAasService.java @@ -24,6 +24,8 @@ ******************************************************************************/ package org.eclipse.digitaltwin.basyx.aasservice.feature.mqtt; +import java.io.File; +import java.io.InputStream; import java.util.List; import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; @@ -183,4 +185,19 @@ private String extractShellId() { public AssetInformation getAssetInformation() { return decorated.getAssetInformation(); } + + @Override + public File getThumbnail() { + return decorated.getThumbnail(); + } + + @Override + public void setThumbnail(String fileName, String contentType, InputStream inputStream) { + decorated.setThumbnail(fileName, contentType, inputStream); + } + + @Override + public void deleteThumbnail() { + decorated.deleteThumbnail(); + } } diff --git a/basyx.aasservice/basyx.aasservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/TestMqttAasService.java b/basyx.aasservice/basyx.aasservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/TestMqttAasService.java index e2537024e..03ddc3355 100644 --- a/basyx.aasservice/basyx.aasservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/TestMqttAasService.java +++ b/basyx.aasservice/basyx.aasservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/TestMqttAasService.java @@ -48,6 +48,7 @@ import org.eclipse.digitaltwin.basyx.aasservice.backend.InMemoryAasServiceFactory; import org.eclipse.digitaltwin.basyx.common.mqttcore.encoding.URLEncoder; import org.eclipse.digitaltwin.basyx.common.mqttcore.listener.MqttTestListener; +import org.eclipse.digitaltwin.basyx.core.filerepository.InMemoryFileRepository; import org.eclipse.digitaltwin.basyx.http.Aas4JHTTPSerializationExtension; import org.eclipse.digitaltwin.basyx.http.BaSyxHTTPConfiguration; import org.eclipse.digitaltwin.basyx.http.SerializationExtension; @@ -102,7 +103,7 @@ protected AasService getAasService(AssetAdministrationShell shell) { } private static AasServiceFactory createMqttAasServiceFactory(MqttClient client) { - AasServiceFactory serviceFactory = new InMemoryAasServiceFactory(); + AasServiceFactory serviceFactory = new InMemoryAasServiceFactory(new InMemoryFileRepository()); MqttAasServiceFeature mqttFeature = new MqttAasServiceFeature(client, aasRepository, objectMapper); return mqttFeature.decorate(serviceFactory); diff --git a/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/MongoDBSubmodelRepositoryConfiguration.java b/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/MongoDBSubmodelRepositoryConfiguration.java index b8f3342f5..680df9beb 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/MongoDBSubmodelRepositoryConfiguration.java +++ b/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/MongoDBSubmodelRepositoryConfiguration.java @@ -24,7 +24,7 @@ ******************************************************************************/ package org.eclipse.digitaltwin.basyx.submodelrepository; -import org.eclipse.digitaltwin.basyx.core.filerepository.InMemoryFileRepository; +import org.eclipse.digitaltwin.basyx.core.filerepository.FileRepository; import org.eclipse.digitaltwin.basyx.submodelservice.InMemorySubmodelServiceFactory; import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelServiceFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; @@ -45,7 +45,7 @@ @ConditionalOnExpression("'${basyx.backend}'.equals('MongoDB')") public class MongoDBSubmodelRepositoryConfiguration { @Bean - public SubmodelServiceFactory getInMemorySubmodelServiceFactory() { - return new InMemorySubmodelServiceFactory(new InMemoryFileRepository()); + public SubmodelServiceFactory getInMemorySubmodelServiceFactory(FileRepository fileRepository) { + return new InMemorySubmodelServiceFactory(fileRepository); } }