Browse Source

Lwm2m: RPC composite read

pull/4791/head
nickAS21 5 years ago
parent
commit
a94810126d
  1. 1
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java
  2. 66
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java
  3. 40
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java
  4. 5
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java
  5. 27
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  6. 56
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java
  7. 35
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/HasVersionedIds.java
  8. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java
  9. 5
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java
  10. 7
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MUplinkTargetedCallback.java
  11. 34
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/AbstractTbLwM2MTargetedDownlinkCompositeRequest.java
  12. 9
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeCallback.java
  13. 10
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MReadCompositeRequest.java
  14. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteCompositeRequest.java
  15. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/composite/TbLwM2MWriteResponseCompositeCallback.java
  16. 58
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java
  17. 1
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/IdOrKeyRequest.java
  18. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java
  19. 11
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java
  20. 53
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcLwM2MDownlinkCompositeCallback.java
  21. 17
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadCompositeRequest.java
  22. 37
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java
  23. 29
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcWriteCompositeRequest.java
  24. 20
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java
  25. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java

1
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 PowerMode powerMode;
private String fwUpdateResource; private String fwUpdateResource;
private String swUpdateResource; private String swUpdateResource;
private boolean composite;
} }

66
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));
}
}

40
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java

@ -22,37 +22,37 @@ import lombok.Getter;
*/ */
public enum LwM2mOperationType { public enum LwM2mOperationType {
READ(0, "Read", true), READ(0, "Read", 1),
READ_COMPOSITE(1, "ReadComposite", true), READ_COMPOSITE(1, "ReadComposite", 2),
DISCOVER(2, "Discover", true), DISCOVER(2, "Discover", 1),
DISCOVER_ALL(3, "DiscoverAll", false), DISCOVER_ALL(3, "DiscoverAll", 0),
OBSERVE_READ_ALL(4, "ObserveReadAll", false), OBSERVE_READ_ALL(4, "ObserveReadAll", 0),
OBSERVE(5, "Observe", true), OBSERVE(5, "Observe", 1),
OBSERVE_COMPOSITE(6, "ObserveComposite", true), OBSERVE_COMPOSITE(6, "ObserveComposite", 2),
OBSERVE_CANCEL(7, "ObserveCancel", true), OBSERVE_CANCEL(7, "ObserveCancel", 1),
OBSERVE_COMPOSITE_CANCEL(8, "ObserveCompositeCancel", true), OBSERVE_COMPOSITE_CANCEL(8, "ObserveCompositeCancel", 2),
OBSERVE_CANCEL_ALL(9, "ObserveCancelAll", false), OBSERVE_CANCEL_ALL(9, "ObserveCancelAll", 0),
EXECUTE(10, "Execute", true), EXECUTE(10, "Execute", 1),
/** /**
* Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see * 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). * section 5.3.3 of the LW M2M spec).
* if all resources are to be replaced * 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 * 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). * 5.3.3 of the LW M2M spec).
* if this is a partial update request * if this is a partial update request
*/ */
WRITE_UPDATE(12, "WriteUpdate", true), WRITE_UPDATE(12, "WriteUpdate", 1),
WRITE_COMPOSITE(14, "WriteComposite", true), WRITE_COMPOSITE(14, "WriteComposite", 2),
WRITE_ATTRIBUTES(15, "WriteAttributes", true), WRITE_ATTRIBUTES(15, "WriteAttributes", 1),
DELETE(16, "Delete", true), DELETE(16, "Delete", 1),
// only for RPC // only for RPC
FW_UPDATE(17, "FirmwareUpdate", false); FW_UPDATE(17, "FirmwareUpdate", 0);
// FW_READ_INFO(18, "FirmwareReadInfo"), // FW_READ_INFO(18, "FirmwareReadInfo"),
// SW_READ_INFO(19, "SoftwareReadInfo"), // SW_READ_INFO(19, "SoftwareReadInfo"),
@ -64,12 +64,12 @@ public enum LwM2mOperationType {
@Getter @Getter
private final String type; private final String type;
@Getter @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.code = code;
this.type = type; this.type = type;
this.hasObjectId = hasObjectId; this.hasObjectIdOrComposite = hasObjectIdOrComposite;
} }
public static LwM2mOperationType fromType(String type) { public static LwM2mOperationType fromType(String type) {

5
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.DeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.transport.TransportServiceCallback; 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.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; 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 @Slf4j
public class LwM2mTransportUtil { 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_TELEMETRY = "logLwm2m";
public static final String LOG_LWM2M_INFO = "info"; public static final String LOG_LWM2M_INFO = "info";
@ -303,7 +304,7 @@ public class LwM2mTransportUtil {
public static String convertObjectIdToVersionedId(String path, Registration registration) { public static String convertObjectIdToVersionedId(String path, Registration registration) {
String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId()); 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 { try {
String[] keyArray = path.split(LWM2M_SEPARATOR_PATH); String[] keyArray = path.split(LWM2M_SEPARATOR_PATH);
if (keyArray.length > 1) { if (keyArray.length > 1) {

27
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.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; 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 org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest;
import java.util.Collection; import java.util.Collection;
@ -53,7 +54,7 @@ import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; 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.convertObjectIdToVersionedId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
@ -243,11 +244,11 @@ public class LwM2mClient implements Cloneable {
.getObjectModel(pathIds.getObjectId()) : null; .getObjectModel(pathIds.getObjectId()) : null;
} }
public String objectToString(LwM2mObject lwM2mObject, LwM2mValueConverter converter, String pathIdVer) { public String objectToString(LwM2mObject lwM2mObject) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={"); builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={");
lwM2mObject.getInstances().forEach((instId, inst) -> { 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(", "); int startInd = builder.lastIndexOf(", ");
if (startInd > 0) { if (startInd > 0) {
@ -257,11 +258,11 @@ public class LwM2mClient implements Cloneable {
return builder.toString(); return builder.toString();
} }
public String instanceToString(LwM2mObjectInstance objectInstance, LwM2mValueConverter converter, String pathIdVer) { public String instanceToString(LwM2mObjectInstance objectInstance) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={"); builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={");
objectInstance.getResources().forEach((resId, res) -> { 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(", "); int startInd = builder.lastIndexOf(", ");
if (startInd > 0) { if (startInd > 0) {
@ -271,8 +272,9 @@ public class LwM2mClient implements Cloneable {
return builder.toString(); return builder.toString();
} }
public String resourceToString(LwM2mResource lwM2mResource, LwM2mValueConverter converter, String pathIdVer) { public String resourceToString(LwM2mResource lwM2mResource) {
return lwM2mResource.getValue().toString();
return lwM2mResource.isMultiInstances() ? lwM2mResource.getInstances().toString() : lwM2mResource.getValue().toString();
} }
public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider, public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
@ -308,11 +310,14 @@ public class LwM2mClient implements Cloneable {
return resources; return resources;
} }
public boolean isValidObjectVersion(String path) { public void isValidObjectVersion(String path) {
LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path));
String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
String verRez = getVerFromPathIdVerOrId(path); 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() { public ContentFormat getDefaultContentFormat() {
if (registration == null) { if (registration == null) {
return ContentFormat.DEFAULT; return ContentFormat.DEFAULT;
} else if (registration.getLwM2mVersion().equals("1.0")) {
return ContentFormat.TLV;
} else { } else {
return ContentFormat.TEXT; return LwM2mVersion.fromContentFormat(registration.getLwM2mVersion());
} }
} }

56
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.LwM2mTransportContext;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 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.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.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; 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.MAXIMUM_PERIOD;
import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD; import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD;
import static org.eclipse.leshan.core.attributes.Attribute.STEP; import static org.eclipse.leshan.core.attributes.Attribute.STEP;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
@Slf4j @Slf4j
@Service @Service
@ -121,27 +124,26 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
} }
@Override @Override
// public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback) { public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback) {
public void sendReadCompositeRequest(LwM2mClient client, String [] paths, DefaultLwM2MUplinkMsgHandler lwM2MUplinkMsgHandler) { validateVersionedIds(client, request);
// validateVersionedId(client, request);
DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback = new TbLwM2MReadCompositeCallback(lwM2MUplinkMsgHandler, logService, client, null);
ContentFormat requestContentFormat = ContentFormat.SENML_JSON; ContentFormat requestContentFormat = ContentFormat.SENML_JSON;
ContentFormat responseContentFormat = 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); sendReadRequestComposite(client, downlink, this.config.getTimeout(), callback);
} }
@Override @Override
public void sendWriteCompositeRequest(LwM2mClient client, Map<String, Object> nodes, DefaultLwM2MUplinkMsgHandler handler) { public void sendWriteCompositeRequest(LwM2mClient client, Map<String, Object> nodes, DefaultLwM2MUplinkMsgHandler handler) {
// ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); // ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider());
TbLwM2MWriteResponseCompositeCallback callback = new TbLwM2MWriteResponseCompositeCallback (handler, logService, client, null); TbLwM2MWriteResponseCompositeCallback callback = new TbLwM2MWriteResponseCompositeCallback(handler, logService, client, null);
ContentFormat contentFormat = ContentFormat.SENML_JSON; ContentFormat contentFormat = ContentFormat.SENML_JSON;
try { try {
WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, nodes); WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, nodes);
sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback); sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback);
} catch (Exception e) { } catch (Exception e) {
callback.onError(JacksonUtil.toString(nodes), e); callback.onError(JacksonUtil.toString(nodes), e);
} }
} }
@ -277,7 +279,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
*/ */
Collection<LwM2mResource> resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); Collection<LwM2mResource> resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter);
if (resources.size() > 0) { 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); WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resources);
sendRequest(client, downlink, request.getTimeout(), callback); sendRequest(client, downlink, request.getTimeout(), callback);
} else { } else {
@ -407,14 +409,23 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
} }
private void validateVersionedId(LwM2mClient client, HasVersionedId request) { private void validateVersionedId(LwM2mClient client, HasVersionedId request) {
if (!client.isValidObjectVersion(request.getVersionedId())) { client.isValidObjectVersion(request.getVersionedId());
throw new IllegalArgumentException("Specified resource id is not configured in the device profile!");
}
if (request.getObjectId() == null) { if (request.getObjectId() == null) {
throw new IllegalArgumentException("Specified object id is 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 <T> void addAttribute(List<Attribute> attributes, String attributeName, T value) { private static <T> void addAttribute(List<Attribute> attributes, String attributeName, T value) {
addAttribute(attributes, attributeName, value, null, null); addAttribute(attributes, attributeName, value, null, null);
} }
@ -447,6 +458,15 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
} }
private static ContentFormat getRequestContentFormat(LwM2mClient client, HasContentFormat request) { 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();
}
}
} }
} }

