Skip to content

Commit

Permalink
Adapt MultiNodeDecoder to support WriteComposite.
Browse files Browse the repository at this point in the history
  • Loading branch information
sbernard31 committed Mar 5, 2021
1 parent 3a184ab commit 6285f0d
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ public <T extends LwM2mNode> T decode(byte[] content, ContentFormat format, LwM2
public Map<LwM2mPath, LwM2mNode> decodeNodes(byte[] content, ContentFormat format, List<LwM2mPath> paths,
LwM2mModel model) throws CodecException {
LOG.debug("Decoding value for path {} and format {}: {}", paths, format, content);
Validate.notNull(paths);
if (paths != null)
Validate.notEmpty(paths);

if (format == null) {
throw new CodecException("Content format is mandatory. [%s]", paths);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.eclipse.leshan.core.model.LwM2mModel;
import org.eclipse.leshan.core.node.LwM2mNode;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResourceInstance;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.TimestampedLwM2mNode;
import org.eclipse.leshan.core.request.ContentFormat;

Expand Down Expand Up @@ -69,7 +71,9 @@ <T extends LwM2mNode> T decode(byte[] content, ContentFormat format, LwM2mPath p
*
* @param content the content
* @param format the content format
* @param paths the list of path of node to build.
* @param paths the list of path of node to build. The list of path can be <code>null</code> meaning that we don't
* know which kind of {@link LwM2mNode} is encoded. In this case, let's assume this is a list of
* {@link LwM2mSingleResource} or {@link LwM2mResourceInstance}.
* @param model the collection of supported object models
* @return the Map of {@link LwM2mPath} to decoded {@link LwM2mNode}. value can be <code>null</code> if no data was
* available for a given path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.eclipse.leshan.core.model.LwM2mModel;
import org.eclipse.leshan.core.node.LwM2mNode;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResourceInstance;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.request.ContentFormat;

/**
Expand All @@ -36,7 +38,9 @@ public interface MultiNodeDecoder {
* Expected type is guess from list of {@link LwM2mPath}.
*
* @param content the content
* @param paths the list of path of node to build.
* @param paths the list of path of node to build. The list of path can be <code>null</code> meaning that we don't
* know which kind of {@link LwM2mNode} is encoded. In this case, let's assume this is a list of
* {@link LwM2mSingleResource} or {@link LwM2mResourceInstance}.
* @param model the collection of supported object models
* @return the Map of {@link LwM2mPath} to decoded {@link LwM2mNode}. value can be <code>null</code> if no data was
* available for a given path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package org.eclipse.leshan.core.node.codec.senml;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
Expand Down Expand Up @@ -107,28 +108,43 @@ public Map<LwM2mPath, LwM2mNode> decodeNodes(byte[] content, List<LwM2mPath> pat
// Decode SenML pack
SenMLPack pack = decoder.fromSenML(content);

// Resolve records & Group it by time-stamp
Map<LwM2mPath, Collection<LwM2mResolvedSenMLRecord>> recordsByPath = groupByPath(pack.getRecords(), paths);

// Fill nodes collections
Map<LwM2mPath, LwM2mNode> nodes = new HashMap<>();
for (LwM2mPath path : paths) {
Collection<LwM2mResolvedSenMLRecord> records = recordsByPath.get(path);
if (records.isEmpty()) {
// Node can be null as the LWM2M specification says that "Read-Composite operation is
// treated as non-atomic and handled as best effort by the client. That is, if any of the
// requested
// resources do not have a valid value to return, they will not be included in the response".
// Meaning that a given path could have no corresponding value.
nodes.put(path, null);
} else {
LwM2mNode node = parseRecords(recordsByPath.get(path), path, model,
if (paths != null) {
// Resolve records & Group it by time-stamp
Map<LwM2mPath, Collection<LwM2mResolvedSenMLRecord>> recordsByPath = groupByPath(pack.getRecords(),
paths);

for (LwM2mPath path : paths) {
Collection<LwM2mResolvedSenMLRecord> records = recordsByPath.get(path);
if (records.isEmpty()) {
// Node can be null as the LWM2M specification says that "Read-Composite operation is
// treated as non-atomic and handled as best effort by the client. That is, if any of the
// requested
// resources do not have a valid value to return, they will not be included in the response".
// Meaning that a given path could have no corresponding value.
nodes.put(path, null);
} else {
LwM2mNode node = parseRecords(recordsByPath.get(path), path, model,
DefaultLwM2mNodeDecoder.nodeClassFromPath(path));
nodes.put(path, node);
}
}
} else {
// Paths are not given so we given so we can not regroup by path
// let's assume that each path refer to a single resource or single resource instances.
LwM2mSenMLResolver resolver = new LwM2mSenMLResolver();
for (SenMLRecord record : pack.getRecords()) {
LwM2mResolvedSenMLRecord resolvedRecord = resolver.resolve(record);
LwM2mPath path = resolvedRecord.getPath();
LwM2mNode node = parseRecords(Arrays.asList(resolvedRecord), path, model,
DefaultLwM2mNodeDecoder.nodeClassFromPath(path));
nodes.put(path, node);
}
}
return nodes;
} catch (SenMLException e) {
} catch (

SenMLException e) {
String jsonStrValue = content != null ? new String(content) : "";
throw new CodecException(e, "Unable to decode nodes[path:%s] : %s", paths, jsonStrValue, e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,33 @@ public void senml_json_decode_mixed_resource_and_instance() {
Assert.assertEquals(nodes, res);
}

@Test
public void senml_json_decode_mixed_resource_without_given_path() {
// Prepare data to decode
StringBuilder b = new StringBuilder();
b.append("[{\"bn\":\"/4/0/0\",\"v\":45},");
b.append("{\"bn\":\"/4/0/1\",\"v\":30},");
b.append("{\"bn\":\"/4/0/2\",\"v\":100},");
b.append("{\"bn\":\"/6/0/\",\"n\":\"0\",\"v\":43.918998},");
b.append("{\"n\":\"1\",\"v\":2.351149},");
b.append("{\"n\":\"5\",\"v\":1610029880}]");

// Decode
Map<LwM2mPath, LwM2mNode> res = decoder.decodeNodes(b.toString().getBytes(), ContentFormat.SENML_JSON, null,
model);

// Expected result
Map<LwM2mPath, LwM2mNode> nodes = new HashMap<>();
nodes.put(new LwM2mPath("4/0/0"), LwM2mSingleResource.newIntegerResource(0, 45));
nodes.put(new LwM2mPath("4/0/1"), LwM2mSingleResource.newIntegerResource(1, 30));
nodes.put(new LwM2mPath("4/0/2"), LwM2mSingleResource.newIntegerResource(2, 100));
nodes.put(new LwM2mPath("6/0/0"), LwM2mSingleResource.newFloatResource(0, 43.918998));
nodes.put(new LwM2mPath("6/0/1"), LwM2mSingleResource.newFloatResource(1, 2.351149));
nodes.put(new LwM2mPath("6/0/5"), LwM2mSingleResource.newDateResource(5, new Date(1610029880000l)));

Assert.assertEquals(nodes, res);
}

@Test
public void senml_json_decode_path_using_name() {
// Prepare data to decode
Expand Down

0 comments on commit 6285f0d

Please sign in to comment.