From d8435246dde65ddffa1f065bf3b7d8a1f56fff9e Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 18 Apr 2025 19:24:45 +0300 Subject: [PATCH] lwm2m: add Base64 from java.util and add Test FW to objectId=19 jsonNode --- .../rpc/sql/RpcLwm2mIntegrationWriteTest.java | 65 ++++++++++++++++--- .../DefaultLwM2mDownlinkMsgHandler.java | 2 +- .../ota/DefaultLwM2MOtaUpdateService.java | 2 - .../common/transport/util/JsonUtils.java | 9 ++- 4 files changed, 65 insertions(+), 13 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java index 9d64e1a64d..01030c24bd 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java @@ -16,26 +16,22 @@ package org.thingsboard.server.transport.lwm2m.rpc.sql; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.hash.Hashing; +import org.eclipse.leshan.client.resource.LwM2mObjectEnabler; import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.node.LwM2mPath; import org.junit.Test; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.script.api.tbel.TbUtils; import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; +import java.util.Base64; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_2; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_0; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_14; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_15; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_9; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_3_14; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_INSTANCE_ID_2; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.*; +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.*; public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTest { @@ -77,6 +73,28 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes String expected = "LwM2mSingleResource [id=" + RESOURCE_ID_14 + ", value=" + expectedValue + ", type=STRING]"; assertTrue(actualValues.contains(expected)); } + + @Test + public void testWriteReplaceValueMultipleResource_Result_CHANGED_Multi_Instance_Resource_must_One_ValueJsonNodeToBase64() throws Exception { + LwM2mObjectEnabler lwM2mObjectEnabler = lwM2MTestClient.getLeshanClient().getObjectTree().getObjectEnabler(BINARY_APP_DATA_CONTAINER); + if (lwM2mObjectEnabler != null) { + String expectedPath = objectIdVer_19 + "/" + FW_INSTANCE_ID + "/"; + String expectedValueStr = getJsonNodeBase64(); + String expectedValue = "{\"" + RESOURCE_ID_0 + "\":{\"0\":\"" + expectedValueStr + "\"}}"; + String actualResult = sendRPCreateById(expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CREATED.getName(), rpcActualResult.get("result").asText()); + actualResult = sendRPCReadById(expectedPath); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String actualValues = rpcActualResult.get("value").asText(); + byte[] expectedValue0 = TbUtils.base64ToBytes(expectedValueStr); + String expectedInstance = "LwM2mObjectInstance [id=" + FW_INSTANCE_ID; + assertTrue(actualValues.contains(expectedInstance)); + String expected = "{0=LwM2mMultipleResource [id=0, values={0=LwM2mResourceInstance [id=0, value=" + expectedValue0.length + "Bytes, type=OPAQUE]}"; + assertTrue(actualValues.contains(expected)); + } + } + @Test public void testWriteReplaceValueMultipleResource_Result_CHANGED_Multi_Instance_Resource_must_One() throws Exception { int resourceInstanceId0 = 0; @@ -525,4 +543,33 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes String setRpcRequest = "{\"method\": \"WriteComposite\", \"params\": {\"nodes\":" + nodes + "}}"; return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(), setRpcRequest, String.class, status().isOk()); } + + /** + * ObjectId = 19/65533/0 + * { + * "title" : "My firmware", + * "version" : "fw.v.1.5.0-update", + * "checksum" : "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a", + * "fileSize" : 1, + * "fileName" : "filename.txt" + * } + */ + private String getJsonNodeBase64() { + ObjectNode objectNodeInfoOta = JacksonUtil.newObjectNode(); + byte[] firmwareChunk = new byte[]{1}; + String fileChecksumSHA256 = Hashing.sha256().hashBytes(firmwareChunk).toString(); + objectNodeInfoOta.put(OTA_INFO_19_TITLE, "My firmware"); + objectNodeInfoOta.put(OTA_INFO_19_VERSION, "fw.v.1.5.0-update"); + objectNodeInfoOta.put(OTA_INFO_19_FILE_CHECKSUM256, fileChecksumSHA256); + objectNodeInfoOta.put(OTA_INFO_19_FILE_SIZE, firmwareChunk.length); + objectNodeInfoOta.put(OTA_INFO_19_FILE_NAME, "filename.txt"); + String objectNodeInfoOtaStr = JacksonUtil.toString(objectNodeInfoOta); + assert objectNodeInfoOtaStr != null; + return Base64.getEncoder().encodeToString(objectNodeInfoOtaStr.getBytes()); + } + + private String sendRPCreateById(String path, String value) throws Exception { + String setRpcRequest = "{\"method\": \"Create\", \"params\": {\"id\": \"" + path + "\", \"value\": " + value + " }}"; + return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(), setRpcRequest, String.class, status().isOk()); + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 787db56411..ed685dfc6c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -99,7 +99,6 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; -import static org.apache.commons.codec.binary.Base64.isBase64; import static org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes.DIMENSION; import static org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes.ENABLER_VERSION; import static org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes.EVALUATE_MAXIMUM_PERIOD; @@ -114,6 +113,7 @@ import static org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes.SHOR import static org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes.STEP; import static org.eclipse.leshan.core.model.ResourceModel.Type.OBJLNK; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; +import static org.thingsboard.server.common.transport.util.JsonUtils.isBase64; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.convertMultiResourceValuesFromRpcBody; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.createModelsDefault; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fromVersionedIdToObjectId; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index cfa8feb89f..da94c19422 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -701,8 +701,6 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl String objectNodeInfoOtaStr = JacksonUtil.toString(objectNodeInfoOta); assert objectNodeInfoOtaStr != null; String objectNodeInfoOtaBase64 = Base64.getEncoder().encodeToString(objectNodeInfoOtaStr.getBytes()); - - LwM2mPath pathOtaInstance = new LwM2mPath(targetId); if (client.getRegistration().getAvailableInstances().contains(pathOtaInstance)) { String versionId = targetIdVer + "/0/0"; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java index cdbc371c60..a79d897daf 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java @@ -23,10 +23,13 @@ import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto; import java.util.List; import java.util.Map; -import static org.apache.commons.codec.binary.Base64.isBase64; +import java.util.regex.Pattern; public class JsonUtils { + private static final Pattern BASE64_PATTERN = + Pattern.compile("^[A-Za-z0-9+/]+={0,2}$"); + public static JsonObject getJsonObject(List tsKv) { JsonObject json = new JsonObject(); for (KeyValueProto kv : tsKv) { @@ -84,4 +87,8 @@ public class JsonUtils { return jsonObject; } + + public static boolean isBase64(String value) { + return value.length() % 4 == 0 && BASE64_PATTERN.matcher(value).matches(); + } }