Showing
27 changed files
with
730 additions
and
83 deletions
@@ -27,5 +27,6 @@ public class OtherConfiguration { | @@ -27,5 +27,6 @@ public class OtherConfiguration { | ||
27 | private PowerMode powerMode; | 27 | private PowerMode powerMode; |
28 | private String fwUpdateResource; | 28 | private String fwUpdateResource; |
29 | private String swUpdateResource; | 29 | private String swUpdateResource; |
30 | + private boolean composite; | ||
30 | 31 | ||
31 | } | 32 | } |
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.lwm2m.config; | ||
17 | + | ||
18 | +import lombok.Getter; | ||
19 | +import org.eclipse.leshan.core.LwM2m.Version; | ||
20 | +import org.eclipse.leshan.core.request.ContentFormat; | ||
21 | + | ||
22 | +public enum LwM2mVersion { | ||
23 | + VERSION_1_0(0, Version.V1_0, ContentFormat.TLV), | ||
24 | + VERSION_1_1(1, Version.V1_1, ContentFormat.TEXT); | ||
25 | + | ||
26 | + @Getter | ||
27 | + private final int code; | ||
28 | + @Getter | ||
29 | + private final Version version; | ||
30 | + @Getter | ||
31 | + private final ContentFormat contentFormat; | ||
32 | + | ||
33 | + LwM2mVersion(int code, Version version, ContentFormat contentFormat) { | ||
34 | + this.code = code; | ||
35 | + this.version = version; | ||
36 | + this.contentFormat = contentFormat; | ||
37 | + } | ||
38 | + | ||
39 | + public static LwM2mVersion fromVersion(Version version) { | ||
40 | + for (LwM2mVersion to : LwM2mVersion.values()) { | ||
41 | + if (to.version.equals(version)) { | ||
42 | + return to; | ||
43 | + } | ||
44 | + } | ||
45 | + throw new IllegalArgumentException(String.format("Unsupported typeLwM2mVersion type : %s", version)); | ||
46 | + } | ||
47 | + | ||
48 | + public static LwM2mVersion fromVersionStr(String versionStr) { | ||
49 | + for (LwM2mVersion to : LwM2mVersion.values()) { | ||
50 | + if (to.version.toString().equals(versionStr)) { | ||
51 | + return to; | ||
52 | + } | ||
53 | + } | ||
54 | + throw new IllegalArgumentException(String.format("Unsupported contentFormatLwM2mVersion version : %s", versionStr)); | ||
55 | + } | ||
56 | + | ||
57 | + public static LwM2mVersion fromCode(int code) { | ||
58 | + for (LwM2mVersion to : LwM2mVersion.values()) { | ||
59 | + if (to.code == code) { | ||
60 | + return to; | ||
61 | + } | ||
62 | + } | ||
63 | + throw new IllegalArgumentException(String.format("Unsupported codeLwM2mVersion code : %d", code)); | ||
64 | + } | ||
65 | +} | ||
66 | + |
@@ -23,37 +23,41 @@ import lombok.Getter; | @@ -23,37 +23,41 @@ import lombok.Getter; | ||
23 | public enum LwM2mOperationType { | 23 | public enum LwM2mOperationType { |
24 | 24 | ||
25 | READ(0, "Read", true), | 25 | READ(0, "Read", true), |
26 | - DISCOVER(1, "Discover", true), | ||
27 | - DISCOVER_ALL(2, "DiscoverAll", false), | ||
28 | - OBSERVE_READ_ALL(3, "ObserveReadAll", false), | 26 | + READ_COMPOSITE(1, "ReadComposite", false, true), |
27 | + DISCOVER(2, "Discover", true), | ||
28 | + DISCOVER_ALL(3, "DiscoverAll", false), | ||
29 | + OBSERVE_READ_ALL(4, "ObserveReadAll", false), | ||
29 | 30 | ||
30 | - OBSERVE(4, "Observe", true), | ||
31 | - OBSERVE_CANCEL(5, "ObserveCancel", true), | ||
32 | - OBSERVE_CANCEL_ALL(6, "ObserveCancelAll", false), | ||
33 | - EXECUTE(7, "Execute", true), | 31 | + OBSERVE(5, "Observe", true), |
32 | + OBSERVE_COMPOSITE(6, "ObserveComposite", false, true), | ||
33 | + OBSERVE_CANCEL(7, "ObserveCancel", true), | ||
34 | + OBSERVE_COMPOSITE_CANCEL(8, "ObserveCompositeCancel", false, true), | ||
35 | + OBSERVE_CANCEL_ALL(9, "ObserveCancelAll", false), | ||
36 | + EXECUTE(10, "Execute", true), | ||
34 | /** | 37 | /** |
35 | * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see | 38 | * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see |
36 | * section 5.3.3 of the LW M2M spec). | 39 | * section 5.3.3 of the LW M2M spec). |
37 | * if all resources are to be replaced | 40 | * if all resources are to be replaced |
38 | */ | 41 | */ |
39 | - WRITE_REPLACE(8, "WriteReplace", true), | 42 | + WRITE_REPLACE(11, "WriteReplace", true), |
40 | 43 | ||
41 | /** | 44 | /** |
42 | * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section | 45 | * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section |
43 | * 5.3.3 of the LW M2M spec). | 46 | * 5.3.3 of the LW M2M spec). |
44 | * if this is a partial update request | 47 | * if this is a partial update request |
45 | */ | 48 | */ |
46 | - WRITE_UPDATE(9, "WriteUpdate", true), | ||
47 | - WRITE_ATTRIBUTES(10, "WriteAttributes", true), | ||
48 | - DELETE(11, "Delete", true), | 49 | + WRITE_UPDATE(12, "WriteUpdate", true), |
50 | + WRITE_COMPOSITE(14, "WriteComposite", false, true), | ||
51 | + WRITE_ATTRIBUTES(15, "WriteAttributes", true), | ||
52 | + DELETE(16, "Delete", true), | ||
49 | 53 | ||
50 | // only for RPC | 54 | // only for RPC |
51 | - FW_UPDATE(12, "FirmwareUpdate", false); | 55 | + FW_UPDATE(17, "FirmwareUpdate", false); |
52 | 56 | ||
53 | -// FW_READ_INFO(12, "FirmwareReadInfo"), | ||
54 | -// SW_READ_INFO(15, "SoftwareReadInfo"), | ||
55 | -// SW_UPDATE(16, "SoftwareUpdate"), | ||
56 | -// SW_UNINSTALL(18, "SoftwareUninstall"); | 57 | +// FW_READ_INFO(18, "FirmwareReadInfo"), |
58 | +// SW_READ_INFO(19, "SoftwareReadInfo"), | ||
59 | +// SW_UPDATE(20, "SoftwareUpdate"), | ||
60 | +// SW_UNINSTALL(21, "SoftwareUninstall"); | ||
57 | 61 | ||
58 | @Getter | 62 | @Getter |
59 | private final int code; | 63 | private final int code; |
@@ -62,10 +66,21 @@ public enum LwM2mOperationType { | @@ -62,10 +66,21 @@ public enum LwM2mOperationType { | ||
62 | @Getter | 66 | @Getter |
63 | private final boolean hasObjectId; | 67 | private final boolean hasObjectId; |
64 | 68 | ||
69 | + @Getter | ||
70 | + private final boolean composite; | ||
71 | + | ||
65 | LwM2mOperationType(int code, String type, boolean hasObjectId) { | 72 | LwM2mOperationType(int code, String type, boolean hasObjectId) { |
73 | + this(code, type, hasObjectId, false); | ||
74 | + } | ||
75 | + | ||
76 | + LwM2mOperationType(int code, String type, boolean hasObjectId, boolean composite) { | ||
66 | this.code = code; | 77 | this.code = code; |
67 | this.type = type; | 78 | this.type = type; |
68 | this.hasObjectId = hasObjectId; | 79 | this.hasObjectId = hasObjectId; |
80 | + this.composite = composite; | ||
81 | + if(hasObjectId && composite){ | ||
82 | + throw new IllegalArgumentException("Can't set both Composite and hasObjectId for the same operation!"); | ||
83 | + } | ||
69 | } | 84 | } |
70 | 85 | ||
71 | public static LwM2mOperationType fromType(String type) { | 86 | public static LwM2mOperationType fromType(String type) { |
@@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfigurati | @@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfigurati | ||
44 | import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; | 44 | import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; |
45 | import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; | 45 | import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; |
46 | import org.thingsboard.server.common.transport.TransportServiceCallback; | 46 | import org.thingsboard.server.common.transport.TransportServiceCallback; |
47 | +import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; | ||
47 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | 48 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
48 | import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; | 49 | import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; |
49 | import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; | 50 | import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; |
@@ -85,7 +86,7 @@ import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaU | @@ -85,7 +86,7 @@ import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaU | ||
85 | @Slf4j | 86 | @Slf4j |
86 | public class LwM2mTransportUtil { | 87 | public class LwM2mTransportUtil { |
87 | 88 | ||
88 | - public static final String LWM2M_VERSION_DEFAULT = "1.0"; | 89 | + public static final String LWM2M_OBJECT_VERSION_DEFAULT = "1.0"; |
89 | 90 | ||
90 | public static final String LOG_LWM2M_TELEMETRY = "transportLog"; | 91 | public static final String LOG_LWM2M_TELEMETRY = "transportLog"; |
91 | public static final String LOG_LWM2M_INFO = "info"; | 92 | public static final String LOG_LWM2M_INFO = "info"; |
@@ -234,7 +235,7 @@ public class LwM2mTransportUtil { | @@ -234,7 +235,7 @@ public class LwM2mTransportUtil { | ||
234 | 235 | ||
235 | public static String convertObjectIdToVersionedId(String path, Registration registration) { | 236 | public static String convertObjectIdToVersionedId(String path, Registration registration) { |
236 | String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId()); | 237 | String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId()); |
237 | - ver = ver != null ? ver : LWM2M_VERSION_DEFAULT; | 238 | + ver = ver != null ? ver : LwM2mVersion.VERSION_1_0.getVersion().toString(); |
238 | try { | 239 | try { |
239 | String[] keyArray = path.split(LWM2M_SEPARATOR_PATH); | 240 | String[] keyArray = path.split(LWM2M_SEPARATOR_PATH); |
240 | if (keyArray.length > 1) { | 241 | if (keyArray.length > 1) { |
@@ -381,4 +382,5 @@ public class LwM2mTransportUtil { | @@ -381,4 +382,5 @@ public class LwM2mTransportUtil { | ||
381 | } | 382 | } |
382 | return lwm2mResourceValue; | 383 | return lwm2mResourceValue; |
383 | } | 384 | } |
385 | + | ||
384 | } | 386 | } |
@@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.id.TenantId; | @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.id.TenantId; | ||
37 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | 37 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; |
38 | import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; | 38 | import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; |
39 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; | 39 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; |
40 | +import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; | ||
40 | 41 | ||
41 | import java.io.IOException; | 42 | import java.io.IOException; |
42 | import java.io.ObjectInputStream; | 43 | import java.io.ObjectInputStream; |
@@ -52,7 +53,7 @@ import java.util.concurrent.locks.ReentrantLock; | @@ -52,7 +53,7 @@ import java.util.concurrent.locks.ReentrantLock; | ||
52 | import java.util.stream.Collectors; | 53 | import java.util.stream.Collectors; |
53 | 54 | ||
54 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; | 55 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; |
55 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_VERSION_DEFAULT; | 56 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_OBJECT_VERSION_DEFAULT; |
56 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; | 57 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; |
57 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; | 58 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; |
58 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; | 59 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; |
@@ -226,6 +227,10 @@ public class LwM2mClient implements Serializable { | @@ -226,6 +227,10 @@ public class LwM2mClient implements Serializable { | ||
226 | .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null; | 227 | .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null; |
227 | } | 228 | } |
228 | 229 | ||
230 | + public boolean isResourceMultiInstances(String pathIdVer, LwM2mModelProvider modelProvider) { | ||
231 | + return getResourceModel(pathIdVer, modelProvider).multiple; | ||
232 | + } | ||
233 | + | ||
229 | public ObjectModel getObjectModel(String pathIdVer, LwM2mModelProvider modelProvider) { | 234 | public ObjectModel getObjectModel(String pathIdVer, LwM2mModelProvider modelProvider) { |
230 | LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); | 235 | LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); |
231 | String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); | 236 | String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); |
@@ -234,11 +239,11 @@ public class LwM2mClient implements Serializable { | @@ -234,11 +239,11 @@ public class LwM2mClient implements Serializable { | ||
234 | .getObjectModel(pathIds.getObjectId()) : null; | 239 | .getObjectModel(pathIds.getObjectId()) : null; |
235 | } | 240 | } |
236 | 241 | ||
237 | - public String objectToString(LwM2mObject lwM2mObject, LwM2mValueConverter converter, String pathIdVer) { | 242 | + public String objectToString(LwM2mObject lwM2mObject) { |
238 | StringBuilder builder = new StringBuilder(); | 243 | StringBuilder builder = new StringBuilder(); |
239 | builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={"); | 244 | builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={"); |
240 | lwM2mObject.getInstances().forEach((instId, inst) -> { | 245 | lwM2mObject.getInstances().forEach((instId, inst) -> { |
241 | - builder.append(instId).append("=").append(this.instanceToString(inst, converter, pathIdVer)).append(", "); | 246 | + builder.append(instId).append("=").append(this.instanceToString(inst)).append(", "); |
242 | }); | 247 | }); |
243 | int startInd = builder.lastIndexOf(", "); | 248 | int startInd = builder.lastIndexOf(", "); |
244 | if (startInd > 0) { | 249 | if (startInd > 0) { |
@@ -248,11 +253,11 @@ public class LwM2mClient implements Serializable { | @@ -248,11 +253,11 @@ public class LwM2mClient implements Serializable { | ||
248 | return builder.toString(); | 253 | return builder.toString(); |
249 | } | 254 | } |
250 | 255 | ||
251 | - public String instanceToString(LwM2mObjectInstance objectInstance, LwM2mValueConverter converter, String pathIdVer) { | 256 | + public String instanceToString(LwM2mObjectInstance objectInstance) { |
252 | StringBuilder builder = new StringBuilder(); | 257 | StringBuilder builder = new StringBuilder(); |
253 | builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={"); | 258 | builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={"); |
254 | objectInstance.getResources().forEach((resId, res) -> { | 259 | objectInstance.getResources().forEach((resId, res) -> { |
255 | - builder.append(resId).append("=").append(this.resourceToString(res, converter, pathIdVer)).append(", "); | 260 | + builder.append(resId).append("=").append(this.resourceToString(res)).append(", "); |
256 | }); | 261 | }); |
257 | int startInd = builder.lastIndexOf(", "); | 262 | int startInd = builder.lastIndexOf(", "); |
258 | if (startInd > 0) { | 263 | if (startInd > 0) { |
@@ -262,8 +267,8 @@ public class LwM2mClient implements Serializable { | @@ -262,8 +267,8 @@ public class LwM2mClient implements Serializable { | ||
262 | return builder.toString(); | 267 | return builder.toString(); |
263 | } | 268 | } |
264 | 269 | ||
265 | - public String resourceToString(LwM2mResource lwM2mResource, LwM2mValueConverter converter, String pathIdVer) { | ||
266 | - return lwM2mResource.getValue().toString(); | 270 | + public String resourceToString(LwM2mResource lwM2mResource) { |
271 | + return lwM2mResource.isMultiInstances() ? lwM2mResource.getInstances().toString() : lwM2mResource.getValue().toString(); | ||
267 | } | 272 | } |
268 | 273 | ||
269 | public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider, | 274 | public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider, |
@@ -299,11 +304,14 @@ public class LwM2mClient implements Serializable { | @@ -299,11 +304,14 @@ public class LwM2mClient implements Serializable { | ||
299 | return resources; | 304 | return resources; |
300 | } | 305 | } |
301 | 306 | ||
302 | - public boolean isValidObjectVersion(String path) { | 307 | + public void isValidObjectVersion(String path) { |
303 | LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path)); | 308 | LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path)); |
304 | String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); | 309 | String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); |
305 | String verRez = getVerFromPathIdVerOrId(path); | 310 | String verRez = getVerFromPathIdVerOrId(path); |
306 | - return verRez == null ? LWM2M_VERSION_DEFAULT.equals(verSupportedObject) : verRez.equals(verSupportedObject); | 311 | + if ((verRez != null && !verRez.equals(verSupportedObject)) || |
312 | + (verRez == null && !LWM2M_OBJECT_VERSION_DEFAULT.equals(verSupportedObject))) { | ||
313 | + throw new IllegalArgumentException(String.format("Specified resource id %s is not valid version! Must be version: %s", path, verSupportedObject)); | ||
314 | + } | ||
307 | } | 315 | } |
308 | 316 | ||
309 | /** | 317 | /** |
@@ -348,10 +356,8 @@ public class LwM2mClient implements Serializable { | @@ -348,10 +356,8 @@ public class LwM2mClient implements Serializable { | ||
348 | public ContentFormat getDefaultContentFormat() { | 356 | public ContentFormat getDefaultContentFormat() { |
349 | if (registration == null) { | 357 | if (registration == null) { |
350 | return ContentFormat.DEFAULT; | 358 | return ContentFormat.DEFAULT; |
351 | - } else if (registration.getLwM2mVersion().equals("1.0")) { | ||
352 | - return ContentFormat.TLV; | ||
353 | } else { | 359 | } else { |
354 | - return ContentFormat.TEXT; | 360 | + return LwM2mVersion.fromVersionStr(registration.getLwM2mVersion()).getContentFormat(); |
355 | } | 361 | } |
356 | } | 362 | } |
357 | 363 |
@@ -26,24 +26,31 @@ import org.eclipse.leshan.core.node.LwM2mResource; | @@ -26,24 +26,31 @@ import org.eclipse.leshan.core.node.LwM2mResource; | ||
26 | import org.eclipse.leshan.core.node.ObjectLink; | 26 | import org.eclipse.leshan.core.node.ObjectLink; |
27 | import org.eclipse.leshan.core.node.codec.CodecException; | 27 | import org.eclipse.leshan.core.node.codec.CodecException; |
28 | import org.eclipse.leshan.core.observation.Observation; | 28 | import org.eclipse.leshan.core.observation.Observation; |
29 | +import org.eclipse.leshan.core.request.CompositeDownlinkRequest; | ||
29 | import org.eclipse.leshan.core.request.ContentFormat; | 30 | import org.eclipse.leshan.core.request.ContentFormat; |
30 | import org.eclipse.leshan.core.request.DeleteRequest; | 31 | import org.eclipse.leshan.core.request.DeleteRequest; |
31 | import org.eclipse.leshan.core.request.DiscoverRequest; | 32 | import org.eclipse.leshan.core.request.DiscoverRequest; |
33 | +import org.eclipse.leshan.core.request.DownlinkRequest; | ||
32 | import org.eclipse.leshan.core.request.ExecuteRequest; | 34 | import org.eclipse.leshan.core.request.ExecuteRequest; |
33 | import org.eclipse.leshan.core.request.ObserveRequest; | 35 | import org.eclipse.leshan.core.request.ObserveRequest; |
36 | +import org.eclipse.leshan.core.request.ReadCompositeRequest; | ||
34 | import org.eclipse.leshan.core.request.ReadRequest; | 37 | import org.eclipse.leshan.core.request.ReadRequest; |
35 | import org.eclipse.leshan.core.request.SimpleDownlinkRequest; | 38 | import org.eclipse.leshan.core.request.SimpleDownlinkRequest; |
36 | import org.eclipse.leshan.core.request.WriteAttributesRequest; | 39 | import org.eclipse.leshan.core.request.WriteAttributesRequest; |
40 | +import org.eclipse.leshan.core.request.WriteCompositeRequest; | ||
37 | import org.eclipse.leshan.core.request.WriteRequest; | 41 | import org.eclipse.leshan.core.request.WriteRequest; |
38 | import org.eclipse.leshan.core.response.DeleteResponse; | 42 | import org.eclipse.leshan.core.response.DeleteResponse; |
39 | import org.eclipse.leshan.core.response.DiscoverResponse; | 43 | import org.eclipse.leshan.core.response.DiscoverResponse; |
40 | import org.eclipse.leshan.core.response.ExecuteResponse; | 44 | import org.eclipse.leshan.core.response.ExecuteResponse; |
41 | import org.eclipse.leshan.core.response.LwM2mResponse; | 45 | import org.eclipse.leshan.core.response.LwM2mResponse; |
42 | import org.eclipse.leshan.core.response.ObserveResponse; | 46 | import org.eclipse.leshan.core.response.ObserveResponse; |
47 | +import org.eclipse.leshan.core.response.ReadCompositeResponse; | ||
43 | import org.eclipse.leshan.core.response.ReadResponse; | 48 | import org.eclipse.leshan.core.response.ReadResponse; |
44 | import org.eclipse.leshan.core.response.WriteAttributesResponse; | 49 | import org.eclipse.leshan.core.response.WriteAttributesResponse; |
50 | +import org.eclipse.leshan.core.response.WriteCompositeResponse; | ||
45 | import org.eclipse.leshan.core.response.WriteResponse; | 51 | import org.eclipse.leshan.core.response.WriteResponse; |
46 | import org.eclipse.leshan.core.util.Hex; | 52 | import org.eclipse.leshan.core.util.Hex; |
53 | +import org.eclipse.leshan.server.model.LwM2mModelProvider; | ||
47 | import org.eclipse.leshan.server.registration.Registration; | 54 | import org.eclipse.leshan.server.registration.Registration; |
48 | import org.springframework.stereotype.Service; | 55 | import org.springframework.stereotype.Service; |
49 | import org.thingsboard.common.util.JacksonUtil; | 56 | import org.thingsboard.common.util.JacksonUtil; |
@@ -53,7 +60,10 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; | @@ -53,7 +60,10 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; | ||
53 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; | 60 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; |
54 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | 61 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
55 | import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService; | 62 | import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService; |
63 | +import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest; | ||
64 | +import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MWriteResponseCompositeCallback; | ||
56 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; | 65 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; |
66 | +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; | ||
57 | import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; | 67 | import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; |
58 | 68 | ||
59 | import javax.annotation.PostConstruct; | 69 | import javax.annotation.PostConstruct; |
@@ -63,6 +73,7 @@ import java.util.Collection; | @@ -63,6 +73,7 @@ import java.util.Collection; | ||
63 | import java.util.Date; | 73 | import java.util.Date; |
64 | import java.util.LinkedList; | 74 | import java.util.LinkedList; |
65 | import java.util.List; | 75 | import java.util.List; |
76 | +import java.util.Map; | ||
66 | import java.util.Set; | 77 | import java.util.Set; |
67 | import java.util.function.Function; | 78 | import java.util.function.Function; |
68 | import java.util.function.Predicate; | 79 | import java.util.function.Predicate; |
@@ -73,6 +84,7 @@ import static org.eclipse.leshan.core.attributes.Attribute.LESSER_THAN; | @@ -73,6 +84,7 @@ import static org.eclipse.leshan.core.attributes.Attribute.LESSER_THAN; | ||
73 | import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD; | 84 | import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD; |
74 | import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD; | 85 | import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD; |
75 | import static org.eclipse.leshan.core.attributes.Attribute.STEP; | 86 | import static org.eclipse.leshan.core.attributes.Attribute.STEP; |
87 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; | ||
76 | 88 | ||
77 | @Slf4j | 89 | @Slf4j |
78 | @Service | 90 | @Service |
@@ -110,8 +122,31 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -110,8 +122,31 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
110 | @Override | 122 | @Override |
111 | public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback) { | 123 | public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback) { |
112 | validateVersionedId(client, request); | 124 | validateVersionedId(client, request); |
113 | - ReadRequest downlink = new ReadRequest(getContentFormat(client, request), request.getObjectId()); | ||
114 | - sendRequest(client, downlink, request.getTimeout(), callback); | 125 | + ReadRequest downlink = new ReadRequest(getRequestContentFormat(client, request, this.config.getModelProvider()), request.getObjectId()); |
126 | + sendSimpleRequest(client, downlink, request.getTimeout(), callback); | ||
127 | + } | ||
128 | + | ||
129 | + @Override | ||
130 | + public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback) { | ||
131 | + validateVersionedIds(client, request); | ||
132 | + ContentFormat requestContentFormat = ContentFormat.SENML_JSON; | ||
133 | + ContentFormat responseContentFormat = ContentFormat.SENML_JSON; | ||
134 | + | ||
135 | + ReadCompositeRequest downlink = new ReadCompositeRequest(requestContentFormat, responseContentFormat, request.getObjectIds()); | ||
136 | + sendCompositeRequest(client, downlink, this.config.getTimeout(), callback); | ||
137 | + } | ||
138 | + | ||
139 | + @Override | ||
140 | + public void sendWriteCompositeRequest(LwM2mClient client, Map<String, Object> nodes, DefaultLwM2MUplinkMsgHandler handler) { | ||
141 | +// ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); | ||
142 | + TbLwM2MWriteResponseCompositeCallback callback = new TbLwM2MWriteResponseCompositeCallback(handler, logService, client, null); | ||
143 | + ContentFormat contentFormat = ContentFormat.SENML_JSON; | ||
144 | + try { | ||
145 | + WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, nodes); | ||
146 | + sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback); | ||
147 | + } catch (Exception e) { | ||
148 | + callback.onError(JacksonUtil.toString(nodes), e); | ||
149 | + } | ||
115 | } | 150 | } |
116 | 151 | ||
117 | @Override | 152 | @Override |
@@ -121,7 +156,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -121,7 +156,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
121 | Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration()); | 156 | Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration()); |
122 | if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) { | 157 | if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) { |
123 | ObserveRequest downlink; | 158 | ObserveRequest downlink; |
124 | - ContentFormat contentFormat = getContentFormat(client, request); | 159 | + ContentFormat contentFormat = getRequestContentFormat(client, request, this.config.getModelProvider()); |
125 | if (resultIds.isResource()) { | 160 | if (resultIds.isResource()) { |
126 | downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); | 161 | downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); |
127 | } else if (resultIds.isObjectInstance()) { | 162 | } else if (resultIds.isObjectInstance()) { |
@@ -130,7 +165,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -130,7 +165,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
130 | downlink = new ObserveRequest(contentFormat, resultIds.getObjectId()); | 165 | downlink = new ObserveRequest(contentFormat, resultIds.getObjectId()); |
131 | } | 166 | } |
132 | log.info("[{}] Send observation: {}.", client.getEndpoint(), request.getVersionedId()); | 167 | log.info("[{}] Send observation: {}.", client.getEndpoint(), request.getVersionedId()); |
133 | - sendRequest(client, downlink, request.getTimeout(), callback); | 168 | + sendSimpleRequest(client, downlink, request.getTimeout(), callback); |
134 | } else { | 169 | } else { |
135 | callback.onValidationError(resultIds.toString(), "Observation is already registered!"); | 170 | callback.onValidationError(resultIds.toString(), "Observation is already registered!"); |
136 | } | 171 | } |
@@ -158,13 +193,13 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -158,13 +193,13 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
158 | } else { | 193 | } else { |
159 | downlink = new ExecuteRequest(request.getVersionedId()); | 194 | downlink = new ExecuteRequest(request.getVersionedId()); |
160 | } | 195 | } |
161 | - sendRequest(client, downlink, request.getTimeout(), callback); | 196 | + sendSimpleRequest(client, downlink, request.getTimeout(), callback); |
162 | } | 197 | } |
163 | } | 198 | } |
164 | 199 | ||
165 | @Override | 200 | @Override |
166 | public void sendDeleteRequest(LwM2mClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback<DeleteRequest, DeleteResponse> callback) { | 201 | public void sendDeleteRequest(LwM2mClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback<DeleteRequest, DeleteResponse> callback) { |
167 | - sendRequest(client, new DeleteRequest(request.getObjectId()), request.getTimeout(), callback); | 202 | + sendSimpleRequest(client, new DeleteRequest(request.getObjectId()), request.getTimeout(), callback); |
168 | } | 203 | } |
169 | 204 | ||
170 | @Override | 205 | @Override |
@@ -182,7 +217,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -182,7 +217,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
182 | @Override | 217 | @Override |
183 | public void sendDiscoverRequest(LwM2mClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback<DiscoverRequest, DiscoverResponse> callback) { | 218 | public void sendDiscoverRequest(LwM2mClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback<DiscoverRequest, DiscoverResponse> callback) { |
184 | validateVersionedId(client, request); | 219 | validateVersionedId(client, request); |
185 | - sendRequest(client, new DiscoverRequest(request.getObjectId()), request.getTimeout(), callback); | 220 | + sendSimpleRequest(client, new DiscoverRequest(request.getObjectId()), request.getTimeout(), callback); |
186 | } | 221 | } |
187 | 222 | ||
188 | @Override | 223 | @Override |
@@ -202,7 +237,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -202,7 +237,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
202 | addAttribute(attributes, LESSER_THAN, params.getLt()); | 237 | addAttribute(attributes, LESSER_THAN, params.getLt()); |
203 | addAttribute(attributes, STEP, params.getSt()); | 238 | addAttribute(attributes, STEP, params.getSt()); |
204 | AttributeSet attributeSet = new AttributeSet(attributes); | 239 | AttributeSet attributeSet = new AttributeSet(attributes); |
205 | - sendRequest(client, new WriteAttributesRequest(request.getObjectId(), attributeSet), request.getTimeout(), callback); | 240 | + sendSimpleRequest(client, new WriteAttributesRequest(request.getObjectId(), attributeSet), request.getTimeout(), callback); |
206 | } | 241 | } |
207 | 242 | ||
208 | @Override | 243 | @Override |
@@ -214,7 +249,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -214,7 +249,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
214 | LwM2mPath path = new LwM2mPath(request.getObjectId()); | 249 | LwM2mPath path = new LwM2mPath(request.getObjectId()); |
215 | WriteRequest downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat, | 250 | WriteRequest downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat, |
216 | path.getObjectId(), path.getObjectInstanceId(), path.getResourceId(), request.getValue()); | 251 | path.getObjectId(), path.getObjectInstanceId(), path.getResourceId(), request.getValue()); |
217 | - sendRequest(client, downlink, request.getTimeout(), callback); | 252 | + sendSimpleRequest(client, downlink, request.getTimeout(), callback); |
218 | } catch (Exception e) { | 253 | } catch (Exception e) { |
219 | callback.onError(JacksonUtil.toString(request), e); | 254 | callback.onError(JacksonUtil.toString(request), e); |
220 | } | 255 | } |
@@ -236,7 +271,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -236,7 +271,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
236 | ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : convertResourceModelTypeToContentFormat(client, resourceModelWrite.type); | 271 | ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : convertResourceModelTypeToContentFormat(client, resourceModelWrite.type); |
237 | WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), | 272 | WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), |
238 | resultIds.getObjectInstanceId(), resources); | 273 | resultIds.getObjectInstanceId(), resources); |
239 | - sendRequest(client, downlink, request.getTimeout(), callback); | 274 | + sendSimpleRequest(client, downlink, request.getTimeout(), callback); |
240 | } else if (resultIds.isObjectInstance()) { | 275 | } else if (resultIds.isObjectInstance()) { |
241 | /* | 276 | /* |
242 | * params = "{\"id\":0,\"resources\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}" | 277 | * params = "{\"id\":0,\"resources\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}" |
@@ -245,9 +280,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -245,9 +280,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
245 | */ | 280 | */ |
246 | Collection<LwM2mResource> resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); | 281 | Collection<LwM2mResource> resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); |
247 | if (resources.size() > 0) { | 282 | if (resources.size() > 0) { |
248 | - ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : client.getDefaultContentFormat(); | 283 | + ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : ContentFormat.DEFAULT; |
249 | WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resources); | 284 | WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resources); |
250 | - sendRequest(client, downlink, request.getTimeout(), callback); | 285 | + sendSimpleRequest(client, downlink, request.getTimeout(), callback); |
251 | } else { | 286 | } else { |
252 | callback.onValidationError(JacksonUtil.toString(request), "No resources to update!"); | 287 | callback.onValidationError(JacksonUtil.toString(request), "No resources to update!"); |
253 | } | 288 | } |
@@ -256,10 +291,42 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -256,10 +291,42 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
256 | } | 291 | } |
257 | } | 292 | } |
258 | 293 | ||
259 | - private <R extends SimpleDownlinkRequest<T>, T extends LwM2mResponse> void sendRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback<R, T> callback) { | 294 | + |
295 | + private <R extends SimpleDownlinkRequest<T>, T extends LwM2mResponse> void sendSimpleRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback<R, T> callback) { | ||
296 | + sendRequest(client, request, timeoutInMs, callback, r -> request.getPath().toString()); | ||
297 | + } | ||
298 | + | ||
299 | + private <R extends CompositeDownlinkRequest<T>, T extends LwM2mResponse> void sendCompositeRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback<R, T> callback) { | ||
300 | + sendRequest(client, request, timeoutInMs, callback, r -> request.getPaths().toString()); | ||
301 | + } | ||
302 | + | ||
303 | + private <R extends DownlinkRequest<T>, T extends LwM2mResponse> void sendRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback<R, T> callback, Function<R, String> pathToStringFunction) { | ||
304 | + Registration registration = client.getRegistration(); | ||
305 | + try { | ||
306 | + logService.log(client, String.format("[%s][%s] Sending request: %s to %s", registration.getId(), registration.getSocketAddress(), request.getClass().getSimpleName(), pathToStringFunction.apply(request))); | ||
307 | + context.getServer().send(registration, request, timeoutInMs, response -> { | ||
308 | + executor.submit(() -> { | ||
309 | + try { | ||
310 | + callback.onSuccess(request, response); | ||
311 | + } catch (Exception e) { | ||
312 | + log.error("[{}] failed to process successful response [{}] ", registration.getEndpoint(), response, e); | ||
313 | + } | ||
314 | + }); | ||
315 | + }, e -> { | ||
316 | + executor.submit(() -> { | ||
317 | + callback.onError(JacksonUtil.toString(request), e); | ||
318 | + }); | ||
319 | + }); | ||
320 | + } catch (Exception e) { | ||
321 | + callback.onError(JacksonUtil.toString(request), e); | ||
322 | + } | ||
323 | + } | ||
324 | + | ||
325 | + private <R extends SimpleDownlinkRequest<T>, T extends LwM2mResponse> void sendWriteCompositeRequest(LwM2mClient client, WriteCompositeRequest request, long timeoutInMs, | ||
326 | + DownlinkRequestCallback<WriteCompositeRequest, WriteCompositeResponse> callback) { | ||
260 | Registration registration = client.getRegistration(); | 327 | Registration registration = client.getRegistration(); |
261 | try { | 328 | try { |
262 | - logService.log(client, String.format("[%s][%s] Sending request: %s to %s", registration.getId(), registration.getSocketAddress(), request.getClass().getSimpleName(), request.getPath())); | 329 | + logService.log(client, String.format("[%s][%s] Sending request: %s to %s", registration.getId(), registration.getSocketAddress(), request.getClass().getSimpleName(), request.getPaths())); |
263 | context.getServer().send(registration, request, timeoutInMs, response -> { | 330 | context.getServer().send(registration, request, timeoutInMs, response -> { |
264 | executor.submit(() -> { | 331 | executor.submit(() -> { |
265 | try { | 332 | try { |
@@ -278,6 +345,52 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -278,6 +345,52 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
278 | } | 345 | } |
279 | } | 346 | } |
280 | 347 | ||
348 | +// private <R extends DownlinkRequest<T>, T extends LwM2mResponse> void sendReadRequestComposite(LwM2mClient client, ReadCompositeRequest request, long timeoutInMs, | ||
349 | +// DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback) { | ||
350 | +// Registration registration = client.getRegistration(); | ||
351 | +// try { | ||
352 | +// logService.log(client, String.format("[%s][%s] Sending request: %s to %s", registration.getId(), registration.getSocketAddress(), request.getClass().getSimpleName(), request.getPaths())); | ||
353 | +// context.getServer().send(registration, request, timeoutInMs, response -> { | ||
354 | +// executor.submit(() -> { | ||
355 | +// try { | ||
356 | +// /** | ||
357 | +// * [{"bn":"/3/0/","n":"0","vs":"Thingsboard Test Device"}, | ||
358 | +// * {"n":"1","vs":"Model 500"}, | ||
359 | +// * {"n":"2","vs":"TH-500-000-0001"}, | ||
360 | +// * {"n":"3","vs":"TestThingsboard@TestMore1024_2.04"}, | ||
361 | +// * {"n":"6","v":1},{"n":"7","v":56}, | ||
362 | +// * {"n":"8","v":42},{"n":"9","v":16}, | ||
363 | +// * {"n":"10","v":127619},{"n":"13","v":1624520988}, | ||
364 | +// * {"n":"14","vs":"+03"},{"n":"15","vs":"Europe/Kiev"}, | ||
365 | +// * {"n":"16","vs":"U"},{"n":"17","vs":"smart meters"}, | ||
366 | +// * {"n":"18","vs":"1.01"},{"n":"19","vs":"1.02"}, | ||
367 | +// * {"n":"20","v":3},{"n":"21","v":256000}, | ||
368 | +// * {"bn":"/5/0/","n":"1","vs":""}, | ||
369 | +// * {"n":"3","v":0},{"n":"5","v":0}, | ||
370 | +// * {"n":"6","vs":""},{"n":"7","vs":""}, | ||
371 | +// * {"n":"8/0","v":0},{"n":"8/1","v":1}, | ||
372 | +// * {"n":"9","v":2}, | ||
373 | +// * {"bn":"/1/0/","n":"0","v":123}, | ||
374 | +// * {"n":"1","v":300}, | ||
375 | +// * {"n":"6","vb":false}, | ||
376 | +// * {"n":"22","vs":"U"}, | ||
377 | +// * {"n":"7","vs":"U"}] | ||
378 | +// */ | ||
379 | +// callback.onSuccess(request, response); | ||
380 | +// } catch (Exception e) { | ||
381 | +// log.error("[{}] failed to process successful response [{}] ", registration.getEndpoint(), response, e); | ||
382 | +// } | ||
383 | +// }); | ||
384 | +// }, e -> { | ||
385 | +// executor.submit(() -> { | ||
386 | +// callback.onError(JacksonUtil.toString(request), e); | ||
387 | +// }); | ||
388 | +// }); | ||
389 | +// } catch (Exception e) { | ||
390 | +// callback.onError(JacksonUtil.toString(request), e); | ||
391 | +// } | ||
392 | +// } | ||
393 | + | ||
281 | private WriteRequest getWriteRequestSingleResource(ResourceModel.Type type, ContentFormat contentFormat, int objectId, int instanceId, int resourceId, Object value) { | 394 | private WriteRequest getWriteRequestSingleResource(ResourceModel.Type type, ContentFormat contentFormat, int objectId, int instanceId, int resourceId, Object value) { |
282 | switch (type) { | 395 | switch (type) { |
283 | case STRING: // String | 396 | case STRING: // String |
@@ -308,14 +421,23 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -308,14 +421,23 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
308 | } | 421 | } |
309 | 422 | ||
310 | private void validateVersionedId(LwM2mClient client, HasVersionedId request) { | 423 | private void validateVersionedId(LwM2mClient client, HasVersionedId request) { |
311 | - if (!client.isValidObjectVersion(request.getVersionedId())) { | ||
312 | - throw new IllegalArgumentException("Specified resource id is not configured in the device profile!"); | ||
313 | - } | 424 | + client.isValidObjectVersion(request.getVersionedId()); |
314 | if (request.getObjectId() == null) { | 425 | if (request.getObjectId() == null) { |
315 | throw new IllegalArgumentException("Specified object id is null!"); | 426 | throw new IllegalArgumentException("Specified object id is null!"); |
316 | } | 427 | } |
317 | } | 428 | } |
318 | 429 | ||
430 | + private void validateVersionedIds(LwM2mClient client, HasVersionedIds request) { | ||
431 | + for (String versionedId : request.getVersionedIds()) { | ||
432 | + client.isValidObjectVersion(versionedId); | ||
433 | + } | ||
434 | + for (String objectId : request.getObjectIds()) { | ||
435 | + if (objectId == null) { | ||
436 | + throw new IllegalArgumentException("Specified object id is null!"); | ||
437 | + } | ||
438 | + } | ||
439 | + } | ||
440 | + | ||
319 | private static <T> void addAttribute(List<Attribute> attributes, String attributeName, T value) { | 441 | private static <T> void addAttribute(List<Attribute> attributes, String attributeName, T value) { |
320 | addAttribute(attributes, attributeName, value, null, null); | 442 | addAttribute(attributes, attributeName, value, null, null); |
321 | } | 443 | } |
@@ -347,7 +469,23 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | @@ -347,7 +469,23 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im | ||
347 | throw new CodecException("Invalid ResourceModel_Type for %s ContentFormat.", type); | 469 | throw new CodecException("Invalid ResourceModel_Type for %s ContentFormat.", type); |
348 | } | 470 | } |
349 | 471 | ||
350 | - private static ContentFormat getContentFormat(LwM2mClient client, HasContentFormat request) { | ||
351 | - return request.getContentFormat() != null ? request.getContentFormat() : client.getDefaultContentFormat(); | 472 | + private static ContentFormat getRequestContentFormat(LwM2mClient client, HasContentFormat request, LwM2mModelProvider modelProvider) { |
473 | + if (request.getRequestContentFormat() != null) { | ||
474 | + return request.getRequestContentFormat(); | ||
475 | + } else { | ||
476 | + String versionedId = null; | ||
477 | + if (request instanceof TbLwM2MReadRequest) { | ||
478 | + versionedId = ((TbLwM2MReadRequest) request).getVersionedId(); | ||
479 | + } else if (request instanceof TbLwM2MObserveRequest) { | ||
480 | + versionedId = ((TbLwM2MObserveRequest) request).getVersionedId(); | ||
481 | + } | ||
482 | + String id = fromVersionedIdToObjectId(versionedId); | ||
483 | + if (id != null && new LwM2mPath(id).isResource() && !client.isResourceMultiInstances(versionedId, modelProvider)) { | ||
484 | + return client.getDefaultContentFormat(); | ||
485 | + } | ||
486 | + else { | ||
487 | + return ContentFormat.DEFAULT; | ||
488 | + } | ||
489 | + } | ||
352 | } | 490 | } |
353 | } | 491 | } |
@@ -19,5 +19,9 @@ import org.eclipse.leshan.core.request.ContentFormat; | @@ -19,5 +19,9 @@ import org.eclipse.leshan.core.request.ContentFormat; | ||
19 | 19 | ||
20 | public interface HasContentFormat { | 20 | public interface HasContentFormat { |
21 | 21 | ||
22 | - ContentFormat getContentFormat(); | 22 | + ContentFormat getRequestContentFormat(); |
23 | + | ||
24 | + default ContentFormat getResponseContentFormat() { | ||
25 | + return null; | ||
26 | + } | ||
23 | } | 27 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.lwm2m.server.downlink; | ||
17 | + | ||
18 | +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; | ||
19 | + | ||
20 | +import java.util.Set; | ||
21 | +import java.util.concurrent.ConcurrentHashMap; | ||
22 | + | ||
23 | +public interface HasVersionedIds { | ||
24 | + | ||
25 | + String[] getVersionedIds(); | ||
26 | + | ||
27 | + default String[] getObjectIds() { | ||
28 | + Set objectIds = ConcurrentHashMap.newKeySet(); | ||
29 | + for (String versionedId : getVersionedIds()) { | ||
30 | + objectIds.add(LwM2mTransportUtil.fromVersionedIdToObjectId(versionedId)); | ||
31 | + } | ||
32 | + return (String[]) objectIds.toArray(String[]::new); | ||
33 | + } | ||
34 | + | ||
35 | +} |
@@ -20,6 +20,7 @@ import org.eclipse.leshan.core.request.DeleteRequest; | @@ -20,6 +20,7 @@ import org.eclipse.leshan.core.request.DeleteRequest; | ||
20 | import org.eclipse.leshan.core.request.DiscoverRequest; | 20 | import org.eclipse.leshan.core.request.DiscoverRequest; |
21 | import org.eclipse.leshan.core.request.ExecuteRequest; | 21 | import org.eclipse.leshan.core.request.ExecuteRequest; |
22 | import org.eclipse.leshan.core.request.ObserveRequest; | 22 | import org.eclipse.leshan.core.request.ObserveRequest; |
23 | +import org.eclipse.leshan.core.request.ReadCompositeRequest; | ||
23 | import org.eclipse.leshan.core.request.ReadRequest; | 24 | import org.eclipse.leshan.core.request.ReadRequest; |
24 | import org.eclipse.leshan.core.request.WriteAttributesRequest; | 25 | import org.eclipse.leshan.core.request.WriteAttributesRequest; |
25 | import org.eclipse.leshan.core.request.WriteRequest; | 26 | import org.eclipse.leshan.core.request.WriteRequest; |
@@ -27,18 +28,24 @@ import org.eclipse.leshan.core.response.DeleteResponse; | @@ -27,18 +28,24 @@ import org.eclipse.leshan.core.response.DeleteResponse; | ||
27 | import org.eclipse.leshan.core.response.DiscoverResponse; | 28 | import org.eclipse.leshan.core.response.DiscoverResponse; |
28 | import org.eclipse.leshan.core.response.ExecuteResponse; | 29 | import org.eclipse.leshan.core.response.ExecuteResponse; |
29 | import org.eclipse.leshan.core.response.ObserveResponse; | 30 | import org.eclipse.leshan.core.response.ObserveResponse; |
31 | +import org.eclipse.leshan.core.response.ReadCompositeResponse; | ||
30 | import org.eclipse.leshan.core.response.ReadResponse; | 32 | import org.eclipse.leshan.core.response.ReadResponse; |
31 | import org.eclipse.leshan.core.response.WriteAttributesResponse; | 33 | import org.eclipse.leshan.core.response.WriteAttributesResponse; |
32 | import org.eclipse.leshan.core.response.WriteResponse; | 34 | import org.eclipse.leshan.core.response.WriteResponse; |
33 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | 35 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
36 | +import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest; | ||
37 | +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; | ||
34 | 38 | ||
35 | import java.util.List; | 39 | import java.util.List; |
40 | +import java.util.Map; | ||
36 | import java.util.Set; | 41 | import java.util.Set; |
37 | 42 | ||
38 | public interface LwM2mDownlinkMsgHandler { | 43 | public interface LwM2mDownlinkMsgHandler { |
39 | 44 | ||
40 | void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback); | 45 | void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback); |
41 | 46 | ||
47 | + void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback); | ||
48 | + | ||
42 | void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback); | 49 | void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback); |
43 | 50 | ||
44 | void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback<TbLwM2MObserveAllRequest, Set<String>> callback); | 51 | void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback<TbLwM2MObserveAllRequest, Set<String>> callback); |
@@ -59,6 +66,8 @@ public interface LwM2mDownlinkMsgHandler { | @@ -59,6 +66,8 @@ public interface LwM2mDownlinkMsgHandler { | ||
59 | 66 | ||
60 | void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback); | 67 | void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback); |
61 | 68 | ||
69 | + void sendWriteCompositeRequest(LwM2mClient client, Map<String, Object> nodes, DefaultLwM2MUplinkMsgHandler handler); | ||
70 | + | ||
62 | void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback); | 71 | void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback); |
63 | 72 | ||
64 | 73 |
@@ -24,12 +24,12 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; | @@ -24,12 +24,12 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; | ||
24 | public class TbLwM2MObserveRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ObserveResponse> implements HasContentFormat { | 24 | public class TbLwM2MObserveRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ObserveResponse> implements HasContentFormat { |
25 | 25 | ||
26 | @Getter | 26 | @Getter |
27 | - private final ContentFormat contentFormat; | 27 | + private final ContentFormat requestContentFormat; |
28 | 28 | ||
29 | @Builder | 29 | @Builder |
30 | - private TbLwM2MObserveRequest(String versionedId, long timeout, ContentFormat contentFormat) { | 30 | + private TbLwM2MObserveRequest(String versionedId, long timeout, ContentFormat requestContentFormat) { |
31 | super(versionedId, timeout); | 31 | super(versionedId, timeout); |
32 | - this.contentFormat = contentFormat; | 32 | + this.requestContentFormat = requestContentFormat; |
33 | } | 33 | } |
34 | 34 | ||
35 | @Override | 35 | @Override |
@@ -24,12 +24,12 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; | @@ -24,12 +24,12 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; | ||
24 | public class TbLwM2MReadRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ReadResponse> implements HasContentFormat { | 24 | public class TbLwM2MReadRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ReadResponse> implements HasContentFormat { |
25 | 25 | ||
26 | @Getter | 26 | @Getter |
27 | - private final ContentFormat contentFormat; | 27 | + private final ContentFormat requestContentFormat; |
28 | 28 | ||
29 | @Builder | 29 | @Builder |
30 | - private TbLwM2MReadRequest(String versionedId, long timeout, ContentFormat contentFormat) { | 30 | + private TbLwM2MReadRequest(String versionedId, long timeout, ContentFormat requestContentFormat) { |
31 | super(versionedId, timeout); | 31 | super(versionedId, timeout); |
32 | - this.contentFormat = contentFormat; | 32 | + this.requestContentFormat = requestContentFormat; |
33 | } | 33 | } |
34 | 34 | ||
35 | @Override | 35 | @Override |
@@ -18,7 +18,8 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; | @@ -18,7 +18,8 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | 19 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
20 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; | 20 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; |
21 | -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; | 21 | + |
22 | +import java.util.Arrays; | ||
22 | 23 | ||
23 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; | 24 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; |
24 | 25 | ||
@@ -26,18 +27,26 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L | @@ -26,18 +27,26 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L | ||
26 | public abstract class TbLwM2MTargetedCallback<R, T> extends AbstractTbLwM2MRequestCallback<R, T> { | 27 | public abstract class TbLwM2MTargetedCallback<R, T> extends AbstractTbLwM2MRequestCallback<R, T> { |
27 | 28 | ||
28 | protected final String versionedId; | 29 | protected final String versionedId; |
30 | + protected final String[] versionedIds; | ||
29 | 31 | ||
30 | public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) { | 32 | public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) { |
31 | super(logService, client); | 33 | super(logService, client); |
32 | this.versionedId = versionedId; | 34 | this.versionedId = versionedId; |
35 | + this.versionedIds = null; | ||
36 | + } | ||
37 | + | ||
38 | + public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { | ||
39 | + super(logService, client); | ||
40 | + this.versionedId = null; | ||
41 | + this.versionedIds = versionedIds; | ||
33 | } | 42 | } |
34 | 43 | ||
35 | @Override | 44 | @Override |
36 | public void onSuccess(R request, T response) { | 45 | public void onSuccess(R request, T response) { |
37 | //TODO convert camelCase to "camel case" using .split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])") | 46 | //TODO convert camelCase to "camel case" using .split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])") |
38 | String requestName = request.getClass().getSimpleName(); | 47 | String requestName = request.getClass().getSimpleName(); |
39 | - log.trace("[{}] {} [{}] successful: {}", client.getEndpoint(), requestName, versionedId, response); | ||
40 | - logService.log(client, String.format("[%s]: %s [%s] successful. Result: [%s]", LOG_LWM2M_INFO, requestName, versionedId, response)); | 48 | + log.trace("[{}] {} [{}] successful: {}", client.getEndpoint(), requestName, versionedId != null ? versionedId : versionedIds, response); |
49 | + logService.log(client, String.format("[%s]: %s [%s] successful. Result: [%s]", LOG_LWM2M_INFO, requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), response)); | ||
41 | } | 50 | } |
42 | 51 | ||
43 | } | 52 | } |
@@ -20,8 +20,6 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | @@ -20,8 +20,6 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | ||
20 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; | 20 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; |
21 | import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; | 21 | import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; |
22 | 22 | ||
23 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; | ||
24 | - | ||
25 | @Slf4j | 23 | @Slf4j |
26 | public abstract class TbLwM2MUplinkTargetedCallback<R, T> extends TbLwM2MTargetedCallback<R, T> { | 24 | public abstract class TbLwM2MUplinkTargetedCallback<R, T> extends TbLwM2MTargetedCallback<R, T> { |
27 | 25 | ||
@@ -32,4 +30,9 @@ public abstract class TbLwM2MUplinkTargetedCallback<R, T> extends TbLwM2MTargete | @@ -32,4 +30,9 @@ public abstract class TbLwM2MUplinkTargetedCallback<R, T> extends TbLwM2MTargete | ||
32 | this.handler = handler; | 30 | this.handler = handler; |
33 | } | 31 | } |
34 | 32 | ||
33 | + public TbLwM2MUplinkTargetedCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { | ||
34 | + super(logService, client, versionedIds); | ||
35 | + this.handler = handler; | ||
36 | + } | ||
37 | + | ||
35 | } | 38 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.lwm2m.server.downlink.composite; | ||
17 | + | ||
18 | +import lombok.Getter; | ||
19 | +import org.thingsboard.server.transport.lwm2m.server.downlink.HasVersionedIds; | ||
20 | +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDownlinkRequest; | ||
21 | + | ||
22 | +public abstract class AbstractTbLwM2MTargetedDownlinkCompositeRequest<T> implements TbLwM2MDownlinkRequest<T>, HasVersionedIds { | ||
23 | + | ||
24 | + @Getter | ||
25 | + private final String [] versionedIds; | ||
26 | + @Getter | ||
27 | + private final long timeout; | ||
28 | + | ||
29 | + public AbstractTbLwM2MTargetedDownlinkCompositeRequest(String [] versionedIds, long timeout) { | ||
30 | + this.versionedIds = versionedIds; | ||
31 | + this.timeout = timeout; | ||
32 | + } | ||
33 | + | ||
34 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.lwm2m.server.downlink.composite; | ||
17 | + | ||
18 | +import lombok.extern.slf4j.Slf4j; | ||
19 | +import org.eclipse.leshan.core.request.ReadCompositeRequest; | ||
20 | +import org.eclipse.leshan.core.response.ReadCompositeResponse; | ||
21 | +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | ||
22 | +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MUplinkTargetedCallback; | ||
23 | +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; | ||
24 | +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; | ||
25 | + | ||
26 | +@Slf4j | ||
27 | +public class TbLwM2MReadCompositeCallback extends TbLwM2MUplinkTargetedCallback<ReadCompositeRequest, ReadCompositeResponse> { | ||
28 | + | ||
29 | + public TbLwM2MReadCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String[] versionedIds) { | ||
30 | + super(handler, logService, client, versionedIds); | ||
31 | + } | ||
32 | + | ||
33 | + @Override | ||
34 | + public void onSuccess(ReadCompositeRequest request, ReadCompositeResponse response) { | ||
35 | + super.onSuccess(request, response); | ||
36 | + handler.onUpdateValueAfterReadCompositeResponse(client.getRegistration(), response); | ||
37 | + } | ||
38 | + | ||
39 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.lwm2m.server.downlink.composite; | ||
17 | + | ||
18 | +import lombok.Builder; | ||
19 | +import lombok.Getter; | ||
20 | +import org.eclipse.leshan.core.request.ContentFormat; | ||
21 | +import org.eclipse.leshan.core.response.ReadCompositeResponse; | ||
22 | +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; | ||
23 | +import org.thingsboard.server.transport.lwm2m.server.downlink.HasContentFormat; | ||
24 | + | ||
25 | +public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlinkCompositeRequest<ReadCompositeResponse> implements HasContentFormat { | ||
26 | + | ||
27 | + @Getter | ||
28 | + private final ContentFormat requestContentFormat; | ||
29 | + | ||
30 | + @Getter | ||
31 | + private final ContentFormat responseContentFormat; | ||
32 | + | ||
33 | + @Builder | ||
34 | + private TbLwM2MReadCompositeRequest(String [] versionedIds, long timeout, ContentFormat requestContentFormat, ContentFormat responseContentFormat) { | ||
35 | + super(versionedIds, timeout); | ||
36 | + this.requestContentFormat = requestContentFormat; | ||
37 | + this.responseContentFormat = responseContentFormat; | ||
38 | + } | ||
39 | + | ||
40 | + @Override | ||
41 | + public LwM2mOperationType getType() { | ||
42 | + return LwM2mOperationType.READ_COMPOSITE; | ||
43 | + } | ||
44 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.lwm2m.server.downlink.composite; | ||
17 | + | ||
18 | +import lombok.Builder; | ||
19 | +import lombok.Getter; | ||
20 | +import org.eclipse.leshan.core.request.ContentFormat; | ||
21 | +import org.eclipse.leshan.core.response.WriteCompositeResponse; | ||
22 | +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; | ||
23 | +import org.thingsboard.server.transport.lwm2m.server.downlink.AbstractTbLwM2MTargetedDownlinkRequest; | ||
24 | + | ||
25 | +public class TbLwM2MWriteCompositeRequest extends AbstractTbLwM2MTargetedDownlinkRequest<WriteCompositeResponse> { | ||
26 | + | ||
27 | + @Getter | ||
28 | + private final ContentFormat contentFormat; | ||
29 | + @Getter | ||
30 | + private final Object value; | ||
31 | + | ||
32 | + @Builder | ||
33 | + private TbLwM2MWriteCompositeRequest(String versionedId, long timeout, ContentFormat contentFormat, Object value) { | ||
34 | + super(versionedId, timeout); | ||
35 | + this.contentFormat = contentFormat; | ||
36 | + this.value = value; | ||
37 | + } | ||
38 | + | ||
39 | + @Override | ||
40 | + public LwM2mOperationType getType() { | ||
41 | + return LwM2mOperationType.WRITE_REPLACE; | ||
42 | + } | ||
43 | + | ||
44 | + | ||
45 | + | ||
46 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.lwm2m.server.downlink.composite; | ||
17 | + | ||
18 | +import org.eclipse.leshan.core.request.WriteCompositeRequest; | ||
19 | +import org.eclipse.leshan.core.response.WriteCompositeResponse; | ||
20 | +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | ||
21 | +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MUplinkTargetedCallback; | ||
22 | +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; | ||
23 | +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; | ||
24 | + | ||
25 | +public class TbLwM2MWriteResponseCompositeCallback extends TbLwM2MUplinkTargetedCallback<WriteCompositeRequest, WriteCompositeResponse> { | ||
26 | + | ||
27 | + public TbLwM2MWriteResponseCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) { | ||
28 | + super(handler, logService, client, targetId); | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public void onSuccess(WriteCompositeRequest request, WriteCompositeResponse response) { | ||
33 | + super.onSuccess(request, response); | ||
34 | + handler.onWriteCompositeResponseOk(client, request); | ||
35 | + } | ||
36 | + | ||
37 | +} |
@@ -50,7 +50,12 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib | @@ -50,7 +50,12 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib | ||
50 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; | 50 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; |
51 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback; | 51 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback; |
52 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteUpdateRequest; | 52 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteUpdateRequest; |
53 | +import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeCallback; | ||
54 | +import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest; | ||
53 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; | 55 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; |
56 | +import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadCompositeRequest; | ||
57 | +import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadResponseCompositeCallback; | ||
58 | +import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest; | ||
54 | import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; | 59 | import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; |
55 | 60 | ||
56 | import java.util.Map; | 61 | import java.util.Map; |
@@ -125,6 +130,17 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { | @@ -125,6 +130,17 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { | ||
125 | default: | 130 | default: |
126 | throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); | 131 | throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); |
127 | } | 132 | } |
133 | + } else if (operationType.isComposite()) { | ||
134 | + switch (operationType) { | ||
135 | + case READ_COMPOSITE: | ||
136 | + sendReadCompositeRequest(client, rpcRequst); | ||
137 | + break; | ||
138 | + case WRITE_COMPOSITE: | ||
139 | + sendWriteCompositeRequest(client, rpcRequst); | ||
140 | + break; | ||
141 | + default: | ||
142 | + throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); | ||
143 | + } | ||
128 | } else { | 144 | } else { |
129 | switch (operationType) { | 145 | switch (operationType) { |
130 | case OBSERVE_CANCEL_ALL: | 146 | case OBSERVE_CANCEL_ALL: |
@@ -151,14 +167,22 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { | @@ -151,14 +167,22 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { | ||
151 | private void sendReadRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { | 167 | private void sendReadRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { |
152 | TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); | 168 | TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); |
153 | var mainCallback = new TbLwM2MReadCallback(uplinkHandler, logService, client, versionedId); | 169 | var mainCallback = new TbLwM2MReadCallback(uplinkHandler, logService, client, versionedId); |
154 | - var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, versionedId, mainCallback); | 170 | + var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, mainCallback); |
155 | downlinkHandler.sendReadRequest(client, request, rpcCallback); | 171 | downlinkHandler.sendReadRequest(client, request, rpcCallback); |
156 | } | 172 | } |
157 | 173 | ||
174 | + private void sendReadCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { | ||
175 | + String[] versionedIds = getIdsFromParameters(client, requestMsg); | ||
176 | + TbLwM2MReadCompositeRequest request = TbLwM2MReadCompositeRequest.builder().versionedIds(versionedIds).timeout(this.config.getTimeout()).build(); | ||
177 | + var mainCallback = new TbLwM2MReadCompositeCallback(uplinkHandler, logService, client, versionedIds); | ||
178 | + var rpcCallback = new RpcReadResponseCompositeCallback(transportService, client, requestMsg, mainCallback); | ||
179 | + downlinkHandler.sendReadCompositeRequest(client, request, rpcCallback); | ||
180 | + } | ||
181 | + | ||
158 | private void sendObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { | 182 | private void sendObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { |
159 | TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); | 183 | TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); |
160 | var mainCallback = new TbLwM2MObserveCallback(uplinkHandler, logService, client, versionedId); | 184 | var mainCallback = new TbLwM2MObserveCallback(uplinkHandler, logService, client, versionedId); |
161 | - var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, versionedId, mainCallback); | 185 | + var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, mainCallback); |
162 | downlinkHandler.sendObserveRequest(client, request, rpcCallback); | 186 | downlinkHandler.sendObserveRequest(client, request, rpcCallback); |
163 | } | 187 | } |
164 | 188 | ||
@@ -215,6 +239,16 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { | @@ -215,6 +239,16 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { | ||
215 | downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback); | 239 | downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback); |
216 | } | 240 | } |
217 | 241 | ||
242 | + private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) { | ||
243 | + RpcWriteCompositeRequest nodes = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class); | ||
244 | +// TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId) | ||
245 | +// .value(requestBody.getValue()) | ||
246 | +// .timeout(this.config.getTimeout()).build(); | ||
247 | +// var mainCallback = new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId); | ||
248 | +// var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback); | ||
249 | +// downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback); | ||
250 | + } | ||
251 | + | ||
218 | private void sendCancelObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { | 252 | private void sendCancelObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { |
219 | TbLwM2MCancelObserveRequest downlink = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); | 253 | TbLwM2MCancelObserveRequest downlink = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build(); |
220 | var mainCallback = new TbLwM2MCancelObserveCallback(logService, client, versionedId); | 254 | var mainCallback = new TbLwM2MCancelObserveCallback(logService, client, versionedId); |
@@ -249,6 +283,24 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { | @@ -249,6 +283,24 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { | ||
249 | return targetId; | 283 | return targetId; |
250 | } | 284 | } |
251 | 285 | ||
286 | + private String[] getIdsFromParameters(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequst) { | ||
287 | + RpcReadCompositeRequest requestParams = JacksonUtil.fromString(rpcRequst.getParams(), RpcReadCompositeRequest.class); | ||
288 | + if (requestParams.getKeys() != null && requestParams.getKeys().length > 0) { | ||
289 | + Set targetIds = ConcurrentHashMap.newKeySet(); | ||
290 | + for (String key : requestParams.getKeys()) { | ||
291 | + String targetId = clientContext.getObjectIdByKeyNameFromProfile(client, key); | ||
292 | + if (targetId != null) { | ||
293 | + targetIds.add(targetId); | ||
294 | + } | ||
295 | + } | ||
296 | + return (String[]) targetIds.toArray(String[]::new); | ||
297 | + } else if (requestParams.getIds() != null && requestParams.getIds().length > 0) { | ||
298 | + return requestParams.getIds(); | ||
299 | + } else { | ||
300 | + throw new IllegalArgumentException("Can't find 'key' or 'id' in the requestParams parameters!"); | ||
301 | + } | ||
302 | + } | ||
303 | + | ||
252 | private void sendErrorRpcResponse(TransportProtos.SessionInfoProto sessionInfo, int requestId, String result, String error) { | 304 | private void sendErrorRpcResponse(TransportProtos.SessionInfoProto sessionInfo, int requestId, String result, String error) { |
253 | String payload = JacksonUtil.toString(JacksonUtil.newObjectNode().put("result", result).put("error", error)); | 305 | String payload = JacksonUtil.toString(JacksonUtil.newObjectNode().put("result", result).put("error", error)); |
254 | TransportProtos.ToDeviceRpcResponseMsg msg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId).setPayload(payload).build(); | 306 | TransportProtos.ToDeviceRpcResponseMsg msg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId).setPayload(payload).build(); |
@@ -16,13 +16,11 @@ | @@ -16,13 +16,11 @@ | ||
16 | package org.thingsboard.server.transport.lwm2m.server.rpc; | 16 | package org.thingsboard.server.transport.lwm2m.server.rpc; |
17 | 17 | ||
18 | import org.eclipse.leshan.core.ResponseCode; | 18 | import org.eclipse.leshan.core.ResponseCode; |
19 | -import org.eclipse.leshan.core.node.codec.LwM2mValueConverter; | ||
20 | import org.thingsboard.common.util.JacksonUtil; | 19 | import org.thingsboard.common.util.JacksonUtil; |
21 | import org.thingsboard.server.common.transport.TransportService; | 20 | import org.thingsboard.server.common.transport.TransportService; |
22 | import org.thingsboard.server.gen.transport.TransportProtos; | 21 | import org.thingsboard.server.gen.transport.TransportProtos; |
23 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | 22 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
24 | import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; | 23 | import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; |
25 | -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; | ||
26 | 24 | ||
27 | public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkRequestCallback<R, T> { | 25 | public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkRequestCallback<R, T> { |
28 | 26 | ||
@@ -31,14 +29,12 @@ public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkR | @@ -31,14 +29,12 @@ public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkR | ||
31 | private final DownlinkRequestCallback<R, T> callback; | 29 | private final DownlinkRequestCallback<R, T> callback; |
32 | 30 | ||
33 | protected final LwM2mClient client; | 31 | protected final LwM2mClient client; |
34 | - protected final LwM2mValueConverter converter; | ||
35 | 32 | ||
36 | public RpcDownlinkRequestCallbackProxy(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) { | 33 | public RpcDownlinkRequestCallbackProxy(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) { |
37 | this.transportService = transportService; | 34 | this.transportService = transportService; |
38 | this.client = client; | 35 | this.client = client; |
39 | this.request = requestMsg; | 36 | this.request = requestMsg; |
40 | this.callback = callback; | 37 | this.callback = callback; |
41 | - this.converter = LwM2mValueConverterImpl.getInstance(); | ||
42 | } | 38 | } |
43 | 39 | ||
44 | @Override | 40 | @Override |
@@ -29,22 +29,19 @@ import java.util.Optional; | @@ -29,22 +29,19 @@ import java.util.Optional; | ||
29 | 29 | ||
30 | public class RpcReadResponseCallback<R extends LwM2mRequest<T>, T extends ReadResponse> extends RpcLwM2MDownlinkCallback<R, T> { | 30 | public class RpcReadResponseCallback<R extends LwM2mRequest<T>, T extends ReadResponse> extends RpcLwM2MDownlinkCallback<R, T> { |
31 | 31 | ||
32 | - private final String versionedId; | ||
33 | - | ||
34 | - public RpcReadResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId, DownlinkRequestCallback<R, T> callback) { | 32 | + public RpcReadResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) { |
35 | super(transportService, client, requestMsg, callback); | 33 | super(transportService, client, requestMsg, callback); |
36 | - this.versionedId = versionedId; | ||
37 | } | 34 | } |
38 | 35 | ||
39 | @Override | 36 | @Override |
40 | protected Optional<String> serializeSuccessfulResponse(T response) { | 37 | protected Optional<String> serializeSuccessfulResponse(T response) { |
41 | Object value = null; | 38 | Object value = null; |
42 | if (response.getContent() instanceof LwM2mObject) { | 39 | if (response.getContent() instanceof LwM2mObject) { |
43 | - value = client.objectToString((LwM2mObject) response.getContent(), this.converter, versionedId); | 40 | + value = client.objectToString((LwM2mObject) response.getContent()); |
44 | } else if (response.getContent() instanceof LwM2mObjectInstance) { | 41 | } else if (response.getContent() instanceof LwM2mObjectInstance) { |
45 | - value = client.instanceToString((LwM2mObjectInstance) response.getContent(), this.converter, versionedId); | 42 | + value = client.instanceToString((LwM2mObjectInstance) response.getContent()); |
46 | } else if (response.getContent() instanceof LwM2mResource) { | 43 | } else if (response.getContent() instanceof LwM2mResource) { |
47 | - value = client.resourceToString((LwM2mResource) response.getContent(), this.converter, versionedId); | 44 | + value = client.resourceToString((LwM2mResource) response.getContent()); |
48 | } | 45 | } |
49 | return Optional.of(String.format("%s", value)); | 46 | return Optional.of(String.format("%s", value)); |
50 | } | 47 | } |
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadCompositeRequest.java
renamed from
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/client/LwM2mSoftwareUpdate.java
@@ -13,15 +13,16 @@ | @@ -13,15 +13,16 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.transport.lwm2m.client; | 16 | +package org.thingsboard.server.transport.lwm2m.server.rpc.composite; |
17 | 17 | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
18 | import lombok.Data; | 19 | import lombok.Data; |
19 | 20 | ||
20 | -import java.util.UUID; | ||
21 | - | ||
22 | @Data | 21 | @Data |
23 | -public class LwM2mSoftwareUpdate { | ||
24 | - private volatile String clientSwVersion; | ||
25 | - private volatile String currentSwVersion; | ||
26 | - private volatile UUID currentSwId; | ||
27 | -} | ||
22 | +@JsonIgnoreProperties(ignoreUnknown = true) | ||
23 | +public class RpcReadCompositeRequest { | ||
24 | + | ||
25 | + private String [] keys; | ||
26 | + private String [] ids; | ||
27 | + | ||
28 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.lwm2m.server.rpc.composite; | ||
17 | + | ||
18 | +import org.eclipse.leshan.core.request.LwM2mRequest; | ||
19 | +import org.eclipse.leshan.core.request.ReadCompositeRequest; | ||
20 | +import org.eclipse.leshan.core.response.ReadCompositeResponse; | ||
21 | +import org.thingsboard.server.common.transport.TransportService; | ||
22 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
23 | +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | ||
24 | +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback; | ||
25 | +import org.thingsboard.server.transport.lwm2m.server.rpc.RpcLwM2MDownlinkCallback; | ||
26 | + | ||
27 | +import java.util.Optional; | ||
28 | + | ||
29 | +public class RpcReadResponseCompositeCallback<R extends LwM2mRequest<T>, T extends ReadCompositeResponse> extends RpcLwM2MDownlinkCallback<R, T> { | ||
30 | + | ||
31 | + public RpcReadResponseCompositeCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) { | ||
32 | + super(transportService, client, requestMsg, callback); | ||
33 | + } | ||
34 | + | ||
35 | + @Override | ||
36 | + protected Optional<String> serializeSuccessfulResponse(T response) { | ||
37 | + return Optional.of(String.format("%s", response.getContent().toString())); | ||
38 | + } | ||
39 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.lwm2m.server.rpc.composite; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
19 | +import lombok.Data; | ||
20 | + | ||
21 | +import java.util.Map; | ||
22 | + | ||
23 | +@Data | ||
24 | +@JsonIgnoreProperties(ignoreUnknown = true) | ||
25 | +public class RpcWriteCompositeRequest { | ||
26 | + | ||
27 | + private Map<String, Object> nodes; | ||
28 | + | ||
29 | +} |
@@ -30,8 +30,10 @@ import org.eclipse.leshan.core.node.LwM2mResource; | @@ -30,8 +30,10 @@ import org.eclipse.leshan.core.node.LwM2mResource; | ||
30 | import org.eclipse.leshan.core.observation.Observation; | 30 | import org.eclipse.leshan.core.observation.Observation; |
31 | import org.eclipse.leshan.core.request.ObserveRequest; | 31 | import org.eclipse.leshan.core.request.ObserveRequest; |
32 | import org.eclipse.leshan.core.request.ReadRequest; | 32 | import org.eclipse.leshan.core.request.ReadRequest; |
33 | +import org.eclipse.leshan.core.request.WriteCompositeRequest; | ||
33 | import org.eclipse.leshan.core.request.WriteRequest; | 34 | import org.eclipse.leshan.core.request.WriteRequest; |
34 | import org.eclipse.leshan.core.response.ObserveResponse; | 35 | import org.eclipse.leshan.core.response.ObserveResponse; |
36 | +import org.eclipse.leshan.core.response.ReadCompositeResponse; | ||
35 | import org.eclipse.leshan.core.response.ReadResponse; | 37 | import org.eclipse.leshan.core.response.ReadResponse; |
36 | import org.eclipse.leshan.server.registration.Registration; | 38 | import org.eclipse.leshan.server.registration.Registration; |
37 | import org.springframework.context.annotation.Lazy; | 39 | import org.springframework.context.annotation.Lazy; |
@@ -89,6 +91,7 @@ import javax.annotation.PreDestroy; | @@ -89,6 +91,7 @@ import javax.annotation.PreDestroy; | ||
89 | import java.util.ArrayList; | 91 | import java.util.ArrayList; |
90 | import java.util.Collection; | 92 | import java.util.Collection; |
91 | import java.util.Collections; | 93 | import java.util.Collections; |
94 | +import java.util.HashMap; | ||
92 | import java.util.HashSet; | 95 | import java.util.HashSet; |
93 | import java.util.List; | 96 | import java.util.List; |
94 | import java.util.Map; | 97 | import java.util.Map; |
@@ -315,6 +318,24 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | @@ -315,6 +318,24 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | ||
315 | } | 318 | } |
316 | } | 319 | } |
317 | 320 | ||
321 | + public void onUpdateValueAfterReadCompositeResponse(Registration registration, ReadCompositeResponse response) { | ||
322 | + log.warn("201) ReadCompositeResponse: [{}]", response); | ||
323 | + if (response.getContent() != null) { | ||
324 | + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); | ||
325 | + response.getContent().forEach((k, v) -> { | ||
326 | + if (v != null) { | ||
327 | + if (v instanceof LwM2mObject) { | ||
328 | + this.updateObjectResourceValue(lwM2MClient, (LwM2mObject) v, k.toString()); | ||
329 | + } else if (v instanceof LwM2mObjectInstance) { | ||
330 | + this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString()); | ||
331 | + } else if (v instanceof LwM2mResource) { | ||
332 | + this.updateResourcesValue(lwM2MClient, (LwM2mResource) v, k.toString()); | ||
333 | + } | ||
334 | + } | ||
335 | + }); | ||
336 | + } | ||
337 | + } | ||
338 | + | ||
318 | /** | 339 | /** |
319 | * @param sessionInfo - | 340 | * @param sessionInfo - |
320 | * @param deviceProfile - | 341 | * @param deviceProfile - |
@@ -406,6 +427,17 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | @@ -406,6 +427,17 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | ||
406 | if (supportedObjects != null && supportedObjects.size() > 0) { | 427 | if (supportedObjects != null && supportedObjects.size() > 0) { |
407 | // #1 | 428 | // #1 |
408 | this.sendReadRequests(lwM2MClient, profile, supportedObjects); | 429 | this.sendReadRequests(lwM2MClient, profile, supportedObjects); |
430 | + // test composite | ||
431 | + String[] paths = new String[]{"/3/0", "/1/0", "/5/0"}; | ||
432 | +// String [] paths = new String[] {"/5"}; | ||
433 | +// String [] paths = new String[] {"/"}; | ||
434 | +// String [] paths = new String[] {"/9"}; | ||
435 | +// defaultLwM2MDownlinkMsgHandler.sendReadCompositeRequest(lwM2MClient, paths, this); | ||
436 | + Map<String, Object> nodes = new HashMap<>(); | ||
437 | + nodes.put("/3/0/14", "+02"); | ||
438 | + nodes.put("/1/0/2", 100); | ||
439 | + nodes.put("/5/0/1", "coap://localhost:5685"); | ||
440 | +// defaultLwM2MDownlinkMsgHandler.sendWriteCompositeRequest(lwM2MClient, nodes, this); | ||
409 | this.sendObserveRequests(lwM2MClient, profile, supportedObjects); | 441 | this.sendObserveRequests(lwM2MClient, profile, supportedObjects); |
410 | this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects); | 442 | this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects); |
411 | // Removed. Used only for debug. | 443 | // Removed. Used only for debug. |
@@ -682,6 +714,14 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | @@ -682,6 +714,14 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | ||
682 | } | 714 | } |
683 | } | 715 | } |
684 | 716 | ||
717 | + @Override | ||
718 | + public void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request) { | ||
719 | + log.warn("202) ReadCompositeResponse: [{}]", request.getNodes()); | ||
720 | + request.getNodes().forEach((k, v) -> { | ||
721 | + this.updateResourcesValue(client, (LwM2mResource) v, k.toString()); | ||
722 | + }); | ||
723 | + } | ||
724 | + | ||
685 | //TODO: review and optimize the logic to minimize number of the requests to device. | 725 | //TODO: review and optimize the logic to minimize number of the requests to device. |
686 | private void onDeviceProfileUpdate(List<LwM2mClient> clients, DeviceProfile deviceProfile) { | 726 | private void onDeviceProfileUpdate(List<LwM2mClient> clients, DeviceProfile deviceProfile) { |
687 | var oldProfile = clientContext.getProfile(deviceProfile.getUuidId()); | 727 | var oldProfile = clientContext.getProfile(deviceProfile.getUuidId()); |
@@ -16,7 +16,9 @@ | @@ -16,7 +16,9 @@ | ||
16 | package org.thingsboard.server.transport.lwm2m.server.uplink; | 16 | package org.thingsboard.server.transport.lwm2m.server.uplink; |
17 | 17 | ||
18 | import org.eclipse.leshan.core.observation.Observation; | 18 | import org.eclipse.leshan.core.observation.Observation; |
19 | +import org.eclipse.leshan.core.request.WriteCompositeRequest; | ||
19 | import org.eclipse.leshan.core.request.WriteRequest; | 20 | import org.eclipse.leshan.core.request.WriteRequest; |
21 | +import org.eclipse.leshan.core.response.ReadCompositeResponse; | ||
20 | import org.eclipse.leshan.core.response.ReadResponse; | 22 | import org.eclipse.leshan.core.response.ReadResponse; |
21 | import org.eclipse.leshan.server.registration.Registration; | 23 | import org.eclipse.leshan.server.registration.Registration; |
22 | import org.thingsboard.server.common.data.Device; | 24 | import org.thingsboard.server.common.data.Device; |
@@ -40,6 +42,8 @@ public interface LwM2mUplinkMsgHandler { | @@ -40,6 +42,8 @@ public interface LwM2mUplinkMsgHandler { | ||
40 | 42 | ||
41 | void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response); | 43 | void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response); |
42 | 44 | ||
45 | + void onUpdateValueAfterReadCompositeResponse(Registration registration, ReadCompositeResponse response); | ||
46 | + | ||
43 | void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile); | 47 | void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile); |
44 | 48 | ||
45 | void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt); | 49 | void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt); |
@@ -52,6 +56,8 @@ public interface LwM2mUplinkMsgHandler { | @@ -52,6 +56,8 @@ public interface LwM2mUplinkMsgHandler { | ||
52 | 56 | ||
53 | void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request); | 57 | void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request); |
54 | 58 | ||
59 | + void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request); | ||
60 | + | ||
55 | void onToTransportUpdateCredentials(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToTransportUpdateCredentialsProto updateCredentials); | 61 | void onToTransportUpdateCredentials(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToTransportUpdateCredentialsProto updateCredentials); |
56 | 62 | ||
57 | LwM2MTransportServerConfig getConfig(); | 63 | LwM2MTransportServerConfig getConfig(); |