Browse Source

lwm2m - refactoring review - 02 and tests

pull/14881/head
nickAS21 5 months ago
parent
commit
444d856fb8
  1. 37
      application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java
  2. 52
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java
  3. 12
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java

37
application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java

@ -119,7 +119,8 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
}
/**
* execute_resource_with_parameters (execute Factory Reset after connect with link on device)
* execute_resource_with_parameters (execute Factory Reset with two arguments:
* digit 2 without a value and digit 0 with the link value on device)
* Execute {"id":"3/0/5","value":"2,0='https://thingsboard.io/docs/reference/lwm2m-api/'"}
*/
@Test
@ -132,7 +133,8 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
}
/**
* execute_resource_with_parameters (execute Factory Reset after connect with link on device)
* execute_resource_with_parameters (execute Factory Reset with multiple arguments without values)
* According to the OMA LwM2M execute arguments format, this represents ten arguments (digits 0-9), all without values.
* Execute {"id":"3/0/5","value":"0,1,2,3,4,5,6,7,8,9"}
*/
@Test
@ -148,10 +150,9 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
/**
* execute_resource_with_parameters (execute Factory Reset after 60 seconds on device)
* Execute {"id":"3/0/5","value":"'60'"}
*/
@Test
public void testExecuteResourceWithParametersSingleDigitValueInvalidById_BAD_REQUEST_Error_UintegerBetween_0_And_9_Expected() throws Exception {
public void testExecuteResourceWithParametersSingleDigitValueInvalidById_Result_BAD_REQUEST_Error_IntegerBetween_0_And_9_Expected() throws Exception {
String expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_5;
Object expectedValue = "'60'";
String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue);
@ -159,7 +160,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
String expected = "Unable to parse Arguments [" + expectedValue + "] : Invalid digit ['] (an integer between 0 and 9 is expected)";
String actual = rpcActualResult.get("error").asText();
assertTrue(actual.equals(expected));
assertTrue(actual.contains(expected));
}
/**
@ -175,7 +176,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
String expected = "Unable to parse Arguments [" + expectedValue + "] : [,] separator expected at index 21 after [0,1,2,3,4,5,6,7,8,9,6]";
String actual = rpcActualResult.get("error").asText();
assertTrue(actual.equals(expected));
assertTrue(actual.contains(expected));
}
/**
@ -234,7 +235,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
* {"result":"BAD_REQUEST","error":"Specified object id 0 absent in the list supported objects of the client or is security object!"}
*/
@Test
public void testExecuteSecurityObjectById_Result_BAD_REQUEST_Error_InvalidDigit() throws Exception {
public void testExecuteSecurityObjectById_Result_BAD_REQUEST_Error_SpecifiedObjectAbsent() throws Exception {
String expectedPath = objectIdVer_0 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_3;
String actualResult = sendRPCExecuteById(expectedPath);
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
@ -253,8 +254,26 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
}
private String sendRPCExecuteWithValueById(String path, Object value) throws Exception {
String setRpcRequest = "{\"method\": \"Execute\", \"params\": {\"id\": \"" + path + "\", \"value\": \"" + value + "\"}}";
return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(), setRpcRequest, String.class, status().isOk());
ObjectNode params = JacksonUtil.newObjectNode();
params.put("id", path);
// Jackson сам вирішить: ставити лапки (рядок) чи ні (число/boolean/null)
if (value instanceof String) {
params.put("value", (String) value);
} else if (value instanceof Integer) {
params.put("value", (Integer) value);
} else if (value instanceof Boolean) {
params.put("value", (Boolean) value);
} else {
params.set("value", JacksonUtil.valueToTree(value));
}
ObjectNode setRpcRequest = JacksonUtil.newObjectNode();
setRpcRequest.put("method", "Execute");
setRpcRequest.set("params", params);
return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(),
JacksonUtil.toString(setRpcRequest), String.class, status().isOk());
}
}

52
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java

