Skip to content

Commit 2c68a75

Browse files
Implement Remaining MQTTSubmodelRepo Methods (#544)
* 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 <[email protected]>
1 parent fe1c07e commit 2c68a75

File tree

5 files changed

+259
-41
lines changed

5 files changed

+259
-41
lines changed

basyx.common/basyx.mqttcore/src/main/java/org/eclipse/digitaltwin/basyx/common/mqttcore/serializer/SubmodelElementSerializer.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
package org.eclipse.digitaltwin.basyx.common.mqttcore.serializer;
2727

28+
import java.util.ArrayList;
29+
import java.util.List;
2830
import java.util.Optional;
2931

3032
import org.eclipse.digitaltwin.aas4j.v3.dataformat.core.DeserializationException;
@@ -72,6 +74,34 @@ public static String serializeSubmodelElement(SubmodelElement submodelElement) {
7274
throw new RuntimeException(e);
7375
}
7476
}
77+
78+
/**
79+
* Serializer to create a JSON String for the given submodel elements.
80+
*
81+
* @param submodelElement
82+
* @return serialized list of submodelElements as JSON String
83+
*/
84+
public static String serializeSubmodelElements(List<SubmodelElement> submodelElements) {
85+
try {
86+
List<SubmodelElement> updatedSubmodelElements = new ArrayList<>();
87+
88+
for(int i = 0; i < submodelElements.size(); i++) {
89+
SubmodelElement elem = submodelElements.get(i);
90+
SubmodelElement localElement;
91+
if (shouldSendEmptyValueEvent(elem)) {
92+
localElement = getSubmodelElementWithoutValue(elem);
93+
} else {
94+
localElement = elem;
95+
}
96+
97+
updatedSubmodelElements.add(localElement);
98+
}
99+
100+
return new JsonSerializer().writeList(updatedSubmodelElements);
101+
} catch (SerializationException | DeserializationException e) {
102+
throw new RuntimeException(e);
103+
}
104+
}
75105

76106
/**
77107
* Generator to create a copy of a submodelElement without its value.

basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/Readme.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ This feature provides hierarchical MQTT eventing for a multitude of events:
99
| SubmodelElement Created | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/created | Created SubmodelElement JSON |
1010
| SubmodelElement Updated | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/updated | Updated SubmodelElement JSON |
1111
| SubmodelElement Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/deleted | Deleted SubmodelElement JSON |
12+
| SubmodelElements Patched | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/patched | Patched SubmodelElements JSON |
13+
| FileValue Updated | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/attachment/updated | Updated SubmodelElement JSON |
14+
| FileValue Deleted | sm-repository/$repoId/submodels/$submodelIdBase64URLEncoded/submodelElements/$idShortPath/attachment/deleted | Deleted SubmodelElement JSON |
1215

1316
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*

basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java

Lines changed: 73 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
1+
/*******************************************************************************
2+
* Copyright (C) 2024 the Eclipse BaSyx Authors
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining
5+
* a copy of this software and associated documentation files (the
6+
* "Software"), to deal in the Software without restriction, including
7+
* without limitation the rights to use, copy, modify, merge, publish,
8+
* distribute, sublicense, and/or sell copies of the Software, and to
9+
* permit persons to whom the Software is furnished to do so, subject to
10+
* the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be
13+
* included in all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22+
*
23+
* SPDX-License-Identifier: MIT
24+
******************************************************************************/
25+
126
package org.eclipse.digitaltwin.basyx.submodelrepository.feature.mqtt;
227

28+
import java.io.File;
329
import java.io.InputStream;
430
import java.util.List;
531

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