35
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);
}
}

6
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.DiscoverRequest;
import org.eclipse.leshan.core.request.ExecuteRequest; import org.eclipse.leshan.core.request.ExecuteRequest;
import org.eclipse.leshan.core.request.ObserveRequest; 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.ReadRequest;
import org.eclipse.leshan.core.request.WriteAttributesRequest; import org.eclipse.leshan.core.request.WriteAttributesRequest;
import org.eclipse.leshan.core.request.WriteRequest; 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.DiscoverResponse;
import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.core.response.ExecuteResponse;
import org.eclipse.leshan.core.response.ObserveResponse; 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.ReadResponse;
import org.eclipse.leshan.core.response.WriteAttributesResponse; import org.eclipse.leshan.core.response.WriteAttributesResponse;
import org.eclipse.leshan.core.response.WriteResponse; import org.eclipse.leshan.core.response.WriteResponse;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 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 org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import java.util.List; import java.util.List;
@ -41,8 +44,7 @@ public interface LwM2mDownlinkMsgHandler {
void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback); void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback);
// void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback); void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback);
void sendReadCompositeRequest(LwM2mClient client, String [] paths, DefaultLwM2MUplinkMsgHandler lwM2MUplinkMsgHandler);
void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback); void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback);

5
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<R, T> extends AbstractTbLwM2MRequestCallback<R, T> { public abstract class TbLwM2MTargetedCallback<R, T> extends AbstractTbLwM2MRequestCallback<R, T> {
protected final String versionedId; protected final String versionedId;
protected final String[] versionedIds;
public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) { public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) {
super(logService, client); super(logService, client);
this.versionedId = versionedId; this.versionedId = versionedId;
this.versionedIds = null;
} }
public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client) { public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) {
super(logService, client); super(logService, client);
this.versionedId = null; this.versionedId = null;
this.versionedIds = versionedIds;
} }
@Override @Override

