From 00dd769de602d50c14e16d3cf167b528ec01b33d Mon Sep 17 00:00:00 2001 From: ShehriyarShariq-Fraunhofer Date: Wed, 13 Nov 2024 10:30:26 +0100 Subject: [PATCH 1/8] stash --- .../serializer/SubmodelElementSerializer.java | 30 +++++++ .../Readme.md | 5 ++ .../feature/mqtt/MqttSubmodelRepository.java | 82 +++++++++++-------- .../MqttSubmodelRepositoryTopicFactory.java | 32 ++++++++ .../mqtt/TestMqttSubmodelObserver.java | 61 ++++++++++++++ 5 files changed, 177 insertions(+), 33 deletions(-) diff --git a/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java b/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java index f2395f0f5..cf0e09996 100644 --- a/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java +++ b/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java @@ -25,6 +25,8 @@ package org.eclipse.digitaltwin.basyx.common.mqttcore.serializer; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import org.eclipse.digitaltwin.aas4j.v3.dataformat.core.DeserializationException; @@ -72,6 +74,34 @@ public static String serializeSubmodelElement(SubmodelElement submodelElement) { throw new RuntimeException(e); } } + + /** + * Serializer to create a JSON String for the given submodel elements. + * + * @param submodelElement + * @return serialized list of submodelElements as JSON String + */ + public static String serializeSubmodelElements(List submodelElements) { + try { + List updatedSubmodelElements = new ArrayList(); + + for(int i = 0; i < submodelElements.size(); i++) { + SubmodelElement elem = submodelElements.get(i); + SubmodelElement localElement; + if (shouldSendEmptyValueEvent(elem)) { + localElement = getSubmodelElementWithoutValue(elem); + } else { + localElement = elem; + } + + updatedSubmodelElements.add(new JsonSerializer().write(localElement)); + } + + return new JsonSerializer().write(updatedSubmodelElements); + } catch (SerializationException | DeserializationException e) { + throw new RuntimeException(e); + } + } /** * Generator to create a copy of a submodelElement without its value. diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md index 628ebfdf5..6a7472946 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md @@ -10,4 +10,9 @@ This feature provides hierarchical MQTT eventing for a multitude of events: | SubmodelElement Updated | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/updated | Updated SubmodelElement JSON | | SubmodelElement Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/deleted | Deleted SubmodelElement JSON | +| SubmodelElements Patched | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/patched | Patched SubmodelElement JSON | + +| FileValue Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/deleted | Deleted SubmodelElement JSON | +| FileValue Uploaded | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/deleted | Deleted SubmodelElement JSON | + Per default, the SubmodelElement topic payloads include the SubmodelElement's value. If this is not desired, the SubmodelElement can be annotated with a Qualifier of type *emptyValueUpdateEvent* and value *true* diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java index 86d11bc29..5107968d0 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java @@ -1,5 +1,6 @@ package org.eclipse.digitaltwin.basyx.submodelrepository.feature.mqtt; +import java.io.File; import java.io.InputStream; import java.util.List; @@ -126,6 +127,13 @@ public void deleteSubmodelElement(String submodelId, String idShortPath) throws submodelElementDeleted(submodelElement, getName(), submodelId, idShortPath); } + @Override + public void patchSubmodelElements(String submodelId, List submodelElementList) { + decorated.patchSubmodelElements(submodelId, submodelElementList); + List patchedSubmodelElements = decorated.getSubmodelElements(submodelId, PaginationInfo.NO_LIMIT).getResult(); + submodelElementsPatched(patchedSubmodelElements, getName(), submodelId); + } + @Override public String getName() { return decorated.getName(); @@ -141,6 +149,35 @@ public Submodel getSubmodelByIdMetadata(String submodelId) { return decorated.getSubmodelByIdMetadata(submodelId); } + @Override + public OperationVariable[] invokeOperation(String submodelId, String idShortPath, OperationVariable[] input) throws ElementDoesNotExistException { + return decorated.invokeOperation(submodelId, idShortPath, input); + } + + @Override + public java.io.File getFileByPathSubmodel(String submodelId, String idShortPath) { + return decorated.getFileByPathSubmodel(submodelId, idShortPath); + } + + @Override + public void deleteFileValue(String identifier, String idShortPath) { + SubmodelElement submodelElement = decorated.getSubmodelElement(identifier, idShortPath); + decorated.deleteFileValue(identifier, idShortPath); + fileValueDeleted(submodelElement, getName(), identifier, idShortPath); + } + + @Override + public void setFileValue(String submodelId, String idShortPath, String fileName, InputStream inputStream){ + SubmodelElement submodelElement = decorated.getSubmodelElement(submodelId, idShortPath); + decorated.setFileValue(submodelId, idShortPath, fileName, inputStream); + fileValueUpdated(submodelElement, getName(), submodelId, idShortPath, fileName); + } + + @Override + public InputStream getFileByFilePath(String submodelId, String filePath) { + return decorated.getFileByFilePath(submodelId, filePath); + } + private void submodelCreated(Submodel submodel, String repoId) { sendMqttMessage(topicFactory.createCreateSubmodelTopic(repoId), SubmodelSerializer.serializeSubmodel(submodel)); } @@ -164,6 +201,18 @@ private void submodelElementUpdated(SubmodelElement submodelElement, String repo private void submodelElementDeleted(SubmodelElement submodelElement, String repoId, String submodelId, String submodelElementId) { sendMqttMessage(topicFactory.createDeleteSubmodelElementTopic(repoId, submodelId, submodelElementId), SubmodelElementSerializer.serializeSubmodelElement(submodelElement)); } + + private void submodelElementsPatched(List submodelElements, String repoId, String submodelId) { + sendMqttMessage(topicFactory.createPatchSubmodelElementsTopic(repoId, submodelId), SubmodelElementSerializer.serializeSubmodelElements(submodelElements)); + } + + private void fileValueDeleted(SubmodelElement submodelElement, String repoId, String submodelId, String submodelElementId) { + sendMqttMessage(topicFactory.createDeleteFileValueTopic(repoId, submodelId, submodelElementId), SubmodelElementSerializer.serializeSubmodelElement(submodelElement)); + } + + private void fileValueUpdated(SubmodelElement submodelElement, String repoId, String submodelId, String submodelElementId, String fileName) { + sendMqttMessage(topicFactory.createUpdateFileValueTopic(repoId, submodelId, submodelElementId, fileName), SubmodelElementSerializer.serializeSubmodelElement(submodelElement)); + } /** * Sends MQTT message to connected broker @@ -194,37 +243,4 @@ private MqttMessage createMqttMessage(String payload) { } } - @Override - public OperationVariable[] invokeOperation(String submodelId, String idShortPath, OperationVariable[] input) throws ElementDoesNotExistException { - return decorated.invokeOperation(submodelId, idShortPath, input); - } - - @Override - public java.io.File getFileByPathSubmodel(String submodelId, String idShortPath) { - return decorated.getFileByPathSubmodel(submodelId, idShortPath); - } - - @Override - public void deleteFileValue(String identifier, String idShortPath) { - // TODO: Eventing - decorated.deleteFileValue(identifier, idShortPath); - } - - @Override - public void setFileValue(String submodelId, String idShortPath, String fileName, InputStream inputStream){ - // TODO: Eventing - decorated.setFileValue(submodelId, idShortPath, fileName, inputStream); - } - - @Override - public void patchSubmodelElements(String submodelId, List submodelElementList) { - // TODO: Eventing - decorated.patchSubmodelElements(submodelId, submodelElementList); - } - - @Override - public InputStream getFileByFilePath(String submodelId, String filePath) { - return decorated.getFileByFilePath(submodelId, filePath); - } - } diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepositoryTopicFactory.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepositoryTopicFactory.java index ea4d29263..655cb9b96 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepositoryTopicFactory.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepositoryTopicFactory.java @@ -41,7 +41,9 @@ public class MqttSubmodelRepositoryTopicFactory extends AbstractMqttTopicFactory private static final String CREATED = "created"; private static final String UPDATED = "updated"; private static final String DELETED = "deleted"; + private static final String PATCHED = "patched"; private static final String SUBMODELELEMENTS = "submodelElements"; + private static final String FILEVALUE = "fileValue"; /** * @param encoder @@ -104,4 +106,34 @@ public String createUpdateSubmodelElementTopic(String repoId, String submodelId, public String createDeleteSubmodelElementTopic(String repoId, String submodelId, String submodelElementId) { return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(submodelElementId).add(DELETED).toString(); } + + /** + * Creates the hierarchical topic for the patch event of submodelElements + * + * @param repoId + * @param submodelId + */ + public String createPatchSubmodelElementsTopic(String repoId, String submodelId) { + return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(PATCHED).toString(); + } + + /** + * Creates the hierarchical topic for the delete event of a file of a file element + * + * @param repoId + * + */ + public String createDeleteFileValueTopic(String repoId, String submodelId, String submodelElementId) { + return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(submodelElementId).add(FILEVALUE).add(DELETED).toString(); + } + + /** + * Creates the hierarchical topic for the update event of a file of a file element + * + * @param repoId + * + */ + public String createUpdateFileValueTopic(String repoId, String submodelId, String submodelElementId, String fileName) { + return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(submodelElementId).add(FILEVALUE).add(fileName).add(UPDATED).toString(); + } } diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java index 1198e9ab1..2af0bdc1b 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java @@ -29,11 +29,13 @@ import static org.junit.Assert.assertNotEquals; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eclipse.digitaltwin.aas4j.v3.dataformat.core.DeserializationException; import org.eclipse.digitaltwin.aas4j.v3.dataformat.json.JsonDeserializer; +import org.eclipse.digitaltwin.aas4j.v3.model.File; import org.eclipse.digitaltwin.aas4j.v3.model.Property; import org.eclipse.digitaltwin.aas4j.v3.model.Qualifier; import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; @@ -49,6 +51,7 @@ import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepositoryFactory; import org.eclipse.digitaltwin.basyx.submodelrepository.backend.SimpleSubmodelRepositoryFactory; import org.eclipse.digitaltwin.basyx.submodelservice.InMemorySubmodelServiceFactory; +import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelServiceHelper; import org.eclipse.digitaltwin.basyx.submodelservice.value.PropertyValue; import org.eclipse.digitaltwin.basyx.submodelservice.value.SubmodelElementValue; import org.eclipse.paho.client.mqttv3.MqttClient; @@ -175,6 +178,43 @@ public void createSubmodelElementWithoutValueEvent() throws DeserializationExcep assertEquals(submodelElement, deserializeSubmodelElementPayload(listener.lastPayload)); } + @Test + public void patchSubmodelElementsEvent() throws DeserializationException { + Submodel submodel = createSubmodelDummy("patchSubmodelForElementEventId"); + submodelRepository.createSubmodel(submodel); + + List submodelElements = createSubmodelElementsListDummy(2); + + submodelElements.forEach(submodelElement -> { + submodelRepository.createSubmodelElement(submodel.getId(), submodelElement); + }); + + for (int i = 0; i < submodelElements.size(); i++) { + SubmodelElement submodelElement = submodelElements.get(i); + submodelElement.setIdShort("patchedSubmodelElementId_" + i); + } + + submodelRepository.patchSubmodelElements(submodel.getId(), submodelElements); + + assertEquals(topicFactory.createPatchSubmodelElementsTopic(submodelRepository.getName(), submodel.getId()), listener.lastTopic); + assertEquals(submodelElements, deserializeSubmodelElementsListPayload(listener.lastPayload)); + } + + @Test + public void deleteFileValueEvent() throws DeserializationException { + Submodel submodel = createSubmodelDummy("deleteSubmodelFileValueEventId"); + submodelRepository.createSubmodel(submodel); + SubmodelElement submodelElement = createSubmodelElementDummy("deleteFileValueSubmodelElementEventId"); + submodelRepository.createSubmodelElement(submodel.getId(), submodelElement); + + + + submodelRepository.deleteFileValue(submodel.getId(), submodelElement.getIdShort()); + + assertEquals(topicFactory.createDeleteFileValueTopic(submodelRepository.getName(), submodel.getId(), submodelElement.getIdShort()), listener.lastTopic); + assertEquals(submodelElement, deserializeSubmodelElementPayload(listener.lastPayload)); + } + private List createNoValueQualifierList() { Qualifier emptyValueQualifier = new DefaultQualifier.Builder().type(SubmodelElementSerializer.EMPTYVALUEUPDATE_TYPE).value("true").build(); return Arrays.asList(emptyValueQualifier); @@ -187,6 +227,17 @@ private Submodel deserializeSubmodelPayload(String payload) throws Deserializati private SubmodelElement deserializeSubmodelElementPayload(String payload) throws DeserializationException { return new JsonDeserializer().read(payload, SubmodelElement.class); } + + private List deserializeSubmodelElementsListPayload(String payload) throws DeserializationException { + List deserializedSubmodelElements = new ArrayList(); + List deserializedStringList = new JsonDeserializer().read(payload, List.class); + + for (int i = 0; i < deserializedStringList.size(); i++) { + deserializedSubmodelElements.add(new JsonDeserializer().read(deserializedStringList.get(i), SubmodelElement.class)); + } + + return deserializedSubmodelElements; + } private Submodel createSubmodelDummy(String submodelId) { return new DefaultSubmodel.Builder().id(submodelId).build(); @@ -195,6 +246,16 @@ private Submodel createSubmodelDummy(String submodelId) { private SubmodelElement createSubmodelElementDummy(String submodelElementId) { return new DefaultProperty.Builder().idShort(submodelElementId).value("defaultValue").build(); } + + private List createSubmodelElementsListDummy(int count) { + List submodelElements = new ArrayList(); + + for (int i = 0; i < count; i++) { + submodelElements.add(createSubmodelElementDummy("submodelElementId_" + i)); + } + + return submodelElements; + } private static SubmodelRepository createMqttSubmodelRepository(MqttClient client) { SubmodelRepositoryFactory repoFactory = new SimpleSubmodelRepositoryFactory(new SubmodelInMemoryBackendProvider(), new InMemorySubmodelServiceFactory(new InMemoryFileRepository())); From 85c4847f19e92e21006e3ae17b6789ab23f84f16 Mon Sep 17 00:00:00 2001 From: ShehriyarShariq-Fraunhofer Date: Tue, 26 Nov 2024 07:34:12 +0100 Subject: [PATCH 2/8] fix: remove sideeffects from all tests --- .../serializer/SubmodelElementSerializer.java | 8 +- .../feature/mqtt/MqttSubmodelRepository.java | 2 +- .../mqtt/TestMqttSubmodelObserver.java | 112 +++++++++++++----- 3 files changed, 88 insertions(+), 34 deletions(-) diff --git a/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java b/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java index cf0e09996..fd8a74ec6 100644 --- a/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java +++ b/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java @@ -83,7 +83,8 @@ public static String serializeSubmodelElement(SubmodelElement submodelElement) { */ public static String serializeSubmodelElements(List submodelElements) { try { - List updatedSubmodelElements = new ArrayList(); +// List updatedSubmodelElements = new ArrayList<>(); + List updatedSubmodelElements = new ArrayList<>(); for(int i = 0; i < submodelElements.size(); i++) { SubmodelElement elem = submodelElements.get(i); @@ -94,10 +95,11 @@ public static String serializeSubmodelElements(List submodelEle localElement = elem; } - updatedSubmodelElements.add(new JsonSerializer().write(localElement)); +// updatedSubmodelElements.add(new JsonSerializer().write(localElement)); + updatedSubmodelElements.add(localElement); } - return new JsonSerializer().write(updatedSubmodelElements); + return new JsonSerializer().writeList(submodelElements); } catch (SerializationException | DeserializationException e) { throw new RuntimeException(e); } diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java index 5107968d0..e44d8496d 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java @@ -168,8 +168,8 @@ public void deleteFileValue(String identifier, String idShortPath) { @Override public void setFileValue(String submodelId, String idShortPath, String fileName, InputStream inputStream){ - SubmodelElement submodelElement = decorated.getSubmodelElement(submodelId, idShortPath); decorated.setFileValue(submodelId, idShortPath, fileName, inputStream); + SubmodelElement submodelElement = decorated.getSubmodelElement(submodelId, idShortPath); fileValueUpdated(submodelElement, getName(), submodelId, idShortPath, fileName); } diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java index 2af0bdc1b..d8736c341 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java @@ -28,7 +28,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -40,18 +43,21 @@ import org.eclipse.digitaltwin.aas4j.v3.model.Qualifier; import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement; +import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultFile; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultProperty; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultQualifier; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodel; import org.eclipse.digitaltwin.basyx.common.mqttcore.encoding.Base64URLEncoder; import org.eclipse.digitaltwin.basyx.common.mqttcore.serializer.SubmodelElementSerializer; +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.filerepository.InMemoryFileRepository; import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelInMemoryBackendProvider; import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository; import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepositoryFactory; import org.eclipse.digitaltwin.basyx.submodelrepository.backend.SimpleSubmodelRepositoryFactory; import org.eclipse.digitaltwin.basyx.submodelservice.InMemorySubmodelServiceFactory; -import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelServiceHelper; import org.eclipse.digitaltwin.basyx.submodelservice.value.PropertyValue; import org.eclipse.digitaltwin.basyx.submodelservice.value.SubmodelElementValue; import org.eclipse.paho.client.mqttv3.MqttClient; @@ -61,6 +67,9 @@ import org.junit.BeforeClass; import org.junit.Test; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; + import io.moquette.broker.Server; import io.moquette.broker.config.ClasspathResourceLoader; import io.moquette.broker.config.IConfig; @@ -77,7 +86,13 @@ public class TestMqttSubmodelObserver { private static MqttSubmodelRepositoryTopicFactory topicFactory = new MqttSubmodelRepositoryTopicFactory(new Base64URLEncoder()); private static SubmodelRepository submodelRepository; + + private static JsonDeserializer deserializer = new JsonDeserializer(); + private static final String FILE_SUBMODEL_ELEMENT_NAME = "testFile.txt"; + private static final String FILE_SUBMODEL_ELEMENT_CONTENT = "This is a text file."; + private static String SAVED_FILE_PATH = ""; + @BeforeClass public static void setUpClass() throws MqttException, IOException { mqttBroker = startBroker(); @@ -138,10 +153,10 @@ public void createSubmodelElementEvent() throws DeserializationException { @Test public void updateSubmodelElementEvent() throws DeserializationException { - Submodel submodel = createSubmodelDummy("updateSubmodelForElementEventId"); + Submodel submodel = createSubmodelDummyWithSubmodelElement("updateSubmodelForElementEventId", "updateSubmodelElementEventId"); submodelRepository.createSubmodel(submodel); - SubmodelElement submodelElement = createSubmodelElementDummy("updateSubmodelElementEventId"); - submodelRepository.createSubmodelElement(submodel.getId(), submodelElement); + SubmodelElement submodelElement = submodel.getSubmodelElements().get(0); + SubmodelElementValue value = new PropertyValue("updatedValue"); submodelRepository.setSubmodelElementValue(submodel.getId(), submodelElement.getIdShort(), value); @@ -151,10 +166,11 @@ public void updateSubmodelElementEvent() throws DeserializationException { @Test public void deleteSubmodelElementEvent() throws DeserializationException { - Submodel submodel = createSubmodelDummy("deleteSubmodelForElementEventId"); + Submodel submodel = createSubmodelDummyWithSubmodelElement("deleteSubmodelForElementEventId", "deleteSubmodelElementEventId"); submodelRepository.createSubmodel(submodel); - SubmodelElement submodelElement = createSubmodelElementDummy("deleteSubmodelElementEventId"); - submodelRepository.createSubmodelElement(submodel.getId(), submodelElement); + + SubmodelElement submodelElement = submodel.getSubmodelElements().get(0); + submodelRepository.deleteSubmodelElement(submodel.getId(), submodelElement.getIdShort()); assertEquals(topicFactory.createDeleteSubmodelElementTopic(submodelRepository.getName(), submodel.getId(), submodelElement.getIdShort()), listener.lastTopic); @@ -179,15 +195,11 @@ public void createSubmodelElementWithoutValueEvent() throws DeserializationExcep } @Test - public void patchSubmodelElementsEvent() throws DeserializationException { - Submodel submodel = createSubmodelDummy("patchSubmodelForElementEventId"); + public void patchSubmodelElementsEvent() throws DeserializationException, JsonMappingException, JsonProcessingException { + Submodel submodel = createSubmodelDummyWithSubmodelElements("patchSubmodelForElementEventId"); submodelRepository.createSubmodel(submodel); - List submodelElements = createSubmodelElementsListDummy(2); - - submodelElements.forEach(submodelElement -> { - submodelRepository.createSubmodelElement(submodel.getId(), submodelElement); - }); + List submodelElements = submodel.getSubmodelElements(); for (int i = 0; i < submodelElements.size(); i++) { SubmodelElement submodelElement = submodelElements.get(i); @@ -201,13 +213,24 @@ public void patchSubmodelElementsEvent() throws DeserializationException { } @Test - public void deleteFileValueEvent() throws DeserializationException { - Submodel submodel = createSubmodelDummy("deleteSubmodelFileValueEventId"); + public void setFileValueEvent() throws DeserializationException, IOException { + Submodel submodel = createSubmodelDummyWithFileSubmodelElement("setSubmodelFileValueEventId", "setFileValueSubmodelElementEventId"); submodelRepository.createSubmodel(submodel); - SubmodelElement submodelElement = createSubmodelElementDummy("deleteFileValueSubmodelElementEventId"); - submodelRepository.createSubmodelElement(submodel.getId(), submodelElement); + + File submodelElement = (File) submodel.getSubmodelElements().get(0); + submodelRepository.setFileValue(submodel.getId(), submodelElement.getIdShort(), FILE_SUBMODEL_ELEMENT_NAME, getInputStreamOfDummyFile(FILE_SUBMODEL_ELEMENT_CONTENT)); + assertEquals(topicFactory.createUpdateFileValueTopic(submodelRepository.getName(), submodel.getId(), submodelElement.getIdShort(), FILE_SUBMODEL_ELEMENT_NAME), listener.lastTopic); + assertEquals(submodelElement, deserializeSubmodelElementPayload(listener.lastPayload)); + } + + @Test + public void deleteFileValueEvent() throws DeserializationException, IOException { + Submodel submodel = createSubmodelDummyWithFileSubmodelElement("deleteSubmodelFileValueEventId", "deleteFileValueSubmodelElementEventId"); + submodelRepository.createSubmodel(submodel); + + File submodelElement = (File) submodel.getSubmodelElements().get(0); submodelRepository.deleteFileValue(submodel.getId(), submodelElement.getIdShort()); @@ -227,26 +250,51 @@ private Submodel deserializeSubmodelPayload(String payload) throws Deserializati private SubmodelElement deserializeSubmodelElementPayload(String payload) throws DeserializationException { return new JsonDeserializer().read(payload, SubmodelElement.class); } - - private List deserializeSubmodelElementsListPayload(String payload) throws DeserializationException { - List deserializedSubmodelElements = new ArrayList(); - List deserializedStringList = new JsonDeserializer().read(payload, List.class); - - for (int i = 0; i < deserializedStringList.size(); i++) { - deserializedSubmodelElements.add(new JsonDeserializer().read(deserializedStringList.get(i), SubmodelElement.class)); - } - - return deserializedSubmodelElements; + + private List deserializeSubmodelElementsListPayload(String payload) throws DeserializationException, JsonMappingException, JsonProcessingException { + return deserializer.readList(payload, SubmodelElement.class); } private Submodel createSubmodelDummy(String submodelId) { return new DefaultSubmodel.Builder().id(submodelId).build(); } + + private Submodel createSubmodelDummyWithSubmodelElement(String submodelId, String submodelElementId) { + List submodelElements = new ArrayList<>(); + + submodelElements.add(createSubmodelElementDummy(submodelElementId)); + + return new DefaultSubmodel.Builder().id(submodelId).submodelElements(submodelElements).build(); + } + + private Submodel createSubmodelDummyWithFileSubmodelElement(String submodelId, String submodelElementId) { + List submodelElements = new ArrayList<>(); + + submodelElements.add(createFileSubmodelElement(submodelElementId)); + + return new DefaultSubmodel.Builder().id(submodelId).submodelElements(submodelElements).build(); + } + + private Submodel createSubmodelDummyWithSubmodelElements(String submodelId) { + List submodelElements = createSubmodelElementsListDummy(2); + + return new DefaultSubmodel.Builder().id(submodelId).submodelElements(submodelElements).build(); + } private SubmodelElement createSubmodelElementDummy(String submodelElementId) { + Property defaultProp = new DefaultProperty.Builder().idShort(submodelElementId).value("defaultValue").build(); + return new DefaultProperty.Builder().idShort(submodelElementId).value("defaultValue").build(); } + public File createFileSubmodelElement(String submodelElementId) { + return new DefaultFile.Builder().idShort(submodelElementId).value(SAVED_FILE_PATH).contentType("text/plain").build(); + } + + private static InputStream getInputStreamOfDummyFile(String fileContent) throws FileNotFoundException, IOException { + return new ByteArrayInputStream(fileContent.getBytes()); + } + private List createSubmodelElementsListDummy(int count) { List submodelElements = new ArrayList(); @@ -257,8 +305,12 @@ private List createSubmodelElementsListDummy(int count) { return submodelElements; } - private static SubmodelRepository createMqttSubmodelRepository(MqttClient client) { - SubmodelRepositoryFactory repoFactory = new SimpleSubmodelRepositoryFactory(new SubmodelInMemoryBackendProvider(), new InMemorySubmodelServiceFactory(new InMemoryFileRepository())); + private static SubmodelRepository createMqttSubmodelRepository(MqttClient client) throws FileHandlingException, FileNotFoundException, IOException { + FileRepository fileRepository = new InMemoryFileRepository(); + + SAVED_FILE_PATH = fileRepository.save(new FileMetadata(FILE_SUBMODEL_ELEMENT_NAME, "", getInputStreamOfDummyFile(FILE_SUBMODEL_ELEMENT_CONTENT))); + + SubmodelRepositoryFactory repoFactory = new SimpleSubmodelRepositoryFactory(new SubmodelInMemoryBackendProvider(), new InMemorySubmodelServiceFactory(fileRepository)); return new MqttSubmodelRepositoryFactory(repoFactory, client, new MqttSubmodelRepositoryTopicFactory(new Base64URLEncoder())).create(); } From 426e3c278f51c48fcd2403f16a82184ff055db23 Mon Sep 17 00:00:00 2001 From: ShehriyarShariq-Fraunhofer Date: Tue, 26 Nov 2024 07:37:55 +0100 Subject: [PATCH 3/8] fix: update serializeSubmodelElements method --- .../common/mqttcore/serializer/SubmodelElementSerializer.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java b/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java index fd8a74ec6..771fd9c43 100644 --- a/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java +++ b/basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java @@ -83,7 +83,6 @@ public static String serializeSubmodelElement(SubmodelElement submodelElement) { */ public static String serializeSubmodelElements(List submodelElements) { try { -// List updatedSubmodelElements = new ArrayList<>(); List updatedSubmodelElements = new ArrayList<>(); for(int i = 0; i < submodelElements.size(); i++) { @@ -95,11 +94,10 @@ public static String serializeSubmodelElements(List submodelEle localElement = elem; } -// updatedSubmodelElements.add(new JsonSerializer().write(localElement)); updatedSubmodelElements.add(localElement); } - return new JsonSerializer().writeList(submodelElements); + return new JsonSerializer().writeList(updatedSubmodelElements); } catch (SerializationException | DeserializationException e) { throw new RuntimeException(e); } From 86ffb23b64a26ae52952538962bf55b954c97cd1 Mon Sep 17 00:00:00 2001 From: ShehriyarShariq-Fraunhofer Date: Tue, 26 Nov 2024 07:42:21 +0100 Subject: [PATCH 4/8] fix: Update events in README --- .../basyx.submodelrepository-feature-mqtt/Readme.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md index 6a7472946..1afbac766 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md @@ -9,10 +9,8 @@ This feature provides hierarchical MQTT eventing for a multitude of events: | SubmodelElement Created | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/created | Created SubmodelElement JSON | | SubmodelElement Updated | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/updated | Updated SubmodelElement JSON | | SubmodelElement Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/deleted | Deleted SubmodelElement JSON | - -| SubmodelElements Patched | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/patched | Patched SubmodelElement JSON | - -| FileValue Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/deleted | Deleted SubmodelElement JSON | -| FileValue Uploaded | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/deleted | Deleted SubmodelElement JSON | +| SubmodelElements Patched | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/patched | Patched SubmodelElements JSON | +| FileValue Updated | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/fileValue/$fileName/updated | Updated SubmodelElement JSON | +| FileValue Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/fileValue/deleted | Deleted SubmodelElement JSON | Per default, the SubmodelElement topic payloads include the SubmodelElement's value. If this is not desired, the SubmodelElement can be annotated with a Qualifier of type *emptyValueUpdateEvent* and value *true* From 8239244416fae52bad6af7af5f1badba6583a2da Mon Sep 17 00:00:00 2001 From: Mateus Molina Date: Fri, 29 Nov 2024 08:42:07 +0100 Subject: [PATCH 5/8] chore: add missing license header --- .../feature/mqtt/MqttSubmodelRepository.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java index e44d8496d..5dcde354d 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.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.submodelrepository.feature.mqtt; import java.io.File; From c84de43f35a579cec68661e1078382d5e40aea68 Mon Sep 17 00:00:00 2001 From: ShehriyarShariq-Fraunhofer Date: Tue, 3 Dec 2024 07:44:52 +0100 Subject: [PATCH 6/8] fix: Update File Value events --- .../basyx.submodelrepository-feature-mqtt/Readme.md | 4 ++-- .../feature/mqtt/MqttSubmodelRepository.java | 6 +++--- .../feature/mqtt/MqttSubmodelRepositoryTopicFactory.java | 8 ++++---- .../feature/mqtt/TestMqttSubmodelObserver.java | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md index 1afbac766..a46cf6d65 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md @@ -10,7 +10,7 @@ This feature provides hierarchical MQTT eventing for a multitude of events: | SubmodelElement Updated | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/updated | Updated SubmodelElement JSON | | SubmodelElement Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/deleted | Deleted SubmodelElement JSON | | SubmodelElements Patched | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/patched | Patched SubmodelElements JSON | -| FileValue Updated | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/fileValue/$fileName/updated | Updated SubmodelElement JSON | -| FileValue Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/fileValue/deleted | Deleted SubmodelElement JSON | +| FileValue Updated | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/attachment/updated | Updated SubmodelElement JSON | +| FileValue Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/attachment/deleted | Deleted SubmodelElement JSON | Per default, the SubmodelElement topic payloads include the SubmodelElement's value. If this is not desired, the SubmodelElement can be annotated with a Qualifier of type *emptyValueUpdateEvent* and value *true* diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java index e44d8496d..f54604f72 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java @@ -170,7 +170,7 @@ public void deleteFileValue(String identifier, String idShortPath) { public void setFileValue(String submodelId, String idShortPath, String fileName, InputStream inputStream){ decorated.setFileValue(submodelId, idShortPath, fileName, inputStream); SubmodelElement submodelElement = decorated.getSubmodelElement(submodelId, idShortPath); - fileValueUpdated(submodelElement, getName(), submodelId, idShortPath, fileName); + fileValueUpdated(submodelElement, getName(), submodelId, idShortPath); } @Override @@ -210,8 +210,8 @@ private void fileValueDeleted(SubmodelElement submodelElement, String repoId, St sendMqttMessage(topicFactory.createDeleteFileValueTopic(repoId, submodelId, submodelElementId), SubmodelElementSerializer.serializeSubmodelElement(submodelElement)); } - private void fileValueUpdated(SubmodelElement submodelElement, String repoId, String submodelId, String submodelElementId, String fileName) { - sendMqttMessage(topicFactory.createUpdateFileValueTopic(repoId, submodelId, submodelElementId, fileName), SubmodelElementSerializer.serializeSubmodelElement(submodelElement)); + private void fileValueUpdated(SubmodelElement submodelElement, String repoId, String submodelId, String submodelElementId) { + sendMqttMessage(topicFactory.createUpdateFileValueTopic(repoId, submodelId, submodelElementId), SubmodelElementSerializer.serializeSubmodelElement(submodelElement)); } /** diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepositoryTopicFactory.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepositoryTopicFactory.java index 655cb9b96..14ab1f0e5 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepositoryTopicFactory.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepositoryTopicFactory.java @@ -43,7 +43,7 @@ public class MqttSubmodelRepositoryTopicFactory extends AbstractMqttTopicFactory private static final String DELETED = "deleted"; private static final String PATCHED = "patched"; private static final String SUBMODELELEMENTS = "submodelElements"; - private static final String FILEVALUE = "fileValue"; + private static final String ATTACHMENT = "attachment"; /** * @param encoder @@ -124,7 +124,7 @@ public String createPatchSubmodelElementsTopic(String repoId, String submodelId) * */ public String createDeleteFileValueTopic(String repoId, String submodelId, String submodelElementId) { - return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(submodelElementId).add(FILEVALUE).add(DELETED).toString(); + return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(submodelElementId).add(ATTACHMENT).add(DELETED).toString(); } /** @@ -133,7 +133,7 @@ public String createDeleteFileValueTopic(String repoId, String submodelId, Strin * @param repoId * */ - public String createUpdateFileValueTopic(String repoId, String submodelId, String submodelElementId, String fileName) { - return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(submodelElementId).add(FILEVALUE).add(fileName).add(UPDATED).toString(); + public String createUpdateFileValueTopic(String repoId, String submodelId, String submodelElementId) { + return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(submodelElementId).add(ATTACHMENT).add(UPDATED).toString(); } } diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java index d8736c341..2afc466d0 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java @@ -221,7 +221,7 @@ public void setFileValueEvent() throws DeserializationException, IOException { submodelRepository.setFileValue(submodel.getId(), submodelElement.getIdShort(), FILE_SUBMODEL_ELEMENT_NAME, getInputStreamOfDummyFile(FILE_SUBMODEL_ELEMENT_CONTENT)); - assertEquals(topicFactory.createUpdateFileValueTopic(submodelRepository.getName(), submodel.getId(), submodelElement.getIdShort(), FILE_SUBMODEL_ELEMENT_NAME), listener.lastTopic); + assertEquals(topicFactory.createUpdateFileValueTopic(submodelRepository.getName(), submodel.getId(), submodelElement.getIdShort()), listener.lastTopic); assertEquals(submodelElement, deserializeSubmodelElementPayload(listener.lastPayload)); } From cb277b67501adfe3bb348428cbeb49431d33c038 Mon Sep 17 00:00:00 2001 From: Mateus Molina Date: Tue, 3 Dec 2024 14:11:29 +0100 Subject: [PATCH 7/8] ci: rerun --- .../basyx.submodelrepository-feature-mqtt/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md index a46cf6d65..fd810ae9c 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md @@ -11,6 +11,6 @@ This feature provides hierarchical MQTT eventing for a multitude of events: | SubmodelElement Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/deleted | Deleted SubmodelElement JSON | | SubmodelElements Patched | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/patched | Patched SubmodelElements JSON | | FileValue Updated | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/attachment/updated | Updated SubmodelElement JSON | -| FileValue Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/attachment/deleted | Deleted SubmodelElement JSON | +| FileValue Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/attachment/deleted | Deleted SubmodelElement JSON | Per default, the SubmodelElement topic payloads include the SubmodelElement's value. If this is not desired, the SubmodelElement can be annotated with a Qualifier of type *emptyValueUpdateEvent* and value *true* From 9a5873913da2c8e1c888b79101dd6a1587ffccca Mon Sep 17 00:00:00 2001 From: ShehriyarShariq-Fraunhofer Date: Tue, 3 Dec 2024 16:09:04 +0100 Subject: [PATCH 8/8] fix: patchSubmodelElements remove pagination --- .../feature/mqtt/MqttSubmodelRepository.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java index cd73a79e3..9b4e661be 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java @@ -155,8 +155,7 @@ public void deleteSubmodelElement(String submodelId, String idShortPath) throws @Override public void patchSubmodelElements(String submodelId, List submodelElementList) { decorated.patchSubmodelElements(submodelId, submodelElementList); - List patchedSubmodelElements = decorated.getSubmodelElements(submodelId, PaginationInfo.NO_LIMIT).getResult(); - submodelElementsPatched(patchedSubmodelElements, getName(), submodelId); + submodelElementsPatched(submodelElementList, getName(), submodelId); } @Override