From 684ad858b2b55b7e45544cbcfa922159839cb817 Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 22 May 2024 07:44:59 +0300 Subject: [PATCH 1/2] lwm2m: fix bug Content Format M14 --- .../lwm2m/AbstractLwM2MIntegrationTest.java | 5 +- .../lwm2m/client/LwM2MTestClient.java | 33 ++++++- .../rpc/AbstractRpcLwM2MIntegrationTest.java | 3 + .../sql/RpcLwm2mIntegrationWriteCborTest.java | 98 +++++++++++++++++++ .../rpc/sql/RpcLwm2mIntegrationWriteTest.java | 27 +++++ .../lwm2m/server/client/LwM2mClient.java | 9 +- .../DefaultLwM2mDownlinkMsgHandler.java | 50 ++-------- 7 files changed, 175 insertions(+), 50 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteCborTest.java diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index a44d2b6a62..983cfde0e5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -178,6 +178,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportInte private String[] resources; protected String deviceId; protected boolean isWriteAttribute = false; + protected boolean supportFormatOnly_SenMLJSON_SenMLCBOR = false; @Before public void startInit() throws Exception { @@ -318,8 +319,8 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportInte try (ServerSocket socket = new ServerSocket(0)) { int clientPort = socket.getLocalPort(); lwM2MTestClient.init(security, securityBs, clientPort, isRpc, - this.defaultLwM2mUplinkMsgHandlerTest, this.clientContextTest, isWriteAttribute - , clientDtlsCidLength, queueMode); + this.defaultLwM2mUplinkMsgHandlerTest, this.clientContextTest, isWriteAttribute, + clientDtlsCidLength, queueMode, supportFormatOnly_SenMLJSON_SenMLCBOR); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 00a5510788..02ff8be9d4 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -47,10 +47,19 @@ import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.StaticModel; import org.eclipse.leshan.core.node.codec.DefaultLwM2mDecoder; import org.eclipse.leshan.core.node.codec.DefaultLwM2mEncoder; +import org.eclipse.leshan.core.node.codec.NodeDecoder; +import org.eclipse.leshan.core.node.codec.NodeEncoder; +import org.eclipse.leshan.core.node.codec.cbor.LwM2mNodeCborDecoder; +import org.eclipse.leshan.core.node.codec.cbor.LwM2mNodeCborEncoder; +import org.eclipse.leshan.core.node.codec.senml.LwM2mNodeSenMLDecoder; +import org.eclipse.leshan.core.node.codec.senml.LwM2mNodeSenMLEncoder; import org.eclipse.leshan.core.request.BootstrapRequest; +import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; +import org.eclipse.leshan.senml.cbor.upokecenter.SenMLCborUpokecenterEncoderDecoder; +import org.eclipse.leshan.senml.json.jackson.SenMLJsonJacksonEncoderDecoder; import org.junit.Assert; import org.mockito.Mockito; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; @@ -78,6 +87,7 @@ import static org.eclipse.leshan.core.LwM2mId.LOCATION; import static org.eclipse.leshan.core.LwM2mId.SECURITY; import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT; +import static org.eclipse.leshan.core.node.codec.DefaultLwM2mEncoder.getDefaultPathEncoder; import static org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest.serverId; import static org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest.serverIdBs; import static org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest.shortServerId; @@ -130,7 +140,8 @@ public class LwM2MTestClient { public void init(Security security, Security securityBs, int port, boolean isRpc, LwM2mUplinkMsgHandler defaultLwM2mUplinkMsgHandler, - LwM2mClientContext clientContext, boolean isWriteAttribute, Integer cIdLength, boolean queueMode) throws InvalidDDFFileException, IOException { + LwM2mClientContext clientContext, boolean isWriteAttribute, Integer cIdLength, boolean queueMode, + boolean supportFormatOnly_SenMLJSON_SenMLCBOR) throws InvalidDDFFileException, IOException { Assert.assertNull("client already initialized", leshanClient); this.defaultLwM2mUplinkMsgHandlerTest = defaultLwM2mUplinkMsgHandler; this.clientContext = clientContext; @@ -274,12 +285,28 @@ public class LwM2MTestClient { builder.setEndpointsProviders(endpointsProvider.toArray(new LwM2mClientEndpointsProvider[endpointsProvider.size()])); builder.setDataSenders(new ManualDataSender()); builder.setRegistrationEngineFactory(engineFactory); - boolean supportOldFormat = true; - if (supportOldFormat) { + Map decoders = new HashMap<>(); + Map encoders = new HashMap<>(); + if (supportFormatOnly_SenMLJSON_SenMLCBOR) { +// decoders.put(ContentFormat.OPAQUE, new LwM2mNodeOpaqueDecoder()); + decoders.put(ContentFormat.CBOR, new LwM2mNodeCborDecoder()); + decoders.put(ContentFormat.SENML_JSON, new LwM2mNodeSenMLDecoder(new SenMLJsonJacksonEncoderDecoder(), true)); + decoders.put(ContentFormat.SENML_CBOR, new LwM2mNodeSenMLDecoder(new SenMLCborUpokecenterEncoderDecoder(), false)); + builder.setDecoder(new DefaultLwM2mDecoder(decoders)); + +// encoders.put(ContentFormat.OPAQUE, new LwM2mNodeOpaqueEncoder()); + encoders.put(ContentFormat.CBOR, new LwM2mNodeCborEncoder()); + encoders.put(ContentFormat.SENML_JSON, new LwM2mNodeSenMLEncoder(new SenMLJsonJacksonEncoderDecoder())); + encoders.put(ContentFormat.SENML_CBOR, new LwM2mNodeSenMLEncoder(new SenMLCborUpokecenterEncoderDecoder())); + builder.setEncoder(new DefaultLwM2mEncoder(new LwM2mValueConverterImpl(), false)); + builder.setEncoder(new DefaultLwM2mEncoder(encoders, getDefaultPathEncoder(), new LwM2mValueConverterImpl())); + } else { + boolean supportOldFormat = true; builder.setDecoder(new DefaultLwM2mDecoder(supportOldFormat)); builder.setEncoder(new DefaultLwM2mEncoder(new LwM2mValueConverterImpl(), supportOldFormat)); } + builder.setRegistrationEngineFactory(engineFactory); builder.setSharedExecutor(executor); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index 1c6e384ae1..b5f23c3e9a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -86,6 +86,9 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg if (this.getClass().getSimpleName().equals("RpcLwm2mIntegrationDiscoverWriteAttributesTest")){ isWriteAttribute = true; } + if (this.getClass().getSimpleName().equals("RpcLwm2mIntegrationWriteCborTest")){ + supportFormatOnly_SenMLJSON_SenMLCBOR = true; + } initRpc(); } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteCborTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteCborTest.java new file mode 100644 index 0000000000..2850d5b8cd --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteCborTest.java @@ -0,0 +1,98 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.rpc.sql; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.eclipse.leshan.core.ResponseCode; +import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; + +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.RESOURCE_ID_0; + +public class RpcLwm2mIntegrationWriteCborTest extends AbstractRpcLwM2MIntegrationTest { + + /** + * Client with ContentFormat ={} + */ + + /** + * Resource: + * Opaque + * Input type String (HexDec) + * WriteReplace {"id": "/19_1.1/0/0","value": {"0":"01234567890CAB"}} + * return Hex.decodeHex(((String)value).toCharArray()) - ok [1, 35, 69, 103, -119, 12, -85, -1] + * {"result":"CHANGED"} -> Actual Value Equals expectedValue0 + */ + @Test + public void testWriteReplaceValueMultipleResource_InputFormatData_Ok_Result_CHANGED_Value_Equals_expectedValue0() throws Exception { + String expectedPath = objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0; + int resourceInstanceId0 = 0; + String expectedValue0 = "01234567890CABFF"; + String expectedValue = "{\"" + resourceInstanceId0 + "\":\"" + expectedValue0 + "\"}"; + String actualResult = sendRPCWriteObjectById("WriteReplace", expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + String expectedPath0 = expectedPath + "/" + resourceInstanceId0; + actualResult = sendRPCReadById(expectedPath0); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String actualValues = rpcActualResult.get("value").asText(); + String expected = "LwM2mResourceInstance [id=" + resourceInstanceId0 + ", value=" + expectedValue0.length()/2 + "Bytes, type=OPAQUE]"; + assertTrue(actualValues.contains(expected)); + } + + /** + * Resource: + * Opaque + * Input type String (not HexDec) + * return Hex.decodeHex(((String)value).toCharArray()) - error + * return Base64.getDecoder().decode(((String) value).getBytes()) - ok; + * WriteReplace {"id": "/19_1.1/0/0","value": {"0":"01234567890"}} + * {"result":"CHANGED"} -> Actual Value Not Equals expectedValue0 + */ + @Test + public void testWriteReplaceValueMultipleResource_Error_InputFormatData_Result_CHANGED_Value_Not_Equals_expectedValue0() throws Exception { + String expectedPath = objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0; + int resourceInstanceId0 = 0; + String expectedValue0 = "01234567890"; + String expectedValue = "{\"" + resourceInstanceId0 + "\":\"" + expectedValue0 + "\"}"; + String actualResult = sendRPCWriteObjectById("WriteReplace", expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + String expectedPath0 = expectedPath + "/" + resourceInstanceId0; + actualResult = sendRPCReadById(expectedPath0); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String actualValues = rpcActualResult.get("value").asText(); + String expected = "LwM2mResourceInstance [id=" + resourceInstanceId0 + ", value=" + expectedValue0.length()/2 + "Bytes, type=OPAQUE]"; + assertFalse(actualValues.contains(expected)); + } + + + private String sendRPCWriteObjectById(String method, String path, Object value) throws Exception { + String setRpcRequest = "{\"method\": \"" + method + "\", \"params\": {\"id\": \"" + path + "\", \"value\": " + value + " }}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } + + private String sendRPCReadById(String id) throws Exception { + String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"id\": \"" + id + "\"}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); + } +} 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 a230b17eb3..f99826780e 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 @@ -23,6 +23,7 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; 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; @@ -107,6 +108,32 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes assertTrue(actualValues.contains(expected)); } + /** + * Resource: + * Opaque + * Input type String (not HexDec) + * return Hex.decodeHex(((String)value).toCharArray()) - error + * return Base64.getDecoder().decode(((String) value).getBytes()) - ok; + * WriteReplace {"id": "/19_1.1/0/0","value": {"0":"01234567890"}} + * {"result":"CHANGED"} -> Actual Value Not Equals expectedValue0 + */ + @Test + public void testWriteReplaceValueMultipleResource_Error_InputFormatData_Result_CHANGED_Value_Not_Equals_expectedValue0() throws Exception { + String expectedPath = objectIdVer_19 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_0; + int resourceInstanceId0 = 0; + String expectedValue0 = "01234567890"; + String expectedValue = "{\"" + resourceInstanceId0 + "\":\"" + expectedValue0 + "\"}"; + String actualResult = sendRPCWriteObjectById("WriteReplace", expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); + String expectedPath0 = expectedPath + "/" + resourceInstanceId0; + actualResult = sendRPCReadById(expectedPath0); + rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + String actualValues = rpcActualResult.get("value").asText(); + String expected = "LwM2mResourceInstance [id=" + resourceInstanceId0 + ", value=" + expectedValue0.length()/2 + "Bytes, type=OPAQUE]"; + assertFalse(actualValues.contains(expected)); + } + /** * bad: singleResource, operation="R" - only read * WriteReplace {"id":"/3/0/9","value":90} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 141aa83b7e..5672ae33c3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -61,7 +61,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; -import java.util.stream.Stream; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LWM2M_OBJECT_VERSION_DEFAULT; @@ -417,14 +416,14 @@ public class LwM2mClient { private static Set clientSupportContentFormat(Registration registration) { Set contentFormats = new HashSet<>(); - contentFormats.add(ContentFormat.DEFAULT); Attribute ct = Arrays.stream(registration.getObjectLinks()) .filter(link -> link.getUriReference().equals("/")) .findFirst() .map(link -> link.getAttributes().get("ct")).orElse(null); - if (ct != null) { - Set codes = Stream.of(ct.getValue()).collect(Collectors.toSet()); - contentFormats.addAll(codes); + if (ct != null && ct.getValue() instanceof Collection) { + contentFormats.addAll((Collection) ct.getValue()); + } else { + contentFormats.add(ContentFormat.DEFAULT); } return contentFormats; } 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 af127dba88..15171b168f 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 @@ -98,7 +98,6 @@ import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -115,8 +114,6 @@ import static org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes.OBJE import static org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes.SERVER_URI; import static org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes.SHORT_SERVER_ID; 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.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; @@ -742,19 +739,8 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im private static ContentFormat getRequestContentFormat(LwM2mClient client, String versionedId, LwM2mModelProvider modelProvider) { 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 (OBJLNK.equals(resourceModel.type)) { - return ContentFormat.LINK; - } else if (OPAQUE.equals(resourceModel.type)) { - return ContentFormat.OPAQUE; - } else { - return findFirstContentFormatForComp(client.getClientSupportContentFormats(), client.getDefaultContentFormat(), ContentFormat.CBOR, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON); - } - } else { - return getContentFormatForComplex(client); - } + if (pathIds.isResourceInstance()) { + return findFirstContentFormatForComp(client.getClientSupportContentFormats(), client.getDefaultContentFormat(), ContentFormat.CBOR, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON); } else { return getContentFormatForComplex(client); } @@ -783,37 +769,21 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } - private ContentFormat findFirstContentFormatForComposite (Set clientSupportContentFormats) { - ContentFormat contentFormat = findFirstContentFormatForComp(clientSupportContentFormats, null, ContentFormat.SENML_JSON, ContentFormat.SENML_CBOR); + private ContentFormat findFirstContentFormatForComposite (Set clientSupportContentFormats) { + ContentFormat contentFormat = findFirstContentFormatForComp(clientSupportContentFormats, null, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON); if (contentFormat != null) { return contentFormat; } else { throw new RuntimeException("This device does not support Composite Operation"); } } - private static ContentFormat findFirstContentFormatForComp(Set clientSupportContentFormats, ContentFormat defaultValue, ContentFormat... desiredFormats) { - AtomicReference compositeContentFormat = new AtomicReference<>(); - clientSupportContentFormats.forEach(c -> { - if (c instanceof Collection) { - for (ContentFormat contentFormat : desiredFormats) { - if (((Collection) c).contains(contentFormat)) { - compositeContentFormat.set(contentFormat); - break; - } - } - } else if (compositeContentFormat.get() == null && c instanceof ContentFormat) { - compositeContentFormat.set(Arrays.stream(desiredFormats).filter(f -> f.equals(c)).findFirst().get()); - } - }); - return compositeContentFormat.get() != null ? compositeContentFormat.get() : defaultValue; - } - - private static boolean containsObserveComposite(List l1, List l2) { - for (T elem : l1) { - if (l2.contains(elem)) { - return true; + private static ContentFormat findFirstContentFormatForComp(Set clientSupportContentFormats, ContentFormat defaultValue, ContentFormat... desiredFormats) { + List desiredFormatsList = Arrays.asList(desiredFormats); + for (ContentFormat c : clientSupportContentFormats) { + if (desiredFormatsList.contains(c)) { + return c; } } - return false; + return defaultValue; } } From 5d2b4508cdb47fa01e22a72ee8872d20803b89de Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 22 May 2024 13:35:18 +0300 Subject: [PATCH 2/2] lwm2m: getDefault content Format for Request --- .../DefaultLwM2mDownlinkMsgHandler.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) 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 15171b168f..77e427fc77 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 @@ -114,6 +114,8 @@ import static org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes.OBJE import static org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes.SERVER_URI; import static org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes.SHORT_SERVER_ID; 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.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; @@ -739,8 +741,21 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im private static ContentFormat getRequestContentFormat(LwM2mClient client, String versionedId, LwM2mModelProvider modelProvider) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); - if (pathIds.isResourceInstance()) { - return findFirstContentFormatForComp(client.getClientSupportContentFormats(), client.getDefaultContentFormat(), ContentFormat.CBOR, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON); + if (pathIds.isResourceInstance() || pathIds.isResource()) { + ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); + if (resourceModel != null && (pathIds.isResourceInstance() || (pathIds.isResource() && !resourceModel.multiple))) { + ContentFormat[] desiredFormats; + if (OBJLNK.equals(resourceModel.type)) { + desiredFormats = new ContentFormat[]{ContentFormat.LINK, ContentFormat.CBOR, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON}; + } else if (OPAQUE.equals(resourceModel.type)) { + desiredFormats = new ContentFormat[]{ContentFormat.OPAQUE, ContentFormat.CBOR, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON}; + } else { + desiredFormats = new ContentFormat[]{ContentFormat.CBOR, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON}; + } + return findFirstContentFormatForComp(client.getClientSupportContentFormats(), client.getDefaultContentFormat(), desiredFormats); + } else { + return getContentFormatForComplex(client); + } } else { return getContentFormatForComplex(client); } @@ -748,9 +763,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im private static ContentFormat getContentFormatForComplex(LwM2mClient client) { if (LwM2m.LwM2mVersion.V1_0.equals(client.getRegistration().getLwM2mVersion())) { - return ContentFormat.TLV; + return client.getDefaultContentFormat(); } else if (LwM2m.LwM2mVersion.V1_1.equals(client.getRegistration().getLwM2mVersion())) { - ContentFormat result = findFirstContentFormatForComp(client.getClientSupportContentFormats(), null, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON, ContentFormat.TLV, ContentFormat.JSON); + ContentFormat result = findFirstContentFormatForComp(client.getClientSupportContentFormats(), client.getDefaultContentFormat(), ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON, ContentFormat.TLV, ContentFormat.JSON); if (result != null) { return result; } else {