Skip to content

Commit

Permalink
Ensure that LwM2M node is created with valid ID
Browse files Browse the repository at this point in the history
  • Loading branch information
sbernard31 committed Jan 2, 2020
1 parent 6224546 commit 998873d
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ public class LwM2mMultipleResource implements LwM2mResource {
private final Type type;

protected LwM2mMultipleResource(int id, Map<Integer, ?> values, Type type) {
Validate.notNull(values);
LwM2mNodeUtil.validateResourceId(id);

for (Integer instanceId : values.keySet()) {
LwM2mNodeUtil.validateResourceInstanceId(instanceId);
}
this.id = id;
this.values = Collections.unmodifiableMap(new HashMap<>(values));
this.type = type;
Expand Down Expand Up @@ -241,8 +247,8 @@ private boolean internalMapEquals(Map<?, ?> m1, Object o2) {
return false;
} else {
// Custom equals to handle byte arrays
return type == Type.OPAQUE ? Arrays.equals((byte[]) value, (byte[]) m2.get(key)) : value.equals(m2
.get(key));
return type == Type.OPAQUE ? Arrays.equals((byte[]) value, (byte[]) m2.get(key))
: value.equals(m2.get(key));
}
}
} catch (ClassCastException | NullPointerException unused) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*******************************************************************************
* Copyright (c) 2019 Sierra Wireless and others.
*
* 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:
* Sierra Wireless - initial API and implementation
*******************************************************************************/
package org.eclipse.leshan.core.node;

