From 65270dc10061d073447effd6af7b85a21bbb5935 Mon Sep 17 00:00:00 2001 From: Mohammad Ghazanfar Ali Danish Date: Sun, 3 Sep 2023 18:06:15 +0200 Subject: [PATCH] Adapts the Submodel Repository - Refactors code Signed-off-by: Mohammad Ghazanfar Ali Danish --- .../TestMongoDBAasRepository.java | 2 +- ...stMongoDBConceptDescriptionRepository.java | 6 +- .../pom.xml | 10 ++ .../TestMongoDBSubmodelRepository.java | 120 +++++++++++++++--- .../src/test/resources/DummySubmodel.json | 12 ++ .../core/SubmodelRepositorySuite.java | 2 +- 6 files changed, 130 insertions(+), 22 deletions(-) create mode 100644 basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/test/resources/DummySubmodel.json diff --git a/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/TestMongoDBAasRepository.java b/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/TestMongoDBAasRepository.java index 3a183b2e6..6e5ee34c8 100644 --- a/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/TestMongoDBAasRepository.java +++ b/basyx.aasrepository/basyx.aasrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/TestMongoDBAasRepository.java @@ -110,7 +110,7 @@ public void getConfiguredMongoDBAasRepositoryName() { } @Test - public void retrieveRawJson() throws FileNotFoundException, IOException { + public void retrieveRawAasJson() throws FileNotFoundException, IOException { AssetAdministrationShell dummyAas = createDummyShellOnRepo(getAasRepositoryFactory().create(), "dummyAAS"); String expectedAASJson = getAasJSONString(); diff --git a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/TestMongoDBConceptDescriptionRepository.java b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/TestMongoDBConceptDescriptionRepository.java index 0adc89f79..66113427b 100644 --- a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/TestMongoDBConceptDescriptionRepository.java +++ b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/TestMongoDBConceptDescriptionRepository.java @@ -133,14 +133,12 @@ public void updatedConceptDescriptionIsPersisted() { } @Test - public void retrieveRawJson() throws FileNotFoundException, IOException { - MongoTemplate template = createMongoTemplate(); - + public void retrieveRawCDJson() throws FileNotFoundException, IOException { createDummyConceptDescriptionOnRepo(getConceptDescriptionRepository()); String expectedCDJson = getDummyCDJSONString(); - Document cdDocument = template.findOne(new Query().addCriteria(Criteria.where("id").is("dummy")), + Document cdDocument = createMongoTemplate().findOne(new Query().addCriteria(Criteria.where("id").is("dummy")), Document.class, COLLECTION); assertSameJSONContent(expectedCDJson, cdDocument.toJson()); diff --git a/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/pom.xml b/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/pom.xml index afc17f693..9bf049f1d 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/pom.xml +++ b/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/pom.xml @@ -37,5 +37,15 @@ org.eclipse.digitaltwin.basyx basyx.submodelservice-core + + org.eclipse.digitaltwin.basyx + basyx.submodelrepository-http + test + + + commons-io + commons-io + test + \ No newline at end of file diff --git a/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/TestMongoDBSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/TestMongoDBSubmodelRepository.java index 27f0d29be..c93102e57 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/TestMongoDBSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/TestMongoDBSubmodelRepository.java @@ -26,48 +26,77 @@ import static org.junit.Assert.assertEquals; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import org.apache.commons.io.IOUtils; +import org.bson.Document; import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; +import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement; import org.eclipse.digitaltwin.basyx.InvokableOperation; +import org.eclipse.digitaltwin.basyx.common.mongocore.CustomIdentifiableMappingMongoConverter; import org.eclipse.digitaltwin.basyx.common.mongocore.MongoDBUtilities; import org.eclipse.digitaltwin.basyx.core.exceptions.FeatureNotSupportedException; +import org.eclipse.digitaltwin.basyx.http.Aas4JHTTPSerializationExtension; +import org.eclipse.digitaltwin.basyx.http.BaSyxHTTPConfiguration; +import org.eclipse.digitaltwin.basyx.http.SerializationExtension; import org.eclipse.digitaltwin.basyx.submodelrepository.core.SubmodelRepositorySuite; +import org.eclipse.digitaltwin.basyx.submodelrepository.http.SubmodelRepositoryHTTPSerializationExtension; import org.eclipse.digitaltwin.basyx.submodelservice.InMemorySubmodelServiceFactory; import org.junit.Test; +import org.springframework.core.io.ClassPathResource; +import org.springframework.data.mongodb.MongoDatabaseFactory; import org.springframework.data.mongodb.core.MongoTemplate; -import org.junit.Test; +import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; public class TestMongoDBSubmodelRepository extends SubmodelRepositorySuite { private final String COLLECTION = "submodelTestCollection"; - private final String CONNECTION_URL = "mongodb://mongoAdmin:mongoPassword@localhost:27017"; - private final MongoClient CLIENT = MongoClients.create(CONNECTION_URL); - private final MongoTemplate TEMPLATE = new MongoTemplate(CLIENT, "BaSyxTestDb"); + + private MongoTemplate mongoTemplate; + private final InMemorySubmodelServiceFactory SUBMODEL_SERVICE_FACTORY = new InMemorySubmodelServiceFactory(); private static final String CONFIGURED_SM_REPO_NAME = "configured-sm-repo-name"; @Override protected SubmodelRepository getSubmodelRepository() { - MongoDBUtilities.clearCollection(TEMPLATE, COLLECTION); + mongoTemplate = createMongoTemplate(); + + MongoDBUtilities.clearCollection(mongoTemplate, COLLECTION); - return new MongoDBSubmodelRepositoryFactory(TEMPLATE, COLLECTION, SUBMODEL_SERVICE_FACTORY).create(); + return new MongoDBSubmodelRepositoryFactory(mongoTemplate, COLLECTION, SUBMODEL_SERVICE_FACTORY).create(); } @Override protected SubmodelRepository getSubmodelRepository(Collection submodels) { - MongoDBUtilities.clearCollection(TEMPLATE, COLLECTION); + mongoTemplate = createMongoTemplate(); + + MongoDBUtilities.clearCollection(mongoTemplate, COLLECTION); - // TODO: Remove this after MongoDB uses AAS4J serializer - submodels.forEach(this::removeInvokableFromInvokableOperation); + // Remove InvokableOperation from the Submodels + submodels.forEach(this::removeInvokableOperation); - return new MongoDBSubmodelRepositoryFactory(TEMPLATE, COLLECTION, SUBMODEL_SERVICE_FACTORY, submodels).create(); + return new MongoDBSubmodelRepositoryFactory(mongoTemplate, COLLECTION, SUBMODEL_SERVICE_FACTORY, submodels).create(); } @Test public void getConfiguredMongoDBSmRepositoryName() { - SubmodelRepository repo = new MongoDBSubmodelRepository(TEMPLATE, COLLECTION, SUBMODEL_SERVICE_FACTORY, CONFIGURED_SM_REPO_NAME); + mongoTemplate = createMongoTemplate(); + + SubmodelRepository repo = new MongoDBSubmodelRepository(mongoTemplate, COLLECTION, SUBMODEL_SERVICE_FACTORY, CONFIGURED_SM_REPO_NAME); assertEquals(CONFIGURED_SM_REPO_NAME, repo.getName()); } @@ -83,12 +112,71 @@ public void invokeOperation() { public void invokeNonOperation() { super.invokeNonOperation(); } + + @Test + public void retrieveRawSMJson() throws FileNotFoundException, IOException { + String dummySMId = "dummySubmodelId"; + + createDummySubmodelOnRepository(dummySMId); + + String expectedSMJson = getSubmodelJSONString(); + + Document smDocument = createMongoTemplate().findOne(new Query().addCriteria(Criteria.where("id").is(dummySMId)), + Document.class, COLLECTION); + + assertSameJSONContent(expectedSMJson, smDocument.toJson()); + } + + private void assertSameJSONContent(String expectedSMJson, String actualSMJson) throws JsonMappingException, JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + + assertEquals(mapper.readTree(expectedSMJson), mapper.readTree(actualSMJson)); + } - private void removeInvokableFromInvokableOperation(Submodel sm) { - sm.getSubmodelElements().stream() - .filter(InvokableOperation.class::isInstance) - .map(InvokableOperation.class::cast) - .forEach(o -> o.setInvokable(null)); + private void createDummySubmodelOnRepository(String dummySMId) { + Submodel dummySubmodel = buildDummySubmodel(dummySMId); + + SubmodelRepository repository = getSubmodelRepository(); + repository.createSubmodel(dummySubmodel); + } + + private void removeInvokableOperation(Submodel sm) { + Iterator iterator = sm.getSubmodelElements().iterator(); + while (iterator.hasNext()) { + SubmodelElement element = iterator.next(); + if (element instanceof InvokableOperation) { + iterator.remove(); + } + } + } + + private MongoTemplate createMongoTemplate() { + List extensions = Arrays.asList(new Aas4JHTTPSerializationExtension(), new SubmodelRepositoryHTTPSerializationExtension()); + + ObjectMapper mapper = new BaSyxHTTPConfiguration().jackson2ObjectMapperBuilder(extensions).build(); + + MongoDatabaseFactory databaseFactory = createDatabaseFactory(); + + return new MongoTemplate(databaseFactory, new CustomIdentifiableMappingMongoConverter(databaseFactory, new MongoMappingContext(), mapper)); + } + + private MongoDatabaseFactory createDatabaseFactory() { + String connectionString = createConnectionString(); + + MongoClient client = MongoClients.create(connectionString); + + return new SimpleMongoClientDatabaseFactory(client, "BaSyxTestDb"); + } + + private String createConnectionString() { + return String.format("mongodb://%s:%s@%s:%s", "mongoAdmin", "mongoPassword", "127.0.0.1", "27017"); + } + + private String getSubmodelJSONString() throws FileNotFoundException, IOException { + ClassPathResource classPathResource = new ClassPathResource("DummySubmodel.json"); + InputStream in = classPathResource.getInputStream(); + + return IOUtils.toString(in, StandardCharsets.UTF_8.name()); } } diff --git a/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/test/resources/DummySubmodel.json b/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/test/resources/DummySubmodel.json new file mode 100644 index 000000000..4da7fffac --- /dev/null +++ b/basyx.submodelrepository/basyx.submodelrepository-backend-mongodb/src/test/resources/DummySubmodel.json @@ -0,0 +1,12 @@ +{ + "modelType": "Submodel", + "id": "dummySubmodelId", + "submodelElements": [ + { + "modelType": "Property", + "value": "testValue", + "valueType": "xs:string", + "idShort": "prop" + } + ] +} \ No newline at end of file diff --git a/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java b/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java index 37ba5d562..9889c5457 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java +++ b/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java @@ -398,7 +398,7 @@ private SubmodelElement getExpectedSubmodelElement() { .get(); } - private Submodel buildDummySubmodel(String id) { + protected Submodel buildDummySubmodel(String id) { return new DefaultSubmodel.Builder().id(id) .submodelElements(new DefaultProperty.Builder().idShort("prop") .value("testValue")