if write request can not be parsed to "multiple" we parse that to single

This commit is contained in:
YevhenBondarenko 2021-12-24 15:53:24 +02:00
parent 95e3f3c05b
commit 19d8aca4a1
4 changed files with 25 additions and 54 deletions

View File

@ -33,7 +33,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponse
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler;
@ -42,6 +41,7 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteRespon
import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import java.util.ArrayList;
@ -191,7 +191,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
@Override
public void onAttributesUpdate(LwM2mClient lwM2MClient, List<TransportProtos.TsKvProto> tsKvProtos, boolean logFailedUpdateOfNonChangedValue) {
log.trace("[{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), tsKvProtos);
Map <String, TransportProtos.TsKvProto> attributesUpdate = new ConcurrentHashMap<>();
Map<String, TransportProtos.TsKvProto> attributesUpdate = new ConcurrentHashMap<>();
tsKvProtos.forEach(tsKvProto -> {
try {
String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey());
@ -207,8 +207,8 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
attributesUpdate.put(pathIdVer, tsKvProto);
}
}
} catch (IllegalArgumentException e){
log.error("Failed update resource ["+lwM2MClient.getEndpoint()+"] onAttributesUpdate:", e);
} catch (IllegalArgumentException e) {
log.error("Failed update resource [" + lwM2MClient.getEndpoint() + "] onAttributesUpdate:", e);
String logMsg = String.format("%s: Failed update resource onAttributesUpdate %s.",
LOG_LWM2M_ERROR, e.getMessage());
logService.log(lwM2MClient, logMsg);
@ -226,8 +226,8 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
try {
pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto,
(Map<Integer, LwM2mResourceInstance>) oldResourceValue, pathIdVer, logFailedUpdateOfNonChangedValue);
} catch (Exception e){
log.error("Failed update resource ["+lwM2MClient.getEndpoint()+"] onAttributesUpdate:", e);
} catch (Exception e) {
log.error("Failed update resource [" + lwM2MClient.getEndpoint() + "] onAttributesUpdate:", e);
String logMsg = String.format("%s: Failed update resource onAttributesUpdate %s.",
LOG_LWM2M_ERROR, e.getMessage());
logService.log(lwM2MClient, logMsg);
@ -243,7 +243,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
LOG_LWM2M_ERROR, versionedId, "null");
logService.log(lwM2MClient, logMsg);
log.error("Failed update resource [{}] [{}]", versionedId, "null");
} else if ((oldValue == null) || !valueEquals(newValue, oldValue)) {
} else if ((oldValue == null) || !valueEquals(newValue, oldValue)) {
TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValue).timeout(clientContext.getRequestTimeout(lwM2MClient)).build();
downlinkHandler.sendWriteReplaceRequest(lwM2MClient, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, lwM2MClient, versionedId));
} else if (logFailedUpdateOfNonChangedValue) {
@ -256,10 +256,10 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto,
Map<Integer, LwM2mResourceInstance> valueOld, String versionedId,
boolean logFailedUpdateOfNonChangedValue) throws Exception {
Map newValues = convertMultiResourceValuesFromJson(newValProto, resourceModel.type, versionedId);
boolean logFailedUpdateOfNonChangedValue) {
Map<Integer, Object> newValues = convertMultiResourceValuesFromJson(newValProto, resourceModel.type, versionedId);
if (newValues.size() > 0 && valueOld != null && valueOld.size() > 0) {
valueOld.values().stream().forEach((v) -> {
valueOld.values().forEach((v) -> {
if (newValues.containsKey(v.getId())) {
if (valueEquals(newValues.get(v.getId()), v.getValue())) {
newValues.remove(v.getId());

View File

@ -300,14 +300,13 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
String msgError = "";
if (resourceModelWrite.multiple) {
try {
Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId());
Map<Integer, Object> value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId());
downlink = new WriteRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(),
value, resourceModelWrite.type);
} catch (Exception e) {
msgError = "Resource id=" + resultIds.toString() + ", value = " + request.getValue() +
", class = " + request.getValue().getClass().getSimpleName() + ". Format value is bad. Value for this Multi-Instance Resource must be in Json format!";
}
} else {
}
if (downlink == null) {
try {
downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat,
resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), request.getValue());
@ -319,15 +318,11 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
if (downlink != null) {
sendSimpleRequest(client, downlink, request.getTimeout(), callback);
} else {
if (msgError.isEmpty()) {
msgError = "WriteRequest is null.";
}
callback.onValidationError(toString(request), msgError);
}
} catch (Exception e) {
callback.onError(toString(request), e);
}
} else {
callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!");
}
@ -378,7 +373,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
if (resourceModelWrite != null) {
if (resourceModelWrite.multiple) {
try {
Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId());
Map<Integer, Object> value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId());
downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(),
resultIds.getObjectInstanceId(), resultIds.getResourceId(),
value, resourceModelWrite.type);
@ -608,7 +603,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(versionedId));
if (pathIds.isResource() || pathIds.isResourceInstance()) {
ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider);
if (resourceModel!= null && (pathIds.isResourceInstance() || (pathIds.isResource() && !resourceModel.multiple))) {
if (resourceModel != null && (pathIds.isResourceInstance() || (pathIds.isResource() && !resourceModel.multiple))) {
if (OBJLNK.equals(resourceModel.type)) {
return ContentFormat.LINK;
} else if (OPAQUE.equals(resourceModel.type)) {

View File

@ -278,11 +278,9 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider);
if (resourceModel != null && resourceModel.multiple) {
try {
Map value = convertMultiResourceValuesFromRpcBody(requestBody.getValue(), resourceModel.type, versionedId);
Map<Integer, Object> value = convertMultiResourceValuesFromRpcBody(requestBody.getValue(), resourceModel.type, versionedId);
requestBody.setValue(value);
} catch (Exception e) {
throw new IllegalArgumentException("Resource id=" + versionedId + ", class = " +
requestBody.getValue().getClass().getSimpleName() + ", value = " + requestBody.getValue() + " is bad. Value of Multi-Instance Resource must be in Json format!");
}
}
}
@ -304,7 +302,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
*/
private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) {
RpcWriteCompositeRequest rpcWriteCompositeRequest = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class);
Map validNodes = validateNodes(client, rpcWriteCompositeRequest.getNodes());
Map<String, Object> validNodes = validateNodes(client, rpcWriteCompositeRequest.getNodes());
if (validNodes.size() > 0) {
rpcWriteCompositeRequest.setNodes(validNodes);
var mainCallback = new TbLwM2MWriteResponseCompositeCallback(uplinkHandler, logService, client, null);
@ -315,22 +313,21 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
}
}
private Map validateNodes(LwM2mClient client, Map nodes) {
Map newNodes = new LinkedHashMap();
private Map<String, Object> validateNodes(LwM2mClient client, Map<String, Object> nodes) {
Map<String, Object> newNodes = new LinkedHashMap<>();
nodes.forEach((key, value) -> {
String versionedId;
try {
// validate key.toString()
LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(key.toString()));
LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(key));
if (path.isResource() || path.isResourceInstance()) {
versionedId = key.toString();
versionedId = key;
}
else {
throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " +
"The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString()));
}
} catch (Exception e) {
versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key.toString());
versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key);
}
// validate value. Must be only primitive, not JsonObject or JsonArray
try {

View File

@ -351,14 +351,14 @@ public class LwM2MTransportUtil {
}
}
public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception {
public static Map<Integer, Object> convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception {
String valueJsonStr = JsonUtils.writeValueAsString(value);
JsonElement element = JsonUtils.parse(valueJsonStr);
return convertMultiResourceValuesFromJson(element, type, versionedId);
}
public static Map convertMultiResourceValuesFromJson(JsonElement newValProto, ResourceModel.Type type, String versionedId) throws Exception{
Map newValues = equalsMultiResourceValuesResourceType(type);
public static Map<Integer, Object> convertMultiResourceValuesFromJson(JsonElement newValProto, ResourceModel.Type type, String versionedId) {
Map<Integer, Object> newValues = new HashMap<>();
newValProto.getAsJsonObject().entrySet().forEach((obj) -> {
newValues.put(Integer.valueOf(obj.getKey()), LwM2mValueConverterImpl.getInstance().convertValue(obj.getValue().getAsString(),
STRING, type, new LwM2mPath(fromVersionedIdToObjectId(versionedId))));
@ -366,27 +366,6 @@ public class LwM2MTransportUtil {
return newValues;
}
public static Map equalsMultiResourceValuesResourceType(ResourceModel.Type type) {
switch (type) {
case FLOAT:
return new HashMap<Integer, Float>();
case INTEGER:
return new HashMap<Integer, Integer>();
case STRING:
return new HashMap<Integer, String>();
case BOOLEAN:
return new HashMap<Integer, Boolean>();
case OPAQUE:
return new HashMap<Integer, byte[]>();
case TIME:
return new HashMap<Integer, Date>();
case OBJLNK:
return new HashMap<Integer, ObjectLink>();
default:
return null;
}
}
public static Object convertWriteAttributes(String type, Object value, DefaultLwM2mUplinkMsgHandler serviceImpl, String target) {
switch (type) {
/** Integer [0:255]; */