Skip to content

Commit

Permalink
Add CoreLink datatype support.
Browse files Browse the repository at this point in the history
Signed-off-by: Julien Vermillard <jvermillard@sierrawireless.com>
Also-by: Simon Bernard <sbernard@sierrawireless.com>
  • Loading branch information
jvermillard authored and sbernard31 committed Jun 3, 2022
1 parent 491a51c commit d5e5a7d
Show file tree
Hide file tree
Showing 19 changed files with 405 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@

import org.eclipse.leshan.client.resource.SimpleInstanceEnabler;
import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.link.attributes.Attribute;
import org.eclipse.leshan.core.link.attributes.QuotedStringAttribute;
import org.eclipse.leshan.core.link.attributes.ResourceTypeAttribute;
import org.eclipse.leshan.core.link.attributes.UnquotedStringAttribute;
import org.eclipse.leshan.core.link.lwm2m.LwM2mLink;
import org.eclipse.leshan.core.link.lwm2m.MixedLwM2mLink;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mResourceInstance;
Expand Down Expand Up @@ -57,6 +64,7 @@ public class LwM2mTestObject extends SimpleInstanceEnabler {
public static final byte[] INITIAL_OPAQUE_VALUE = Hex.decodeHex("0123456789ABCDEF".toCharArray());
public static final Date INITIAL_TIME_VALUE = new Date(946684800000l);
public static final ObjectLink INITIAL_OBJLINK_VALUE = new ObjectLink(3, 0);
public static final Link[] INITIAL_CORELINK_VALUE = new Link[] { new LwM2mLink(null, new LwM2mPath(3442)) };

private Random random = new Random(System.currentTimeMillis());

Expand All @@ -76,6 +84,7 @@ public LwM2mTestObject() {
initialValues.put(150, INITIAL_OPAQUE_VALUE);
initialValues.put(160, INITIAL_TIME_VALUE);
initialValues.put(170, INITIAL_OBJLINK_VALUE);
initialValues.put(180, INITIAL_CORELINK_VALUE);

// multi
initialValues.put(1110, LwM2mResourceInstance.newStringInstance(0, INITIAL_STRING_VALUE));
Expand All @@ -86,6 +95,7 @@ public LwM2mTestObject() {
initialValues.put(1150, LwM2mResourceInstance.newBinaryInstance(0, INITIAL_OPAQUE_VALUE));
initialValues.put(1160, LwM2mResourceInstance.newDateInstance(0, INITIAL_TIME_VALUE));
initialValues.put(1170, LwM2mResourceInstance.newObjectLinkInstance(0, INITIAL_OBJLINK_VALUE));
initialValues.put(1180, LwM2mResourceInstance.newCoreLinkInstance(0, INITIAL_CORELINK_VALUE));
}

private void clearValues() {
Expand All @@ -103,6 +113,7 @@ private void clearValues() {
clearedValues.put(150, new byte[0]);
clearedValues.put(160, new Date(0l));
clearedValues.put(170, new ObjectLink());
clearedValues.put(180, new Link[0]);

// multi
clearedValues.put(1110, Collections.EMPTY_MAP);
Expand All @@ -113,6 +124,7 @@ private void clearValues() {
clearedValues.put(1150, Collections.EMPTY_MAP);
clearedValues.put(1160, Collections.EMPTY_MAP);
clearedValues.put(1170, Collections.EMPTY_MAP);
clearedValues.put(1180, Collections.EMPTY_MAP);

fireResourcesChange(applyValues(clearedValues));
}
Expand All @@ -135,6 +147,7 @@ private void randomValues() {
randomValues.put(150, new BytesGenerator().generate());
randomValues.put(160, new DateGenerator().generate());
randomValues.put(170, new ObjectLinkGenerator().generate());
randomValues.put(180, new CoreLinkGenerator().generate());

// multi
randomValues.put(1110, generateResourceInstances(new StringGenerator()));
Expand All @@ -145,6 +158,7 @@ private void randomValues() {
randomValues.put(1150, generateResourceInstances(new BytesGenerator()));
randomValues.put(1160, generateResourceInstances(new DateGenerator()));
randomValues.put(1170, generateResourceInstances(new ObjectLinkGenerator()));
randomValues.put(1180, generateResourceInstances(new CoreLinkGenerator()));

fireResourcesChange(applyValues(randomValues));
}
Expand Down Expand Up @@ -323,4 +337,67 @@ public ObjectLink generate() {
return new ObjectLink(random.nextInt(ObjectLink.MAXID - 1), random.nextInt(ObjectLink.MAXID - 1));
}
}

class CoreLinkGenerator implements ValueGenerator<Link[]> {

private LwM2mPath generatePath() {
int dice4Value = random.nextInt(4);
switch (dice4Value) {
case 0:
return new LwM2mPath(random.nextInt(ObjectLink.MAXID - 1));
case 1:
return new LwM2mPath(random.nextInt(ObjectLink.MAXID - 1), random.nextInt(ObjectLink.MAXID - 1));
case 2:
return new LwM2mPath(random.nextInt(ObjectLink.MAXID - 1), random.nextInt(ObjectLink.MAXID - 1),
random.nextInt(ObjectLink.MAXID - 1));
case 3:
return new LwM2mPath(random.nextInt(ObjectLink.MAXID - 1), random.nextInt(ObjectLink.MAXID - 1),
random.nextInt(ObjectLink.MAXID - 1), random.nextInt(ObjectLink.MAXID - 1));
}
return null; // should not happened
}

private Attribute[] generateAttributes() {
int nbAttributes = random.nextInt(3);
Map<String, Attribute> attributes = new HashMap<>(nbAttributes);
for (int i = 0; i < nbAttributes; i++) {
int dice2value = random.nextInt(2);
Attribute attr = null;
switch (dice2value) {
case 0:
attr = new QuotedStringAttribute(RandomStringUtils.randomAlphabetic(random.nextInt(5) + 1),
RandomStringUtils.randomAlphanumeric(random.nextInt(5) + 1));
break;
case 1:
attr = new UnquotedStringAttribute(RandomStringUtils.randomAlphabetic(random.nextInt(5) + 1),
RandomStringUtils.randomAlphanumeric(random.nextInt(5) + 1));
break;
}
attributes.put(attr.getName(), attr);
}
return attributes.values().toArray(new Attribute[attributes.size()]);
}

@Override
public Link[] generate() {
// define if root path is used or not
String rootpath = random.nextInt(4) == 0 ? "/" + RandomStringUtils.randomAlphanumeric(random.nextInt(4) + 1)
: null;

// define number of link
int nbLink = random.nextInt(10);
// create links
Link[] links = new Link[nbLink];
for (int i = 0; i < links.length; i++) {
// when there is a rootpath first link has oma attribute
if (rootpath != null && i == 0) {
links[i] = new MixedLwM2mLink(rootpath, LwM2mPath.ROOTPATH, new ResourceTypeAttribute("oma.lwm2m"));
} else {
// generate random link with random path and attributes
links[i] = new MixedLwM2mLink(rootpath, generatePath(), generateAttributes());
}
}
return links;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.NoSuchElementException;
import java.util.TreeMap;

import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.model.ResourceModel.Type;
import org.eclipse.leshan.core.util.Validate;
import org.eclipse.leshan.core.util.datatype.ULong;
Expand Down Expand Up @@ -103,6 +104,9 @@ public static LwM2mMultipleResource newResource(int id, Map<Integer, ?> values,
case OBJLNK:
LwM2mNodeUtil.allElementsOfType(values.values(), ObjectLink.class);
break;
case CORELINK:
LwM2mNodeUtil.allElementsOfType(values.values(), (new Link[] {}).getClass());
break;
case UNSIGNED_INTEGER:
LwM2mNodeUtil.allElementsOfType(values.values(), ULong.class);
break;
Expand Down Expand Up @@ -142,6 +146,11 @@ public static LwM2mMultipleResource newObjectLinkResource(int id, Map<Integer, O
return new LwM2mMultipleResource(id, values, Type.OBJLNK);
}

public static LwM2mMultipleResource newCoreLinkResource(int id, Map<Integer, Link[]> values) {
LwM2mNodeUtil.noNullElements(values.values());
return new LwM2mMultipleResource(id, values, Type.CORELINK);
}

public static LwM2mMultipleResource newBinaryResource(int id, Map<Integer, byte[]> values) {
LwM2mNodeUtil.noNullElements(values.values());
return new LwM2mMultipleResource(id, values, Type.OPAQUE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Arrays;
import java.util.Date;

import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.model.ResourceModel.Type;
import org.eclipse.leshan.core.util.datatype.ULong;

Expand Down Expand Up @@ -63,6 +64,9 @@ public static LwM2mResourceInstance newInstance(int id, Object value) {
if (value instanceof ObjectLink) {
return new LwM2mResourceInstance(id, value, Type.OBJLNK);
}
if (value instanceof Link[]) {
return new LwM2mResourceInstance(id, value, Type.CORELINK);
}
if (value instanceof ULong) {
return new LwM2mResourceInstance(id, value, Type.UNSIGNED_INTEGER);
}
Expand Down Expand Up @@ -101,6 +105,10 @@ public static LwM2mResourceInstance newInstance(int id, Object value, Type type)
if (!(value instanceof ObjectLink))
throw new LwM2mNodeException(doesNotMatchMessage);
break;
case CORELINK:
if (!(value instanceof Link[]))
throw new LwM2mNodeException(doesNotMatchMessage);
break;
case UNSIGNED_INTEGER:
if (!(value instanceof ULong))
throw new LwM2mNodeException(doesNotMatchMessage);
Expand All @@ -123,6 +131,10 @@ public static LwM2mResourceInstance newObjectLinkInstance(int id, ObjectLink obj
return new LwM2mResourceInstance(id, objlink, Type.OBJLNK);
}

public static LwM2mResourceInstance newCoreLinkInstance(int id, Link[] coreLink) {
return new LwM2mResourceInstance(id, coreLink, Type.CORELINK);
}

public static LwM2mResourceInstance newBooleanInstance(int id, boolean value) {
return new LwM2mResourceInstance(id, value, Type.BOOLEAN);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Map;
import java.util.NoSuchElementException;

import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.model.ResourceModel.Type;
import org.eclipse.leshan.core.util.datatype.ULong;

Expand Down Expand Up @@ -67,6 +68,9 @@ public static LwM2mSingleResource newResource(int id, Object value) {
if (value instanceof ObjectLink) {
return new LwM2mSingleResource(id, value, Type.OBJLNK);
}
if (value instanceof Link[]) {
return new LwM2mSingleResource(id, value, Type.CORELINK);
}
if (value instanceof ULong) {
return new LwM2mSingleResource(id, value, Type.UNSIGNED_INTEGER);
}
Expand Down Expand Up @@ -116,6 +120,11 @@ public static LwM2mSingleResource newResource(int id, Object value, Type type) {
throw new LwM2mNodeException(
String.format(doesNotMatchMessage, value.getClass().getSimpleName(), type));
break;
case CORELINK:
if (!(value instanceof Link[]))
throw new LwM2mNodeException(
String.format(doesNotMatchMessage, value.getClass().getSimpleName(), type));
break;
case UNSIGNED_INTEGER:
if (!(value instanceof ULong)) {
throw new LwM2mNodeException(
Expand All @@ -140,6 +149,10 @@ public static LwM2mSingleResource newObjectLinkResource(int id, ObjectLink objli
return new LwM2mSingleResource(id, objlink, Type.OBJLNK);
}

public static LwM2mSingleResource newCoreLinkResource(int id, Link[] coreLinks) {
return new LwM2mSingleResource(id, coreLinks, Type.CORELINK);
}

public static LwM2mSingleResource newBooleanResource(int id, boolean value) {
return new LwM2mSingleResource(id, value, Type.BOOLEAN);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

import java.util.Date;

import org.eclipse.leshan.core.link.LinkParseException;
import org.eclipse.leshan.core.link.LinkParser;
import org.eclipse.leshan.core.link.lwm2m.DefaultLwM2mLinkParser;
import org.eclipse.leshan.core.model.LwM2mModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.model.ResourceModel.Type;
Expand All @@ -39,6 +42,22 @@
public class LwM2mNodeCborDecoder implements NodeDecoder {
private static final Logger LOG = LoggerFactory.getLogger(LwM2mNodeCborDecoder.class);

// parser used for core link data type
private final LinkParser linkParser;

public LwM2mNodeCborDecoder() {
this(new DefaultLwM2mLinkParser());
}

/**
* Create a new LwM2mNodeCborDecoder with a custom {@link LinkParser}.
*
* @param linkParser the link parser for core link format resources.
*/
public LwM2mNodeCborDecoder(LinkParser linkParser) {
this.linkParser = linkParser;
}

@Override
@SuppressWarnings("unchecked")
public <T extends LwM2mNode> T decode(byte[] content, LwM2mPath path, LwM2mModel model, Class<T> nodeClass)
Expand Down Expand Up @@ -155,6 +174,10 @@ private Object parseCborValue(CBORObject cborObject, Type type, LwM2mPath path)
if (cborObject.getType() == CBORType.TextString) {
return ObjectLink.decodeFromString(cborObject.AsString());
}
case CORELINK:
if (cborObject.getType() == CBORType.TextString) {
return linkParser.parseCoreLinkFormat(cborObject.AsString().getBytes());
}
case OPAQUE:
if (cborObject.getType() == CBORType.ByteString) {
return cborObject.GetByteString();
Expand All @@ -163,7 +186,7 @@ private Object parseCborValue(CBORObject cborObject, Type type, LwM2mPath path)
default:
throw new CodecException("Unsupported type %s for resource %s", type, path);
}
} catch (IllegalStateException | ArithmeticException | NumberFormatException e) {
} catch (IllegalStateException | ArithmeticException | NumberFormatException | LinkParseException e) {
throw new CodecException(e, "Unable to convert CBOR value %s of type %s in type %s for resource %s",
cborObject.toString(), cborObject.getType(), type, path);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

import java.util.Date;

import org.eclipse.leshan.core.link.DefaultLinkSerializer;
import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.link.LinkSerializer;
import org.eclipse.leshan.core.model.LwM2mModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.model.ResourceModel.Type;
Expand All @@ -43,6 +46,16 @@ public class LwM2mNodeCborEncoder implements NodeEncoder {

private static final Logger LOG = LoggerFactory.getLogger(LwM2mNodeCborEncoder.class);

private final LinkSerializer linkSerializer;

public LwM2mNodeCborEncoder() {
this(new DefaultLinkSerializer());
}

public LwM2mNodeCborEncoder(LinkSerializer linkSerializer) {
this.linkSerializer = linkSerializer;
}

@Override
public byte[] encode(LwM2mNode node, LwM2mPath path, LwM2mModel model, LwM2mValueConverter converter)
throws CodecException {
Expand All @@ -58,7 +71,7 @@ public byte[] encode(LwM2mNode node, LwM2mPath path, LwM2mModel model, LwM2mValu
return internalEncoder.encoded;
}

private static class InternalEncoder implements LwM2mNodeVisitor {
private class InternalEncoder implements LwM2mNodeVisitor {
// visitor inputs
private LwM2mPath path;
private LwM2mModel model;
Expand Down Expand Up @@ -153,6 +166,10 @@ private CBORObject getCborValue(Type expectedType, Object val) {
ObjectLink objlnk = (ObjectLink) val;
cbor = CBORObject.FromObject(objlnk.encodeToString());
break;
case CORELINK:
Link[] links = (Link[]) val;
cbor = CBORObject.FromObject(linkSerializer.serializeCoreLinkFormat(links));
break;
case OPAQUE:
cbor = CBORObject.FromObject((byte[]) val);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import org.eclipse.leshan.core.json.LwM2mJsonDecoder;
import org.eclipse.leshan.core.json.LwM2mJsonException;
import org.eclipse.leshan.core.json.jackson.LwM2mJsonJacksonEncoderDecoder;
import org.eclipse.leshan.core.link.LinkParser;
import org.eclipse.leshan.core.link.lwm2m.DefaultLwM2mLinkParser;
import org.eclipse.leshan.core.model.LwM2mModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.model.ResourceModel.Type;
Expand Down Expand Up @@ -60,13 +62,15 @@ public class LwM2mNodeJsonDecoder implements TimestampedNodeDecoder {
private static final Logger LOG = LoggerFactory.getLogger(LwM2mNodeJsonDecoder.class);

private final LwM2mJsonDecoder decoder;
private final LinkParser linkParser;

public LwM2mNodeJsonDecoder() {
this.decoder = new LwM2mJsonJacksonEncoderDecoder();
this(new LwM2mJsonJacksonEncoderDecoder(), new DefaultLwM2mLinkParser());
}

public LwM2mNodeJsonDecoder(LwM2mJsonDecoder jsonDecoder) {
public LwM2mNodeJsonDecoder(LwM2mJsonDecoder jsonDecoder, LinkParser linkParser) {
this.decoder = jsonDecoder;
this.linkParser = linkParser;
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -455,6 +459,8 @@ private Object parseJsonValue(Object value, Type expectedType, LwM2mPath path) t
return value;
case OBJLNK:
return ObjectLink.decodeFromString((String) value);
case CORELINK:
return linkParser.parseCoreLinkFormat(((String) value).getBytes());
default:
throw new CodecException("Unsupported type %s for path %s", expectedType, path);
}
Expand Down
Loading

0 comments on commit d5e5a7d

Please sign in to comment.