Skip to content

Commit

Permalink
eclipse-leshan#682: Add SenML-CBOR encoder in leshan-core + unit tests.
Browse files Browse the repository at this point in the history
Signed-off-by: Boya Zhang <zhangboya@gmail.com>
  • Loading branch information
cavenaghi9 committed Jun 26, 2019
1 parent 4feb9bb commit 85eeb21
Show file tree
Hide file tree
Showing 14 changed files with 374 additions and 185 deletions.
4 changes: 4 additions & 0 deletions leshan-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ Contributors:
<groupId>com.eclipsesource.minimal-json</groupId>
<artifactId>minimal-json</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-cbor</artifactId>
</dependency>

<!-- test dependencies -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static byte[] encode(LwM2mNode node, LwM2mPath path, LwM2mModel model, Lw

SenMLPack pack = new SenMLPack();
pack.setRecords(internalEncoder.records);
return SenMLJson.toJsonSenML(pack).getBytes();
return SenMLJson.toSenMLJson(pack).getBytes();
}

private static class InternalEncoder implements LwM2mNodeVisitor {
Expand Down
26 changes: 26 additions & 0 deletions leshan-core/src/main/java/org/eclipse/leshan/senml/SenMLCbor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*******************************************************************************
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Boya Zhang - initial API and implementation
*******************************************************************************/

package org.eclipse.leshan.senml;

/**
* Helper for encoding/decoding SenML CBOR format
*/
public class SenMLCbor {
private static final SenMLCborPackSerDes serDes = new SenMLCborPackSerDes();

public static byte[] toSenMLCbor(SenMLPack pack) throws SenMLCborException {
return serDes.serializeToCbor(pack);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*******************************************************************************
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Boya Zhang - initial API and implementation
*******************************************************************************/

package org.eclipse.leshan.senml;

/**
* Exception thrown in case of Cbor encoding error
*/
public class SenMLCborException extends Exception {

private static final long serialVersionUID = 1L;

public SenMLCborException(String message) {
super(message);
}

public SenMLCborException(String message, Exception cause) {
super(message, cause);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*******************************************************************************
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Boya Zhang - initial API and implementation
*******************************************************************************/

package org.eclipse.leshan.senml;

import java.io.ByteArrayOutputStream;

import org.eclipse.leshan.core.model.ResourceModel.Type;

import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
import com.fasterxml.jackson.dataformat.cbor.CBORGenerator;

public class SenMLCborPackSerDes {

public byte[] serializeToCbor(SenMLPack pack) throws SenMLCborException {
CBORFactory factory = new CBORFactory();
ByteArrayOutputStream out = new ByteArrayOutputStream();

try {
CBORGenerator generator = factory.createGenerator(out);
generator.writeStartArray(pack.getRecords().size());

for (SenMLRecord record : pack.getRecords()) {
boolean hasBaseName = false;
boolean hasBaseTime = false;
boolean hasName = false;
boolean hasTime = false;
int objectSize = 1;

if (record.getBaseName() != null && !record.getBaseName().isEmpty()) {
hasBaseName = true;
objectSize++;
}

if (record.getBaseTime() != null) {
hasBaseTime = true;
objectSize++;
}

if (record.getName() != null && !record.getName().isEmpty()) {
hasName = true;
objectSize++;
}

if (record.getTime() != null) {
hasTime = true;
objectSize++;
}

generator.writeStartObject(objectSize);

if (hasBaseName) {
generator.writeFieldId(-2);
generator.writeString(record.getBaseName());
}

if (hasBaseTime) {
generator.writeFieldId(-3);
generator.writeNumber(record.getBaseTime());
}

if (hasName) {
generator.writeFieldId(0);
generator.writeString(record.getName());
}

if (hasTime) {
generator.writeFieldId(6);
generator.writeNumber(record.getTime());
}

Type type = record.getType();
if (type != null) {
switch (record.getType()) {
case FLOAT:
generator.writeFieldId(2);
generator.writeNumber(record.getFloatValue().intValue());
break;
case BOOLEAN:
generator.writeFieldId(4);
generator.writeBoolean(record.getBooleanValue());
break;
case OBJLNK:
generator.writeStringField("vlo", record.getObjectLinkValue());
break;
case OPAQUE:
generator.writeFieldId(8);
generator.writeBinary(record.getOpaqueValue());
case STRING:
generator.writeFieldId(3);
generator.writeString(record.getStringValue());
break;
default:
break;
}
}
generator.writeEndObject();
}

generator.writeEndArray();
generator.close();
} catch (Exception ex) {
throw new SenMLCborException("Impossible to encode pack to CBOR: \n" + pack, ex);
}

return out.toByteArray();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
* Helper for encoding/decoding SenML JSON format
*/
public class SenMLJson {
private static final SenMLPackSerDes serDes = new SenMLPackSerDes();
private static final SenMLJsonPackSerDes serDes = new SenMLJsonPackSerDes();

public static String toJsonSenML(SenMLPack pack) {
return serDes.serialize(pack);
public static String toSenMLJson(SenMLPack pack) {
return serDes.serializeToJson(pack);
}

public static SenMLPack fromJsonSenML(String jsonString) {
return serDes.deserialize(Json.parse(jsonString).asArray());
public static SenMLPack fromSenMLJson(String jsonString) {
return serDes.deserializeFromJson(Json.parse(jsonString).asArray());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;

public class SenMLPackSerDes {
public class SenMLJsonPackSerDes {

public String serialize(SenMLPack pack) {
public String serializeToJson(SenMLPack pack) {
JsonArray jsonArray = new JsonArray();

for (SenMLRecord record : pack.getRecords()) {
Expand Down Expand Up @@ -73,7 +73,7 @@ public String serialize(SenMLPack pack) {
return jsonArray.toString();
}

public SenMLPack deserialize(JsonArray array) {
public SenMLPack deserializeFromJson(JsonArray array) {

if (array == null)
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*******************************************************************************
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Boya Zhang - initial API and implementation
*******************************************************************************/

package org.eclipse.leshan.senml;

public abstract class AbstractSenMLTest {
protected void givenResourceWithFloatValue(SenMLPack pack, String n, Number value) {
SenMLRecord elt = new SenMLRecord();
elt.setName(n);
elt.setFloatValue(value);
pack.addRecord(elt);
}

protected void givenResourceWithStringValue(SenMLPack pack, String n, String value) {
givenResourceWithStringValue(pack, null, n, value);
}

protected void givenResourceWithStringValue(SenMLPack pack, String bn, String n, String value) {
SenMLRecord elt = new SenMLRecord();
if (bn != null) {
elt.setBaseName(bn);
}

elt.setName(n);
elt.setStringValue(value);
pack.addRecord(elt);
}

/**
* Example of JSON payload request to Device Object of the LwM2M example client (Read /3/0)
*
* @return JSON payload
*/
protected String givenSenMLJsonExample() {
StringBuilder b = new StringBuilder();
b.append("[{\"bn\":\"/3/0/\",\"n\":\"0\",\"vs\":\"Open Mobile Alliance\"},");
b.append("{\"n\":\"1\",\"vs\":\"Lightweight M2M Client\"},");
b.append("{\"n\":\"2\",\"vs\":\"345000123\"},");
b.append("{\"n\":\"3\",\"vs\":\"1.0\"},");
b.append("{\"n\":\"6/0\",\"v\":1},{\"n\":\"6/1\",\"v\":5},");
b.append("{\"n\":\"7/0\",\"v\":3800},{\"n\":\"7/1\",\"v\":5000},");
b.append("{\"n\":\"8/0\",\"v\":125},{\"n\":\"8/1\",\"v\":900},");
b.append("{\"n\":\"9\",\"v\":100},");
b.append("{\"n\":\"10\",\"v\":15},");
b.append("{\"n\":\"11/0\",\"v\":0},");
b.append("{\"n\":\"13\",\"v\":1.3674912E9},");
b.append("{\"n\":\"14\",\"vs\":\"+02:00\"},");
b.append("{\"n\":\"16\",\"vs\":\"U\"}]");
return b.toString();
}

protected SenMLPack givenDeviceObjectInstance() {
SenMLPack pack = new SenMLPack();

givenResourceWithStringValue(pack, "/3/0/", "0", "Open Mobile Alliance");
givenResourceWithStringValue(pack, "1", "Lightweight M2M Client");
givenResourceWithStringValue(pack, "2", "345000123");
givenResourceWithStringValue(pack, "3", "1.0");

givenResourceWithFloatValue(pack, "6/0", 1);
givenResourceWithFloatValue(pack, "6/1", 5);
givenResourceWithFloatValue(pack, "7/0", 3800);
givenResourceWithFloatValue(pack, "7/1", 5000);
givenResourceWithFloatValue(pack, "8/0", 125);
givenResourceWithFloatValue(pack, "8/1", 900);

givenResourceWithFloatValue(pack, "9", 100);
givenResourceWithFloatValue(pack, "10", 15);
givenResourceWithFloatValue(pack, "11/0", 0);
givenResourceWithFloatValue(pack, "13", 1367491215l);

givenResourceWithStringValue(pack, "14", "+02:00");
givenResourceWithStringValue(pack, "16", "U");

return pack;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*******************************************************************************
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Boya Zhang - initial API and implementation
*******************************************************************************/

package org.eclipse.leshan.senml;

import org.eclipse.leshan.util.Hex;
import org.junit.Assert;
import org.junit.Test;

public class SenMLCborSerializerTest extends AbstractSenMLTest {

@Test
public void serialize_device_object_to_senml_cbor() throws Exception {
byte[] cbor = SenMLCbor.toSenMLCbor(givenDeviceObjectInstance());

String expectedValue = "90a321652f332f302f00613003744f70656e204d6f62696c6520416c6c69616e6365a200613103764c696768747765696768"
+ "74204d324d20436c69656e74a20061320369333435303030313233a20061330363312e30a20063362f300201a20063362f310205a20063372f"
+ "3002190ed8a20063372f3102191388a20063382f3002187da20063382f3102190384a2006139021864a200623130020fa2006431312f300200"
+ "a200623133021a5182428fa20062313403662b30323a3030a200623136036155";

Assert.assertTrue(expectedValue.equals(Hex.encodeHexString(cbor)));
}
}
Loading

0 comments on commit 85eeb21

Please sign in to comment.