7
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.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO;
@Slf4j @Slf4j
public abstract class TbLwM2MUplinkTargetedCallback<R, T> extends TbLwM2MTargetedCallback<R, T> { public abstract class TbLwM2MUplinkTargetedCallback<R, T> extends TbLwM2MTargetedCallback<R, T> {
@ -32,4 +30,9 @@ public abstract class TbLwM2MUplinkTargetedCallback<R, T> extends TbLwM2MTargete
this.handler = handler; this.handler = handler;
} }
public TbLwM2MUplinkTargetedCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) {
super(logService, client, versionedIds);
this.handler = handler;
}
} }

34
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<T> implements TbLwM2MDownlinkRequest<T>, HasVersionedIds {
@Getter
private final String [] versionedIds;
@Getter
private final long timeout;
public AbstractTbLwM2MTargetedDownlinkCompositeRequest(String [] versionedIds, long timeout) {
this.versionedIds = versionedIds;
this.timeout = timeout;
}
}

9
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeCallback.java → 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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 lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.request.ReadCompositeRequest; import org.eclipse.leshan.core.request.ReadCompositeRequest;
import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.eclipse.leshan.core.response.ReadCompositeResponse;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 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.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
@Slf4j @Slf4j
public class TbLwM2MReadCompositeCallback extends TbLwM2MUplinkTargetedCallback<ReadCompositeRequest, ReadCompositeResponse> { public class TbLwM2MReadCompositeCallback extends TbLwM2MUplinkTargetedCallback<ReadCompositeRequest, ReadCompositeResponse> {
public TbLwM2MReadCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { public TbLwM2MReadCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) {
super(handler, logService, client, targetId); super(handler, logService, client, versionedIds);
} }
@Override @Override
public void onSuccess(ReadCompositeRequest request, ReadCompositeResponse response) { public void onSuccess(ReadCompositeRequest request, ReadCompositeResponse response) {
super.onSuccess(request, response); super.onSuccess(request, response);
handler.onUpdateValueAfterReadCompositeResponse(client.getRegistration(), versionedId, response); handler.onUpdateValueAfterReadCompositeResponse(client.getRegistration(), response);
} }
} }