@ -271,40 +271,34 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
validateVersionedId(client, request);
LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(request.getVersionedId()));
ResourceModel resourceModelExecute = client.getResourceModel(request.getVersionedId(), modelProvider);
if (resourceModelExecute == null) {
LwM2mModel model = createModelsDefault();
if (pathIds.isResource()) {
resourceModelExecute = model.getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
}
if (resourceModelExecute == null && pathIds.isResource()) {
resourceModelExecute = createModelsDefault().getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
}
if (resourceModelExecute == null) {
callback.onValidationError(request.toString(), "ResourceModel with " + request.getVersionedId() +
" is absent in system. Need to add Model with id=" + pathIds.getObjectId() + " ver=" +
getVerFromPathIdVerOrId(request.getVersionedId()) + " to profile.");
} else if (resourceModelExecute.operations.isExecutable()) {
ExecuteRequest downlink;
if (request.getParams() != null && !resourceModelExecute.multiple) {
Object params = request.getParams();
ResourceModel.Type resourceModel = equalsResourceTypeGetSimpleName(params);
if (resourceModel == null) {
throw new InvalidArgumentException("Unsupported parameter type: " + params.getClass().getSimpleName() +
". Only simple types (String, Integer, Boolean, etc.) are allowed for Execute arguments.");
}
String args = (String) this.converter.convertValue(params, resourceModel, ResourceModel.Type.STRING, new LwM2mPath(request.getObjectId()));
try {
Arguments arguments = Arguments.parse(args);
downlink = new ExecuteRequest(request.getObjectId(), arguments);
} catch (IllegalArgumentException e) {
downlink = new ExecuteRequest(request.getObjectId(), args);
}
} else {
downlink = new ExecuteRequest(request.getObjectId());
throw new InvalidArgumentException(String.format("ResourceModel with %s is absent in the system. Need to add Model with id= %s ver=%s to profile.",
request.getVersionedId(), pathIds.getObjectId(), getVerFromPathIdVerOrId(request.getVersionedId())));
}
if (!resourceModelExecute.operations.isExecutable()) {
throw new InvalidArgumentException(String.format("Resource with %s is not executable.", request.getVersionedId()));
}
ExecuteRequest downlink;
Object params = request.getParams();
// 4. Handle parameters if they exist and the resource is not a multiple-instance resource
if (params != null && !resourceModelExecute.multiple) {
ResourceModel.Type resourceModelType = equalsResourceTypeGetSimpleName(params);
if (resourceModelType == null) {
throw new InvalidArgumentException(String.format("Unsupported parameter type: %s. Only simple types (String, Integer, Boolean, etc.) are allowed for Execute arguments.",
params.getClass().getSimpleName()));
}
sendSimpleRequest(client, downlink, request.getTimeout(), callback);
String args = (String) this.converter.convertValue(params, resourceModelType, ResourceModel.Type.STRING, pathIds);
downlink = new ExecuteRequest(request.getObjectId(), args);
} else {
callback.onValidationError(request.toString(), "Resource with " + request.getVersionedId() + " is not executable.");
downlink = new ExecuteRequest(request.getObjectId());
}
} catch (InvalidRequestException | InvalidArgumentException e) {
sendSimpleRequest(client, downlink, request.getTimeout(), callback);
} catch (Exception e) {
log.error("[{}] Validation failed for Execute request: {}", client.getEndpoint(), e.getMessage());
callback.onValidationError(request.toString(), e.getMessage());
}
}

12
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java

@ -242,12 +242,12 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
private void sendExecuteRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
RpcExecuteRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcExecuteRequest.class);
TbLwM2MExecuteRequest downlink = TbLwM2MExecuteRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build();
if (!requestMsg.getParams().isEmpty()) {
downlink = TbLwM2MExecuteRequest.builder().versionedId(versionedId)
.params(requestBody.getValue())
.timeout(clientContext.getRequestTimeout(client)).build();
}
Object value = requestBody != null ? requestBody.getValue() : null;
TbLwM2MExecuteRequest downlink = TbLwM2MExecuteRequest.builder()
.versionedId(versionedId)
.params(value)
.timeout(clientContext.getRequestTimeout(client))
.build();
var mainCallback = new TbLwM2MExecuteCallback(logService, client, versionedId);
var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendExecuteRequest(client, downlink, rpcCallback);

Loading…
Cancel
Save