Skip to content

Commit

Permalink
Implement Remaining MQTTSubmodelRepo Methods (#544)
Browse files Browse the repository at this point in the history
* stash

* fix: remove sideeffects from all tests

* fix: update serializeSubmodelElements method

* fix: Update events in README

* chore: add missing license header

* fix: Update File Value events

* ci: rerun

* fix: patchSubmodelElements remove pagination

---------

Co-authored-by: Mateus Molina <mateus.molina@iese.fraunhofer.de>
1 parent fe1c07e commit 2c68a75
Showing 5 changed files with 259 additions and 41 deletions.
Original file line number Diff line number Diff line change
@@ -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<SubmodelElement> submodelElements) {
try {
List<SubmodelElement> 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(localElement);
}

return new JsonSerializer().writeList(updatedSubmodelElements);
} catch (SerializationException | DeserializationException e) {
throw new RuntimeException(e);
}
}

/**
* Generator to create a copy of a submodelElement without its value.
Original file line number Diff line number Diff line change
@@ -9,5 +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 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 |

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*
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
/*******************************************************************************
* 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;
import java.io.InputStream;
import java.util.List;

@@ -126,6 +152,12 @@ public void deleteSubmodelElement(String submodelId, String idShortPath) throws
submodelElementDeleted(submodelElement, getName(), submodelId, idShortPath);
}

@Override
public void patchSubmodelElements(String submodelId, List<SubmodelElement> submodelElementList) {
decorated.patchSubmodelElements(submodelId, submodelElementList);
submodelElementsPatched(submodelElementList, getName(), submodelId);
}

@Override
public String getName() {
return decorated.getName();
@@ -141,6 +173,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){
decorated.setFileValue(submodelId, idShortPath, fileName, inputStream);
SubmodelElement submodelElement = decorated.getSubmodelElement(submodelId, idShortPath);
fileValueUpdated(submodelElement, getName(), submodelId, idShortPath);
}

@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 +225,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<SubmodelElement> 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) {
sendMqttMessage(topicFactory.createUpdateFileValueTopic(repoId, submodelId, submodelElementId), SubmodelElementSerializer.serializeSubmodelElement(submodelElement));
}

/**
* Sends MQTT message to connected broker
@@ -194,37 +267,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<SubmodelElement> submodelElementList) {
// TODO: Eventing
decorated.patchSubmodelElements(submodelId, submodelElementList);
}

@Override
public InputStream getFileByFilePath(String submodelId, String filePath) {
return decorated.getFileByFilePath(submodelId, filePath);
}

}
Original file line number Diff line number Diff line change
@@ -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 ATTACHMENT = "attachment";

/**
* @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(ATTACHMENT).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) {
return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(submodelElementId).add(ATTACHMENT).add(UPDATED).toString();
}
}
Loading

0 comments on commit 2c68a75

Please sign in to comment.