10
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCompositeRequest.java → 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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.Builder;
import lombok.Getter; import lombok.Getter;
import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.response.ReadCompositeResponse; import org.eclipse.leshan.core.response.ReadCompositeResponse;
import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
import org.thingsboard.server.transport.lwm2m.server.downlink.HasContentFormat;
public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ReadCompositeResponse> implements HasContentFormat { public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlinkCompositeRequest<ReadCompositeResponse> implements HasContentFormat {
@Getter @Getter
private final ContentFormat requestContentFormat; private final ContentFormat requestContentFormat;
@ -30,8 +31,8 @@ public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlink
private final ContentFormat responseContentFormat; private final ContentFormat responseContentFormat;
@Builder @Builder
private TbLwM2MReadCompositeRequest(String versionedId, long timeout, ContentFormat requestContentFormat, ContentFormat responseContentFormat) { private TbLwM2MReadCompositeRequest(String [] versionedIds, long timeout, ContentFormat requestContentFormat, ContentFormat responseContentFormat) {
super(versionedId, timeout); super(versionedIds, timeout);
this.requestContentFormat = requestContentFormat; this.requestContentFormat = requestContentFormat;
this.responseContentFormat = responseContentFormat; this.responseContentFormat = responseContentFormat;
} }
@ -40,5 +41,4 @@ public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlink
public LwM2mOperationType getType() { public LwM2mOperationType getType() {
return LwM2mOperationType.READ_COMPOSITE; return LwM2mOperationType.READ_COMPOSITE;
} }
} }

