use of org.eclipse.leshan.json.JsonArrayEntry in project leshan by eclipse.
the class LwM2mNodeJsonDecoder method parseJSON.
private static List<TimestampedLwM2mNode> parseJSON(JsonRootObject jsonObject, LwM2mPath path, LwM2mModel model, Class<? extends LwM2mNode> nodeClass) throws CodecException {
LOG.trace("Parsing JSON content for path {}: {}", path, jsonObject);
// Group JSON entry by time-stamp
Map<Long, Collection<JsonArrayEntry>> jsonEntryByTimestamp = groupJsonEntryByTimestamp(jsonObject);
// Extract baseName
LwM2mPath baseName = extractAndValidateBaseName(jsonObject, path);
if (baseName == null)
// if no base name, use request path as base name
baseName = path;
// fill time-stamped nodes collection
List<TimestampedLwM2mNode> timestampedNodes = new ArrayList<>();
for (Entry<Long, Collection<JsonArrayEntry>> entryByTimestamp : jsonEntryByTimestamp.entrySet()) {
// Group JSON entry by instance
Map<Integer, Collection<JsonArrayEntry>> jsonEntryByInstanceId = groupJsonEntryByInstanceId(entryByTimestamp.getValue(), baseName);
// Create lwm2m node
LwM2mNode node;
if (nodeClass == LwM2mObject.class) {
Collection<LwM2mObjectInstance> instances = new ArrayList<>();
for (Entry<Integer, Collection<JsonArrayEntry>> entryByInstanceId : jsonEntryByInstanceId.entrySet()) {
Map<Integer, LwM2mResource> resourcesMap = extractLwM2mResources(entryByInstanceId.getValue(), baseName, model);
instances.add(new LwM2mObjectInstance(entryByInstanceId.getKey(), resourcesMap.values()));
}
node = new LwM2mObject(baseName.getObjectId(), instances);
} else if (nodeClass == LwM2mObjectInstance.class) {
// validate we have resources for only 1 instance
if (jsonEntryByInstanceId.size() != 1)
throw new CodecException("One instance expected in the payload [path:%s]", path);
// Extract resources
Entry<Integer, Collection<JsonArrayEntry>> instanceEntry = jsonEntryByInstanceId.entrySet().iterator().next();
Map<Integer, LwM2mResource> resourcesMap = extractLwM2mResources(instanceEntry.getValue(), baseName, model);
// Create instance
node = new LwM2mObjectInstance(instanceEntry.getKey(), resourcesMap.values());
} else if (nodeClass == LwM2mResource.class) {
// validate we have resources for only 1 instance
if (jsonEntryByInstanceId.size() > 1)
throw new CodecException("Only one instance expected in the payload [path:%s]", path);
// Extract resources
Map<Integer, LwM2mResource> resourcesMap = extractLwM2mResources(jsonEntryByInstanceId.values().iterator().next(), baseName, model);
// validate there is only 1 resource
if (resourcesMap.size() != 1)
throw new CodecException("One resource should be present in the payload [path:%s]", path);
node = resourcesMap.values().iterator().next();
} else {
throw new IllegalArgumentException("invalid node class: " + nodeClass);
}
// compute time-stamp
Long timestamp = computeTimestamp(jsonObject.getBaseTime(), entryByTimestamp.getKey());
// add time-stamped node
timestampedNodes.add(new TimestampedLwM2mNode(timestamp, node));
}
return timestampedNodes;
}
use of org.eclipse.leshan.json.JsonArrayEntry in project leshan by eclipse.
the class LwM2mNodeJsonDecoder method groupJsonEntryByTimestamp.
/**
* Group all JsonArrayEntry by time-stamp
*
* @return a map (relativeTimestamp => collection of JsonArrayEntry)
*/
private static SortedMap<Long, Collection<JsonArrayEntry>> groupJsonEntryByTimestamp(JsonRootObject jsonObject) {
SortedMap<Long, Collection<JsonArrayEntry>> result = new TreeMap<>(new Comparator<Long>() {
@Override
public int compare(Long o1, Long o2) {
// - reverses natural order (most recent value in first)
return Long.compare(o2 == null ? 0 : o2, o1 == null ? 0 : o1);
}
});
for (JsonArrayEntry e : jsonObject.getResourceList()) {
// Get time for this entry
Long time = e.getTime();
// Get jsonArray for this time-stamp
Collection<JsonArrayEntry> jsonArray = result.get(time);
if (jsonArray == null) {
jsonArray = new ArrayList<>();
result.put(time, jsonArray);
}
// Add it to the list
jsonArray.add(e);
}
// Ensure there is at least one entry for null timestamp
if (result.isEmpty()) {
result.put((Long) null, new ArrayList<JsonArrayEntry>());
}
return result;
}
use of org.eclipse.leshan.json.JsonArrayEntry in project leshan by eclipse.
the class LwM2mNodeJsonDecoder method groupJsonEntryByInstanceId.
/**
* Group all JsonArrayEntry by instanceId
*
* @param jsonEntries
* @param baseName
*
* @return a map (instanceId => collection of JsonArrayEntry)
*/
private static Map<Integer, Collection<JsonArrayEntry>> groupJsonEntryByInstanceId(Collection<JsonArrayEntry> jsonEntries, LwM2mPath baseName) throws CodecException {
Map<Integer, Collection<JsonArrayEntry>> result = new HashMap<>();
for (JsonArrayEntry e : jsonEntries) {
// Build resource path
LwM2mPath nodePath = baseName.append(e.getName());
// Validate path
if (!nodePath.isResourceInstance() && !nodePath.isResource()) {
throw new CodecException("Invalid path [%s] for resource, it should be a resource or a resource instance path", nodePath);
}
// Get jsonArray for this instance
Collection<JsonArrayEntry> jsonArray = result.get(nodePath.getObjectInstanceId());
if (jsonArray == null) {
jsonArray = new ArrayList<>();
result.put(nodePath.getObjectInstanceId(), jsonArray);
}
// Add it to the list
jsonArray.add(e);
}
// Create an entry for an empty instance if possible
if (result.isEmpty() && baseName.getObjectInstanceId() != null) {
result.put(baseName.getObjectInstanceId(), new ArrayList<JsonArrayEntry>());
}
return result;
}
use of org.eclipse.leshan.json.JsonArrayEntry in project leshan by eclipse.
the class LwM2mNodeJsonEncoder method encodeTimestampedData.
public static byte[] encodeTimestampedData(List<TimestampedLwM2mNode> timestampedNodes, LwM2mPath path, LwM2mModel model, LwM2mValueConverter converter) {
Validate.notNull(timestampedNodes);
Validate.notNull(path);
Validate.notNull(model);
InternalEncoder internalEncoder = new InternalEncoder();
ArrayList<JsonArrayEntry> entries = new ArrayList<>();
for (TimestampedLwM2mNode timestampedLwM2mNode : timestampedNodes) {
internalEncoder.objectId = path.getObjectId();
internalEncoder.model = model;
internalEncoder.requestPath = path;
internalEncoder.converter = converter;
internalEncoder.resourceList = null;
internalEncoder.timestamp = timestampedLwM2mNode.getTimestamp();
timestampedLwM2mNode.getNode().accept(internalEncoder);
entries.addAll(internalEncoder.resourceList);
}
JsonRootObject jsonObject = new JsonRootObject();
jsonObject.setResourceList(entries);
jsonObject.setBaseName(path.toString());
return LwM2mJson.toJsonLwM2m(jsonObject).getBytes();
}
use of org.eclipse.leshan.json.JsonArrayEntry in project leshan by eclipse.
the class LwM2mNodeJsonDecoder method extractLwM2mResources.
private static Map<Integer, LwM2mResource> extractLwM2mResources(Collection<JsonArrayEntry> jsonArrayEntries, LwM2mPath baseName, LwM2mModel model) throws CodecException {
if (jsonArrayEntries == null)
return Collections.emptyMap();
// Extract LWM2M resources from JSON resource list
Map<Integer, LwM2mResource> lwM2mResourceMap = new HashMap<>();
Map<LwM2mPath, Map<Integer, JsonArrayEntry>> multiResourceMap = new HashMap<>();
for (JsonArrayEntry resourceElt : jsonArrayEntries) {
// Build resource path
LwM2mPath nodePath = baseName.append(resourceElt.getName());
// handle LWM2M resources
if (nodePath.isResourceInstance()) {
// Multi-instance resource
// Store multi-instance resource values in a map
// we will deal with it later
LwM2mPath resourcePath = new LwM2mPath(nodePath.getObjectId(), nodePath.getObjectInstanceId(), nodePath.getResourceId());
Map<Integer, JsonArrayEntry> multiResource = multiResourceMap.get(resourcePath);
if (multiResource == null) {
multiResource = new HashMap<>();
multiResourceMap.put(resourcePath, multiResource);
}
multiResource.put(nodePath.getResourceInstanceId(), resourceElt);
} else if (nodePath.isResource()) {
// Single resource
Type expectedType = getResourceType(nodePath, model, resourceElt);
LwM2mResource res = LwM2mSingleResource.newResource(nodePath.getResourceId(), parseJsonValue(resourceElt.getResourceValue(), expectedType, nodePath), expectedType);
lwM2mResourceMap.put(nodePath.getResourceId(), res);
} else {
throw new CodecException("Invalid path [%s] for resource, it should be a resource or a resource instance path", nodePath);
}
}
// Handle multi-instance resource.
for (Map.Entry<LwM2mPath, Map<Integer, JsonArrayEntry>> entry : multiResourceMap.entrySet()) {
LwM2mPath resourcePath = entry.getKey();
Map<Integer, JsonArrayEntry> jsonEntries = entry.getValue();
if (jsonEntries != null && !jsonEntries.isEmpty()) {
Type expectedType = getResourceType(resourcePath, model, jsonEntries.values().iterator().next());
Map<Integer, Object> values = new HashMap<>();
for (Entry<Integer, JsonArrayEntry> e : jsonEntries.entrySet()) {
Integer resourceInstanceId = e.getKey();
values.put(resourceInstanceId, parseJsonValue(e.getValue().getResourceValue(), expectedType, resourcePath));
}
LwM2mResource resource = LwM2mMultipleResource.newResource(resourcePath.getResourceId(), values, expectedType);
lwM2mResourceMap.put(resourcePath.getResourceId(), resource);
}
}
// If we found nothing, we try to create an empty multi-instance resource
if (lwM2mResourceMap.isEmpty() && baseName.isResource()) {
ResourceModel resourceModel = model.getResourceModel(baseName.getObjectId(), baseName.getResourceId());
// We create it only if this respect the model
if (resourceModel == null || resourceModel.multiple) {
Type resourceType = getResourceType(baseName, model, null);
lwM2mResourceMap.put(baseName.getResourceId(), LwM2mMultipleResource.newResource(baseName.getResourceId(), new HashMap<Integer, Object>(), resourceType));
}
}
return lwM2mResourceMap;
}
Aggregations