Skip to content

Commit 036fda2

Browse files
committed
Converted internal representation of Object properties to TreeNode
1 parent 68f55bf commit 036fda2

27 files changed

Lines changed: 307 additions & 172 deletions

File tree

FROST-Server.Core.Model/src/main/java/de/fraunhofer/iosb/ilt/frostserver/model/CollectionsHelper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package de.fraunhofer.iosb.ilt.frostserver.model;
1919

20+
import de.fraunhofer.iosb.ilt.frostserver.util.SimpleJsonMapper;
2021
import java.util.Arrays;
2122
import java.util.HashMap;
2223
import java.util.LinkedHashMap;
@@ -25,6 +26,7 @@
2526
import org.apache.commons.lang3.StringUtils;
2627
import org.slf4j.Logger;
2728
import org.slf4j.LoggerFactory;
29+
import tools.jackson.core.TreeNode;
2830

2931
/**
3032
* A collection of tools for Collections.
@@ -130,6 +132,10 @@ public PropertyBuilder addPath(String path, Object value) {
130132
public Map<String, Object> build() {
131133
return properties;
132134
}
135+
136+
public TreeNode buildTreeNode() {
137+
return SimpleJsonMapper.getSimpleObjectMapper().valueToTree(properties);
138+
}
133139
}
134140

135141
}

FROST-Server.Core.Model/src/main/java/de/fraunhofer/iosb/ilt/frostserver/model/ModelRegistry.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.TreeSet;
3333
import org.slf4j.Logger;
3434
import org.slf4j.LoggerFactory;
35+
import tools.jackson.core.TreeNode;
3536

3637
/**
3738
*
@@ -48,7 +49,7 @@ public class ModelRegistry {
4849
/**
4950
* The global EntityProperty properties.
5051
*/
51-
public static final EntityPropertyMain<Map<String, Object>> EP_PROPERTIES = new EntityPropertyMain<>("properties", TypeComplex.STA_MAP, false, true, true, false);
52+
public static final EntityPropertyMain<TreeNode> EP_PROPERTIES = new EntityPropertyMain<>("properties", TypeComplex.STA_MAP, false, true, true, false);
5253
/**
5354
* The global EntityProperty encodingType.
5455
*/