3
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteCompositeRequest.java → 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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.Builder;
import lombok.Getter; import lombok.Getter;
import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.response.WriteCompositeResponse; import org.eclipse.leshan.core.response.WriteCompositeResponse;
import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
import org.thingsboard.server.transport.lwm2m.server.downlink.AbstractTbLwM2MTargetedDownlinkRequest;
public class TbLwM2MWriteCompositeRequest extends AbstractTbLwM2MTargetedDownlinkRequest<WriteCompositeResponse> { public class TbLwM2MWriteCompositeRequest extends AbstractTbLwM2MTargetedDownlinkRequest<WriteCompositeResponse> {

3
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCompositeCallback.java → 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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.request.WriteCompositeRequest;
import org.eclipse.leshan.core.response.WriteCompositeResponse; import org.eclipse.leshan.core.response.WriteCompositeResponse;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 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.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;

58
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.TbLwM2MWriteReplaceRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback; 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.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.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 org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import java.util.Map; import java.util.Map;
@ -92,7 +97,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
return; return;
} }
try { try {
if (operationType.isHasObjectId()) { if (operationType.getHasObjectIdOrComposite() == 1) {
String objectId = getIdFromParameters(client, rpcRequst); String objectId = getIdFromParameters(client, rpcRequst);
switch (operationType) { switch (operationType) {
case READ: case READ:
@ -125,6 +130,17 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
default: default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); 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 { } else {
switch (operationType) { switch (operationType) {
case OBSERVE_CANCEL_ALL: case OBSERVE_CANCEL_ALL:
@ -151,14 +167,22 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
private void sendReadRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { private void sendReadRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MReadCallback(uplinkHandler, logService, client, versionedId); 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); 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) { private void sendObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MObserveCallback(uplinkHandler, logService, client, versionedId); 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); downlinkHandler.sendObserveRequest(client, request, rpcCallback);
} }
@ -215,6 +239,16 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback); 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) { private void sendCancelObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
TbLwM2MCancelObserveRequest downlink = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); TbLwM2MCancelObserveRequest downlink = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MCancelObserveCallback(logService, client, versionedId); var mainCallback = new TbLwM2MCancelObserveCallback(logService, client, versionedId);
@ -249,6 +283,24 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
return targetId; 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) { private void sendErrorRpcResponse(TransportProtos.SessionInfoProto sessionInfo, int requestId, String result, String error) {
String payload = JacksonUtil.toString(JacksonUtil.newObjectNode().put("result", result).put("error", error)); String payload = JacksonUtil.toString(JacksonUtil.newObjectNode().put("result", result).put("error", error));
TransportProtos.ToDeviceRpcResponseMsg msg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId).setPayload(payload).build(); TransportProtos.ToDeviceRpcResponseMsg msg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId).setPayload(payload).build();

1
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 key;
private String id; private String id;
} }

4
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; package org.thingsboard.server.transport.lwm2m.server.rpc;
import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.ResponseCode;
import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 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.downlink.DownlinkRequestCallback;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkRequestCallback<R, T> { public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkRequestCallback<R, T> {
@ -31,14 +29,12 @@ public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkR
private final DownlinkRequestCallback<R, T> callback; private final DownlinkRequestCallback<R, T> callback;
protected final LwM2mClient client; protected final LwM2mClient client;
protected final LwM2mValueConverter converter;
public RpcDownlinkRequestCallbackProxy(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) { public RpcDownlinkRequestCallbackProxy(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) {
this.transportService = transportService; this.transportService = transportService;
this.client = client; this.client = client;
this.request = requestMsg; this.request = requestMsg;
this.callback = callback; this.callback = callback;
this.converter = LwM2mValueConverterImpl.getInstance();
} }
@Override @Override

11
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<R extends LwM2mRequest<T>, T extends ReadResponse> extends RpcLwM2MDownlinkCallback<R, T> { public class RpcReadResponseCallback<R extends LwM2mRequest<T>, T extends ReadResponse> extends RpcLwM2MDownlinkCallback<R, T> {
private final String versionedId; public RpcReadResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) {
public RpcReadResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId, DownlinkRequestCallback<R, T> callback) {
super(transportService, client, requestMsg, callback); super(transportService, client, requestMsg, callback);
this.versionedId = versionedId;
} }
@Override @Override
protected Optional<String> serializeSuccessfulResponse(T response) { protected Optional<String> serializeSuccessfulResponse(T response) {
Object value = null; Object value = null;
if (response.getContent() instanceof LwM2mObject) { 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) { } 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) { } 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)); return Optional.of(String.format("%s", value));
} }

