Skip to content

Commit 7c5d761

Browse files
Merge pull request #103 from Daespen/fix-submodel-values
Fixes submodel element values serialization with providers
2 parents 43d8a9e + 8fb584a commit 7c5d761

3 files changed

Lines changed: 137 additions & 2 deletions

File tree

src/main/java/org/eclipse/basyx/submodel/restapi/PropertyProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public Object getValue(String path) throws ProviderException {
5252
path = VABPathTools.stripSlashes(path);
5353

5454
if (isValuePath(path)) {
55-
return getProperty().getValue();
55+
return ValueTypeHelper.prepareForSerialization(getProperty().getValue());
5656

5757
} else if (path.isEmpty()) {
5858
return getProperty();

src/main/java/org/eclipse/basyx/submodel/restapi/SubmodelProvider.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@
2626

2727
import java.util.ArrayList;
2828
import java.util.Arrays;
29+
import java.util.LinkedList;
2930
import java.util.List;
3031
import java.util.Map;
32+
import java.util.Map.Entry;
33+
import java.util.Queue;
3134
import java.util.regex.Pattern;
3235

3336
import org.eclipse.basyx.submodel.metamodel.api.ISubmodel;
@@ -36,6 +39,7 @@
3639
import org.eclipse.basyx.submodel.metamodel.facade.submodelelement.SubmodelElementFacadeFactory;
3740
import org.eclipse.basyx.submodel.metamodel.map.Submodel;
3841
import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.property.Property;
42+
import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.property.valuetype.ValueTypeHelper;
3943
import org.eclipse.basyx.submodel.metamodel.map.submodelelement.operation.Operation;
4044
import org.eclipse.basyx.submodel.restapi.api.ISubmodelAPI;
4145
import org.eclipse.basyx.submodel.restapi.vab.VABSubmodelAPI;
@@ -137,7 +141,7 @@ public Object getValue(String path) throws ProviderException {
137141
// Request for submodelElements
138142
if (splitted.length == 1 && splitted[0].equals(VALUES)) {
139143
// Request for values of all submodelElements
140-
return submodelAPI.getSubmodel().getValues();
144+
return getSubmodelProviderValues();
141145
} else if (splitted.length == 1 && splitted[0].equals(MultiSubmodelElementProvider.ELEMENTS)) {
142146
return submodelAPI.getSubmodelElements();
143147
} else if (splitted.length >= 2 && isQualifier(splitted[0])) { // Request for element with specific idShort
@@ -162,6 +166,39 @@ public Object getValue(String path) throws ProviderException {
162166
throw new MalformedRequestException("Unknown path " + path + " was requested");
163167
}
164168

169+
private Object getSubmodelProviderValues() {
170+
Map<String, Object> objectValues = submodelAPI.getSubmodel().getValues();
171+
prepareValuesForSerialization(objectValues);
172+
return objectValues;
173+
}
174+
175+
private void prepareValuesForSerialization(Map<String, Object> objectValues) {
176+
Queue<Map<String, Object>> toBeTransformed = new LinkedList<>();
177+
toBeTransformed.add(objectValues);
178+
while (!toBeTransformed.isEmpty()) {
179+
Map<String, Object> currentMap = toBeTransformed.remove();
180+
List<Map<String, Object>> nextMaps = transformMapEntries(currentMap);
181+
toBeTransformed.addAll(nextMaps);
182+
}
183+
}
184+
185+
@SuppressWarnings("unchecked")
186+
private List<Map<String, Object>> transformMapEntries(Map<String, Object> unprocessedMap) {
187+
List<Map<String, Object>> unprocessedEntries = new LinkedList<>();
188+
for (Entry<String, Object> mapEntry : unprocessedMap.entrySet()) {
189+
Object value = mapEntry.getValue();
190+
191+
if (value instanceof Map<?, ?>) {
192+
unprocessedEntries.add((Map<String, Object>) value);
193+
continue;
194+
}
195+
196+
Object fixedValue = ValueTypeHelper.prepareForSerialization(value);
197+
unprocessedMap.replace(mapEntry.getKey(), fixedValue);
198+
}
199+
return unprocessedEntries;
200+
}
201+
165202
private List<String> getIdShorts(String[] splitted) {
166203
// Create list from array and wrap it in ArrayList to ensure modifiability
167204
List<String> idShorts = new ArrayList<>(Arrays.asList(splitted));
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package org.eclipse.basyx.testsuite.regression.submodel.restapi;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import java.io.ByteArrayOutputStream;
6+
import java.time.Duration;
7+
import java.util.Map;
8+
9+
import org.eclipse.basyx.submodel.metamodel.map.Submodel;
10+
import org.eclipse.basyx.submodel.metamodel.map.submodelelement.SubmodelElement;
11+
import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.property.Property;
12+
import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.property.valuetype.ValueType;
13+
import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.range.Range;
14+
import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.range.RangeValue;
15+
import org.eclipse.basyx.submodel.restapi.SubmodelProvider;
16+
import org.eclipse.basyx.vab.coder.json.provider.JSONProvider;
17+
import org.eclipse.basyx.vab.coder.json.serialization.DefaultTypeFactory;
18+
import org.eclipse.basyx.vab.coder.json.serialization.GSONTools;
19+
import org.eclipse.basyx.vab.modelprovider.VABPathTools;
20+
import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
21+
import org.eclipse.basyx.vab.modelprovider.map.VABMapProvider;
22+
import org.junit.Test;
23+
24+
public class SubmodelProviderIntegrationTest {
25+
protected final String RANGE_IDSHORT = "rangeProperty";
26+
protected final RangeValue RANGE_VALUE = new RangeValue(1, 2);
27+
protected final String DURATION_IDSHORT = "durationProperty";
28+
protected final Duration DURATION_VALUE = Duration.ofSeconds(10);
29+
30+
private final String VALUES_PATH = VABPathTools.concatenatePaths(SubmodelProvider.SUBMODEL, SubmodelProvider.VALUES);
31+
32+
private GSONTools serializer = new GSONTools(new DefaultTypeFactory());
33+
34+
@Test
35+
public void serializePropertyValue() {
36+
Property durationProp = new Property(DURATION_IDSHORT, DURATION_VALUE);
37+
38+
JSONProvider<IModelProvider> jsonProvider = wrapInJSONSubmodelProvider(durationProp);
39+
Object value = deserializeThroughProvider(jsonProvider, getValuePath(DURATION_IDSHORT));
40+
41+
assertEquals(DURATION_VALUE.toString(), value);
42+
}
43+
44+
@Test
45+
@SuppressWarnings("unchecked")
46+
public void serializeSubmodelPropertyValues() {
47+
Property durationProp = new Property(DURATION_IDSHORT, DURATION_VALUE);
48+
49+
JSONProvider<IModelProvider> jsonProvider = wrapInJSONSubmodelProvider(durationProp);
50+
Object values = deserializeThroughProvider(jsonProvider, VALUES_PATH);
51+
52+
Map<String, Object> valuesMap = (Map<String, Object>) values;
53+
assertEquals(1, valuesMap.size());
54+
assertEquals(DURATION_VALUE.toString(), valuesMap.get(DURATION_IDSHORT));
55+
}
56+
57+
@Test
58+
public void serializeNonPropertyValue() {
59+
Range rangeProp = new Range(RANGE_IDSHORT, ValueType.Integer);
60+
rangeProp.setValue(RANGE_VALUE);
61+
62+
JSONProvider<IModelProvider> jsonProvider = wrapInJSONSubmodelProvider(rangeProp);
63+
Object valueMap = deserializeThroughProvider(jsonProvider, getValuePath(RANGE_IDSHORT));
64+
65+
assertEquals(RANGE_VALUE, valueMap);
66+
}
67+
68+
@Test
69+
@SuppressWarnings("unchecked")
70+
public void serializeSubmodelNonPropertyValues() {
71+
Range rangeProp = new Range(RANGE_IDSHORT, ValueType.Integer);
72+
rangeProp.setValue(RANGE_VALUE);
73+
74+
JSONProvider<IModelProvider> jsonProvider = wrapInJSONSubmodelProvider(rangeProp);
75+
Map<String, Object> values = (Map<String, Object>) deserializeThroughProvider(jsonProvider, VALUES_PATH);
76+
77+
assertEquals(1, values.size());
78+
assertEquals(RANGE_VALUE, values.get(RANGE_IDSHORT));
79+
}
80+
81+
private String getValuePath(String propertyIdShort) {
82+
return VABPathTools.concatenatePaths(SubmodelProvider.SUBMODEL, Submodel.SUBMODELELEMENT, propertyIdShort, Property.VALUE);
83+
}
84+
85+
private Object deserializeThroughProvider(JSONProvider<IModelProvider> provider, String path) {
86+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
87+
provider.processBaSysGet(path, outputStream);
88+
return serializer.deserialize(outputStream.toString());
89+
}
90+
91+
private JSONProvider<IModelProvider> wrapInJSONSubmodelProvider(SubmodelElement submodelElement) {
92+
Submodel durationSubmodel = new Submodel();
93+
durationSubmodel.addSubmodelElement(submodelElement);
94+
IModelProvider durationMapProvider = new VABMapProvider(durationSubmodel);
95+
IModelProvider durationSMProvider = new SubmodelProvider(durationMapProvider);
96+
return new JSONProvider<>(durationSMProvider);
97+
}
98+
}

0 commit comments

Comments
 (0)