155+
@Override
156+
public void patchSubmodelElements(String submodelId, List<SubmodelElement> submodelElementList) {
157+
decorated.patchSubmodelElements(submodelId, submodelElementList);
158+
submodelElementsPatched(submodelElementList, getName(), submodelId);
159+
}
160+
129161
@Override
130162
public String getName() {
131163
return decorated.getName();
@@ -141,6 +173,35 @@ public Submodel getSubmodelByIdMetadata(String submodelId) {
141173
return decorated.getSubmodelByIdMetadata(submodelId);
142174
}
143175

176+
@Override
177+
public OperationVariable[] invokeOperation(String submodelId, String idShortPath, OperationVariable[] input) throws ElementDoesNotExistException {
178+
return decorated.invokeOperation(submodelId, idShortPath, input);
179+
}
180+
181+
@Override
182+
public java.io.File getFileByPathSubmodel(String submodelId, String idShortPath) {
183+
return decorated.getFileByPathSubmodel(submodelId, idShortPath);
184+
}
185+
186+
@Override
187+
public void deleteFileValue(String identifier, String idShortPath) {
188+
SubmodelElement submodelElement = decorated.getSubmodelElement(identifier, idShortPath);
189+
decorated.deleteFileValue(identifier, idShortPath);
190+
fileValueDeleted(submodelElement, getName(), identifier, idShortPath);
191+
}
192+
193+
@Override
194+
public void setFileValue(String submodelId, String idShortPath, String fileName, InputStream inputStream){
195+
decorated.setFileValue(submodelId, idShortPath, fileName, inputStream);
196+
SubmodelElement submodelElement = decorated.getSubmodelElement(submodelId, idShortPath);
197+
fileValueUpdated(submodelElement, getName(), submodelId, idShortPath);
198+
}
199+
200+
@Override
201+
public InputStream getFileByFilePath(String submodelId, String filePath) {
202+
return decorated.getFileByFilePath(submodelId, filePath);
203+
}
204+
144205
private void submodelCreated(Submodel submodel, String repoId) {
145206
sendMqttMessage(topicFactory.createCreateSubmodelTopic(repoId), SubmodelSerializer.serializeSubmodel(submodel));
146207
}
@@ -164,6 +225,18 @@ private void submodelElementUpdated(SubmodelElement submodelElement, String repo
164225
private void submodelElementDeleted(SubmodelElement submodelElement, String repoId, String submodelId, String submodelElementId) {
165226
sendMqttMessage(topicFactory.createDeleteSubmodelElementTopic(repoId, submodelId, submodelElementId), SubmodelElementSerializer.serializeSubmodelElement(submodelElement));
166227
}
228+
229+
private void submodelElementsPatched(List<SubmodelElement> submodelElements, String repoId, String submodelId) {
230+
sendMqttMessage(topicFactory.createPatchSubmodelElementsTopic(repoId, submodelId), SubmodelElementSerializer.serializeSubmodelElements(submodelElements));
231+
}
232+
233+
private void fileValueDeleted(SubmodelElement submodelElement, String repoId, String submodelId, String submodelElementId) {
234+
sendMqttMessage(topicFactory.createDeleteFileValueTopic(repoId, submodelId, submodelElementId), SubmodelElementSerializer.serializeSubmodelElement(submodelElement));
235+
}
236+
237+
private void fileValueUpdated(SubmodelElement submodelElement, String repoId, String submodelId, String submodelElementId) {
238+
sendMqttMessage(topicFactory.createUpdateFileValueTopic(repoId, submodelId, submodelElementId), SubmodelElementSerializer.serializeSubmodelElement(submodelElement));
239+
}
167240

168241
/**
169242
* Sends MQTT message to connected broker
@@ -194,37 +267,4 @@ private MqttMessage createMqttMessage(String payload) {
194267
}
195268
}
196269

197-
@Override
198-
public OperationVariable[] invokeOperation(String submodelId, String idShortPath, OperationVariable[] input) throws ElementDoesNotExistException {
199-
return decorated.invokeOperation(submodelId, idShortPath, input);
200-
}
201-
202-
@Override
203-
public java.io.File getFileByPathSubmodel(String submodelId, String idShortPath) {
204-
return decorated.getFileByPathSubmodel(submodelId, idShortPath);
205-
}
206-
207-
@Override
208-
public void deleteFileValue(String identifier, String idShortPath) {
209-
// TODO: Eventing
210-
decorated.deleteFileValue(identifier, idShortPath);
211-
}
212-
213-
@Override
214-
public void setFileValue(String submodelId, String idShortPath, String fileName, InputStream inputStream){
215-
// TODO: Eventing
216-
decorated.setFileValue(submodelId, idShortPath, fileName, inputStream);
217-
}
218-
219-
@Override
220-
public void patchSubmodelElements(String submodelId, List<SubmodelElement> submodelElementList) {
221-
// TODO: Eventing
222-
decorated.patchSubmodelElements(submodelId, submodelElementList);
223-
}
224-
225-
@Override
226-
public InputStream getFileByFilePath(String submodelId, String filePath) {
227-
return decorated.getFileByFilePath(submodelId, filePath);
228-
}
229-
230270
}

basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepositoryTopicFactory.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ public class MqttSubmodelRepositoryTopicFactory extends AbstractMqttTopicFactory
4141
private static final String CREATED = "created";
4242
private static final String UPDATED = "updated";
4343
private static final String DELETED = "deleted";
44+
private static final String PATCHED = "patched";
4445
private static final String SUBMODELELEMENTS = "submodelElements";
46+
private static final String ATTACHMENT = "attachment";
4547

4648
/**
4749
* @param encoder
@@ -104,4 +106,34 @@ public String createUpdateSubmodelElementTopic(String repoId, String submodelId,
104106
public String createDeleteSubmodelElementTopic(String repoId, String submodelId, String submodelElementId) {
105107
return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(submodelElementId).add(DELETED).toString();
106108
}
109+
110+
/**
111+
* Creates the hierarchical topic for the patch event of submodelElements
112+
*
113+
* @param repoId
114+
* @param submodelId
115+
*/
116+
public String createPatchSubmodelElementsTopic(String repoId, String submodelId) {
117+
return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(PATCHED).toString();
118+
}
119+
120+
/**
121+
* Creates the hierarchical topic for the delete event of a file of a file element
122+
*
123+
* @param repoId
124+
*
125+
*/
126+
public String createDeleteFileValueTopic(String repoId, String submodelId, String submodelElementId) {
127+
return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(submodelElementId).add(ATTACHMENT).add(DELETED).toString();
128+
}
129+
130+
/**
131+
* Creates the hierarchical topic for the update event of a file of a file element
132+
*
133+
* @param repoId
134+
*
135+
*/
136+
public String createUpdateFileValueTopic(String repoId, String submodelId, String submodelElementId) {
137+
return new StringJoiner("/", "", "").add(SUBMODELREPOSITORY).add(repoId).add(SUBMODELS).add(encodeId(submodelId)).add(SUBMODELELEMENTS).add(submodelElementId).add(ATTACHMENT).add(UPDATED).toString();
138+
}
107139
}

0 commit comments

Comments
 (0)