public class LwM2mNodeUtil {

public static boolean isUnsignedInt(Integer id) {
return id != null && 0 <= id && id <= 65535;
}

public static boolean isValidObjectId(Integer id) {
return isUnsignedInt(id);
}

public static void validateObjectId(Integer id) {
if (!isValidObjectId(id)) {
throw new IllegalArgumentException(String.format("Invalid object id %d, It MUST be an unsigned int.", id));
}
}

public static boolean isValidObjectInstanceId(Integer id) {
// MAX_ID 65535 is a reserved value and MUST NOT be used for identifying an Object Instance.
return id != null && 0 <= id && id <= 65534;
}

public static void validateObjectInstanceId(Integer id) {
if (!isValidObjectInstanceId(id)) {
throw new IllegalArgumentException(String
.format("Invalid object instance id %d, It MUST be an unsigned int. (65535 is reserved)", id));
}
}

public static boolean isValidResourceId(Integer id) {
return isUnsignedInt(id);
}

public static void validateResourceId(Integer id) {
if (!isValidResourceId(id)) {
throw new IllegalArgumentException(
String.format("Invalid resource id %d, It MUST be an unsigned int.", id));
}
}

public static boolean isValidResourceInstanceId(Integer id) {
return isUnsignedInt(id);
}

public static void validateResourceInstanceId(Integer id) {
if (!isValidResourceInstanceId(id)) {
throw new IllegalArgumentException(
String.format("Invalid resource instance id %d, It MUST be an unsigned int.", id));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class LwM2mObject implements LwM2mNode {

public LwM2mObject(int id, Collection<LwM2mObjectInstance> instances) {
Validate.notNull(instances);
LwM2mNodeUtil.validateObjectId(id);

this.id = id;
HashMap<Integer, LwM2mObjectInstance> instancesMap = new HashMap<>(instances.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,19 @@ public class LwM2mObjectInstance implements LwM2mNode {

private final Map<Integer, LwM2mResource> resources;

public LwM2mObjectInstance(Collection<LwM2mResource> resources) {
Validate.notNull(resources);
this.id = UNDEFINED;
Map<Integer, LwM2mResource> resourcesMap = new HashMap<>(resources.size());
for (LwM2mResource resource : resources) {
resourcesMap.put(resource.getId(), resource);
}
this.resources = Collections.unmodifiableMap(resourcesMap);
}

public LwM2mObjectInstance(int id, Collection<LwM2mResource> resources) {
Validate.notNull(resources);
LwM2mNodeUtil.validateObjectInstanceId(id);

this.id = id;
Map<Integer, LwM2mResource> resourcesMap = new HashMap<>(resources.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public class LwM2mSingleResource implements LwM2mResource {

protected LwM2mSingleResource(int id, Object value, Type type) {
Validate.notNull(value);
LwM2mNodeUtil.validateResourceId(id);

this.id = id;
this.value = value;
this.type = type;
Expand Down Expand Up @@ -192,8 +194,8 @@ public boolean equals(Object obj) {
return false;
} else {
// Custom equals to handle byte arrays
return type == Type.OPAQUE ? Arrays.equals((byte[]) value, (byte[]) other.value) : value
.equals(other.value);
return type == Type.OPAQUE ? Arrays.equals((byte[]) value, (byte[]) other.value)
: value.equals(other.value);
}
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static <T extends LwM2mNode> T decode(byte[] content, LwM2mPath path, LwM
// return the most recent value
return (T) timestampedNodes.get(0).getNode();
}
} catch (LwM2mJsonException e) {
} catch (LwM2mJsonException | IllegalArgumentException e) {
throw new CodecException(e, "Unable to deserialize json [path:%s]", path);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static <T extends LwM2mNode> T decode(byte[] content, LwM2mPath path, LwM
try {
Tlv[] tlvs = TlvDecoder.decode(ByteBuffer.wrap(content != null ? content : new byte[0]));
return parseTlv(tlvs, path, model, nodeClass);
} catch (TlvException e) {
} catch (TlvException | IllegalArgumentException e) {
throw new CodecException(String.format("Unable to decode tlv for path [%s]", path), e);
}
}
Expand Down Expand Up @@ -177,7 +177,11 @@ private static LwM2mObjectInstance parseObjectInstanceTlv(Tlv[] rscTlvs, int obj
previousResource, resource, resource.getId(), resourcePath);
}
}
return new LwM2mObjectInstance(instanceId, resources.values());
if (instanceId == LwM2mObjectInstance.UNDEFINED) {
return new LwM2mObjectInstance(resources.values());
} else {
return new LwM2mObjectInstance(instanceId, resources.values());
}
}

private static LwM2mResource parseResourceTlv(Tlv tlv, LwM2mPath resourcePath, LwM2mModel model)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public void tlv_encode_device_object_instance_as_resources_array() {

@Test
public void tlv_encode_device_object_instance_as_resources_array__undefined_instance_id() {
LwM2mObjectInstance oInstance = new LwM2mObjectInstance(LwM2mObjectInstance.UNDEFINED, getDeviceResources());
LwM2mObjectInstance oInstance = new LwM2mObjectInstance(getDeviceResources());
byte[] encoded = encoder.encode(oInstance, ContentFormat.TLV, new LwM2mPath("/3"), model);

Assert.assertArrayEquals(ENCODED_DEVICE_WITHOUT_INSTANCE, encoded);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,13 @@ public void visit(CreateRequest request) {
coapRequest = Request.newPost();
coapRequest.getOptions().setContentFormat(request.getContentFormat().getCode());
// if no instance id, the client will assign it.
int instanceId = request.getInstanceId() != null ? request.getInstanceId() : LwM2mObjectInstance.UNDEFINED;
coapRequest.setPayload(encoder.encode(new LwM2mObjectInstance(instanceId, request.getResources()),
request.getContentFormat(), request.getPath(), model));
LwM2mObjectInstance instance;
if (request.getInstanceId() == null) {
instance = new LwM2mObjectInstance(request.getResources());
} else {
instance = new LwM2mObjectInstance(request.getInstanceId(), request.getResources());
}
coapRequest.setPayload(encoder.encode(instance, request.getContentFormat(), request.getPath(), model));
setTarget(coapRequest, request.getPath());
}

Expand Down

0 comments on commit 998873d

Please sign in to comment.