Skip to content

Commit

Permalink
#915: Add support of empty multi instance resource to SenML format
Browse files Browse the repository at this point in the history
  • Loading branch information
sbernard31 committed Oct 19, 2021
1 parent 64c0ba6 commit b6528f3
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -214,15 +214,27 @@ private LwM2mNode parseRecords(Collection<LwM2mResolvedSenMLRecord> records, LwM
if (recordsByInstanceId.size() > 1)
throw new CodecException("Only one instance expected in the payload [path:%s]", path);

// Extract resources
Map<Integer, LwM2mResource> resourcesMap = extractLwM2mResources(
recordsByInstanceId.values().iterator().next(), path, model);
// handle empty multi instance resource ?
if (recordsByInstanceId.size() == 0) {
ResourceModel resourceModel = model.getResourceModel(path.getObjectId(), path.getResourceId());
if (resourceModel == null || !resourceModel.multiple) {
throw new CodecException(
"One resource should be present in the payload [path:%s] for single instance resource",
path);
}

// 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 = new LwM2mMultipleResource(path.getResourceId(), resourceModel.type);
} else {
// Extract resources
Map<Integer, LwM2mResource> resourcesMap = extractLwM2mResources(
recordsByInstanceId.values().iterator().next(), path, model);

node = resourcesMap.values().iterator().next();
// 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 if (nodeClass == LwM2mResourceInstance.class) {
// validate we have resources for only 1 instance
if (recordsByInstanceId.size() > 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ public byte[] toSenML(SenMLPack pack) throws SenMLException {
@Override
public SenMLPack fromSenML(byte[] data) throws SenMLException {
try {
// handle empty payload
if (data.length == 0) {
return new SenMLPack();
}

CBORObject cborObject = CBORObject.DecodeFromBytes(data);
if (cborObject.getType() != CBORType.Array) {
throw new SenMLException("Unable to parse SenML CBOR: Array expected but was %s", cborObject.getType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,18 @@ public byte[] toSenML(SenMLPack pack) throws SenMLException {
@Override
public SenMLPack fromSenML(byte[] jsonString) throws SenMLException {
try {
// handle empty payload
if (jsonString == null || jsonString.length == 0) {
return new SenMLPack();
}

JsonNode node = mapper.readTree(jsonString);
if (!node.isArray()) {
throw new SenMLException("Unable to parse SenML JSON: JsonArray expected but was %s",
node.getNodeType());
}
return new SenMLPack(serDes.deserialize(node.iterator()));

} catch (JsonException | ParseException | IOException e) {
throw new SenMLException("Unable to parse SenML JSON.", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ public void tlv_instance_without_id_tlv() throws CodecException {
// this is "special" case where instance ID is not defined ...
byte[] content = TlvEncoder
.encode(new Tlv[] { new Tlv(TlvType.RESOURCE_VALUE, null, TlvEncoder.encodeInteger(11), 1),
new Tlv(TlvType.RESOURCE_VALUE, null, TlvEncoder.encodeInteger(10), 2) })
new Tlv(TlvType.RESOURCE_VALUE, null, TlvEncoder.encodeInteger(10), 2) })
.array();

LwM2mObject object = (LwM2mObject) decoder.decode(content, ContentFormat.TLV, new LwM2mPath(2), model);
Expand All @@ -381,8 +381,7 @@ public void tlv_instance_without_id_tlv() throws CodecException {
public void tlv_unknown_object__missing_instance_tlv() throws CodecException {

byte[] content = TlvEncoder.encode(new Tlv[] { new Tlv(TlvType.RESOURCE_VALUE, null, "value1".getBytes(), 1),
new Tlv(TlvType.RESOURCE_VALUE, null, "value1".getBytes(), 2) })
.array();
new Tlv(TlvType.RESOURCE_VALUE, null, "value1".getBytes(), 2) }).array();

LwM2mObject obj = (LwM2mObject) decoder.decode(content, ContentFormat.TLV, new LwM2mPath(10234), model);

Expand Down Expand Up @@ -950,6 +949,40 @@ public void senml_json_decode_long() {
assertEquals(9223372036854775800l, resource.getValue());
}

@Test
public void senml_json_empty_multi_resource() {
// see : https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues/494

// empty byte array
LwM2mResource resource = null;
resource = (LwM2mResource) decoder.decode(new byte[0], ContentFormat.SENML_JSON, new LwM2mPath(3, 0, 6), model);
assertNotNull(resource);
assertTrue(resource instanceof LwM2mMultipleResource);
assertEquals(6, resource.getId());
assertTrue(resource.getInstances().isEmpty());

// empty string
resource = null;
StringBuilder b = new StringBuilder();
b.append("");
resource = (LwM2mResource) decoder.decode(b.toString().getBytes(), ContentFormat.SENML_JSON,
new LwM2mPath(3, 0, 6), model);
assertNotNull(resource);
assertTrue(resource instanceof LwM2mMultipleResource);
assertEquals(6, resource.getId());
assertTrue(resource.getInstances().isEmpty());

// empty Array
b = new StringBuilder();
b.append("[]");
resource = (LwM2mResource) decoder.decode(b.toString().getBytes(), ContentFormat.SENML_JSON,
new LwM2mPath(3, 0, 6), model);
assertNotNull(resource);
assertTrue(resource instanceof LwM2mMultipleResource);
assertEquals(6, resource.getId());
assertTrue(resource.getInstances().isEmpty());
}

@Test
public void senml_timestamped_resources() throws CodecException {
// json content for instance 0 of device object
Expand Down Expand Up @@ -1192,4 +1225,26 @@ public void senml_cbor_decode_opaque_resource() {

Assert.assertEquals(expected, oResource);
}

@Test
public void senml_cbor_empty_multi_resource() {
// see : https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues/494

// empty byte array
LwM2mResource resource = null;
resource = (LwM2mResource) decoder.decode(new byte[0], ContentFormat.SENML_CBOR, new LwM2mPath(3, 0, 6), model);
assertNotNull(resource);
assertTrue(resource instanceof LwM2mMultipleResource);
assertEquals(6, resource.getId());
assertTrue(resource.getInstances().isEmpty());

// empty Array
// value : []
byte[] cbor = Hex.decodeHex("80".toCharArray());
resource = (LwM2mResource) decoder.decode(cbor, ContentFormat.SENML_CBOR, new LwM2mPath(3, 0, 6), model);
assertNotNull(resource);
assertTrue(resource instanceof LwM2mMultipleResource);
assertEquals(6, resource.getId());
assertTrue(resource.getInstances().isEmpty());
}
}

0 comments on commit b6528f3

Please sign in to comment.