Skip to content

Commit

Permalink
server-demo: add type attribute to REST API to type value of lwm2m node.
Browse files Browse the repository at this point in the history
  • Loading branch information
sbernard31 committed Oct 28, 2021
1 parent abf081c commit 78fee63
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 42 deletions.
Expand Up @@ -22,14 +22,21 @@
import java.util.Iterator;
import java.util.Map;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.model.ResourceModel.Type;
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import org.eclipse.leshan.core.node.LwM2mNode;
import org.eclipse.leshan.core.node.LwM2mObject;
import org.eclipse.leshan.core.node.LwM2mObjectInstance;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mResourceInstance;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.codec.CodecException;
import org.eclipse.leshan.core.util.Hex;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
Expand Down Expand Up @@ -93,7 +100,7 @@ public LwM2mNode deserialize(JsonParser p, DeserializationContext ctxt) throws I
}
// multi-instances resource
Map<Integer, Object> values = new HashMap<>();
org.eclipse.leshan.core.model.ResourceModel.Type expectedType = null;
Type type = Type.valueOf(object.get("type").asText().toUpperCase());

JsonNode valuesNode = object.get("values");
if (!valuesNode.isObject()) {
Expand All @@ -103,15 +110,9 @@ public LwM2mNode deserialize(JsonParser p, DeserializationContext ctxt) throws I
for (Iterator<String> it = valuesNode.fieldNames(); it.hasNext();) {
String nodeName = it.next();
JsonNode nodeValue = valuesNode.get(nodeName);

expectedType = getTypeFor(nodeValue);
values.put(Integer.valueOf(nodeName), deserializeValue(nodeValue, expectedType));
values.put(Integer.valueOf(nodeName), deserializeValue(nodeValue, type));
}

// use string by default;
if (expectedType == null)
expectedType = org.eclipse.leshan.core.model.ResourceModel.Type.STRING;
node = LwM2mMultipleResource.newResource(id, values, expectedType);
node = LwM2mMultipleResource.newResource(id, values, type);
} else if (object.has("value")) {
if (id == null) {
throw new JsonParseException(p, "Missing id");
Expand All @@ -120,13 +121,13 @@ public LwM2mNode deserialize(JsonParser p, DeserializationContext ctxt) throws I
if ("resourceInstance".equals(kind)) {
// resource instance
JsonNode val = object.get("value");
org.eclipse.leshan.core.model.ResourceModel.Type expectedType = getTypeFor(val);
node = LwM2mResourceInstance.newInstance(id, deserializeValue(val, expectedType), expectedType);
Type type = Type.valueOf(object.get("type").asText().toUpperCase());
node = LwM2mResourceInstance.newInstance(id, deserializeValue(val, type), type);
} else {
// single value resource
JsonNode val = object.get("value");
org.eclipse.leshan.core.model.ResourceModel.Type expectedType = getTypeFor(val);
node = LwM2mSingleResource.newResource(id, deserializeValue(val, expectedType), expectedType);
Type type = Type.valueOf(object.get("type").asText().toUpperCase());
node = LwM2mSingleResource.newResource(id, deserializeValue(val, type), type);
}
} else {
throw new JsonParseException(p, "Invalid node element");
Expand All @@ -138,24 +139,8 @@ public LwM2mNode deserialize(JsonParser p, DeserializationContext ctxt) throws I
return node;
}

private org.eclipse.leshan.core.model.ResourceModel.Type getTypeFor(JsonNode val) {
if (val.isBoolean())
return org.eclipse.leshan.core.model.ResourceModel.Type.BOOLEAN;
if (val.isTextual())
return org.eclipse.leshan.core.model.ResourceModel.Type.STRING;
if (val.isNumber()) {
if (val.isDouble()) {
return org.eclipse.leshan.core.model.ResourceModel.Type.FLOAT;
} else {
return org.eclipse.leshan.core.model.ResourceModel.Type.INTEGER;
}
}
// use string as default value
return org.eclipse.leshan.core.model.ResourceModel.Type.STRING;
}

private Object deserializeValue(JsonNode val, ResourceModel.Type expectedType) {
switch (expectedType) {
private Object deserializeValue(JsonNode val, ResourceModel.Type type) {
switch (type) {
case BOOLEAN:
return val.asBoolean();
case STRING:
Expand All @@ -165,10 +150,17 @@ private Object deserializeValue(JsonNode val, ResourceModel.Type expectedType) {
case FLOAT:
return val.asDouble();
case TIME:
try {
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
XMLGregorianCalendar cal = datatypeFactory.newXMLGregorianCalendar(val.asText());
return cal.toGregorianCalendar().getTime();
} catch (DatatypeConfigurationException | IllegalArgumentException e) {
throw new CodecException("Unable to convert string (%s) to date", val.asText(), e);
}
case OPAQUE:
return Hex.decodeHex((val.asText()).toCharArray());
default:
// TODO we need to better handle this.
return val.asText();
throw new UnsupportedOperationException(String.format("Type %s is not supported for now", type));
}
}
}
Expand Up @@ -70,8 +70,10 @@ public void serialize(LwM2mNode src, JsonGenerator gen, SerializerProvider provi
}
element.put("kind", "multiResource");
element.put("values", values);
element.put("type", rsc.getType());
} else {
element.put("kind", "singleResource");
element.put("type", rsc.getType());
if (rsc.getType() == org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE) {
element.put("value", new String(Hex.encodeHex((byte[]) rsc.getValue())));
} else {
Expand All @@ -81,6 +83,7 @@ public void serialize(LwM2mNode src, JsonGenerator gen, SerializerProvider provi
} else if (src instanceof LwM2mResourceInstance) {
element.put("kind", "resourceInstance");
LwM2mResourceInstance rsc = (LwM2mResourceInstance) src;
element.put("type", rsc.getType());
if (rsc.getType() == org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE) {
element.put("value", new String(Hex.encodeHex((byte[]) rsc.getValue())));
} else {
Expand Down
Expand Up @@ -49,6 +49,7 @@
import RequestButton from "../RequestButton.vue";
import ResourceInstanceWriteDialog from "./ResourceInstanceWriteDialog.vue";
import { preference } from "vue-preferences";
import { resourceInstanceToREST } from "../../js/restutils";
const timeout = preference("timeout", { defaultValue: 5 });
const singleFormat = preference("singleformat", { defaultValue: "TLV" });
Expand Down Expand Up @@ -155,11 +156,10 @@ export default {
write(value) {
let requestButton = this.$refs.W;
this.axios
.put(this.requestPath() + this.requestOption(), {
id: this.instanceId,
value: value,
kind: "resourceInstance",
})
.put(
this.requestPath() + this.requestOption(),
resourceInstanceToREST(this.resourcedef, this.instanceId, value)
)
.then((response) => {
this.updateState(response.data, requestButton);
if (response.data.success)
Expand Down
25 changes: 21 additions & 4 deletions leshan-server-demo/webapp/src/js/restutils.js
@@ -1,15 +1,15 @@
/*******************************************************************************
* Copyright (c) 2021 Sierra Wireless and others.
*
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*******************************************************************************/
*******************************************************************************/

/**
* Helper function to convert data from UI Component format
Expand Down Expand Up @@ -68,6 +68,7 @@ function singleInstanceResourceToREST(model, value) {
res.id = model.id;
res.kind = "singleResource";
res.value = value;
res.type = model.type;
return res;
}

Expand All @@ -80,11 +81,27 @@ function multiInstanceResourceToREST(model, value) {
let res = {};
res.id = model.id;
res.kind = "multiResource";
res.type = model.type;
res.values = value.reduce(function(resource, instance) {
resource[instance.id] = instance.val;
return resource;
}, {});
return res;
}

export { resourceToREST, instanceToREST };
/**
* @param {Object} model model of the resource.
* @param {Number} instanceId the id of the resource instance
* @param {*} value the value of the resource instance from UI Component.
* @returns a resource instance usable for REST API.
*/
function resourceInstanceToREST(model, instanceId, value) {
let res = {};
res.id = instanceId;
res.kind = "resourceInstance";
res.value = value;
res.type = model.type;
return res;
}

export { resourceToREST, instanceToREST, resourceInstanceToREST };

0 comments on commit 78fee63

Please sign in to comment.