FROST-Server.Core.Model/src/main/java/de/fraunhofer/iosb/ilt/frostserver/model/ext/TypeReferencesHelper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.HashMap;
2727
import java.util.List;
2828
import java.util.Map;
29+
import java.util.TreeMap;
2930
import java.util.UUID;
3031
import org.apache.commons.lang3.reflect.FieldUtils;
3132
import org.geojson.GeoJsonObject;
@@ -76,6 +77,9 @@ public class TypeReferencesHelper {
7677
public static final TypeReference<Map<String, Object>> TYPE_REFERENCE_MAP = new TypeReference<Map<String, Object>>() {
7778
// Empty on purpose.
7879
};
80+
public static final TypeReference<TreeMap<String, Object>> TYPE_REFERENCE_MAP_SORTED = new TypeReference<TreeMap<String, Object>>() {
81+
// Empty on purpose.
82+
};
7983
public static final TypeReference<Number> TYPE_REFERENCE_NUMBER = new TypeReference<Number>() {
8084
// Empty on purpose.
8185
};

FROST-Server.Core.Model/src/main/java/de/fraunhofer/iosb/ilt/frostserver/path/CustomLinksHelper.java

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
import java.util.regex.Matcher;
3232
import java.util.regex.Pattern;
3333
import org.apache.commons.lang3.StringUtils;
34+
import tools.jackson.core.TreeNode;
35+
import tools.jackson.databind.JsonNode;
36+
import tools.jackson.databind.node.ArrayNode;
37+
import tools.jackson.databind.node.ObjectNode;
38+
import tools.jackson.databind.node.ValueNode;
3439

3540
/**
3641
*
@@ -85,36 +90,51 @@ public void expandCustomLinks(Query query, Entity entity, ResourcePath path) {
8590

8691
private void expandCustomLinks(Query query, EntityPropertyMain property, Entity entity, ResourcePath path, int recurseDepth) {
8792
final Object properties = entity.getProperty(property);
88-
if (properties instanceof Map) {
89-
expandCustomLinks(query, (Map<String, Object>) properties, path, recurseDepth);
93+
if (properties instanceof TreeNode tn) {
94+
expandCustomLinks(query, tn, path, recurseDepth);
9095
}
9196
}
9297

93-
public void expandCustomLinks(Query query, Map<String, Object> properties, ResourcePath path, int recurseDepth) {
98+
public void expandCustomLinks(Query query, TreeNode properties, ResourcePath path, int recurseDepth) {
9499
if (properties == null) {
95100
return;
96101
}
97-
Map<String, Object> toAdd = new LinkedHashMap<>();
98-
for (Map.Entry<String, Object> propertyEntry : properties.entrySet()) {
99-
Object value = propertyEntry.getValue();
100-
if (value instanceof Map) {
101-
Map<String, Object> subMap = (Map<String, Object>) value;
102-
if (recurseDepth > 0) {
103-
expandCustomLinks(query, subMap, path, recurseDepth - 1);
104-
}
105-
} else if (value instanceof Number || value instanceof String) {
102+
if (properties instanceof ObjectNode oNode) {
103+
expandCustomLinks(query, oNode, path, recurseDepth);
104+
} else if (properties instanceof ArrayNode aNode) {
105+
expandCustomLinks(query, aNode, path, recurseDepth);
106+
}
107+
108+
}
109+
110+
public void expandCustomLinks(Query query, ObjectNode properties, ResourcePath path, int recurseDepth) {
111+
Map<String, String> toAdd = new LinkedHashMap<>();
112+
for (Map.Entry<String, JsonNode> propertyEntry : properties.properties()) {
113+
JsonNode value = propertyEntry.getValue();
114+
if (value instanceof ValueNode vn && (vn.isNumber() || vn.isString())) {
106115
String key = propertyEntry.getKey();
107116
Matcher matcher = entityLinkNamePattern.matcher(key);
108117
if (matcher.matches()) {
109118
String name = matcher.group(1);
110119
EntityType type = modelRegistry.getEntityTypeForName(matcher.group(2));
111-
Object id = propertyEntry.getValue();
112120
String navLinkName = name + "." + type.entityName + AT_IOT_NAVIGATION_LINK;
113-
toAdd.put(navLinkName, UrlHelper.generateSelfLink(path.getServiceRootUrl(), path.getVersion(), type, id));
121+
toAdd.put(navLinkName, UrlHelper.generateSelfLink(path.getServiceRootUrl(), path.getVersion(), type, vn));
122+
}
123+
} else {
124+
if (recurseDepth > 0) {
125+
expandCustomLinks(query, value, path, recurseDepth - 1);
114126
}
115127
}
116128
}
117-
properties.putAll(toAdd);
129+
for (Map.Entry<String, String> entry : toAdd.entrySet()) {
130+
properties.put(entry.getKey(), entry.getValue());
131+
}
132+
}
133+
134+
public void expandCustomLinks(Query query, ArrayNode array, ResourcePath path, int recurseDepth) {
135+
for (JsonNode entry : array) {
136+
expandCustomLinks(query, entry, path, recurseDepth);
137+
}
118138
}
119139

120140
public void cleanPropertiesMap(Entity entity) {

FROST-Server.Core.Model/src/main/java/de/fraunhofer/iosb/ilt/frostserver/path/UrlHelper.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.apache.commons.text.StringEscapeUtils;
5454
import org.slf4j.Logger;
5555
import org.slf4j.LoggerFactory;
56+
import tools.jackson.databind.node.ValueNode;
5657

5758
/**
5859
*
@@ -221,6 +222,16 @@ public static String generateSelfLink(String serviceRootUrl, Version version, En
221222
.toString();
222223
}
223224

225+
public static String generateSelfLink(String serviceRootUrl, Version version, EntityType entityType, ValueNode id) {
226+
if (id.isIntegralNumber()) {
227+
return generateSelfLink(serviceRootUrl, version, entityType, id.asBigInteger());
228+
}
229+
if (id.isNumber()) {
230+
return generateSelfLink(serviceRootUrl, version, entityType, id.asDecimal());
231+
}
232+
return generateSelfLink(serviceRootUrl, version, entityType, id.asString());
233+
}
234+
224235
public static String generateSelfLink(String serviceRootUrl, Version version, EntityType entityType, Object id) {
225236
return new StringBuilder(serviceRootUrl)
226237
.append('/')

FROST-Server.Core.Model/src/main/java/de/fraunhofer/iosb/ilt/frostserver/property/NavigationPropertyCustom.java

Lines changed: 78 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
import org.apache.commons.lang3.StringUtils;
3737
import org.slf4j.Logger;
3838
import org.slf4j.LoggerFactory;
39+
import tools.jackson.databind.JsonNode;
40+
import tools.jackson.databind.node.ArrayNode;
41+
import tools.jackson.databind.node.ObjectNode;
3942

4043
/**
4144
*
@@ -135,7 +138,7 @@ public boolean isReadOnly() {
135138

136139
public void setElementOn(Entity entity, NavigableElement expandedElement) {
137140
init(entity);
138-
targetData.containingMap.put(name + "." + type.entityName, expandedElement);
141+
targetData.setKey(name + "." + type.entityName, expandedElement);
139142
}
140143

141144
public PkValue getTargetIdFrom(Entity entity) {
@@ -146,10 +149,7 @@ public PkValue getTargetIdFrom(Entity entity) {
146149
@Override
147150
public Entity getFrom(Entity entity) {
148151
init(entity);
149-
if (targetData.containingMap == null) {
150-
return null;
151-
}
152-
return (Entity) targetData.containingMap.get(targetData.fullKeyEntity);
152+
return (Entity) targetData.getKey(targetData.fullKeyEntity);
153153
}
154154

155155
@Override
@@ -160,10 +160,7 @@ public void setOn(Entity entity, Entity value) {
160160
@Override
161161
public boolean isSetOn(Entity entity) {
162162
init(entity);
163-
if (targetData.containingMap == null) {
164-
return false;
165-
}
166-
return targetData.containingMap.containsKey(targetData.fullKeyEntity);
163+
return targetData.containsKey(targetData.fullKeyEntity);
167164
}
168165

169166
@Override
@@ -191,46 +188,112 @@ private static class LinkTargetData {
191188

192189
private Entity entity;
193190
private Map<String, Object> containingMap;
191+
private ObjectNode containingNode;
194192
private String fullKeyEntity;
195193
private Object targetId;
196194

197195
public void clear() {
198196
entity = null;
199197
containingMap = null;
198+
containingNode = null;
200199
fullKeyEntity = null;
201200
targetId = null;
202201
}
203202

203+
public boolean containsKey(String key) {
204+
if (containingNode != null) {
205+
return containingNode.has(key);
206+
}
207+
if (containingMap != null) {
208+
return containingMap.containsKey(key);
209+
}
210+
return false;
211+
}
212+
213+
public Object getKey(String key) {
214+
if (containingNode != null) {
215+
return containingNode.get(key);
216+
}
217+
if (containingMap != null) {
218+
return containingMap.get(key);
219+
}
220+
return null;
221+
}
222+
223+
public void setKey(String key, NavigableElement value) {
224+
if (containingNode != null) {
225+
containingNode.putPOJO(key, value);
226+
}
227+
if (containingMap != null) {
228+
containingMap.put(key, value);
229+
}
230+
}
231+
204232
public void findLinkTargetData(Entity entity, EntityPropertyMain entityProperty, List<String> subPath, String name, EntityType type) {
205233
clear();
206234
Object curTarget = entityProperty.getFrom(entity);
207235
int count = subPath.size() - 1;
208236
for (int idx = 0; idx < count; idx++) {
209237
String curPathItem = subPath.get(idx);
210-
if (curTarget instanceof Map) {
211-
Map<String, Object> map = (Map<String, Object>) curTarget;
212-
curTarget = map.get(curPathItem);
238+
if (curTarget instanceof ObjectNode on) {
239+
curTarget = on.get(curPathItem);
240+
} else if (curTarget instanceof ArrayNode an) {
241+
try {
242+
int nr = Integer.parseInt(curPathItem);
243+
curTarget = an.get(nr);
244+
} catch (NumberFormatException ex) {
245+
LOGGER.trace("Not a number, can't access array: {}", curPathItem, ex);
246+
return;
247+
}
248+
} else if (curTarget instanceof Map m) {
249+
curTarget = m.get(curPathItem);
213250
} else {
214251
return;
215252
}
216253
}
217-
if (curTarget instanceof Map) {
218-
findLinkEntryInMap((Map<String, Object>) curTarget, name, type);
254+
if (curTarget instanceof ObjectNode on) {
255+
findLinkEntryIn(on, name, type);
256+
} else if (curTarget instanceof Map m) {
257+
findLinkEntryIn(m, name, type);
219258
}
220259
this.entity = entity;
221260
}
222261

223-
private void findLinkEntryInMap(Map<String, Object> map, String name, EntityType type) {
262+
private void findLinkEntryIn(ObjectNode on, String name, EntityType type) {
263+
fullKeyEntity = name + "." + type.entityName;
264+
String keyId = fullKeyEntity + AT_IOT_ID;
265+
JsonNode keyValue = on.get(keyId);
266+
if (keyValue == null) {
267+
LOGGER.trace("Not found in map: {}", name);
268+
} else {
269+
containingMap = null;
270+
containingNode = on;
271+
targetId = valueNodeToObject(keyValue);
272+
}
273+
}
274+
275+
private void findLinkEntryIn(Map<String, Object> map, String name, EntityType type) {
224276
fullKeyEntity = name + "." + type.entityName;
225277
String keyId = fullKeyEntity + AT_IOT_ID;
226278
Object keyValue = map.get(keyId);
227279
if (keyValue == null) {
228280
LOGGER.trace("Not found in map: {}", name);
229281
} else {
230282
containingMap = map;
283+
containingNode = null;
231284
targetId = keyValue;
232285
}
233286
}
287+
288+
private Object valueNodeToObject(JsonNode value) {
289+
if (value.isIntegralNumber()) {
290+
return value.asLong();
291+
}
292+
if (value.isString()) {
293+
return value.asString();
294+
}
295+
return null;
296+
}
234297
}
235298

236299
@Override

FROST-Server.Core.Model/src/main/java/de/fraunhofer/iosb/ilt/frostserver/property/type/ParserUtils.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import tools.jackson.core.JsonGenerator;
2626
import tools.jackson.core.JsonParser;
2727
import tools.jackson.core.JsonToken;
28+
import tools.jackson.core.TreeNode;
2829
import tools.jackson.core.type.TypeReference;
2930
import tools.jackson.databind.DeserializationContext;
3031
import tools.jackson.databind.SerializationContext;
@@ -37,6 +38,9 @@
3738
*/
3839
public class ParserUtils {
3940

41+
private static TreeNodeSerializer treeNodeSerializer;
42+
private static TreeNodeDeserializer treeNodeDeserializer;
43+
4044
private ParserUtils() {
4145
// Utility class
4246
}
@@ -69,6 +73,36 @@ public Object deserialize(JsonParser jp, DeserializationContext dc) throws Jacks
6973
};
7074
}
7175

76+
public static TreeNodeSerializer getTreeNodeSerializer() {
77+
if (treeNodeSerializer == null) {
78+
treeNodeSerializer = new TreeNodeSerializer();
79+
}
80+
return treeNodeSerializer;
81+
}
82+
83+
public static TreeNodeDeserializer getTreeNodeDeserializer() {
84+
if (treeNodeDeserializer == null) {
85+
treeNodeDeserializer = new TreeNodeDeserializer();
86+
}
87+
return treeNodeDeserializer;
88+
}
89+
90+
public static class TreeNodeSerializer extends ValueSerializer<TreeNode> {
91+
92+
@Override
93+
public void serialize(TreeNode value, JsonGenerator jg, SerializationContext sc) throws JacksonException {
94+
jg.writeTree(value);
95+
}
96+
}
97+
98+
public static class TreeNodeDeserializer extends ValueDeserializer<TreeNode> {
99+
100+
@Override
101+
public TreeNode deserialize(JsonParser jp, DeserializationContext dc) throws JacksonException {
102+
return jp.readValueAsTree();
103+
}
104+
}
105+
72106
/**
73107
* @param type the type of the complex type.
74108
* @return The deserialiser.

0 commit comments

Comments
 (0)