53
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<R extends ReadCompositeRequest, T extends ReadCompositeResponse> extends RpcDownlinkRequestCallbackProxy<R, T> {
public RpcLwM2MDownlinkCompositeCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> 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<String> 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<String> serializeSuccessfulResponse(T response);
}

17
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/client/LwM2mSoftwareUpdate.java → 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 * See the License for the specific language governing permissions and
* limitations under the License. * 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 lombok.Data;
import java.util.UUID;
@Data @Data
public class LwM2mSoftwareUpdate { @JsonIgnoreProperties(ignoreUnknown = true)
private volatile String clientSwVersion; public class RpcReadCompositeRequest {
private volatile String currentSwVersion;
private volatile UUID currentSwId; private String [] keys;
} private String [] ids;
}

37
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<R extends ReadCompositeRequest, T extends ReadCompositeResponse> extends RpcLwM2MDownlinkCompositeCallback<R, T> {
public RpcReadResponseCompositeCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) {
super(transportService, client, requestMsg, callback);
}
@Override
protected Optional<String> serializeSuccessfulResponse(T response) {
return Optional.of(String.format("%s", response.getContent().toString()));
}
}

29
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<String, Object> nodes;
}

20
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); log.warn("201) ReadCompositeResponse: [{}]", response);
if (response.getContent() != null) { if (response.getContent() != null) {
LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());
response.getContent().forEach((k, v) -> { response.getContent().forEach((k, v) -> {
if (v instanceof LwM2mObject) { if (v != null) {
this.updateObjectResourceValue(lwM2MClient, (LwM2mObject) v, k.toString()); if (v instanceof LwM2mObject) {
} else if (v instanceof LwM2mObjectInstance) { this.updateObjectResourceValue(lwM2MClient, (LwM2mObject) v, k.toString());
this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString()); } else if (v instanceof LwM2mObjectInstance) {
} else if (v instanceof LwM2mResource) { this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString());
this.updateResourcesValue(lwM2MClient, (LwM2mResource) 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[] {"/5"};
// String [] paths = new String[] {"/"}; // String [] paths = new String[] {"/"};
// String [] paths = new String[] {"/9"}; // String [] paths = new String[] {"/9"};
defaultLwM2MDownlinkMsgHandler.sendReadCompositeRequest(lwM2MClient, paths, this); // defaultLwM2MDownlinkMsgHandler.sendReadCompositeRequest(lwM2MClient, paths, this);
Map<String, Object> nodes = new HashMap<>(); Map<String, Object> nodes = new HashMap<>();
nodes.put("/3/0/14", "+02"); nodes.put("/3/0/14", "+02");
nodes.put("/1/0/2", 100); nodes.put("/1/0/2", 100);
nodes.put("/5/0/1", "coap://localhost:5685"); nodes.put("/5/0/1", "coap://localhost:5685");
defaultLwM2MDownlinkMsgHandler.sendWriteCompositeRequest(lwM2MClient, nodes, this); // defaultLwM2MDownlinkMsgHandler.sendWriteCompositeRequest(lwM2MClient, nodes, this);
this.sendObserveRequests(lwM2MClient, profile, supportedObjects); this.sendObserveRequests(lwM2MClient, profile, supportedObjects);
this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects); this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects);
// Removed. Used only for debug. // Removed. Used only for debug.

2
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 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); void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile);

Loading…
Cancel
Save