From 99238feae030b6f5f340aafb6ce3561d11d94a85 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 24 Jun 2021 18:28:27 +0300 Subject: [PATCH 1/4] Lwm2m: composite read/write --- .../lwm2m/server/LwM2mOperationType.java | 36 +++--- .../lwm2m/server/LwM2mTransportUtil.java | 1 + .../DefaultLwM2mDownlinkMsgHandler.java | 107 +++++++++++++++++- .../server/downlink/HasContentFormat.java | 6 +- .../downlink/LwM2mDownlinkMsgHandler.java | 7 ++ .../downlink/TbLwM2MObserveRequest.java | 6 +- .../TbLwM2MReadCompositeCallback.java | 38 +++++++ .../downlink/TbLwM2MReadCompositeRequest.java | 44 +++++++ .../server/downlink/TbLwM2MReadRequest.java | 6 +- .../downlink/TbLwM2MTargetedCallback.java | 6 +- .../TbLwM2MWriteCompositeRequest.java | 45 ++++++++ ...TbLwM2MWriteResponseCompositeCallback.java | 36 ++++++ .../uplink/DefaultLwM2MUplinkMsgHandler.java | 41 ++++++- .../server/uplink/LwM2mUplinkMsgHandler.java | 6 + 14 files changed, 354 insertions(+), 31 deletions(-) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeCallback.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeRequest.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteCompositeRequest.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCompositeCallback.java diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java index f9b3f93854..29a8bd1626 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java @@ -23,37 +23,41 @@ import lombok.Getter; public enum LwM2mOperationType { READ(0, "Read", true), - DISCOVER(1, "Discover", true), - DISCOVER_ALL(2, "DiscoverAll", false), - OBSERVE_READ_ALL(3, "ObserveReadAll", false), + READ_COMPOSITE(1, "ReadComposite", true), + DISCOVER(2, "Discover", true), + DISCOVER_ALL(3, "DiscoverAll", false), + OBSERVE_READ_ALL(4, "ObserveReadAll", false), - OBSERVE(4, "Observe", true), - OBSERVE_CANCEL(5, "ObserveCancel", true), - OBSERVE_CANCEL_ALL(6, "ObserveCancelAll", false), - EXECUTE(7, "Execute", true), + OBSERVE(5, "Observe", true), + OBSERVE_COMPOSITE(6, "ObserveComposite", true), + OBSERVE_CANCEL(7, "ObserveCancel", true), + OBSERVE_COMPOSITE_CANCEL(8, "ObserveCompositeCancel", true), + OBSERVE_CANCEL_ALL(9, "ObserveCancelAll", false), + EXECUTE(10, "Execute", true), /** * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see * section 5.3.3 of the LW M2M spec). * if all resources are to be replaced */ - WRITE_REPLACE(8, "WriteReplace", true), + WRITE_REPLACE(11, "WriteReplace", true), /** * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section * 5.3.3 of the LW M2M spec). * if this is a partial update request */ - WRITE_UPDATE(9, "WriteUpdate", true), - WRITE_ATTRIBUTES(10, "WriteAttributes", true), - DELETE(11, "Delete", true), + WRITE_UPDATE(12, "WriteUpdate", true), + WRITE_COMPOSITE(14, "WriteComposite", true), + WRITE_ATTRIBUTES(15, "WriteAttributes", true), + DELETE(16, "Delete", true), // only for RPC - FW_UPDATE(12, "FirmwareUpdate", false); + FW_UPDATE(17, "FirmwareUpdate", false); -// FW_READ_INFO(12, "FirmwareReadInfo"), -// SW_READ_INFO(15, "SoftwareReadInfo"), -// SW_UPDATE(16, "SoftwareUpdate"), -// SW_UNINSTALL(18, "SoftwareUninstall"); +// FW_READ_INFO(18, "FirmwareReadInfo"), +// SW_READ_INFO(19, "SoftwareReadInfo"), +// SW_UPDATE(20, "SoftwareUpdate"), +// SW_UNINSTALL(21, "SoftwareUninstall"); @Getter private final int code; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java index bbab28ded5..048d363205 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java @@ -450,4 +450,5 @@ public class LwM2mTransportUtil { } return lwm2mResourceValue; } + } 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 52ef83bf8e..041b7aea41 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 @@ -31,17 +31,21 @@ import org.eclipse.leshan.core.request.DeleteRequest; import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.request.ExecuteRequest; import org.eclipse.leshan.core.request.ObserveRequest; +import org.eclipse.leshan.core.request.ReadCompositeRequest; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.request.SimpleDownlinkRequest; import org.eclipse.leshan.core.request.WriteAttributesRequest; +import org.eclipse.leshan.core.request.WriteCompositeRequest; import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.response.DeleteResponse; import org.eclipse.leshan.core.response.DiscoverResponse; import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.core.response.LwM2mResponse; import org.eclipse.leshan.core.response.ObserveResponse; +import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteAttributesResponse; +import org.eclipse.leshan.core.response.WriteCompositeResponse; import org.eclipse.leshan.core.response.WriteResponse; import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.registration.Registration; @@ -54,6 +58,7 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; @@ -63,6 +68,7 @@ import java.util.Collection; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; @@ -110,10 +116,36 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback) { validateVersionedId(client, request); - ReadRequest downlink = new ReadRequest(getContentFormat(client, request), request.getObjectId()); + ReadRequest downlink = new ReadRequest(getRequestContentFormat(client, request), request.getObjectId()); sendRequest(client, downlink, request.getTimeout(), callback); } + @Override +// public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback) { + public void sendReadCompositeRequest(LwM2mClient client, String [] paths, DefaultLwM2MUplinkMsgHandler lwM2MUplinkMsgHandler) { +// validateVersionedId(client, request); + DownlinkRequestCallback callback = new TbLwM2MReadCompositeCallback(lwM2MUplinkMsgHandler, logService, client, null); + ContentFormat requestContentFormat = ContentFormat.SENML_JSON; + ContentFormat responseContentFormat = ContentFormat.SENML_JSON; + ReadCompositeRequest downlink = new ReadCompositeRequest(requestContentFormat, responseContentFormat, paths); + sendReadRequestComposite(client, downlink, this.config.getTimeout(), callback); + } + + @Override + public void sendWriteCompositeRequest(LwM2mClient client, Map nodes, DefaultLwM2MUplinkMsgHandler handler) { +// ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); + TbLwM2MWriteResponseCompositeCallback callback = new TbLwM2MWriteResponseCompositeCallback (handler, logService, client, null); + ContentFormat contentFormat = ContentFormat.SENML_JSON; + try { + WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, nodes); + sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback); + } catch (Exception e) { + callback.onError(JacksonUtil.toString(nodes), e); + } + + } + + @Override public void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback) { validateVersionedId(client, request); @@ -121,7 +153,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im Set observations = context.getServer().getObservationService().getObservations(client.getRegistration()); if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) { ObserveRequest downlink; - ContentFormat contentFormat = getContentFormat(client, request); + ContentFormat contentFormat = getRequestContentFormat(client, request); if (resultIds.isResource()) { downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); } else if (resultIds.isObjectInstance()) { @@ -278,6 +310,73 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } + private , T extends LwM2mResponse> void sendWriteCompositeRequest(LwM2mClient client, WriteCompositeRequest request, long timeoutInMs, DownlinkRequestCallback callback) { + Registration registration = client.getRegistration(); + try { + logService.log(client, String.format("[%s][%s] Sending request: %s to %s", registration.getId(), registration.getSocketAddress(), request.getClass().getSimpleName(), request.getPaths())); + context.getServer().send(registration, request, timeoutInMs, response -> { + executor.submit(() -> { + try { + callback.onSuccess(request, response); + } catch (Exception e) { + log.error("[{}] failed to process successful response [{}] ", registration.getEndpoint(), response, e); + } + }); + }, e -> { + executor.submit(() -> { + callback.onError(JacksonUtil.toString(request), e); + }); + }); + } catch (Exception e) { + callback.onError(JacksonUtil.toString(request), e); + } + } + + private , T extends LwM2mResponse> void sendReadRequestComposite(LwM2mClient client, ReadCompositeRequest request, long timeoutInMs, DownlinkRequestCallback callback) { + Registration registration = client.getRegistration(); + try { + logService.log(client, String.format("[%s][%s] Sending request: %s to %s", registration.getId(), registration.getSocketAddress(), request.getClass().getSimpleName(), request.getPaths())); + context.getServer().send(registration, request, timeoutInMs, response -> { + executor.submit(() -> { + try { + /** + * [{"bn":"/3/0/","n":"0","vs":"Thingsboard Test Device"}, + * {"n":"1","vs":"Model 500"}, + * {"n":"2","vs":"TH-500-000-0001"}, + * {"n":"3","vs":"TestThingsboard@TestMore1024_2.04"}, + * {"n":"6","v":1},{"n":"7","v":56}, + * {"n":"8","v":42},{"n":"9","v":16}, + * {"n":"10","v":127619},{"n":"13","v":1624520988}, + * {"n":"14","vs":"+03"},{"n":"15","vs":"Europe/Kiev"}, + * {"n":"16","vs":"U"},{"n":"17","vs":"smart meters"}, + * {"n":"18","vs":"1.01"},{"n":"19","vs":"1.02"}, + * {"n":"20","v":3},{"n":"21","v":256000}, + * {"bn":"/5/0/","n":"1","vs":""}, + * {"n":"3","v":0},{"n":"5","v":0}, + * {"n":"6","vs":""},{"n":"7","vs":""}, + * {"n":"8/0","v":0},{"n":"8/1","v":1}, + * {"n":"9","v":2}, + * {"bn":"/1/0/","n":"0","v":123}, + * {"n":"1","v":300}, + * {"n":"6","vb":false}, + * {"n":"22","vs":"U"}, + * {"n":"7","vs":"U"}] + */ + callback.onSuccess(request, response); + } catch (Exception e) { + log.error("[{}] failed to process successful response [{}] ", registration.getEndpoint(), response, e); + } + }); + }, e -> { + executor.submit(() -> { + callback.onError(JacksonUtil.toString(request), e); + }); + }); + } catch (Exception e) { + callback.onError(JacksonUtil.toString(request), e); + } + } + private WriteRequest getWriteRequestSingleResource(ResourceModel.Type type, ContentFormat contentFormat, int objectId, int instanceId, int resourceId, Object value) { switch (type) { case STRING: // String @@ -347,7 +446,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im throw new CodecException("Invalid ResourceModel_Type for %s ContentFormat.", type); } - private static ContentFormat getContentFormat(LwM2mClient client, HasContentFormat request) { - return request.getContentFormat() != null ? request.getContentFormat() : client.getDefaultContentFormat(); + private static ContentFormat getRequestContentFormat(LwM2mClient client, HasContentFormat request) { + return request.getRequestContentFormat() != null ? request.getRequestContentFormat() : client.getDefaultContentFormat(); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasContentFormat.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasContentFormat.java index 6d2ecc98ed..f2618224e7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasContentFormat.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasContentFormat.java @@ -19,5 +19,9 @@ import org.eclipse.leshan.core.request.ContentFormat; public interface HasContentFormat { - ContentFormat getContentFormat(); + ContentFormat getRequestContentFormat(); + + default ContentFormat getResponseContentFormat() { + return null; + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java index adb2e32293..48fe411e16 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java @@ -31,14 +31,19 @@ import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteAttributesResponse; import org.eclipse.leshan.core.response.WriteResponse; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; import java.util.List; +import java.util.Map; import java.util.Set; public interface LwM2mDownlinkMsgHandler { void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback); +// void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback); + void sendReadCompositeRequest(LwM2mClient client, String [] paths, DefaultLwM2MUplinkMsgHandler lwM2MUplinkMsgHandler); + void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback); void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback> callback); @@ -59,6 +64,8 @@ public interface LwM2mDownlinkMsgHandler { void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback callback); + void sendWriteCompositeRequest(LwM2mClient client, Map nodes, DefaultLwM2MUplinkMsgHandler handler); + void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback callback); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java index f3348aa2c9..0d13b4a1ff 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MObserveRequest.java @@ -24,12 +24,12 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; public class TbLwM2MObserveRequest extends AbstractTbLwM2MTargetedDownlinkRequest implements HasContentFormat { @Getter - private final ContentFormat contentFormat; + private final ContentFormat requestContentFormat; @Builder - private TbLwM2MObserveRequest(String versionedId, long timeout, ContentFormat contentFormat) { + private TbLwM2MObserveRequest(String versionedId, long timeout, ContentFormat requestContentFormat) { super(versionedId, timeout); - this.contentFormat = contentFormat; + this.requestContentFormat = requestContentFormat; } @Override diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeCallback.java new file mode 100644 index 0000000000..4dbece6daa --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeCallback.java @@ -0,0 +1,38 @@ +/** + * Copyright © 2016-2021 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.server.downlink; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.request.ReadCompositeRequest; +import org.eclipse.leshan.core.response.ReadCompositeResponse; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; + +@Slf4j +public class TbLwM2MReadCompositeCallback extends TbLwM2MUplinkTargetedCallback { + + public TbLwM2MReadCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + super(handler, logService, client, targetId); + } + + @Override + public void onSuccess(ReadCompositeRequest request, ReadCompositeResponse response) { + super.onSuccess(request, response); + handler.onUpdateValueAfterReadCompositeResponse(client.getRegistration(), versionedId, response); + } + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeRequest.java new file mode 100644 index 0000000000..1e45427aba --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeRequest.java @@ -0,0 +1,44 @@ +/** + * Copyright © 2016-2021 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.server.downlink; + +import lombok.Builder; +import lombok.Getter; +import org.eclipse.leshan.core.request.ContentFormat; +import org.eclipse.leshan.core.response.ReadCompositeResponse; +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; + +public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlinkRequest implements HasContentFormat { + + @Getter + private final ContentFormat requestContentFormat; + + @Getter + private final ContentFormat responseContentFormat; + + @Builder + private TbLwM2MReadCompositeRequest(String versionedId, long timeout, ContentFormat requestContentFormat, ContentFormat responseContentFormat) { + super(versionedId, timeout); + this.requestContentFormat = requestContentFormat; + this.responseContentFormat = responseContentFormat; + } + + @Override + public LwM2mOperationType getType() { + return LwM2mOperationType.READ_COMPOSITE; + } + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java index a07e738465..6f388237c2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadRequest.java @@ -24,12 +24,12 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; public class TbLwM2MReadRequest extends AbstractTbLwM2MTargetedDownlinkRequest implements HasContentFormat { @Getter - private final ContentFormat contentFormat; + private final ContentFormat requestContentFormat; @Builder - private TbLwM2MReadRequest(String versionedId, long timeout, ContentFormat contentFormat) { + private TbLwM2MReadRequest(String versionedId, long timeout, ContentFormat requestContentFormat) { super(versionedId, timeout); - this.contentFormat = contentFormat; + this.requestContentFormat = requestContentFormat; } @Override diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java index 373c882ec4..a7d0572b38 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java @@ -18,7 +18,6 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; @@ -32,6 +31,11 @@ public abstract class TbLwM2MTargetedCallback extends AbstractTbLwM2MReque this.versionedId = versionedId; } + public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client) { + super(logService, client); + this.versionedId = null; + } + @Override public void onSuccess(R request, T response) { //TODO convert camelCase to "camel case" using .split("(? { + + @Getter + private final ContentFormat contentFormat; + @Getter + private final Object value; + + @Builder + private TbLwM2MWriteCompositeRequest(String versionedId, long timeout, ContentFormat contentFormat, Object value) { + super(versionedId, timeout); + this.contentFormat = contentFormat; + this.value = value; + } + + @Override + public LwM2mOperationType getType() { + return LwM2mOperationType.WRITE_REPLACE; + } + + + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCompositeCallback.java new file mode 100644 index 0000000000..0d681ed486 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCompositeCallback.java @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2021 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.server.downlink; + +import org.eclipse.leshan.core.request.WriteCompositeRequest; +import org.eclipse.leshan.core.response.WriteCompositeResponse; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; + +public class TbLwM2MWriteResponseCompositeCallback extends TbLwM2MUplinkTargetedCallback { + + public TbLwM2MWriteResponseCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { + super(handler, logService, client, targetId); + } + + @Override + public void onSuccess(WriteCompositeRequest request, WriteCompositeResponse response) { + super.onSuccess(request, response); + handler.onWriteCompositeResponseOk(client, request); + } + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index 1d14de3ba0..ad13254f37 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -30,14 +30,15 @@ import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.request.ObserveRequest; import org.eclipse.leshan.core.request.ReadRequest; +import org.eclipse.leshan.core.request.WriteCompositeRequest; import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.response.ObserveResponse; +import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.server.registration.Registration; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.common.util.DonAsynchron; -import org.thingsboard.server.cache.ota.OtaPackageDataCache; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.StringUtils; @@ -83,8 +84,6 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest; 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.ota.firmware.LwM2MFirmwareUpdateStrategy; -import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareUpdateStrategy; import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; @@ -94,6 +93,7 @@ import javax.annotation.PreDestroy; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -354,6 +354,22 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } + public void onUpdateValueAfterReadCompositeResponse(Registration registration, String path, ReadCompositeResponse response) { + log.warn("201) ReadCompositeResponse: [{}]", response); + if (response.getContent() != null) { + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); + response.getContent().forEach((k, v) -> { + if (v instanceof LwM2mObject) { + this.updateObjectResourceValue(lwM2MClient, (LwM2mObject) v, k.toString()); + } else if (v instanceof LwM2mObjectInstance) { + this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString()); + } else if (v instanceof LwM2mResource) { + this.updateResourcesValue(lwM2MClient, (LwM2mResource) v, k.toString()); + } + }); + } + } + /** * @param sessionInfo - * @param deviceProfile - @@ -429,6 +445,17 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl if (supportedObjects != null && supportedObjects.size() > 0) { // #1 this.sendReadRequests(lwM2MClient, profile, supportedObjects); + // test composite + String[] paths = new String[]{"/3/0", "/1/0", "/5/0"}; +// String [] paths = new String[] {"/5"}; +// String [] paths = new String[] {"/"}; +// String [] paths = new String[] {"/9"}; + defaultLwM2MDownlinkMsgHandler.sendReadCompositeRequest(lwM2MClient, paths, this); + Map nodes = new HashMap<>(); + nodes.put("/3/0/14", "+02"); + nodes.put("/1/0/2", 100); + nodes.put("/5/0/1", "coap://localhost:5685"); + defaultLwM2MDownlinkMsgHandler.sendWriteCompositeRequest(lwM2MClient, nodes, this); this.sendObserveRequests(lwM2MClient, profile, supportedObjects); this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects); // Removed. Used only for debug. @@ -712,6 +739,14 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } + @Override + public void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request) { + log.warn("202) ReadCompositeResponse: [{}]", request.getNodes()); + request.getNodes().forEach((k, v) -> { + this.updateResourcesValue(client, (LwM2mResource) v, k.toString()); + }); + } + //TODO: review and optimize the logic to minimize number of the requests to device. private void onDeviceProfileUpdate(List clients, DeviceProfile deviceProfile) { var oldProfile = clientContext.getProfile(deviceProfile.getUuidId()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java index 372daa7052..7926e90907 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java @@ -16,7 +16,9 @@ package org.thingsboard.server.transport.lwm2m.server.uplink; import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.request.WriteCompositeRequest; import org.eclipse.leshan.core.request.WriteRequest; +import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.server.common.data.Device; @@ -40,6 +42,8 @@ public interface LwM2mUplinkMsgHandler { void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response); + void onUpdateValueAfterReadCompositeResponse(Registration registration, String path, ReadCompositeResponse response); + void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile); void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt); @@ -54,6 +58,8 @@ public interface LwM2mUplinkMsgHandler { void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request); + void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request); + void onToTransportUpdateCredentials(TransportProtos.ToTransportUpdateCredentialsProto updateCredentials); LwM2MTransportServerConfig getConfig(); From a94810126dfa08057f0d10f41da11dec59e5b250 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 28 Jun 2021 17:28:02 +0300 Subject: [PATCH 2/4] Lwm2m: RPC composite read --- .../device/data/lwm2m/OtherConfiguration.java | 1 + .../transport/lwm2m/config/LwM2mVersion.java | 66 +++++++++++++++++++ .../lwm2m/server/LwM2mOperationType.java | 40 +++++------ .../lwm2m/server/LwM2mTransportUtil.java | 5 +- .../lwm2m/server/client/LwM2mClient.java | 27 ++++---- .../DefaultLwM2mDownlinkMsgHandler.java | 56 +++++++++++----- .../server/downlink/HasVersionedIds.java | 35 ++++++++++ .../downlink/LwM2mDownlinkMsgHandler.java | 6 +- .../downlink/TbLwM2MTargetedCallback.java | 5 +- .../TbLwM2MUplinkTargetedCallback.java | 7 +- ...LwM2MTargetedDownlinkCompositeRequest.java | 34 ++++++++++ .../TbLwM2MReadCompositeCallback.java | 9 +-- .../TbLwM2MReadCompositeRequest.java | 10 +-- .../TbLwM2MWriteCompositeRequest.java | 3 +- ...TbLwM2MWriteResponseCompositeCallback.java | 3 +- .../rpc/DefaultLwM2MRpcRequestHandler.java | 58 +++++++++++++++- .../lwm2m/server/rpc/IdOrKeyRequest.java | 1 - .../rpc/RpcDownlinkRequestCallbackProxy.java | 4 -- .../server/rpc/RpcReadResponseCallback.java | 11 ++-- .../RpcLwM2MDownlinkCompositeCallback.java | 53 +++++++++++++++ .../composite/RpcReadCompositeRequest.java} | 17 ++--- .../RpcReadResponseCompositeCallback.java | 37 +++++++++++ .../composite/RpcWriteCompositeRequest.java | 29 ++++++++ .../uplink/DefaultLwM2MUplinkMsgHandler.java | 20 +++--- .../server/uplink/LwM2mUplinkMsgHandler.java | 2 +- 25 files changed, 438 insertions(+), 101 deletions(-) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/AbstractTbLwM2MTargetedDownlinkCompositeRequest.java rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/{ => composite}/TbLwM2MReadCompositeCallback.java (84%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/{ => composite}/TbLwM2MReadCompositeRequest.java (75%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/{ => composite}/TbLwM2MWriteCompositeRequest.java (89%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/{ => composite}/TbLwM2MWriteResponseCompositeCallback.java (90%) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcLwM2MDownlinkCompositeCallback.java rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/{client/LwM2mSoftwareUpdate.java => server/rpc/composite/RpcReadCompositeRequest.java} (70%) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcWriteCompositeRequest.java diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java index e45a3d0e31..81d9d56a8c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java @@ -27,5 +27,6 @@ public class OtherConfiguration { private PowerMode powerMode; private String fwUpdateResource; private String swUpdateResource; + private boolean composite; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java new file mode 100644 index 0000000000..15acc496d9 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java @@ -0,0 +1,66 @@ +/** + * Copyright © 2016-2021 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.config; + +import lombok.Getter; +import org.eclipse.leshan.core.LwM2m.Version; +import org.eclipse.leshan.core.request.ContentFormat; + +public enum LwM2mVersion { + VERSION_1_0(0, Version.V1_0, ContentFormat.TLV), + VERSION_1_1(1, Version.V1_1, ContentFormat.TEXT); + + @Getter + private final int code; + @Getter + private final Version version; + @Getter + private final ContentFormat contentFormat; + + LwM2mVersion(int code, Version version, ContentFormat contentFormat) { + this.code = code; + this.version = version; + this.contentFormat = contentFormat; + } + + public static LwM2mVersion fromType(Version version) { + for (LwM2mVersion to : LwM2mVersion.values()) { + if (to.version.equals(version)) { + return to; + } + } + throw new IllegalArgumentException(String.format("Unsupported typeLwM2mVersion type : %d", version)); + } + + public static ContentFormat fromContentFormat(String versionStr) { + for (LwM2mVersion to : LwM2mVersion.values()) { + if (to.version.toString().equals(versionStr)) { + return to.contentFormat; + } + } + throw new IllegalArgumentException(String.format("Unsupported contentFormatLwM2mVersion version : %d", versionStr)); + } + + public static LwM2mVersion fromCode(int code) { + for (LwM2mVersion to : LwM2mVersion.values()) { + if (to.code == code) { + return to; + } + } + throw new IllegalArgumentException(String.format("Unsupported codeLwM2mVersion code : %d", code)); + } +} + diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java index 29a8bd1626..a396847d9e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java @@ -22,37 +22,37 @@ import lombok.Getter; */ public enum LwM2mOperationType { - READ(0, "Read", true), - READ_COMPOSITE(1, "ReadComposite", true), - DISCOVER(2, "Discover", true), - DISCOVER_ALL(3, "DiscoverAll", false), - OBSERVE_READ_ALL(4, "ObserveReadAll", false), + READ(0, "Read", 1), + READ_COMPOSITE(1, "ReadComposite", 2), + DISCOVER(2, "Discover", 1), + DISCOVER_ALL(3, "DiscoverAll", 0), + OBSERVE_READ_ALL(4, "ObserveReadAll", 0), - OBSERVE(5, "Observe", true), - OBSERVE_COMPOSITE(6, "ObserveComposite", true), - OBSERVE_CANCEL(7, "ObserveCancel", true), - OBSERVE_COMPOSITE_CANCEL(8, "ObserveCompositeCancel", true), - OBSERVE_CANCEL_ALL(9, "ObserveCancelAll", false), - EXECUTE(10, "Execute", true), + OBSERVE(5, "Observe", 1), + OBSERVE_COMPOSITE(6, "ObserveComposite", 2), + OBSERVE_CANCEL(7, "ObserveCancel", 1), + OBSERVE_COMPOSITE_CANCEL(8, "ObserveCompositeCancel", 2), + OBSERVE_CANCEL_ALL(9, "ObserveCancelAll", 0), + EXECUTE(10, "Execute", 1), /** * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see * section 5.3.3 of the LW M2M spec). * if all resources are to be replaced */ - WRITE_REPLACE(11, "WriteReplace", true), + WRITE_REPLACE(11, "WriteReplace", 1), /** * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section * 5.3.3 of the LW M2M spec). * if this is a partial update request */ - WRITE_UPDATE(12, "WriteUpdate", true), - WRITE_COMPOSITE(14, "WriteComposite", true), - WRITE_ATTRIBUTES(15, "WriteAttributes", true), - DELETE(16, "Delete", true), + WRITE_UPDATE(12, "WriteUpdate", 1), + WRITE_COMPOSITE(14, "WriteComposite", 2), + WRITE_ATTRIBUTES(15, "WriteAttributes", 1), + DELETE(16, "Delete", 1), // only for RPC - FW_UPDATE(17, "FirmwareUpdate", false); + FW_UPDATE(17, "FirmwareUpdate", 0); // FW_READ_INFO(18, "FirmwareReadInfo"), // SW_READ_INFO(19, "SoftwareReadInfo"), @@ -64,12 +64,12 @@ public enum LwM2mOperationType { @Getter private final String type; @Getter - private final boolean hasObjectId; + private final int hasObjectIdOrComposite; - LwM2mOperationType(int code, String type, boolean hasObjectId) { + LwM2mOperationType(int code, String type, int hasObjectIdOrComposite) { this.code = code; this.type = type; - this.hasObjectId = hasObjectId; + this.hasObjectIdOrComposite = hasObjectIdOrComposite; } public static LwM2mOperationType fromType(String type) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java index de67d11bc8..cdac9d8fe4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java @@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfigurati import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.transport.TransportServiceCallback; +import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; @@ -85,7 +86,7 @@ import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaU @Slf4j public class LwM2mTransportUtil { - public static final String LWM2M_VERSION_DEFAULT = "1.0"; + public static final String LWM2M_OBJECT_VERSION_DEFAULT = "1.0"; public static final String LOG_LWM2M_TELEMETRY = "logLwm2m"; public static final String LOG_LWM2M_INFO = "info"; @@ -303,7 +304,7 @@ public class LwM2mTransportUtil { public static String convertObjectIdToVersionedId(String path, Registration registration) { String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId()); - ver = ver != null ? ver : LWM2M_VERSION_DEFAULT; + ver = ver != null ? ver : LwM2mVersion.VERSION_1_0.getVersion().toString(); try { String[] keyArray = path.split(LWM2M_SEPARATOR_PATH); if (keyArray.length > 1) { 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 5fa0858359..2aa7eeab2a 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 @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; +import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest; import java.util.Collection; @@ -53,7 +54,7 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_VERSION_DEFAULT; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_OBJECT_VERSION_DEFAULT; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; @@ -243,11 +244,11 @@ public class LwM2mClient implements Cloneable { .getObjectModel(pathIds.getObjectId()) : null; } - public String objectToString(LwM2mObject lwM2mObject, LwM2mValueConverter converter, String pathIdVer) { + public String objectToString(LwM2mObject lwM2mObject) { StringBuilder builder = new StringBuilder(); builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={"); lwM2mObject.getInstances().forEach((instId, inst) -> { - builder.append(instId).append("=").append(this.instanceToString(inst, converter, pathIdVer)).append(", "); + builder.append(instId).append("=").append(this.instanceToString(inst)).append(", "); }); int startInd = builder.lastIndexOf(", "); if (startInd > 0) { @@ -257,11 +258,11 @@ public class LwM2mClient implements Cloneable { return builder.toString(); } - public String instanceToString(LwM2mObjectInstance objectInstance, LwM2mValueConverter converter, String pathIdVer) { + public String instanceToString(LwM2mObjectInstance objectInstance) { StringBuilder builder = new StringBuilder(); builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={"); objectInstance.getResources().forEach((resId, res) -> { - builder.append(resId).append("=").append(this.resourceToString(res, converter, pathIdVer)).append(", "); + builder.append(resId).append("=").append(this.resourceToString(res)).append(", "); }); int startInd = builder.lastIndexOf(", "); if (startInd > 0) { @@ -271,8 +272,9 @@ public class LwM2mClient implements Cloneable { return builder.toString(); } - public String resourceToString(LwM2mResource lwM2mResource, LwM2mValueConverter converter, String pathIdVer) { - return lwM2mResource.getValue().toString(); + public String resourceToString(LwM2mResource lwM2mResource) { + + return lwM2mResource.isMultiInstances() ? lwM2mResource.getInstances().toString() : lwM2mResource.getValue().toString(); } public Collection getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider, @@ -308,11 +310,14 @@ public class LwM2mClient implements Cloneable { return resources; } - public boolean isValidObjectVersion(String path) { + public void isValidObjectVersion(String path) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path)); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); String verRez = getVerFromPathIdVerOrId(path); - return verRez == null ? LWM2M_VERSION_DEFAULT.equals(verSupportedObject) : verRez.equals(verSupportedObject); + if ((verRez != null && !verRez.equals(verSupportedObject)) || + (verRez == null && !LWM2M_OBJECT_VERSION_DEFAULT.equals(verSupportedObject))) { + throw new IllegalArgumentException(String.format("Specified resource id %s is not valid version! Must be version: %s", path, verSupportedObject)); + } } /** @@ -357,10 +362,8 @@ public class LwM2mClient implements Cloneable { public ContentFormat getDefaultContentFormat() { if (registration == null) { return ContentFormat.DEFAULT; - } else if (registration.getLwM2mVersion().equals("1.0")) { - return ContentFormat.TLV; } else { - return ContentFormat.TEXT; + return LwM2mVersion.fromContentFormat(registration.getLwM2mVersion()); } } 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 041b7aea41..48814242df 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 @@ -57,6 +57,8 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService; +import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest; +import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MWriteResponseCompositeCallback; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; @@ -79,6 +81,7 @@ import static org.eclipse.leshan.core.attributes.Attribute.LESSER_THAN; import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD; import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD; import static org.eclipse.leshan.core.attributes.Attribute.STEP; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; @Slf4j @Service @@ -121,27 +124,26 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } @Override -// public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback) { - public void sendReadCompositeRequest(LwM2mClient client, String [] paths, DefaultLwM2MUplinkMsgHandler lwM2MUplinkMsgHandler) { -// validateVersionedId(client, request); - DownlinkRequestCallback callback = new TbLwM2MReadCompositeCallback(lwM2MUplinkMsgHandler, logService, client, null); + public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback) { + validateVersionedIds(client, request); ContentFormat requestContentFormat = ContentFormat.SENML_JSON; ContentFormat responseContentFormat = ContentFormat.SENML_JSON; - ReadCompositeRequest downlink = new ReadCompositeRequest(requestContentFormat, responseContentFormat, paths); + + ReadCompositeRequest downlink = new ReadCompositeRequest(requestContentFormat, responseContentFormat, request.getObjectIds()); sendReadRequestComposite(client, downlink, this.config.getTimeout(), callback); } @Override public void sendWriteCompositeRequest(LwM2mClient client, Map nodes, DefaultLwM2MUplinkMsgHandler handler) { // ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); - TbLwM2MWriteResponseCompositeCallback callback = new TbLwM2MWriteResponseCompositeCallback (handler, logService, client, null); - ContentFormat contentFormat = ContentFormat.SENML_JSON; - try { - WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, nodes); - sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback); - } catch (Exception e) { - callback.onError(JacksonUtil.toString(nodes), e); - } + TbLwM2MWriteResponseCompositeCallback callback = new TbLwM2MWriteResponseCompositeCallback(handler, logService, client, null); + ContentFormat contentFormat = ContentFormat.SENML_JSON; + try { + WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, nodes); + sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback); + } catch (Exception e) { + callback.onError(JacksonUtil.toString(nodes), e); + } } @@ -277,7 +279,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im */ Collection resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); if (resources.size() > 0) { - ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : client.getDefaultContentFormat(); + ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : ContentFormat.DEFAULT; WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resources); sendRequest(client, downlink, request.getTimeout(), callback); } else { @@ -407,14 +409,23 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } private void validateVersionedId(LwM2mClient client, HasVersionedId request) { - if (!client.isValidObjectVersion(request.getVersionedId())) { - throw new IllegalArgumentException("Specified resource id is not configured in the device profile!"); - } + client.isValidObjectVersion(request.getVersionedId()); if (request.getObjectId() == null) { throw new IllegalArgumentException("Specified object id is null!"); } } + private void validateVersionedIds(LwM2mClient client, HasVersionedIds request) { + for (String versionedId : request.getVersionedIds()) { + client.isValidObjectVersion(versionedId); + } + for (String objectId : request.getObjectIds()) { + if (objectId == null) { + throw new IllegalArgumentException("Specified object id is null!"); + } + } + } + private static void addAttribute(List attributes, String attributeName, T value) { addAttribute(attributes, attributeName, value, null, null); } @@ -447,6 +458,15 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } private static ContentFormat getRequestContentFormat(LwM2mClient client, HasContentFormat request) { - return request.getRequestContentFormat() != null ? request.getRequestContentFormat() : client.getDefaultContentFormat(); + if (request.getRequestContentFormat() != null) { + return request.getRequestContentFormat(); + } else { + String versionedId = fromVersionedIdToObjectId(((TbLwM2MReadRequest) request).getVersionedId()); + if (versionedId != null && (new LwM2mPath(versionedId).isObject() || new LwM2mPath(versionedId).isObjectInstance())) { + return ContentFormat.DEFAULT; + } else { + return client.getDefaultContentFormat(); + } + } } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java new file mode 100644 index 0000000000..d0b920ca1c --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java @@ -0,0 +1,35 @@ +/** + * Copyright © 2016-2021 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.server.downlink; + +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public interface HasVersionedIds { + + String[] getVersionedIds(); + + default String[] getObjectIds() { + Set objectIds = ConcurrentHashMap.newKeySet(); + for (String versionedId : getVersionedIds()) { + objectIds.add(LwM2mTransportUtil.fromVersionedIdToObjectId(versionedId)); + } + return (String[]) objectIds.toArray(String[]::new); + } + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java index 48fe411e16..04c63aec17 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java @@ -20,6 +20,7 @@ import org.eclipse.leshan.core.request.DeleteRequest; import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.request.ExecuteRequest; import org.eclipse.leshan.core.request.ObserveRequest; +import org.eclipse.leshan.core.request.ReadCompositeRequest; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.request.WriteAttributesRequest; import org.eclipse.leshan.core.request.WriteRequest; @@ -27,10 +28,12 @@ import org.eclipse.leshan.core.response.DeleteResponse; import org.eclipse.leshan.core.response.DiscoverResponse; import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.core.response.ObserveResponse; +import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteAttributesResponse; import org.eclipse.leshan.core.response.WriteResponse; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; import java.util.List; @@ -41,8 +44,7 @@ public interface LwM2mDownlinkMsgHandler { void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback); -// void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback); - void sendReadCompositeRequest(LwM2mClient client, String [] paths, DefaultLwM2MUplinkMsgHandler lwM2MUplinkMsgHandler); + void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback callback); void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback callback); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java index a7d0572b38..54eaa1ce7c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java @@ -25,15 +25,18 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L public abstract class TbLwM2MTargetedCallback extends AbstractTbLwM2MRequestCallback { protected final String versionedId; + protected final String[] versionedIds; public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) { super(logService, client); this.versionedId = versionedId; + this.versionedIds = null; } - public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client) { + public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { super(logService, client); this.versionedId = null; + this.versionedIds = versionedIds; } @Override diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java index 2cb717108d..520d49eb30 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java @@ -20,8 +20,6 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; - @Slf4j public abstract class TbLwM2MUplinkTargetedCallback extends TbLwM2MTargetedCallback { @@ -32,4 +30,9 @@ public abstract class TbLwM2MUplinkTargetedCallback extends TbLwM2MTargete this.handler = handler; } + public TbLwM2MUplinkTargetedCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { + super(logService, client, versionedIds); + this.handler = handler; + } + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/AbstractTbLwM2MTargetedDownlinkCompositeRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/AbstractTbLwM2MTargetedDownlinkCompositeRequest.java new file mode 100644 index 0000000000..1625e5aad0 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/AbstractTbLwM2MTargetedDownlinkCompositeRequest.java @@ -0,0 +1,34 @@ +/** + * Copyright © 2016-2021 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.server.downlink.composite; + +import lombok.Getter; +import org.thingsboard.server.transport.lwm2m.server.downlink.HasVersionedIds; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDownlinkRequest; + +public abstract class AbstractTbLwM2MTargetedDownlinkCompositeRequest implements TbLwM2MDownlinkRequest, HasVersionedIds { + + @Getter + private final String [] versionedIds; + @Getter + private final long timeout; + + public AbstractTbLwM2MTargetedDownlinkCompositeRequest(String [] versionedIds, long timeout) { + this.versionedIds = versionedIds; + this.timeout = timeout; + } + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java similarity index 84% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeCallback.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java index 4dbece6daa..82e0936b87 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java @@ -13,26 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.server.downlink; +package org.thingsboard.server.transport.lwm2m.server.downlink.composite; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.request.ReadCompositeRequest; import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MUplinkTargetedCallback; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; @Slf4j public class TbLwM2MReadCompositeCallback extends TbLwM2MUplinkTargetedCallback { - public TbLwM2MReadCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { - super(handler, logService, client, targetId); + public TbLwM2MReadCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { + super(handler, logService, client, versionedIds); } @Override public void onSuccess(ReadCompositeRequest request, ReadCompositeResponse response) { super.onSuccess(request, response); - handler.onUpdateValueAfterReadCompositeResponse(client.getRegistration(), versionedId, response); + handler.onUpdateValueAfterReadCompositeResponse(client.getRegistration(), response); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java similarity index 75% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeRequest.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java index 1e45427aba..43b55f371f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.server.downlink; +package org.thingsboard.server.transport.lwm2m.server.downlink.composite; import lombok.Builder; import lombok.Getter; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.downlink.HasContentFormat; -public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlinkRequest implements HasContentFormat { +public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlinkCompositeRequest implements HasContentFormat { @Getter private final ContentFormat requestContentFormat; @@ -30,8 +31,8 @@ public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlink private final ContentFormat responseContentFormat; @Builder - private TbLwM2MReadCompositeRequest(String versionedId, long timeout, ContentFormat requestContentFormat, ContentFormat responseContentFormat) { - super(versionedId, timeout); + private TbLwM2MReadCompositeRequest(String [] versionedIds, long timeout, ContentFormat requestContentFormat, ContentFormat responseContentFormat) { + super(versionedIds, timeout); this.requestContentFormat = requestContentFormat; this.responseContentFormat = responseContentFormat; } @@ -40,5 +41,4 @@ public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlink public LwM2mOperationType getType() { return LwM2mOperationType.READ_COMPOSITE; } - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteCompositeRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteCompositeRequest.java similarity index 89% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteCompositeRequest.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteCompositeRequest.java index 5dbdbe5185..0e3ffaed28 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteCompositeRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteCompositeRequest.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.server.downlink; +package org.thingsboard.server.transport.lwm2m.server.downlink.composite; import lombok.Builder; import lombok.Getter; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.response.WriteCompositeResponse; import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; +import org.thingsboard.server.transport.lwm2m.server.downlink.AbstractTbLwM2MTargetedDownlinkRequest; public class TbLwM2MWriteCompositeRequest extends AbstractTbLwM2MTargetedDownlinkRequest { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java similarity index 90% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCompositeCallback.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java index 0d681ed486..9dccc98185 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCompositeCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.server.downlink; +package org.thingsboard.server.transport.lwm2m.server.downlink.composite; import org.eclipse.leshan.core.request.WriteCompositeRequest; import org.eclipse.leshan.core.response.WriteCompositeResponse; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MUplinkTargetedCallback; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 0432a5b742..c5b80b30fd 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -50,7 +50,12 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteUpdateRequest; +import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeCallback; +import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; +import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadCompositeRequest; +import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadResponseCompositeCallback; +import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import java.util.Map; @@ -92,7 +97,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { return; } try { - if (operationType.isHasObjectId()) { + if (operationType.getHasObjectIdOrComposite() == 1) { String objectId = getIdFromParameters(client, rpcRequst); switch (operationType) { case READ: @@ -125,6 +130,17 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { default: throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); } + } else if (operationType.getHasObjectIdOrComposite() == 2) { + switch (operationType) { + case READ_COMPOSITE: + sendReadCompositeRequest(client, rpcRequst); + break; + case WRITE_COMPOSITE: + sendWriteCompositeRequest(client, rpcRequst); + break; + default: + throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); + } } else { switch (operationType) { case OBSERVE_CANCEL_ALL: @@ -151,14 +167,22 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { private void sendReadRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); var mainCallback = new TbLwM2MReadCallback(uplinkHandler, logService, client, versionedId); - var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, versionedId, mainCallback); + var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, mainCallback); downlinkHandler.sendReadRequest(client, request, rpcCallback); } + private void sendReadCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { + String[] versionedIds = getIdsFromParameters(client, requestMsg); + TbLwM2MReadCompositeRequest request = TbLwM2MReadCompositeRequest.builder().versionedIds(versionedIds).timeout(this.config.getTimeout()).build(); + var mainCallback = new TbLwM2MReadCompositeCallback(uplinkHandler, logService, client, versionedIds); + var rpcCallback = new RpcReadResponseCompositeCallback(transportService, client, requestMsg, mainCallback); + downlinkHandler.sendReadCompositeRequest(client, request, rpcCallback); + } + private void sendObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); var mainCallback = new TbLwM2MObserveCallback(uplinkHandler, logService, client, versionedId); - var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, versionedId, mainCallback); + var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, mainCallback); downlinkHandler.sendObserveRequest(client, request, rpcCallback); } @@ -215,6 +239,16 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback); } + private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { + RpcWriteCompositeRequest nodes = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class); +// TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId) +// .value(requestBody.getValue()) +// .timeout(this.config.getTimeout()).build(); +// var mainCallback = new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId); +// var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback); +// downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback); + } + private void sendCancelObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { TbLwM2MCancelObserveRequest downlink = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); var mainCallback = new TbLwM2MCancelObserveCallback(logService, client, versionedId); @@ -249,6 +283,24 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { return targetId; } + private String[] getIdsFromParameters(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequst) { + RpcReadCompositeRequest requestParams = JacksonUtil.fromString(rpcRequst.getParams(), RpcReadCompositeRequest.class); + if (requestParams.getKeys() != null && requestParams.getKeys().length > 0) { + Set targetIds = ConcurrentHashMap.newKeySet(); + for (String key : requestParams.getKeys()) { + String targetId = clientContext.getObjectIdByKeyNameFromProfile(client, key); + if (targetId != null) { + targetIds.add(targetId); + } + } + return (String[]) targetIds.toArray(String[]::new); + } else if (requestParams.getIds() != null && requestParams.getIds().length > 0) { + return requestParams.getIds(); + } else { + throw new IllegalArgumentException("Can't find 'key' or 'id' in the requestParams parameters!"); + } + } + private void sendErrorRpcResponse(TransportProtos.SessionInfoProto sessionInfo, int requestId, String result, String error) { String payload = JacksonUtil.toString(JacksonUtil.newObjectNode().put("result", result).put("error", error)); TransportProtos.ToDeviceRpcResponseMsg msg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId).setPayload(payload).build(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/IdOrKeyRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/IdOrKeyRequest.java index 77d8cd3ea1..bef4fa37e8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/IdOrKeyRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/IdOrKeyRequest.java @@ -24,5 +24,4 @@ public class IdOrKeyRequest { private String key; private String id; - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java index 115680b50f..c2e9a43ded 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java @@ -16,13 +16,11 @@ package org.thingsboard.server.transport.lwm2m.server.rpc; import org.eclipse.leshan.core.ResponseCode; -import org.eclipse.leshan.core.node.codec.LwM2mValueConverter; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; public abstract class RpcDownlinkRequestCallbackProxy implements DownlinkRequestCallback { @@ -31,14 +29,12 @@ public abstract class RpcDownlinkRequestCallbackProxy implements DownlinkR private final DownlinkRequestCallback callback; protected final LwM2mClient client; - protected final LwM2mValueConverter converter; public RpcDownlinkRequestCallbackProxy(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { this.transportService = transportService; this.client = client; this.request = requestMsg; this.callback = callback; - this.converter = LwM2mValueConverterImpl.getInstance(); } @Override diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java index d3da6e6a3f..6f7eb4b2b7 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java @@ -29,22 +29,19 @@ import java.util.Optional; public class RpcReadResponseCallback, T extends ReadResponse> extends RpcLwM2MDownlinkCallback { - private final String versionedId; - - public RpcReadResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId, DownlinkRequestCallback callback) { + public RpcReadResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); - this.versionedId = versionedId; } @Override protected Optional serializeSuccessfulResponse(T response) { Object value = null; if (response.getContent() instanceof LwM2mObject) { - value = client.objectToString((LwM2mObject) response.getContent(), this.converter, versionedId); + value = client.objectToString((LwM2mObject) response.getContent()); } else if (response.getContent() instanceof LwM2mObjectInstance) { - value = client.instanceToString((LwM2mObjectInstance) response.getContent(), this.converter, versionedId); + value = client.instanceToString((LwM2mObjectInstance) response.getContent()); } else if (response.getContent() instanceof LwM2mResource) { - value = client.resourceToString((LwM2mResource) response.getContent(), this.converter, versionedId); + value = client.resourceToString((LwM2mResource) response.getContent()); } return Optional.of(String.format("%s", value)); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcLwM2MDownlinkCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcLwM2MDownlinkCompositeCallback.java new file mode 100644 index 0000000000..6b629b450f --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcLwM2MDownlinkCompositeCallback.java @@ -0,0 +1,53 @@ +/** + * Copyright © 2016-2021 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.server.rpc.composite; + +import org.eclipse.leshan.core.request.ReadCompositeRequest; +import org.eclipse.leshan.core.response.ReadCompositeResponse; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; +import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcResponseBody; +import org.thingsboard.server.transport.lwm2m.server.rpc.RpcDownlinkRequestCallbackProxy; + +import java.util.Optional; + +public abstract class RpcLwM2MDownlinkCompositeCallback extends RpcDownlinkRequestCallbackProxy { + + public RpcLwM2MDownlinkCompositeCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + super(transportService, client, requestMsg, callback); + } + + @Override + protected void sendRpcReplyOnSuccess(T response) { + LwM2MRpcResponseBody.LwM2MRpcResponseBodyBuilder builder = LwM2MRpcResponseBody.builder().result(response.getCode().getName()); + if (response.isSuccess()) { + Optional responseValue = serializeSuccessfulResponse(response); + if (responseValue.isPresent() && StringUtils.isNotEmpty(responseValue.get())) { + builder.value(responseValue.get()); + } + } else { + if (StringUtils.isNotEmpty(response.getErrorMessage())) { + builder.error(response.getErrorMessage()); + } + } + reply(builder.build()); + } + + protected abstract Optional serializeSuccessfulResponse(T response); +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/client/LwM2mSoftwareUpdate.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadCompositeRequest.java similarity index 70% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/client/LwM2mSoftwareUpdate.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadCompositeRequest.java index ed8b316fed..ccd4767fee 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/client/LwM2mSoftwareUpdate.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadCompositeRequest.java @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.client; +package org.thingsboard.server.transport.lwm2m.server.rpc.composite; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; -import java.util.UUID; - @Data -public class LwM2mSoftwareUpdate { - private volatile String clientSwVersion; - private volatile String currentSwVersion; - private volatile UUID currentSwId; -} \ No newline at end of file +@JsonIgnoreProperties(ignoreUnknown = true) +public class RpcReadCompositeRequest { + + private String [] keys; + private String [] ids; + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java new file mode 100644 index 0000000000..37f4d86053 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java @@ -0,0 +1,37 @@ +/** + * Copyright © 2016-2021 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.server.rpc.composite; + +import org.eclipse.leshan.core.request.ReadCompositeRequest; +import org.eclipse.leshan.core.response.ReadCompositeResponse; +import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; + +import java.util.Optional; + +public class RpcReadResponseCompositeCallback extends RpcLwM2MDownlinkCompositeCallback { + + public RpcReadResponseCompositeCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { + super(transportService, client, requestMsg, callback); + } + + @Override + protected Optional serializeSuccessfulResponse(T response) { + return Optional.of(String.format("%s", response.getContent().toString())); + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcWriteCompositeRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcWriteCompositeRequest.java new file mode 100644 index 0000000000..ce13f58e9e --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcWriteCompositeRequest.java @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2021 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.server.rpc.composite; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +import java.util.Map; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class RpcWriteCompositeRequest { + + private Map nodes; + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index 9cfc4720f4..d83ff6a27d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java @@ -350,17 +350,19 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl } } - public void onUpdateValueAfterReadCompositeResponse(Registration registration, String path, ReadCompositeResponse response) { + public void onUpdateValueAfterReadCompositeResponse(Registration registration, ReadCompositeResponse response) { log.warn("201) ReadCompositeResponse: [{}]", response); if (response.getContent() != null) { LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); response.getContent().forEach((k, v) -> { - if (v instanceof LwM2mObject) { - this.updateObjectResourceValue(lwM2MClient, (LwM2mObject) v, k.toString()); - } else if (v instanceof LwM2mObjectInstance) { - this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString()); - } else if (v instanceof LwM2mResource) { - this.updateResourcesValue(lwM2MClient, (LwM2mResource) v, k.toString()); + if (v != null) { + if (v instanceof LwM2mObject) { + this.updateObjectResourceValue(lwM2MClient, (LwM2mObject) v, k.toString()); + } else if (v instanceof LwM2mObjectInstance) { + this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString()); + } else if (v instanceof LwM2mResource) { + this.updateResourcesValue(lwM2MClient, (LwM2mResource) v, k.toString()); + } } }); } @@ -474,12 +476,12 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl // String [] paths = new String[] {"/5"}; // String [] paths = new String[] {"/"}; // String [] paths = new String[] {"/9"}; - defaultLwM2MDownlinkMsgHandler.sendReadCompositeRequest(lwM2MClient, paths, this); +// defaultLwM2MDownlinkMsgHandler.sendReadCompositeRequest(lwM2MClient, paths, this); Map nodes = new HashMap<>(); nodes.put("/3/0/14", "+02"); nodes.put("/1/0/2", 100); nodes.put("/5/0/1", "coap://localhost:5685"); - defaultLwM2MDownlinkMsgHandler.sendWriteCompositeRequest(lwM2MClient, nodes, this); +// defaultLwM2MDownlinkMsgHandler.sendWriteCompositeRequest(lwM2MClient, nodes, this); this.sendObserveRequests(lwM2MClient, profile, supportedObjects); this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects); // Removed. Used only for debug. diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java index 7926e90907..4095cab84f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java @@ -42,7 +42,7 @@ public interface LwM2mUplinkMsgHandler { void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response); - void onUpdateValueAfterReadCompositeResponse(Registration registration, String path, ReadCompositeResponse response); + void onUpdateValueAfterReadCompositeResponse(Registration registration, ReadCompositeResponse response); void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile); From a4e3049c279cb46f3181f6b2b1c8d507796039ae Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 29 Jun 2021 12:54:43 +0300 Subject: [PATCH 3/4] Lwm2m: content format for observe fx bug --- .../lwm2m/server/client/LwM2mClient.java | 7 +++++- .../DefaultLwM2mDownlinkMsgHandler.java | 22 +++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) 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 2aa7eeab2a..ca3825b568 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 @@ -236,6 +236,12 @@ public class LwM2mClient implements Cloneable { .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null; } + public boolean isResourceMultiInstances(String pathIdVer, LwM2mModelProvider modelProvider) { + ResourceModel resourceModel = getResourceModel(pathIdVer, modelProvider); + return resourceModel.multiple; + + } + public ObjectModel getObjectModel(String pathIdVer, LwM2mModelProvider modelProvider) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); @@ -273,7 +279,6 @@ public class LwM2mClient implements Cloneable { } public String resourceToString(LwM2mResource lwM2mResource) { - return lwM2mResource.isMultiInstances() ? lwM2mResource.getInstances().toString() : lwM2mResource.getValue().toString(); } 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 48814242df..adbabb4a9e 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 @@ -48,6 +48,7 @@ import org.eclipse.leshan.core.response.WriteAttributesResponse; import org.eclipse.leshan.core.response.WriteCompositeResponse; import org.eclipse.leshan.core.response.WriteResponse; import org.eclipse.leshan.core.util.Hex; +import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.registration.Registration; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; @@ -119,7 +120,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback callback) { validateVersionedId(client, request); - ReadRequest downlink = new ReadRequest(getRequestContentFormat(client, request), request.getObjectId()); + ReadRequest downlink = new ReadRequest(getRequestContentFormat(client, request, this.config.getModelProvider()), request.getObjectId()); sendRequest(client, downlink, request.getTimeout(), callback); } @@ -155,7 +156,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im Set observations = context.getServer().getObservationService().getObservations(client.getRegistration()); if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) { ObserveRequest downlink; - ContentFormat contentFormat = getRequestContentFormat(client, request); + ContentFormat contentFormat = getRequestContentFormat(client, request, this.config.getModelProvider()); if (resultIds.isResource()) { downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); } else if (resultIds.isObjectInstance()) { @@ -457,16 +458,23 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im throw new CodecException("Invalid ResourceModel_Type for %s ContentFormat.", type); } - private static ContentFormat getRequestContentFormat(LwM2mClient client, HasContentFormat request) { + private static ContentFormat getRequestContentFormat(LwM2mClient client, HasContentFormat request, LwM2mModelProvider modelProvider) { if (request.getRequestContentFormat() != null) { return request.getRequestContentFormat(); } else { - String versionedId = fromVersionedIdToObjectId(((TbLwM2MReadRequest) request).getVersionedId()); - if (versionedId != null && (new LwM2mPath(versionedId).isObject() || new LwM2mPath(versionedId).isObjectInstance())) { - return ContentFormat.DEFAULT; - } else { + String versionedId = null; + if (request instanceof TbLwM2MReadRequest) { + versionedId = ((TbLwM2MReadRequest) request).getVersionedId(); + } else if (request instanceof TbLwM2MObserveRequest) { + versionedId = ((TbLwM2MObserveRequest) request).getVersionedId(); + } + String id = fromVersionedIdToObjectId(versionedId); + if (id != null && !client.isResourceMultiInstances(versionedId, modelProvider)) { return client.getDefaultContentFormat(); } + else { + return ContentFormat.DEFAULT; + } } } } From 7f38366a4757cb6dbae6a100406d487160c93f28 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 29 Jun 2021 13:14:14 +0300 Subject: [PATCH 4/4] Lwm2m: merge with master --- .../lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 adbabb4a9e..5c0c9763cc 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 @@ -469,7 +469,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im versionedId = ((TbLwM2MObserveRequest) request).getVersionedId(); } String id = fromVersionedIdToObjectId(versionedId); - if (id != null && !client.isResourceMultiInstances(versionedId, modelProvider)) { + if (id != null && new LwM2mPath(id).isResource() && !client.isResourceMultiInstances(versionedId, modelProvider)) { return client.getDefaultContentFormat(); } else {