Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SenML-CBOR encoder in leshan-core with unit tests #682

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
Copy link
Contributor

@sbernard31 sbernard31 Jun 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, in this project we use "delegation" instead of "inheritance" for reuse code in tests.
But that's not a big deal, if we let it like this :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will take care about it.


@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