Commit 427ab87443b6920c89fcf9a2e87b1e95dca4b254

Authored by Andrew Shvayka
Committed by GitHub
2 parents 8b285c8e 209c9306

Merge pull request #4760 from thingsboard/feature/lwm2m-refactoring-downlink

Lwm2m Refactoring Downlink
Showing 34 changed files with 1049 additions and 2890 deletions

Too many changes to show.

To preserve performance only 34 of 97 files are displayed.

@@ -677,12 +677,11 @@ transport: @@ -677,12 +677,11 @@ transport:
677 timeout: "${LWM2M_TIMEOUT:120000}" 677 timeout: "${LWM2M_TIMEOUT:120000}"
678 recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" 678 recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
679 recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" 679 recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
680 - response_pool_size: "${LWM2M_RESPONSE_POOL_SIZE:100}"  
681 - registered_pool_size: "${LWM2M_REGISTERED_POOL_SIZE:10}" 680 + uplink_pool_size: "${LWM2M_UPLINK_POOL_SIZE:10}"
  681 + downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}"
  682 + ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}"
682 registration_store_pool_size: "${LWM2M_REGISTRATION_STORE_POOL_SIZE:100}" 683 registration_store_pool_size: "${LWM2M_REGISTRATION_STORE_POOL_SIZE:100}"
683 clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" 684 clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}"
684 - update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}"  
685 - un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}"  
686 log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}" 685 log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}"
687 # Use redis for Security and Registration stores 686 # Use redis for Security and Registration stores
688 redis.enabled: "${LWM2M_REDIS_ENABLED:false}" 687 redis.enabled: "${LWM2M_REDIS_ENABLED:false}"
@@ -103,7 +103,9 @@ public class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { @@ -103,7 +103,9 @@ public class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest {
103 " }\n" + 103 " }\n" +
104 " },\n" + 104 " },\n" +
105 " \"clientLwM2mSettings\": {\n" + 105 " \"clientLwM2mSettings\": {\n" +
106 - " \"clientOnlyObserveAfterConnect\": 1\n" + 106 + " \"clientOnlyObserveAfterConnect\": 1,\n" +
  107 + " \"fwUpdateStrategy\": 1,\n" +
  108 + " \"swUpdateStrategy\": 1\n" +
107 " }\n" + 109 " }\n" +
108 "}"; 110 "}";
109 111
@@ -17,11 +17,14 @@ package org.thingsboard.server.transport.lwm2m; @@ -17,11 +17,14 @@ package org.thingsboard.server.transport.lwm2m;
17 17
18 import org.eclipse.californium.core.network.config.NetworkConfig; 18 import org.eclipse.californium.core.network.config.NetworkConfig;
19 import org.eclipse.leshan.client.object.Security; 19 import org.eclipse.leshan.client.object.Security;
20 -import org.jetbrains.annotations.NotNull;  
21 import org.junit.Assert; 20 import org.junit.Assert;
22 import org.junit.Test; 21 import org.junit.Test;
  22 +import org.springframework.mock.web.MockMultipartFile;
  23 +import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder;
  24 +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
23 import org.thingsboard.common.util.JacksonUtil; 25 import org.thingsboard.common.util.JacksonUtil;
24 import org.thingsboard.server.common.data.Device; 26 import org.thingsboard.server.common.data.Device;
  27 +import org.thingsboard.server.common.data.OtaPackageInfo;
25 import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; 28 import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials;
26 import org.thingsboard.server.common.data.query.EntityData; 29 import org.thingsboard.server.common.data.query.EntityData;
27 import org.thingsboard.server.common.data.query.EntityDataPageLink; 30 import org.thingsboard.server.common.data.query.EntityDataPageLink;
@@ -43,6 +46,7 @@ import java.util.List; @@ -43,6 +46,7 @@ import java.util.List;
43 46
44 import static org.eclipse.leshan.client.object.Security.noSec; 47 import static org.eclipse.leshan.client.object.Security.noSec;
45 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 48 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  49 +import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
46 50
47 public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { 51 public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
48 52
@@ -51,7 +55,6 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @@ -51,7 +55,6 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
51 private final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT)); 55 private final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT));
52 private final String ENDPOINT = "deviceAEndpoint"; 56 private final String ENDPOINT = "deviceAEndpoint";
53 57
54 - @NotNull  
55 private Device createDevice() throws Exception { 58 private Device createDevice() throws Exception {
56 Device device = new Device(); 59 Device device = new Device();
57 device.setName("Device A"); 60 device.setName("Device A");
@@ -74,6 +77,29 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @@ -74,6 +77,29 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
74 return device; 77 return device;
75 } 78 }
76 79
  80 + private OtaPackageInfo createFirmware() throws Exception {
  81 + String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a";
  82 +
  83 + OtaPackageInfo firmwareInfo = new OtaPackageInfo();
  84 + firmwareInfo.setDeviceProfileId(deviceProfile.getId());
  85 + firmwareInfo.setType(FIRMWARE);
  86 + firmwareInfo.setTitle("My firmware");
  87 + firmwareInfo.setVersion("v1.0");
  88 +
  89 + OtaPackageInfo savedFirmwareInfo = doPost("/api/otaPackage", firmwareInfo, OtaPackageInfo.class);
  90 +
  91 + MockMultipartFile testData = new MockMultipartFile("file", "filename.txt", "text/plain", new byte[]{1});
  92 +
  93 + return savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, "SHA256");
  94 + }
  95 +
  96 + protected OtaPackageInfo savaData(String urlTemplate, MockMultipartFile content, String... params) throws Exception {
  97 + MockMultipartHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.multipart(urlTemplate, params);
  98 + postRequest.file(content);
  99 + setJwtToken(postRequest);
  100 + return readResponse(mockMvc.perform(postRequest).andExpect(status().isOk()), OtaPackageInfo.class);
  101 + }
  102 +
77 @Test 103 @Test
78 public void testConnectAndObserveTelemetry() throws Exception { 104 public void testConnectAndObserveTelemetry() throws Exception {
79 createDeviceProfile(TRANSPORT_CONFIGURATION); 105 createDeviceProfile(TRANSPORT_CONFIGURATION);
@@ -111,4 +137,53 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @@ -111,4 +137,53 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
111 client.destroy(); 137 client.destroy();
112 } 138 }
113 139
  140 + @Test
  141 + public void testFirmwareUpdateWithClientWithoutFirmwareInfo() throws Exception {
  142 + createDeviceProfile(TRANSPORT_CONFIGURATION);
  143 +
  144 + Device device = createDevice();
  145 +
  146 + OtaPackageInfo firmware = createFirmware();
  147 +
  148 + LwM2MTestClient client = new LwM2MTestClient(executor, ENDPOINT);
  149 + client.init(SECURITY, COAP_CONFIG);
  150 +
  151 + Thread.sleep(1000);
  152 +
  153 + device.setFirmwareId(firmware.getId());
  154 +
  155 + device = doPost("/api/device", device, Device.class);
  156 +
  157 + Thread.sleep(1000);
  158 +
  159 + SingleEntityFilter sef = new SingleEntityFilter();
  160 + sef.setSingleEntity(device.getId());
  161 + LatestValueCmd latestCmd = new LatestValueCmd();
  162 + latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "fw_state")));
  163 + EntityDataQuery edq = new EntityDataQuery(sef, new EntityDataPageLink(1, 0, null, null),
  164 + Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
  165 +
  166 + EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null);
  167 + TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
  168 + wrapper.setEntityDataCmds(Collections.singletonList(cmd));
  169 +
  170 + wsClient.send(mapper.writeValueAsString(wrapper));
  171 + wsClient.waitForReply();
  172 +
  173 + wsClient.registerWaitForUpdate();
  174 +
  175 + String msg = wsClient.waitForUpdate();
  176 +
  177 + EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);
  178 + Assert.assertEquals(1, update.getCmdId());
  179 + List<EntityData> eData = update.getUpdate();
  180 + Assert.assertNotNull(eData);
  181 + Assert.assertEquals(1, eData.size());
  182 + Assert.assertEquals(device.getId(), eData.get(0).getEntityId());
  183 + Assert.assertNotNull(eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES));
  184 + var tsValue = eData.get(0).getLatest().get(EntityKeyType.TIME_SERIES).get("fw_state");
  185 + Assert.assertEquals("FAILED", tsValue.getValue());
  186 + client.destroy();
  187 + }
  188 +
114 } 189 }
@@ -52,7 +52,6 @@ public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @@ -52,7 +52,6 @@ public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
52 private final String endpoint = "deviceAEndpoint"; 52 private final String endpoint = "deviceAEndpoint";
53 private final String serverUri = "coaps://localhost:" + port; 53 private final String serverUri = "coaps://localhost:" + port;
54 54
55 - @NotNull  
56 private Device createDevice(X509ClientCredentials clientCredentials) throws Exception { 55 private Device createDevice(X509ClientCredentials clientCredentials) throws Exception {
57 Device device = new Device(); 56 Device device = new Device();
58 device.setName("Device A"); 57 device.setName("Device A");
@@ -19,8 +19,10 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter; @@ -19,8 +19,10 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter;
19 import com.fasterxml.jackson.annotation.JsonAnySetter; 19 import com.fasterxml.jackson.annotation.JsonAnySetter;
20 import com.fasterxml.jackson.annotation.JsonIgnore; 20 import com.fasterxml.jackson.annotation.JsonIgnore;
21 import lombok.Data; 21 import lombok.Data;
22 -import org.thingsboard.server.common.data.DeviceProfileType;  
23 import org.thingsboard.server.common.data.DeviceTransportType; 22 import org.thingsboard.server.common.data.DeviceTransportType;
  23 +import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration;
  24 +import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration;
  25 +import org.thingsboard.server.common.data.device.data.lwm2m.TelemetryMappingConfiguration;
24 26
25 import java.util.HashMap; 27 import java.util.HashMap;
26 import java.util.Map; 28 import java.util.Map;
  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.common.data.device.data.lwm2m;
  17 +
  18 +import lombok.Data;
  19 +
  20 +import java.util.Map;
  21 +
  22 +@Data
  23 +public class BootstrapConfiguration {
  24 +
  25 + //TODO: define the objects;
  26 + private Map<String, Object> servers;
  27 + private Map<String, Object> lwm2mServer;
  28 + private Map<String, Object> bootstrapServer;
  29 +
  30 +}
  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.common.data.device.data.lwm2m;
  17 +
  18 +import com.fasterxml.jackson.annotation.JsonInclude;
  19 +import lombok.Data;
  20 +
  21 +@Data
  22 +@JsonInclude(JsonInclude.Include.NON_NULL)
  23 +public class ObjectAttributes {
  24 +
  25 + private Long dim;
  26 + private String ver;
  27 + private Long pmin;
  28 + private Long pmax;
  29 + private Double gt;
  30 + private Double lt;
  31 + private Double st;
  32 +
  33 +}
  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.common.data.device.data.lwm2m;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class OtherConfiguration {
  22 +
  23 + private Integer fwUpdateStrategy;
  24 + private Integer swUpdateStrategy;
  25 + private Integer clientOnlyObserveAfterConnect;
  26 + private String fwUpdateRecourse;
  27 + private String swUpdateRecourse;
  28 +
  29 +}
  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.common.data.device.data.lwm2m;
  17 +
  18 +import lombok.Data;
  19 +
  20 +import java.util.Map;
  21 +import java.util.Set;
  22 +
  23 +@Data
  24 +public class TelemetryMappingConfiguration {
  25 +
  26 + private Map<String, String> keyName;
  27 + private Set<String> observe;
  28 + private Set<String> attribute;
  29 + private Set<String> telemetry;
  30 + private Map<String, ObjectAttributes> attributeLwm2m;
  31 +
  32 +}
@@ -15,31 +15,20 @@ @@ -15,31 +15,20 @@
15 */ 15 */
16 package org.thingsboard.server.common.data.device.profile; 16 package org.thingsboard.server.common.data.device.profile;
17 17
18 -import com.fasterxml.jackson.annotation.JsonAnyGetter;  
19 -import com.fasterxml.jackson.annotation.JsonAnySetter;  
20 -import com.fasterxml.jackson.annotation.JsonIgnore;  
21 import lombok.Data; 18 import lombok.Data;
22 -import org.thingsboard.server.common.data.DeviceProfileType;  
23 import org.thingsboard.server.common.data.DeviceTransportType; 19 import org.thingsboard.server.common.data.DeviceTransportType;
24 -  
25 -import java.util.HashMap;  
26 -import java.util.Map; 20 +import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration;
  21 +import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration;
  22 +import org.thingsboard.server.common.data.device.data.lwm2m.TelemetryMappingConfiguration;
27 23
28 @Data 24 @Data
29 public class Lwm2mDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { 25 public class Lwm2mDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration {
30 26
31 - @JsonIgnore  
32 - private Map<String, Object> properties = new HashMap<>();  
33 -  
34 - @JsonAnyGetter  
35 - public Map<String, Object> properties() {  
36 - return this.properties;  
37 - } 27 + private static final long serialVersionUID = 6257277825459600068L;
38 28
39 - @JsonAnySetter  
40 - public void put(String name, Object value) {  
41 - this.properties.put(name, value);  
42 - } 29 + private TelemetryMappingConfiguration observeAttr;
  30 + private BootstrapConfiguration bootstrap;
  31 + private OtherConfiguration clientLwM2mSettings;
43 32
44 @Override 33 @Override
45 public DeviceTransportType getType() { 34 public DeviceTransportType getType() {
@@ -134,8 +134,8 @@ public class OtaPackageTransportResource extends AbstractCoapTransportResource { @@ -134,8 +134,8 @@ public class OtaPackageTransportResource extends AbstractCoapTransportResource {
134 response.setPayload(data); 134 response.setPayload(data);
135 if (exchange.getRequestOptions().getBlock2() != null) { 135 if (exchange.getRequestOptions().getBlock2() != null) {
136 int chunkSize = exchange.getRequestOptions().getBlock2().getSzx(); 136 int chunkSize = exchange.getRequestOptions().getBlock2().getSzx();
137 - boolean moreFlag = data.length > chunkSize;  
138 - response.getOptions().setBlock2(chunkSize, moreFlag, 0); 137 + boolean lastFlag = data.length > chunkSize;
  138 + response.getOptions().setBlock2(chunkSize, lastFlag, 0);
139 } 139 }
140 exchange.respond(response); 140 exchange.respond(response);
141 } 141 }
@@ -15,9 +15,6 @@ @@ -15,9 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.transport.lwm2m.bootstrap.secure; 16 package org.thingsboard.server.transport.lwm2m.bootstrap.secure;
17 17
18 -import com.fasterxml.jackson.core.JsonProcessingException;  
19 -import com.fasterxml.jackson.databind.ObjectMapper;  
20 -import com.google.gson.JsonObject;  
21 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
22 import org.eclipse.leshan.core.SecurityMode; 19 import org.eclipse.leshan.core.SecurityMode;
23 import org.eclipse.leshan.core.util.Hex; 20 import org.eclipse.leshan.core.util.Hex;
@@ -29,6 +26,8 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore; @@ -29,6 +26,8 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore;
29 import org.eclipse.leshan.server.security.SecurityInfo; 26 import org.eclipse.leshan.server.security.SecurityInfo;
30 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 27 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
31 import org.springframework.stereotype.Service; 28 import org.springframework.stereotype.Service;
  29 +import org.thingsboard.common.util.JacksonUtil;
  30 +import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration;
32 import org.thingsboard.server.gen.transport.TransportProtos; 31 import org.thingsboard.server.gen.transport.TransportProtos;
33 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; 32 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
34 import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; 33 import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
@@ -43,12 +42,9 @@ import java.util.Collections; @@ -43,12 +42,9 @@ import java.util.Collections;
43 import java.util.Iterator; 42 import java.util.Iterator;
44 import java.util.UUID; 43 import java.util.UUID;
45 44
46 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.BOOTSTRAP_SERVER;  
47 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR;  
48 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;  
49 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_TELEMETRY;  
50 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_SERVER;  
51 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SERVERS; 45 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR;
  46 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO;
  47 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY;
52 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getBootstrapParametersFromThingsboard; 48 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getBootstrapParametersFromThingsboard;
53 49
54 @Slf4j 50 @Slf4j
@@ -151,35 +147,30 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @@ -151,35 +147,30 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
151 } 147 }
152 148
153 private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) { 149 private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) {
154 - try {  
155 - LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig();  
156 - if (lwM2MBootstrapConfig != null) {  
157 - ObjectMapper mapper = new ObjectMapper();  
158 - JsonObject bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile());  
159 - lwM2MBootstrapConfig.servers = mapper.readValue(bootstrapObject.get(SERVERS).toString(), LwM2MBootstrapServers.class);  
160 - LwM2MServerBootstrap profileServerBootstrap = mapper.readValue(bootstrapObject.get(BOOTSTRAP_SERVER).toString(), LwM2MServerBootstrap.class);  
161 - LwM2MServerBootstrap profileLwm2mServer = mapper.readValue(bootstrapObject.get(LWM2M_SERVER).toString(), LwM2MServerBootstrap.class);  
162 - UUID sessionUUiD = UUID.randomUUID();  
163 - TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits());  
164 - context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, sessionInfo));  
165 - if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) {  
166 - lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);  
167 - lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);  
168 - String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndpoint());  
169 - helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo);  
170 - return lwM2MBootstrapConfig;  
171 - } else {  
172 - log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint());  
173 - log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndpoint());  
174 - String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndpoint());  
175 - helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo);  
176 - return null;  
177 - } 150 + LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig();
  151 + if (lwM2MBootstrapConfig != null) {
  152 + BootstrapConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile());
  153 + lwM2MBootstrapConfig.servers = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class);
  154 + LwM2MServerBootstrap profileServerBootstrap = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class);
  155 + LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class);
  156 + UUID sessionUUiD = UUID.randomUUID();
  157 + TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits());
  158 + context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo));
  159 + if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) {
  160 + lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);
  161 + lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);
  162 + String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint());
  163 + helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo);
  164 + return lwM2MBootstrapConfig;
  165 + } else {
  166 + log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint());
  167 + log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint());
  168 + String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LWM2M_ERROR, store.getEndpoint());
  169 + helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo);
  170 + return null;
178 } 171 }
179 - } catch (JsonProcessingException e) {  
180 - log.error("Unable to decode Json or Certificate for [{}] [{}]", store.getEndpoint(), e.getMessage());  
181 - return null;  
182 } 172 }
  173 +
183 log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint()); 174 log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint());
184 return null; 175 return null;
185 } 176 }
@@ -57,30 +57,22 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @@ -57,30 +57,22 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
57 private boolean recommendedSupportedGroups; 57 private boolean recommendedSupportedGroups;
58 58
59 @Getter 59 @Getter
60 - @Value("${transport.lwm2m.response_pool_size:}")  
61 - private int responsePoolSize; 60 + @Value("${transport.lwm2m.downlink_pool_size:}")
  61 + private int downlinkPoolSize;
62 62
63 @Getter 63 @Getter
64 - @Value("${transport.lwm2m.registered_pool_size:}")  
65 - private int registeredPoolSize; 64 + @Value("${transport.lwm2m.uplink_pool_size:}")
  65 + private int uplinkPoolSize;
66 66
67 @Getter 67 @Getter
68 - @Value("${transport.lwm2m.registration_store_pool_size:}")  
69 - private int registrationStorePoolSize; 68 + @Value("${transport.lwm2m.ota_pool_size:}")
  69 + private int otaPoolSize;
70 70
71 @Getter 71 @Getter
72 @Value("${transport.lwm2m.clean_period_in_sec:}") 72 @Value("${transport.lwm2m.clean_period_in_sec:}")
73 private int cleanPeriodInSec; 73 private int cleanPeriodInSec;
74 74
75 @Getter 75 @Getter
76 - @Value("${transport.lwm2m.update_registered_pool_size:}")  
77 - private int updateRegisteredPoolSize;  
78 -  
79 - @Getter  
80 - @Value("${transport.lwm2m.un_registered_pool_size:}")  
81 - private int unRegisteredPoolSize;  
82 -  
83 - @Getter  
84 @Value("${transport.lwm2m.security.key_store_type:}") 76 @Value("${transport.lwm2m.security.key_store_type:}")
85 private String keyStoreType; 77 private String keyStoreType;
86 78
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;  
17 -  
18 -import com.fasterxml.jackson.core.type.TypeReference;  
19 -import com.google.gson.Gson;  
20 -import com.google.gson.GsonBuilder;  
21 -import com.google.gson.JsonArray;  
22 -import com.google.gson.JsonElement;  
23 -import com.google.gson.JsonObject;  
24 -import com.google.gson.reflect.TypeToken;  
25 -import lombok.extern.slf4j.Slf4j;  
26 -import org.apache.commons.lang3.StringUtils;  
27 -import org.eclipse.leshan.core.model.ObjectModel;  
28 -import org.eclipse.leshan.core.model.ResourceModel;  
29 -import org.eclipse.leshan.core.node.LwM2mObject;  
30 -import org.eclipse.leshan.core.node.LwM2mObjectInstance;  
31 -import org.eclipse.leshan.core.node.LwM2mPath;  
32 -import org.eclipse.leshan.core.node.LwM2mResource;  
33 -import org.eclipse.leshan.core.observation.Observation;  
34 -import org.eclipse.leshan.core.request.WriteRequest;  
35 -import org.eclipse.leshan.core.response.ReadResponse;  
36 -import org.eclipse.leshan.server.registration.Registration;  
37 -import org.springframework.context.annotation.Lazy;  
38 -import org.springframework.stereotype.Service;  
39 -import org.thingsboard.common.util.JacksonUtil;  
40 -import org.thingsboard.common.util.ThingsBoardExecutors;  
41 -import org.thingsboard.server.cache.ota.OtaPackageDataCache;  
42 -import org.thingsboard.server.common.data.Device;  
43 -import org.thingsboard.server.common.data.DeviceProfile;  
44 -import org.thingsboard.server.common.data.id.OtaPackageId;  
45 -import org.thingsboard.server.common.data.ota.OtaPackageKey;  
46 -import org.thingsboard.server.common.data.ota.OtaPackageType;  
47 -import org.thingsboard.server.common.data.ota.OtaPackageUtil;  
48 -import org.thingsboard.server.common.transport.TransportService;  
49 -import org.thingsboard.server.common.transport.TransportServiceCallback;  
50 -import org.thingsboard.server.common.transport.adaptor.AdaptorException;  
51 -import org.thingsboard.server.common.transport.service.DefaultTransportService;  
52 -import org.thingsboard.server.gen.transport.TransportProtos;  
53 -import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;  
54 -import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent;  
55 -import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;  
56 -import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;  
57 -import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;  
58 -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;  
59 -import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;  
60 -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState;  
61 -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientStateException;  
62 -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;  
63 -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;  
64 -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;  
65 -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientRpcRequest;  
66 -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mFwSwUpdate;  
67 -import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;  
68 -import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto;  
69 -import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters;  
70 -import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;  
71 -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;  
72 -  
73 -import javax.annotation.PostConstruct;  
74 -import java.util.ArrayList;  
75 -import java.util.Collection;  
76 -import java.util.Collections;  
77 -import java.util.HashSet;  
78 -import java.util.List;  
79 -import java.util.Map;  
80 -import java.util.Optional;  
81 -import java.util.Random;  
82 -import java.util.Set;  
83 -import java.util.UUID;  
84 -import java.util.concurrent.ConcurrentHashMap;  
85 -import java.util.concurrent.ConcurrentMap;  
86 -import java.util.concurrent.ExecutorService;  
87 -import java.util.concurrent.TimeUnit;  
88 -import java.util.stream.Collectors;  
89 -  
90 -import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST;  
91 -import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;  
92 -import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;  
93 -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED;  
94 -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.INITIATED;  
95 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto;  
96 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEVICE_ATTRIBUTES_REQUEST;  
97 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_5_ID;  
98 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID;  
99 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_STATE_ID;  
100 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR;  
101 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;  
102 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_TELEMETRY;  
103 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE;  
104 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_WARN;  
105 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER;  
106 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE;  
107 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;  
108 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL_ALL;  
109 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.READ;  
110 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;  
111 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;  
112 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_ID;  
113 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertJsonArrayToSet;  
114 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertOtaUpdateValueToString;  
115 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;  
116 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;  
117 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getAckCallback;  
118 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.isFwSwWords;  
119 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.setValidTypeOper;  
120 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validateObjectVerFromKey;  
121 -  
122 -  
123 -@Slf4j  
124 -@Service  
125 -@TbLwM2mTransportComponent  
126 -public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler {  
127 -  
128 - private ExecutorService registrationExecutor;  
129 - private ExecutorService updateRegistrationExecutor;  
130 - private ExecutorService unRegistrationExecutor;  
131 - public LwM2mValueConverterImpl converter;  
132 -  
133 - private final TransportService transportService;  
134 - private final LwM2mTransportContext context;  
135 - public final LwM2MTransportServerConfig config;  
136 - public final OtaPackageDataCache otaPackageDataCache;  
137 - public final LwM2mTransportServerHelper helper;  
138 - private final LwM2MJsonAdaptor adaptor;  
139 - private final TbLwM2MDtlsSessionStore sessionStore;  
140 - public final LwM2mClientContext clientContext;  
141 - public final LwM2mTransportRequest lwM2mTransportRequest;  
142 - private final Map<UUID, Long> rpcSubscriptions;  
143 - public final Map<String, Integer> firmwareUpdateState;  
144 -  
145 - public DefaultLwM2MTransportMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, LwM2mTransportServerHelper helper,  
146 - LwM2mClientContext clientContext,  
147 - @Lazy LwM2mTransportRequest lwM2mTransportRequest,  
148 - OtaPackageDataCache otaPackageDataCache,  
149 - LwM2mTransportContext context, LwM2MJsonAdaptor adaptor, TbLwM2MDtlsSessionStore sessionStore) {  
150 - this.transportService = transportService;  
151 - this.config = config;  
152 - this.helper = helper;  
153 - this.clientContext = clientContext;  
154 - this.lwM2mTransportRequest = lwM2mTransportRequest;  
155 - this.otaPackageDataCache = otaPackageDataCache;  
156 - this.context = context;  
157 - this.adaptor = adaptor;  
158 - this.rpcSubscriptions = new ConcurrentHashMap<>();  
159 - this.firmwareUpdateState = new ConcurrentHashMap<>();  
160 - this.sessionStore = sessionStore;  
161 - }  
162 -  
163 - @PostConstruct  
164 - public void init() {  
165 - this.context.getScheduler().scheduleAtFixedRate(this::reportActivity, new Random().nextInt((int) config.getSessionReportTimeout()), config.getSessionReportTimeout(), TimeUnit.MILLISECONDS);  
166 - this.registrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getRegisteredPoolSize(), "LwM2M registration");  
167 - this.updateRegistrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getUpdateRegisteredPoolSize(), "LwM2M update registration");  
168 - this.unRegistrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getUnRegisteredPoolSize(), "LwM2M unRegistration");  
169 - this.converter = LwM2mValueConverterImpl.getInstance();  
170 - }  
171 -  
172 - /**  
173 - * Start registration device  
174 - * Create session: Map<String <registrationId >, LwM2MClient>  
175 - * 1. replaceNewRegistration -> (solving the problem of incorrect termination of the previous session with this endpoint)  
176 - * 1.1 When we initialize the registration, we register the session by endpoint.  
177 - * 1.2 If the server has incomplete requests (canceling the registration of the previous session),  
178 - * delete the previous session only by the previous registration.getId  
179 - * 1.2 Add Model (Entity) for client (from registration & observe) by registration.getId  
180 - * 1.2 Remove from sessions Model by enpPoint  
181 - * Next -> Create new LwM2MClient for current session -> setModelClient...  
182 - *  
183 - * @param registration - Registration LwM2M Client  
184 - * @param previousObservations - may be null  
185 - */  
186 - public void onRegistered(Registration registration, Collection<Observation> previousObservations) {  
187 - registrationExecutor.submit(() -> {  
188 - LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint());  
189 - try {  
190 - log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId());  
191 - if (lwM2MClient != null) {  
192 - this.clientContext.register(lwM2MClient, registration);  
193 - this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_INFO + ": Client registered with registration id: " + registration.getId());  
194 - SessionInfoProto sessionInfo = lwM2MClient.getSession();  
195 - transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo));  
196 - log.warn("40) sessionId [{}] Registering rpc subscription after Registration client", new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));  
197 - TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder()  
198 - .setSessionInfo(sessionInfo)  
199 - .setSessionEvent(DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN))  
200 - .setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build())  
201 - .setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build())  
202 - .build();  
203 - transportService.process(msg, null);  
204 - this.getInfoFirmwareUpdate(lwM2MClient, null);  
205 - this.getInfoSoftwareUpdate(lwM2MClient, null);  
206 - this.initClientTelemetry(lwM2MClient);  
207 - } else {  
208 - log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null);  
209 - }  
210 - } catch (LwM2MClientStateException stateException) {  
211 - if (LwM2MClientState.UNREGISTERED.equals(stateException.getState())) {  
212 - log.info("[{}] retry registration due to race condition: [{}].", registration.getEndpoint(), stateException.getState());  
213 - // Race condition detected and the client was in progress of unregistration while new registration arrived. Let's try again.  
214 - onRegistered(registration, previousObservations);  
215 - } else {  
216 - this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_WARN + ": Client registration failed due to invalid state: " + stateException.getState());  
217 - }  
218 - } catch (Throwable t) {  
219 - log.error("[{}] endpoint [{}] error Unable registration.", registration.getEndpoint(), t);  
220 - this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_WARN + ": Client registration failed due to: " + t.getMessage());  
221 - }  
222 - });  
223 - }  
224 -  
225 - /**  
226 - * if sessionInfo removed from sessions, then new registerAsyncSession  
227 - *  
228 - * @param registration - Registration LwM2M Client  
229 - */  
230 - public void updatedReg(Registration registration) {  
231 - updateRegistrationExecutor.submit(() -> {  
232 - LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());  
233 - try {  
234 - clientContext.updateRegistration(lwM2MClient, registration);  
235 - TransportProtos.SessionInfoProto sessionInfo = lwM2MClient.getSession();  
236 - this.reportActivityAndRegister(sessionInfo);  
237 - if (registration.usesQueueMode()) {  
238 - LwM2mQueuedRequest request;  
239 - while ((request = lwM2MClient.getQueuedRequests().poll()) != null) {  
240 - request.send();  
241 - }  
242 - }  
243 - } catch (LwM2MClientStateException stateException) {  
244 - if (LwM2MClientState.REGISTERED.equals(stateException.getState())) {  
245 - log.info("[{}] update registration failed because client has different registration id: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage());  
246 - } else {  
247 - onRegistered(registration, Collections.emptyList());  
248 - }  
249 - } catch (Throwable t) {  
250 - log.error("[{}] endpoint [{}] error Unable update registration.", registration.getEndpoint(), t);  
251 - this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_ERROR + String.format(": Client update Registration, %s", t.getMessage()));  
252 - }  
253 - });  
254 - }  
255 -  
256 - /**  
257 - * @param registration - Registration LwM2M Client  
258 - * @param observations - !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect  
259 - */  
260 - public void unReg(Registration registration, Collection<Observation> observations) {  
261 - unRegistrationExecutor.submit(() -> {  
262 - LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint());  
263 - try {  
264 - this.sendLogsToThingsboard(client, LOG_LW2M_INFO + ": Client unRegistration");  
265 - clientContext.unregister(client, registration);  
266 - SessionInfoProto sessionInfo = client.getSession();  
267 - if (sessionInfo != null) {  
268 - this.doCloseSession(sessionInfo);  
269 - transportService.deregisterSession(sessionInfo);  
270 - sessionStore.remove(registration.getEndpoint());  
271 - log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType());  
272 - } else {  
273 - log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);  
274 - }  
275 - } catch (LwM2MClientStateException stateException) {  
276 - log.info("[{}] delete registration: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage());  
277 - } catch (Throwable t) {  
278 - log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t);  
279 - this.sendLogsToThingsboard(client, LOG_LW2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage()));  
280 - }  
281 - });  
282 - }  
283 -  
284 - @Override  
285 - public void onSleepingDev(Registration registration) {  
286 - log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint());  
287 - this.sendLogsToThingsboard(clientContext.getClientByEndpoint(registration.getEndpoint()), LOG_LW2M_INFO + ": Client is sleeping!");  
288 - //TODO: associate endpointId with device information.  
289 - }  
290 -  
291 - /**  
292 - * Cancel observation for All objects for this registration  
293 - */  
294 - @Override  
295 - public void setCancelObservationsAll(Registration registration) {  
296 - if (registration != null) {  
297 - LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint());  
298 - if (client != null && client.getRegistration() != null && client.getRegistration().getId().equals(registration.getId())) {  
299 - this.lwM2mTransportRequest.sendAllRequest(client, null, OBSERVE_CANCEL_ALL,  
300 - null, null, this.config.getTimeout(), null);  
301 - }  
302 - }  
303 - }  
304 -  
305 - /**  
306 - * Sending observe value to thingsboard from ObservationListener.onResponse: object, instance, SingleResource or MultipleResource  
307 - *  
308 - * @param registration - Registration LwM2M Client  
309 - * @param path - observe  
310 - * @param response - observe  
311 - */  
312 - @Override  
313 - public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, LwM2mClientRpcRequest rpcRequest) {  
314 - if (response.getContent() != null) {  
315 - LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());  
316 - ObjectModel objectModelVersion = lwM2MClient.getObjectModel(path, this.config.getModelProvider());  
317 - if (objectModelVersion != null) {  
318 - if (response.getContent() instanceof LwM2mObject) {  
319 - LwM2mObject lwM2mObject = (LwM2mObject) response.getContent();  
320 - this.updateObjectResourceValue(registration, lwM2mObject, path);  
321 - } else if (response.getContent() instanceof LwM2mObjectInstance) {  
322 - LwM2mObjectInstance lwM2mObjectInstance = (LwM2mObjectInstance) response.getContent();  
323 - this.updateObjectInstanceResourceValue(registration, lwM2mObjectInstance, path);  
324 - } else if (response.getContent() instanceof LwM2mResource) {  
325 - LwM2mResource lwM2mResource = (LwM2mResource) response.getContent();  
326 - this.updateResourcesValue(registration, lwM2mResource, path);  
327 - }  
328 - }  
329 - if (rpcRequest != null) {  
330 - this.sendRpcRequestAfterReadResponse(registration, lwM2MClient, path, response, rpcRequest);  
331 - }  
332 - }  
333 - }  
334 -  
335 - private void sendRpcRequestAfterReadResponse(Registration registration, LwM2mClient lwM2MClient, String pathIdVer, ReadResponse response,  
336 - LwM2mClientRpcRequest rpcRequest) {  
337 - Object value = null;  
338 - if (response.getContent() instanceof LwM2mObject) {  
339 - value = lwM2MClient.objectToString((LwM2mObject) response.getContent(), this.converter, pathIdVer);  
340 - } else if (response.getContent() instanceof LwM2mObjectInstance) {  
341 - value = lwM2MClient.instanceToString((LwM2mObjectInstance) response.getContent(), this.converter, pathIdVer);  
342 - } else if (response.getContent() instanceof LwM2mResource) {  
343 - value = lwM2MClient.resourceToString((LwM2mResource) response.getContent(), this.converter, pathIdVer);  
344 - }  
345 - String msg = String.format("%s: type operation %s path - %s value - %s", LOG_LW2M_INFO,  
346 - READ, pathIdVer, value);  
347 - this.sendLogsToThingsboard(lwM2MClient, msg);  
348 - rpcRequest.setValueMsg(String.format("%s", value));  
349 - this.sentRpcResponse(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE);  
350 - }  
351 -  
352 - /**  
353 - * Update - send request in change value resources in Client  
354 - * 1. FirmwareUpdate:  
355 - * - If msg.getSharedUpdatedList().forEach(tsKvProto -> {tsKvProto.getKv().getKey().indexOf(FIRMWARE_UPDATE_PREFIX, 0) == 0  
356 - * 2. Shared Other AttributeUpdate  
357 - * -- Path to resources from profile equal keyName or from ModelObject equal name  
358 - * -- Only for resources: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase)  
359 - * 3. Delete - nothing  
360 - *  
361 - * @param msg -  
362 - */  
363 - @Override  
364 - public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {  
365 - LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo);  
366 - if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) {  
367 - log.warn("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList());  
368 - msg.getSharedUpdatedList().forEach(tsKvProto -> {  
369 - String pathName = tsKvProto.getKv().getKey();  
370 - String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName);  
371 - Object valueNew = getValueFromKvProto(tsKvProto.getKv());  
372 - if ((OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION).equals(pathName)  
373 - && (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())))  
374 - || (OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE).equals(pathName)  
375 - && (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentTitle())))) {  
376 - this.getInfoFirmwareUpdate(lwM2MClient, null);  
377 - } else if ((OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION).equals(pathName)  
378 - && (!valueNew.equals(lwM2MClient.getSwUpdate().getCurrentVersion())))  
379 - || (OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE).equals(pathName)  
380 - && (!valueNew.equals(lwM2MClient.getSwUpdate().getCurrentTitle())))) {  
381 - this.getInfoSoftwareUpdate(lwM2MClient, null);  
382 - }  
383 - if (pathIdVer != null) {  
384 - ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.config  
385 - .getModelProvider());  
386 - if (resourceModel != null && resourceModel.operations.isWritable()) {  
387 - this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer), valueNew, pathIdVer);  
388 - } else {  
389 - log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, valueNew);  
390 - String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated",  
391 - LOG_LW2M_ERROR, pathIdVer, valueNew);  
392 - this.sendLogsToThingsboard(lwM2MClient, logMsg);  
393 - }  
394 - } else if (!isFwSwWords(pathName)) {  
395 - log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew);  
396 - String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated",  
397 - LOG_LW2M_ERROR, pathName, valueNew);  
398 - this.sendLogsToThingsboard(lwM2MClient, logMsg);  
399 - }  
400 -  
401 - });  
402 - } else if (msg.getSharedDeletedCount() > 0 && lwM2MClient != null) {  
403 - msg.getSharedUpdatedList().forEach(tsKvProto -> {  
404 - String pathName = tsKvProto.getKv().getKey();  
405 - Object valueNew = getValueFromKvProto(tsKvProto.getKv());  
406 - if (OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())) {  
407 - lwM2MClient.getFwUpdate().setCurrentVersion((String) valueNew);  
408 - }  
409 - });  
410 - log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo);  
411 - } else if (lwM2MClient == null) {  
412 - log.error("OnAttributeUpdate, lwM2MClient is null");  
413 - }  
414 - }  
415 -  
416 - /**  
417 - * @param sessionInfo -  
418 - * @param deviceProfile -  
419 - */  
420 - @Override  
421 - public void onDeviceProfileUpdate(SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {  
422 - List<LwM2mClient> clients = clientContext.getLwM2mClients()  
423 - .stream().filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toList());  
424 - clients.forEach(client -> client.onDeviceProfileUpdate(deviceProfile));  
425 - if (clients.size() > 0) {  
426 - this.onDeviceProfileUpdate(clients, deviceProfile);  
427 - }  
428 - }  
429 -  
430 - @Override  
431 - public void onDeviceUpdate(SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt) {  
432 - //TODO: check, maybe device has multiple sessions/registrations? Is this possible according to the standard.  
433 - LwM2mClient client = clientContext.getClientByDeviceId(device.getUuidId());  
434 - if (client != null) {  
435 - this.onDeviceUpdate(client, device, deviceProfileOpt);  
436 - }  
437 - }  
438 -  
439 - @Override  
440 - public void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {  
441 - String idVer = resourceUpdateMsgOpt.get().getResourceKey();  
442 - clientContext.getLwM2mClients().forEach(e -> e.updateResourceModel(idVer, this.config.getModelProvider()));  
443 - }  
444 -  
445 - @Override  
446 - public void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt) {  
447 - String pathIdVer = resourceDeleteMsgOpt.get().getResourceKey();  
448 - clientContext.getLwM2mClients().forEach(e -> e.deleteResources(pathIdVer, this.config.getModelProvider()));  
449 - }  
450 -  
451 - /**  
452 - * #1 del from rpcSubscriptions by timeout  
453 - * #2 if not present in rpcSubscriptions by requestId: create new LwM2mClientRpcRequest, after success - add requestId, timeout  
454 - */  
455 - @Override  
456 - public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRpcRequestMsg, SessionInfoProto sessionInfo) {  
457 - // #1  
458 - this.checkRpcRequestTimeout();  
459 - log.warn("4) toDeviceRpcRequestMsg: [{}], sessionUUID: [{}]", toDeviceRpcRequestMsg, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));  
460 - String bodyParams = StringUtils.trimToNull(toDeviceRpcRequestMsg.getParams()) != null ? toDeviceRpcRequestMsg.getParams() : "null";  
461 - LwM2mTypeOper lwM2mTypeOper = setValidTypeOper(toDeviceRpcRequestMsg.getMethodName());  
462 - UUID requestUUID = new UUID(toDeviceRpcRequestMsg.getRequestIdMSB(), toDeviceRpcRequestMsg.getRequestIdLSB());  
463 - if (!this.rpcSubscriptions.containsKey(requestUUID)) {  
464 - this.rpcSubscriptions.put(requestUUID, toDeviceRpcRequestMsg.getExpirationTime());  
465 - LwM2mClientRpcRequest lwm2mClientRpcRequest = null;  
466 - try {  
467 - LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo);  
468 - Registration registration = client.getRegistration();  
469 - if(registration != null) {  
470 - lwm2mClientRpcRequest = new LwM2mClientRpcRequest(lwM2mTypeOper, bodyParams, toDeviceRpcRequestMsg.getRequestId(), sessionInfo, registration, this);  
471 - if (lwm2mClientRpcRequest.getErrorMsg() != null) {  
472 - lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());  
473 - this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);  
474 - } else {  
475 - lwM2mTransportRequest.sendAllRequest(client, lwm2mClientRpcRequest.getTargetIdVer(), lwm2mClientRpcRequest.getTypeOper(),  
476 - null,  
477 - lwm2mClientRpcRequest.getValue() == null ? lwm2mClientRpcRequest.getParams() : lwm2mClientRpcRequest.getValue(),  
478 - this.config.getTimeout(), lwm2mClientRpcRequest);  
479 - }  
480 - } else {  
481 - this.sendErrorRpcResponse(lwm2mClientRpcRequest, "registration == null", sessionInfo);  
482 - }  
483 - } catch (Exception e) {  
484 - this.sendErrorRpcResponse(lwm2mClientRpcRequest, e.getMessage(), sessionInfo);  
485 - }  
486 - }  
487 - }  
488 -  
489 - private void sendErrorRpcResponse(LwM2mClientRpcRequest lwm2mClientRpcRequest, String msgError, SessionInfoProto sessionInfo) {  
490 - if (lwm2mClientRpcRequest == null) {  
491 - lwm2mClientRpcRequest = new LwM2mClientRpcRequest();  
492 - }  
493 - lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());  
494 - if (lwm2mClientRpcRequest.getErrorMsg() == null) {  
495 - lwm2mClientRpcRequest.setErrorMsg(msgError);  
496 - }  
497 - this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);  
498 - }  
499 -  
500 - private void checkRpcRequestTimeout() {  
501 - log.warn("4.1) before rpcSubscriptions.size(): [{}]", rpcSubscriptions.size());  
502 - if (rpcSubscriptions.size() > 0) {  
503 - Set<UUID> rpcSubscriptionsToRemove = rpcSubscriptions.entrySet().stream().filter(kv -> System.currentTimeMillis() > kv.getValue()).map(Map.Entry::getKey).collect(Collectors.toSet());  
504 - log.warn("4.2) System.currentTimeMillis(): [{}]", System.currentTimeMillis());  
505 - log.warn("4.3) rpcSubscriptionsToRemove: [{}]", rpcSubscriptionsToRemove);  
506 - rpcSubscriptionsToRemove.forEach(rpcSubscriptions::remove);  
507 - }  
508 - log.warn("4.4) after rpcSubscriptions.size(): [{}]", rpcSubscriptions.size());  
509 - }  
510 -  
511 - public void sentRpcResponse(LwM2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) {  
512 - rpcRequest.setResponseCode(requestCode);  
513 - if (LOG_LW2M_ERROR.equals(typeMsg)) {  
514 - rpcRequest.setInfoMsg(null);  
515 - rpcRequest.setValueMsg(null);  
516 - if (rpcRequest.getErrorMsg() == null) {  
517 - msg = msg.isEmpty() ? null : msg;  
518 - rpcRequest.setErrorMsg(msg);  
519 - }  
520 - } else if (LOG_LW2M_INFO.equals(typeMsg)) {  
521 - if (rpcRequest.getInfoMsg() == null) {  
522 - rpcRequest.setInfoMsg(msg);  
523 - }  
524 - } else if (LOG_LW2M_VALUE.equals(typeMsg)) {  
525 - if (rpcRequest.getValueMsg() == null) {  
526 - rpcRequest.setValueMsg(msg);  
527 - }  
528 - }  
529 - this.onToDeviceRpcResponse(rpcRequest.getDeviceRpcResponseResultMsg(), rpcRequest.getSessionInfo());  
530 - }  
531 -  
532 - @Override  
533 - public void onToDeviceRpcResponse(TransportProtos.ToDeviceRpcResponseMsg toDeviceResponse, SessionInfoProto sessionInfo) {  
534 - log.warn("5) onToDeviceRpcResponse: [{}], sessionUUID: [{}]", toDeviceResponse, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));  
535 - transportService.process(sessionInfo, toDeviceResponse, null);  
536 - }  
537 -  
538 - public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) {  
539 - log.info("[{}] toServerRpcResponse", toServerResponse);  
540 - }  
541 -  
542 - /**  
543 - * Deregister session in transport  
544 - *  
545 - * @param sessionInfo - lwm2m client  
546 - */  
547 - @Override  
548 - public void doDisconnect(SessionInfoProto sessionInfo) {  
549 - transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.CLOSED), null);  
550 - transportService.deregisterSession(sessionInfo);  
551 - }  
552 -  
553 - /**  
554 - * Session device in thingsboard is closed  
555 - *  
556 - * @param sessionInfo - lwm2m client  
557 - */  
558 - private void doCloseSession(SessionInfoProto sessionInfo) {  
559 - TransportProtos.SessionEvent event = SessionEvent.CLOSED;  
560 - TransportProtos.SessionEventMsg msg = TransportProtos.SessionEventMsg.newBuilder()  
561 - .setSessionType(TransportProtos.SessionType.ASYNC)  
562 - .setEvent(event).build();  
563 - transportService.process(sessionInfo, msg, null);  
564 - }  
565 -  
566 - /**  
567 - * Those methods are called by the protocol stage thread pool, this means that execution MUST be done in a short delay,  
568 - * * if you need to do long time processing use a dedicated thread pool.  
569 - *  
570 - * @param registration -  
571 - */  
572 - @Override  
573 - public void onAwakeDev(Registration registration) {  
574 - log.trace("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint());  
575 - this.sendLogsToThingsboard(clientContext.getClientByEndpoint(registration.getEndpoint()), LOG_LW2M_INFO + ": Client is awake!");  
576 - //TODO: associate endpointId with device information.  
577 - }  
578 -  
579 - /**  
580 - * @param logMsg - text msg  
581 - * @param registrationId - Id of Registration LwM2M Client  
582 - */  
583 - @Override  
584 - public void sendLogsToThingsboard(String registrationId, String logMsg) {  
585 - sendLogsToThingsboard(clientContext.getClientByRegistrationId(registrationId), logMsg);  
586 - }  
587 -  
588 - @Override  
589 - public void sendLogsToThingsboard(LwM2mClient client, String logMsg) {  
590 - if (logMsg != null && client != null && client.getSession() != null) {  
591 - if (logMsg.length() > 1024) {  
592 - logMsg = logMsg.substring(0, 1024);  
593 - }  
594 - this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), client.getSession());  
595 - }  
596 - }  
597 -  
598 - /**  
599 - * #1 clientOnlyObserveAfterConnect == true  
600 - * - Only Observe Request to the client marked as observe from the profile configuration.  
601 - * #2. clientOnlyObserveAfterConnect == false  
602 - * После регистрации отправляю запрос на read всех ресурсов, которые после регистрации есть у клиента,  
603 - * а затем запрос на observe (edited)  
604 - * - Read Request to the client after registration to read all resource values for all objects  
605 - * - then Observe Request to the client marked as observe from the profile configuration.  
606 - *  
607 - * @param lwM2MClient - object with All parameters off client  
608 - */  
609 - private void initClientTelemetry(LwM2mClient lwM2MClient) {  
610 - LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(lwM2MClient.getProfileId());  
611 - Set<String> clientObjects = clientContext.getSupportedIdVerInClient(lwM2MClient);  
612 - if (clientObjects != null && clientObjects.size() > 0) {  
613 - if (LwM2mTransportUtil.LwM2MClientStrategy.CLIENT_STRATEGY_2.code == lwM2MClientProfile.getClientStrategy()) {  
614 - // #2  
615 - lwM2MClient.getPendingReadRequests().addAll(clientObjects);  
616 - clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(lwM2MClient, path, READ,  
617 - null, this.config.getTimeout(), null));  
618 - }  
619 - // #1  
620 - this.initReadAttrTelemetryObserveToClient(lwM2MClient, READ, clientObjects);  
621 - this.initReadAttrTelemetryObserveToClient(lwM2MClient, OBSERVE, clientObjects);  
622 - this.initReadAttrTelemetryObserveToClient(lwM2MClient, WRITE_ATTRIBUTES, clientObjects);  
623 - this.initReadAttrTelemetryObserveToClient(lwM2MClient, DISCOVER, clientObjects);  
624 - }  
625 - }  
626 -  
627 - /**  
628 - * @param registration -  
629 - * @param lwM2mObject -  
630 - * @param pathIdVer -  
631 - */  
632 - private void updateObjectResourceValue(Registration registration, LwM2mObject lwM2mObject, String pathIdVer) {  
633 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));  
634 - lwM2mObject.getInstances().forEach((instanceId, instance) -> {  
635 - String pathInstance = pathIds.toString() + "/" + instanceId;  
636 - this.updateObjectInstanceResourceValue(registration, instance, pathInstance);  
637 - });  
638 - }  
639 -  
640 - /**  
641 - * @param registration -  
642 - * @param lwM2mObjectInstance -  
643 - * @param pathIdVer -  
644 - */  
645 - private void updateObjectInstanceResourceValue(Registration registration, LwM2mObjectInstance lwM2mObjectInstance, String pathIdVer) {  
646 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));  
647 - lwM2mObjectInstance.getResources().forEach((resourceId, resource) -> {  
648 - String pathRez = pathIds.toString() + "/" + resourceId;  
649 - this.updateResourcesValue(registration, resource, pathRez);  
650 - });  
651 - }  
652 -  
653 - /**  
654 - * Sending observe value of resources to thingsboard  
655 - * #1 Return old Value Resource from LwM2MClient  
656 - * #2 Update new Resources (replace old Resource Value on new Resource Value)  
657 - * #3 If fr_update -> UpdateFirmware  
658 - * #4 updateAttrTelemetry  
659 - *  
660 - * @param registration - Registration LwM2M Client  
661 - * @param lwM2mResource - LwM2mSingleResource response.getContent()  
662 - * @param path - resource  
663 - */  
664 - private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) {  
665 - LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());  
666 - if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider())) {  
667 - /** version != null  
668 - * set setClient_fw_info... = value  
669 - **/  
670 - if (lwM2MClient.getFwUpdate() != null && lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {  
671 - lwM2MClient.getFwUpdate().initReadValue(this, this.lwM2mTransportRequest, path);  
672 - }  
673 - if (lwM2MClient.getSwUpdate() != null && lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {  
674 - lwM2MClient.getSwUpdate().initReadValue(this, this.lwM2mTransportRequest, path);  
675 - }  
676 -  
677 - if ((convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path)) ||  
678 - (convertPathFromObjectIdToIdVer(FW_STATE_ID, registration).equals(path))) {  
679 - LwM2mFwSwUpdate fwUpdate = lwM2MClient.getFwUpdate(clientContext);  
680 - log.warn("93) path: [{}] value: [{}]", path, lwM2mResource.getValue());  
681 - fwUpdate.updateStateOta(this, lwM2mTransportRequest, registration, path, ((Long) lwM2mResource.getValue()).intValue());  
682 - }  
683 - Set<String> paths = new HashSet<>();  
684 - paths.add(path);  
685 - this.updateAttrTelemetry(registration, paths);  
686 - } else {  
687 - log.error("Fail update Resource [{}]", lwM2mResource);  
688 - }  
689 - }  
690 -  
691 -  
692 - /**  
693 - * send Attribute and Telemetry to Thingsboard  
694 - * #1 - get AttrName/TelemetryName with value from LwM2MClient:  
695 - * -- resourceId == path from LwM2MClientProfile.postAttributeProfile/postTelemetryProfile/postObserveProfile  
696 - * -- AttrName/TelemetryName == resourceName from ModelObject.objectModel, value from ModelObject.instance.resource(resourceId)  
697 - * #2 - set Attribute/Telemetry  
698 - *  
699 - * @param registration - Registration LwM2M Client  
700 - */  
701 - private void updateAttrTelemetry(Registration registration, Set<String> paths) {  
702 - try {  
703 - ResultsAddKeyValueProto results = this.getParametersFromProfile(registration, paths);  
704 - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registration);  
705 - if (results != null && sessionInfo != null) {  
706 - if (results.getResultAttributes().size() > 0) {  
707 - this.helper.sendParametersOnThingsboardAttribute(results.getResultAttributes(), sessionInfo);  
708 - }  
709 - if (results.getResultTelemetries().size() > 0) {  
710 - this.helper.sendParametersOnThingsboardTelemetry(results.getResultTelemetries(), sessionInfo);  
711 - }  
712 - }  
713 - } catch (Exception e) {  
714 - log.error("UpdateAttrTelemetry", e);  
715 - }  
716 - }  
717 -  
718 - private void initReadAttrTelemetryObserveToClient(LwM2mClient lwM2MClient, LwM2mTypeOper typeOper, Set<String> clientObjects) {  
719 - LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(lwM2MClient.getProfileId());  
720 - Set<String> result = null;  
721 - ConcurrentHashMap<String, Object> params = null;  
722 - if (READ.equals(typeOper)) {  
723 - result = JacksonUtil.fromString(lwM2MClientProfile.getPostAttributeProfile().toString(),  
724 - new TypeReference<>() {  
725 - });  
726 - result.addAll(JacksonUtil.fromString(lwM2MClientProfile.getPostTelemetryProfile().toString(),  
727 - new TypeReference<>() {  
728 - }));  
729 - } else if (OBSERVE.equals(typeOper)) {  
730 - result = JacksonUtil.fromString(lwM2MClientProfile.getPostObserveProfile().toString(),  
731 - new TypeReference<>() {  
732 - });  
733 - } else if (DISCOVER.equals(typeOper)) {  
734 - result = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile()).keySet();  
735 - } else if (WRITE_ATTRIBUTES.equals(typeOper)) {  
736 - params = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile());  
737 - result = params.keySet();  
738 - }  
739 - sendRequestsToClient(lwM2MClient, typeOper, clientObjects, result, params);  
740 - }  
741 -  
742 - private void sendRequestsToClient(LwM2mClient lwM2MClient, LwM2mTypeOper operationType, Set<String> supportedObjectIds, Set<String> desiredObjectIds, ConcurrentHashMap<String, Object> params) {  
743 - if (desiredObjectIds != null && !desiredObjectIds.isEmpty()) {  
744 - Set<String> targetObjectIds = desiredObjectIds.stream().filter(target -> isSupportedTargetId(supportedObjectIds, target)  
745 - ).collect(Collectors.toUnmodifiableSet());  
746 - if (!targetObjectIds.isEmpty()) {  
747 - //TODO: remove this side effect?  
748 - lwM2MClient.getPendingReadRequests().addAll(targetObjectIds);  
749 - targetObjectIds.forEach(target -> {  
750 - Object additionalParams = params != null ? params.get(target) : null;  
751 - lwM2mTransportRequest.sendAllRequest(lwM2MClient, target, operationType, additionalParams, this.config.getTimeout(), null);  
752 - });  
753 - if (OBSERVE.equals(operationType)) {  
754 - lwM2MClient.initReadValue(this, null);  
755 - }  
756 - }  
757 - }  
758 - }  
759 -  
760 - private boolean isSupportedTargetId(Set<String> supportedIds, String targetId) {  
761 - String[] targetIdParts = targetId.split(LWM2M_SEPARATOR_PATH);  
762 - if (targetIdParts.length <= 1) {  
763 - return false;  
764 - }  
765 - String targetIdSearch = targetIdParts[0];  
766 - for (int i = 1; i < targetIdParts.length; i++) {  
767 - targetIdSearch += "/" + targetIdParts[i];  
768 - if (supportedIds.contains(targetIdSearch)) {  
769 - return true;  
770 - }  
771 - }  
772 - return false;  
773 - }  
774 -  
775 - private ConcurrentHashMap<String, Object> getPathForWriteAttributes(JsonObject objectJson) {  
776 - ConcurrentHashMap<String, Object> pathAttributes = new Gson().fromJson(objectJson.toString(),  
777 - new TypeToken<ConcurrentHashMap<String, Object>>() {  
778 - }.getType());  
779 - return pathAttributes;  
780 - }  
781 -  
782 - private void onDeviceUpdate(LwM2mClient lwM2MClient, Device device, Optional<DeviceProfile> deviceProfileOpt) {  
783 - deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singletonList(lwM2MClient), deviceProfile));  
784 - lwM2MClient.onDeviceUpdate(device, deviceProfileOpt);  
785 - }  
786 -  
787 - /**  
788 - * // * @param attributes - new JsonObject  
789 - * // * @param telemetry - new JsonObject  
790 - *  
791 - * @param registration - Registration LwM2M Client  
792 - * @param path -  
793 - */  
794 - private ResultsAddKeyValueProto getParametersFromProfile(Registration registration, Set<String> path) {  
795 - if (path != null && path.size() > 0) {  
796 - ResultsAddKeyValueProto results = new ResultsAddKeyValueProto();  
797 - LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration);  
798 - List<TransportProtos.KeyValueProto> resultAttributes = new ArrayList<>();  
799 - lwM2MClientProfile.getPostAttributeProfile().forEach(pathIdVer -> {  
800 - if (path.contains(pathIdVer.getAsString())) {  
801 - TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer.getAsString(), registration);  
802 - if (kvAttr != null) {  
803 - resultAttributes.add(kvAttr);  
804 - }  
805 - }  
806 - });  
807 - List<TransportProtos.KeyValueProto> resultTelemetries = new ArrayList<>();  
808 - lwM2MClientProfile.getPostTelemetryProfile().forEach(pathIdVer -> {  
809 - if (path.contains(pathIdVer.getAsString())) {  
810 - TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer.getAsString(), registration);  
811 - if (kvAttr != null) {  
812 - resultTelemetries.add(kvAttr);  
813 - }  
814 - }  
815 - });  
816 - if (resultAttributes.size() > 0) {  
817 - results.setResultAttributes(resultAttributes);  
818 - }  
819 - if (resultTelemetries.size() > 0) {  
820 - results.setResultTelemetries(resultTelemetries);  
821 - }  
822 - return results;  
823 - }  
824 - return null;  
825 - }  
826 -  
827 - private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) {  
828 - LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint());  
829 - JsonObject names = clientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile();  
830 - if (names != null && names.has(pathIdVer)) {  
831 - String resourceName = names.get(pathIdVer).getAsString();  
832 - if (resourceName != null && !resourceName.isEmpty()) {  
833 - try {  
834 - LwM2mResource resourceValue = lwM2MClient != null ? getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) : null;  
835 - if (resourceValue != null) {  
836 - ResourceModel.Type currentType = resourceValue.getType();  
837 - ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);  
838 - Object valueKvProto = null;  
839 - if (resourceValue.isMultiInstances()) {  
840 - valueKvProto = new JsonObject();  
841 - Object finalvalueKvProto = valueKvProto;  
842 - Gson gson = new GsonBuilder().create();  
843 - ResourceModel.Type finalCurrentType = currentType;  
844 - resourceValue.getInstances().forEach((k, v) -> {  
845 - Object val = this.converter.convertValue(v, finalCurrentType, expectedType,  
846 - new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));  
847 - JsonElement element = gson.toJsonTree(val, val.getClass());  
848 - ((JsonObject) finalvalueKvProto).add(String.valueOf(k), element);  
849 - });  
850 - valueKvProto = gson.toJson(valueKvProto);  
851 - } else {  
852 - valueKvProto = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,  
853 - new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));  
854 - }  
855 - LwM2mOtaConvert lwM2mOtaConvert = convertOtaUpdateValueToString(pathIdVer, valueKvProto, currentType);  
856 - valueKvProto = lwM2mOtaConvert.getValue();  
857 - currentType = lwM2mOtaConvert.getCurrentType();  
858 - return valueKvProto != null ? this.helper.getKvAttrTelemetryToThingsboard(currentType, resourceName, valueKvProto, resourceValue.isMultiInstances()) : null;  
859 - }  
860 - } catch (Exception e) {  
861 - log.error("Failed to add parameters.", e);  
862 - }  
863 - }  
864 - } else {  
865 - log.error("Failed to add parameters. path: [{}], names: [{}]", pathIdVer, names);  
866 - }  
867 - return null;  
868 - }  
869 -  
870 - /**  
871 - * @param pathIdVer - path resource  
872 - * @return - value of Resource into format KvProto or null  
873 - */  
874 - private Object getResourceValueFormatKv(LwM2mClient lwM2MClient, String pathIdVer) {  
875 - LwM2mResource resourceValue = this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);  
876 - if (resourceValue != null) {  
877 - ResourceModel.Type currentType = resourceValue.getType();  
878 - ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);  
879 - return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,  
880 - new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));  
881 - } else {  
882 - return null;  
883 - }  
884 - }  
885 -  
886 - /**  
887 - * @param lwM2MClient -  
888 - * @param path -  
889 - * @return - return value of Resource by idPath  
890 - */  
891 - private LwM2mResource getResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) {  
892 - LwM2mResource lwm2mResourceValue = null;  
893 - ResourceValue resourceValue = lwM2MClient.getResources().get(path);  
894 - if (resourceValue != null) {  
895 - if (new LwM2mPath(convertPathFromIdVerToObjectId(path)).isResource()) {  
896 - lwm2mResourceValue = lwM2MClient.getResources().get(path).getLwM2mResource();  
897 - }  
898 - }  
899 - return lwm2mResourceValue;  
900 - }  
901 -  
902 - /**  
903 - * Update resource (attribute) value on thingsboard after update value in client  
904 - *  
905 - * @param registration -  
906 - * @param path -  
907 - * @param request -  
908 - */  
909 - public void onWriteResponseOk(Registration registration, String path, WriteRequest request) {  
910 - if (request.getNode() instanceof LwM2mResource) {  
911 - this.updateResourcesValue(registration, ((LwM2mResource) request.getNode()), path);  
912 - } else if (request.getNode() instanceof LwM2mObjectInstance) {  
913 - ((LwM2mObjectInstance) request.getNode()).getResources().forEach((resId, resource) -> {  
914 - this.updateResourcesValue(registration, resource, path + "/" + resId);  
915 - });  
916 - }  
917 -  
918 - }  
919 -  
920 - /**  
921 - * #1 Read new, old Value (Attribute, Telemetry, Observe, KeyName)  
922 - * #2 Update in lwM2MClient: ...Profile if changes from update device  
923 - * #3 Equivalence test: old <> new Value (Attribute, Telemetry, Observe, KeyName)  
924 - * #3.1 Attribute isChange (add&del)  
925 - * #3.2 Telemetry isChange (add&del)  
926 - * #3.3 KeyName isChange (add)  
927 - * #3.4 attributeLwm2m isChange (update WrightAttribute: add/update/del)  
928 - * #4 update  
929 - * #4.1 add If #3 isChange, then analyze and update Value in Transport form Client and send Value to thingsboard  
930 - * #4.2 del  
931 - * -- if add attributes includes del telemetry - result del for observe  
932 - * #5  
933 - * #5.1 Observe isChange (add&del)  
934 - * #5.2 Observe.add  
935 - * -- path Attr/Telemetry includes newObserve and does not include oldObserve: send Request observe to Client  
936 - * #5.3 Observe.del  
937 - * -- different between newObserve and oldObserve: send Request cancel observe to client  
938 - * #6  
939 - * #6.1 - update WriteAttribute  
940 - * #6.2 - del WriteAttribute  
941 - *  
942 - * @param clients -  
943 - * @param deviceProfile -  
944 - */  
945 - private void onDeviceProfileUpdate(List<LwM2mClient> clients, DeviceProfile deviceProfile) {  
946 - LwM2mClientProfile lwM2MClientProfileOld = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone();  
947 - if (clientContext.profileUpdate(deviceProfile) != null) {  
948 - // #1  
949 - JsonArray attributeOld = lwM2MClientProfileOld.getPostAttributeProfile();  
950 - Set<String> attributeSetOld = convertJsonArrayToSet(attributeOld);  
951 - JsonArray telemetryOld = lwM2MClientProfileOld.getPostTelemetryProfile();  
952 - Set<String> telemetrySetOld = convertJsonArrayToSet(telemetryOld);  
953 - JsonArray observeOld = lwM2MClientProfileOld.getPostObserveProfile();  
954 - JsonObject keyNameOld = lwM2MClientProfileOld.getPostKeyNameProfile();  
955 - JsonObject attributeLwm2mOld = lwM2MClientProfileOld.getPostAttributeLwm2mProfile();  
956 -  
957 - LwM2mClientProfile lwM2MClientProfileNew = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone();  
958 - JsonArray attributeNew = lwM2MClientProfileNew.getPostAttributeProfile();  
959 - Set<String> attributeSetNew = convertJsonArrayToSet(attributeNew);  
960 - JsonArray telemetryNew = lwM2MClientProfileNew.getPostTelemetryProfile();  
961 - Set<String> telemetrySetNew = convertJsonArrayToSet(telemetryNew);  
962 - JsonArray observeNew = lwM2MClientProfileNew.getPostObserveProfile();  
963 - JsonObject keyNameNew = lwM2MClientProfileNew.getPostKeyNameProfile();  
964 - JsonObject attributeLwm2mNew = lwM2MClientProfileNew.getPostAttributeLwm2mProfile();  
965 -  
966 - // #3  
967 - ResultsAnalyzerParameters sendAttrToThingsboard = new ResultsAnalyzerParameters();  
968 - // #3.1  
969 - if (!attributeOld.equals(attributeNew)) {  
970 - ResultsAnalyzerParameters postAttributeAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(attributeOld,  
971 - new TypeToken<Set<String>>() {  
972 - }.getType()), attributeSetNew);  
973 - sendAttrToThingsboard.getPathPostParametersAdd().addAll(postAttributeAnalyzer.getPathPostParametersAdd());  
974 - sendAttrToThingsboard.getPathPostParametersDel().addAll(postAttributeAnalyzer.getPathPostParametersDel());  
975 - }  
976 - // #3.2  
977 - if (!telemetryOld.equals(telemetryNew)) {  
978 - ResultsAnalyzerParameters postTelemetryAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(telemetryOld,  
979 - new TypeToken<Set<String>>() {  
980 - }.getType()), telemetrySetNew);  
981 - sendAttrToThingsboard.getPathPostParametersAdd().addAll(postTelemetryAnalyzer.getPathPostParametersAdd());  
982 - sendAttrToThingsboard.getPathPostParametersDel().addAll(postTelemetryAnalyzer.getPathPostParametersDel());  
983 - }  
984 - // #3.3  
985 - if (!keyNameOld.equals(keyNameNew)) {  
986 - ResultsAnalyzerParameters keyNameChange = this.getAnalyzerKeyName(new Gson().fromJson(keyNameOld.toString(),  
987 - new TypeToken<ConcurrentHashMap<String, String>>() {  
988 - }.getType()),  
989 - new Gson().fromJson(keyNameNew.toString(), new TypeToken<ConcurrentHashMap<String, String>>() {  
990 - }.getType()));  
991 - sendAttrToThingsboard.getPathPostParametersAdd().addAll(keyNameChange.getPathPostParametersAdd());  
992 - }  
993 -  
994 - // #3.4, #6  
995 - if (!attributeLwm2mOld.equals(attributeLwm2mNew)) {  
996 - this.getAnalyzerAttributeLwm2m(clients, attributeLwm2mOld, attributeLwm2mNew);  
997 - }  
998 -  
999 - // #4.1 add  
1000 - if (sendAttrToThingsboard.getPathPostParametersAdd().size() > 0) {  
1001 - // update value in Resources  
1002 - clients.forEach(client -> {  
1003 - this.readObserveFromProfile(client, sendAttrToThingsboard.getPathPostParametersAdd(), READ);  
1004 - });  
1005 - }  
1006 - // #4.2 del  
1007 - if (sendAttrToThingsboard.getPathPostParametersDel().size() > 0) {  
1008 - ResultsAnalyzerParameters sendAttrToThingsboardDel = this.getAnalyzerParameters(sendAttrToThingsboard.getPathPostParametersAdd(), sendAttrToThingsboard.getPathPostParametersDel());  
1009 - sendAttrToThingsboard.setPathPostParametersDel(sendAttrToThingsboardDel.getPathPostParametersDel());  
1010 - }  
1011 -  
1012 - // #5.1  
1013 - if (!observeOld.equals(observeNew)) {  
1014 - Set<String> observeSetOld = new Gson().fromJson(observeOld, new TypeToken<Set<String>>() {  
1015 - }.getType());  
1016 - Set<String> observeSetNew = new Gson().fromJson(observeNew, new TypeToken<Set<String>>() {  
1017 - }.getType());  
1018 - //#5.2 add  
1019 - // path Attr/Telemetry includes newObserve  
1020 - attributeSetOld.addAll(telemetrySetOld);  
1021 - ResultsAnalyzerParameters sendObserveToClientOld = this.getAnalyzerParametersIn(attributeSetOld, observeSetOld); // add observe  
1022 - attributeSetNew.addAll(telemetrySetNew);  
1023 - ResultsAnalyzerParameters sendObserveToClientNew = this.getAnalyzerParametersIn(attributeSetNew, observeSetNew); // add observe  
1024 - // does not include oldObserve  
1025 - ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sendObserveToClientOld.getPathPostParametersAdd(), sendObserveToClientNew.getPathPostParametersAdd());  
1026 - // send Request observe to Client  
1027 - clients.forEach(client -> {  
1028 - Registration registration = client.getRegistration();  
1029 - if (postObserveAnalyzer.getPathPostParametersAdd().size() > 0) {  
1030 - this.readObserveFromProfile(client, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE);  
1031 - }  
1032 - // 5.3 del  
1033 - // send Request cancel observe to Client  
1034 - if (postObserveAnalyzer.getPathPostParametersDel().size() > 0) {  
1035 - this.cancelObserveFromProfile(client, postObserveAnalyzer.getPathPostParametersDel());  
1036 - }  
1037 - });  
1038 - }  
1039 - }  
1040 - }  
1041 -  
1042 - /**  
1043 - * Compare old list with new list after change AttrTelemetryObserve in config Profile  
1044 - *  
1045 - * @param parametersOld -  
1046 - * @param parametersNew -  
1047 - * @return ResultsAnalyzerParameters: add && new  
1048 - */  
1049 - private ResultsAnalyzerParameters getAnalyzerParameters(Set<String> parametersOld, Set<String> parametersNew) {  
1050 - ResultsAnalyzerParameters analyzerParameters = null;  
1051 - if (!parametersOld.equals(parametersNew)) {  
1052 - analyzerParameters = new ResultsAnalyzerParameters();  
1053 - analyzerParameters.setPathPostParametersAdd(parametersNew  
1054 - .stream().filter(p -> !parametersOld.contains(p)).collect(Collectors.toSet()));  
1055 - analyzerParameters.setPathPostParametersDel(parametersOld  
1056 - .stream().filter(p -> !parametersNew.contains(p)).collect(Collectors.toSet()));  
1057 - }  
1058 - return analyzerParameters;  
1059 - }  
1060 -  
1061 - private ResultsAnalyzerParameters getAnalyzerParametersIn(Set<String> parametersObserve, Set<String> parameters) {  
1062 - ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters();  
1063 - analyzerParameters.setPathPostParametersAdd(parametersObserve  
1064 - .stream().filter(parameters::contains).collect(Collectors.toSet()));  
1065 - return analyzerParameters;  
1066 - }  
1067 -  
1068 - /**  
1069 - * Update Resource value after change RezAttrTelemetry in config Profile  
1070 - * send response Read to Client and add path to pathResAttrTelemetry in LwM2MClient.getAttrTelemetryObserveValue()  
1071 - *  
1072 - * @param targets - path Resources == [ "/2/0/0", "/2/0/1"]  
1073 - */  
1074 - private void readObserveFromProfile(LwM2mClient client, Set<String> targets, LwM2mTypeOper typeOper) {  
1075 - targets.forEach(target -> {  
1076 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target));  
1077 - if (pathIds.isResource()) {  
1078 - if (READ.equals(typeOper)) {  
1079 - lwM2mTransportRequest.sendAllRequest(client, target, typeOper,  
1080 - null, this.config.getTimeout(), null);  
1081 - } else if (OBSERVE.equals(typeOper)) {  
1082 - lwM2mTransportRequest.sendAllRequest(client, target, typeOper,  
1083 - null, this.config.getTimeout(), null);  
1084 - }  
1085 - }  
1086 - });  
1087 - }  
1088 -  
1089 - private ResultsAnalyzerParameters getAnalyzerKeyName(ConcurrentHashMap<String, String> keyNameOld, ConcurrentHashMap<String, String> keyNameNew) {  
1090 - ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters();  
1091 - Set<String> paths = keyNameNew.entrySet()  
1092 - .stream()  
1093 - .filter(e -> !e.getValue().equals(keyNameOld.get(e.getKey())))  
1094 - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).keySet();  
1095 - analyzerParameters.setPathPostParametersAdd(paths);  
1096 - return analyzerParameters;  
1097 - }  
1098 -  
1099 - /**  
1100 - * #3.4, #6  
1101 - * #6  
1102 - * #6.1 - send update WriteAttribute  
1103 - * #6.2 - send empty WriteAttribute  
1104 - *  
1105 - * @param attributeLwm2mOld -  
1106 - * @param attributeLwm2mNew -  
1107 - * @return  
1108 - */  
1109 - private void getAnalyzerAttributeLwm2m(List<LwM2mClient> clients, JsonObject attributeLwm2mOld, JsonObject attributeLwm2mNew) {  
1110 - ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters();  
1111 - ConcurrentHashMap<String, Object> lwm2mAttributesOld = new Gson().fromJson(attributeLwm2mOld.toString(),  
1112 - new TypeToken<ConcurrentHashMap<String, Object>>() {  
1113 - }.getType());  
1114 - ConcurrentHashMap<String, Object> lwm2mAttributesNew = new Gson().fromJson(attributeLwm2mNew.toString(),  
1115 - new TypeToken<ConcurrentHashMap<String, Object>>() {  
1116 - }.getType());  
1117 - Set<String> pathOld = lwm2mAttributesOld.keySet();  
1118 - Set<String> pathNew = lwm2mAttributesNew.keySet();  
1119 - analyzerParameters.setPathPostParametersAdd(pathNew  
1120 - .stream().filter(p -> !pathOld.contains(p)).collect(Collectors.toSet()));  
1121 - analyzerParameters.setPathPostParametersDel(pathOld  
1122 - .stream().filter(p -> !pathNew.contains(p)).collect(Collectors.toSet()));  
1123 - Set<String> pathCommon = pathNew  
1124 - .stream().filter(p -> pathOld.contains(p)).collect(Collectors.toSet());  
1125 - Set<String> pathCommonChange = pathCommon  
1126 - .stream().filter(p -> !lwm2mAttributesOld.get(p).equals(lwm2mAttributesNew.get(p))).collect(Collectors.toSet());  
1127 - analyzerParameters.getPathPostParametersAdd().addAll(pathCommonChange);  
1128 - // #6  
1129 - // #6.2  
1130 - if (analyzerParameters.getPathPostParametersAdd().size() > 0) {  
1131 - clients.forEach(client -> {  
1132 - Set<String> clientObjects = clientContext.getSupportedIdVerInClient(client);  
1133 - Set<String> pathSend = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))  
1134 - .collect(Collectors.toUnmodifiableSet());  
1135 - if (!pathSend.isEmpty()) {  
1136 - ConcurrentHashMap<String, Object> finalParams = lwm2mAttributesNew;  
1137 - pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(client, target, WRITE_ATTRIBUTES,  
1138 - finalParams.get(target), this.config.getTimeout(), null));  
1139 - }  
1140 - });  
1141 - }  
1142 - // #6.2  
1143 - if (analyzerParameters.getPathPostParametersDel().size() > 0) {  
1144 - clients.forEach(client -> {  
1145 - Registration registration = client.getRegistration();  
1146 - Set<String> clientObjects = clientContext.getSupportedIdVerInClient(client);  
1147 - Set<String> pathSend = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))  
1148 - .collect(Collectors.toUnmodifiableSet());  
1149 - if (!pathSend.isEmpty()) {  
1150 - pathSend.forEach(target -> {  
1151 - Map<String, Object> params = (Map<String, Object>) lwm2mAttributesOld.get(target);  
1152 - params.clear();  
1153 - params.put(OBJECT_VERSION, "");  
1154 - lwM2mTransportRequest.sendAllRequest(client, target, WRITE_ATTRIBUTES, params, this.config.getTimeout(), null);  
1155 - });  
1156 - }  
1157 - });  
1158 - }  
1159 -  
1160 - }  
1161 -  
1162 - private void cancelObserveFromProfile(LwM2mClient lwM2mClient, Set<String> paramAnallyzer) {  
1163 - paramAnallyzer.forEach(pathIdVer -> {  
1164 - if (this.getResourceValueFromLwM2MClient(lwM2mClient, pathIdVer) != null) {  
1165 - lwM2mTransportRequest.sendAllRequest(lwM2mClient, pathIdVer, OBSERVE_CANCEL, null, this.config.getTimeout(), null);  
1166 - }  
1167 - }  
1168 - );  
1169 - }  
1170 -  
1171 - private void updateResourcesValueToClient(LwM2mClient lwM2MClient, Object valueOld, Object valueNew, String path) {  
1172 - if (valueNew != null && (valueOld == null || !valueNew.toString().equals(valueOld.toString()))) {  
1173 - lwM2mTransportRequest.sendAllRequest(lwM2MClient, path, WRITE_REPLACE, valueNew, this.config.getTimeout(), null);  
1174 - } else {  
1175 - log.error("Failed update resource [{}] [{}]", path, valueNew);  
1176 - String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad",  
1177 - LOG_LW2M_ERROR, path, valueNew);  
1178 - this.sendLogsToThingsboard(lwM2MClient, logMsg);  
1179 - log.info("Failed update resource [{}] [{}]", path, valueNew);  
1180 - }  
1181 - }  
1182 -  
1183 - /**  
1184 - * @param updateCredentials - Credentials include config only security Client (without config attr/telemetry...)  
1185 - * config attr/telemetry... in profile  
1186 - */  
1187 - public void onToTransportUpdateCredentials(TransportProtos.ToTransportUpdateCredentialsProto updateCredentials) {  
1188 - log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList());  
1189 - }  
1190 -  
1191 - /**  
1192 - * Get path to resource from profile equal keyName  
1193 - *  
1194 - * @param sessionInfo -  
1195 - * @param name -  
1196 - * @return -  
1197 - */  
1198 - public String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {  
1199 - LwM2mClientProfile profile = clientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));  
1200 - LwM2mClient lwM2mClient = clientContext.getClientBySessionInfo(sessionInfo);  
1201 - return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream()  
1202 - .filter(e -> e.getValue().getAsString().equals(name) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().map(Map.Entry::getKey)  
1203 - .orElse(null);  
1204 - }  
1205 -  
1206 - /**  
1207 - * 1. FirmwareUpdate:  
1208 - * - msg.getSharedUpdatedList().forEach(tsKvProto -> {tsKvProto.getKv().getKey().indexOf(FIRMWARE_UPDATE_PREFIX, 0) == 0  
1209 - * 2. Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values  
1210 - * - Get path resource by result attributesResponse  
1211 - *  
1212 - * @param attributesResponse -  
1213 - * @param sessionInfo -  
1214 - */  
1215 - public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) {  
1216 - try {  
1217 - List<TransportProtos.TsKvProto> tsKvProtos = attributesResponse.getSharedAttributeListList();  
1218 - this.updateAttributeFromThingsboard(tsKvProtos, sessionInfo);  
1219 - } catch (Exception e) {  
1220 - log.error("", e);  
1221 - }  
1222 - }  
1223 -  
1224 - /**  
1225 - * #1.1 If two names have equal path => last time attribute  
1226 - * #2.1 if there is a difference in values between the current resource values and the shared attribute values  
1227 - * => send to client Request Update of value (new value from shared attribute)  
1228 - * and LwM2MClient.delayedRequests.add(path)  
1229 - * #2.1 if there is not a difference in values between the current resource values and the shared attribute values  
1230 - *  
1231 - * @param tsKvProtos  
1232 - * @param sessionInfo  
1233 - */  
1234 - public void updateAttributeFromThingsboard(List<TransportProtos.TsKvProto> tsKvProtos, TransportProtos.SessionInfoProto sessionInfo) {  
1235 - LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo);  
1236 - if (lwM2MClient != null) {  
1237 - log.warn("1) UpdateAttributeFromThingsboard, tsKvProtos [{}]", tsKvProtos);  
1238 - tsKvProtos.forEach(tsKvProto -> {  
1239 - String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, tsKvProto.getKv().getKey());  
1240 - if (pathIdVer != null) {  
1241 - // #1.1  
1242 - if (lwM2MClient.getDelayedRequests().containsKey(pathIdVer) && tsKvProto.getTs() > lwM2MClient.getDelayedRequests().get(pathIdVer).getTs()) {  
1243 - lwM2MClient.getDelayedRequests().put(pathIdVer, tsKvProto);  
1244 - } else if (!lwM2MClient.getDelayedRequests().containsKey(pathIdVer)) {  
1245 - lwM2MClient.getDelayedRequests().put(pathIdVer, tsKvProto);  
1246 - }  
1247 - }  
1248 - });  
1249 - // #2.1  
1250 - lwM2MClient.getDelayedRequests().forEach((pathIdVer, tsKvProto) -> {  
1251 - this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer),  
1252 - getValueFromKvProto(tsKvProto.getKv()), pathIdVer);  
1253 - });  
1254 - } else {  
1255 - log.error("UpdateAttributeFromThingsboard, lwM2MClient is null");  
1256 - }  
1257 - }  
1258 -  
1259 - /**  
1260 - * @param lwM2MClient -  
1261 - * @return SessionInfoProto -  
1262 - */  
1263 - private SessionInfoProto getSessionInfo(LwM2mClient lwM2MClient) {  
1264 - if (lwM2MClient != null && lwM2MClient.getSession() != null) {  
1265 - return lwM2MClient.getSession();  
1266 - }  
1267 - return null;  
1268 - }  
1269 -  
1270 - /**  
1271 - * @param registration - Registration LwM2M Client  
1272 - * @return - sessionInfo after access connect client  
1273 - */  
1274 - public SessionInfoProto getSessionInfoOrCloseSession(Registration registration) {  
1275 - return getSessionInfo(clientContext.getClientByEndpoint(registration.getEndpoint()));  
1276 - }  
1277 -  
1278 - /**  
1279 - * if sessionInfo removed from sessions, then new registerAsyncSession  
1280 - *  
1281 - * @param sessionInfo -  
1282 - */  
1283 - private void reportActivityAndRegister(SessionInfoProto sessionInfo) {  
1284 - if (sessionInfo != null && transportService.reportActivity(sessionInfo) == null) {  
1285 - transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo));  
1286 - this.reportActivitySubscription(sessionInfo);  
1287 - }  
1288 - }  
1289 -  
1290 - private void reportActivity() {  
1291 - clientContext.getLwM2mClients().forEach(client -> reportActivityAndRegister(client.getSession()));  
1292 - }  
1293 -  
1294 - /**  
1295 - * #1. !!! sharedAttr === profileAttr !!!  
1296 - * - If there is a difference in values between the current resource values and the shared attribute values  
1297 - * - when the client connects to the server  
1298 - * #1.1 get attributes name from profile include name resources in ModelObject if resource isWritable  
1299 - * #1.2 #1 size > 0 => send Request getAttributes to thingsboard  
1300 - * #2. FirmwareAttribute subscribe:  
1301 - *  
1302 - * @param lwM2MClient - LwM2M Client  
1303 - */  
1304 - public void putDelayedUpdateResourcesThingsboard(LwM2mClient lwM2MClient) {  
1305 - SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient);  
1306 - if (sessionInfo != null) {  
1307 - //#1.1  
1308 - ConcurrentMap<String, String> keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient);  
1309 - if (keyNamesMap.values().size() > 0) {  
1310 - try {  
1311 - //#1.2  
1312 - TransportProtos.GetAttributeRequestMsg getAttributeMsg = adaptor.convertToGetAttributes(null, keyNamesMap.values());  
1313 - transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST));  
1314 - } catch (AdaptorException e) {  
1315 - log.trace("Failed to decode get attributes request", e);  
1316 - }  
1317 - }  
1318 -  
1319 - }  
1320 - }  
1321 -  
1322 - public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient, LwM2mClientRpcRequest rpcRequest) {  
1323 - if (lwM2MClient.getRegistration().getSupportedVersion(FW_5_ID) != null) {  
1324 - SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient);  
1325 - if (sessionInfo != null) {  
1326 - DefaultLwM2MTransportMsgHandler handler = this;  
1327 - this.transportService.process(sessionInfo, createOtaPackageRequestMsg(sessionInfo, OtaPackageType.FIRMWARE.name()),  
1328 - new TransportServiceCallback<>() {  
1329 - @Override  
1330 - public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) {  
1331 - if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())  
1332 - && response.getType().equals(OtaPackageType.FIRMWARE.name())) {  
1333 - LwM2mFwSwUpdate fwUpdate = lwM2MClient.getFwUpdate(clientContext);  
1334 - if (rpcRequest != null) {  
1335 - fwUpdate.setStateUpdate(INITIATED.name());  
1336 - }  
1337 - if (!FAILED.name().equals(fwUpdate.getStateUpdate())) {  
1338 - log.warn("7) firmware start with ver: [{}]", response.getVersion());  
1339 - fwUpdate.setRpcRequest(rpcRequest);  
1340 - fwUpdate.setCurrentVersion(response.getVersion());  
1341 - fwUpdate.setCurrentTitle(response.getTitle());  
1342 - fwUpdate.setCurrentId(new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB()));  
1343 - if (rpcRequest == null) {  
1344 - fwUpdate.sendReadObserveInfo(lwM2mTransportRequest);  
1345 - } else {  
1346 - fwUpdate.writeFwSwWare(handler, lwM2mTransportRequest);  
1347 - }  
1348 - } else {  
1349 - String msgError = String.format("OtaPackage device: %s, version: %s, stateUpdate: %s",  
1350 - lwM2MClient.getDeviceName(), response.getVersion(), fwUpdate.getStateUpdate());  
1351 - log.warn("7_1 [{}]", msgError);  
1352 - }  
1353 - } else {  
1354 - String msgError = String.format("OtaPackage device: %s, responseStatus: %s",  
1355 - lwM2MClient.getDeviceName(), response.getResponseStatus().toString());  
1356 - log.trace(msgError);  
1357 - if (rpcRequest != null) {  
1358 - sendErrorRpcResponse(rpcRequest, msgError, sessionInfo);  
1359 - }  
1360 - }  
1361 - }  
1362 -  
1363 - @Override  
1364 - public void onError(Throwable e) {  
1365 - log.trace("Failed to process firmwareUpdate ", e);  
1366 - }  
1367 - });  
1368 - }  
1369 - }  
1370 - }  
1371 -  
1372 - public void getInfoSoftwareUpdate(LwM2mClient lwM2MClient, LwM2mClientRpcRequest rpcRequest) {  
1373 - if (lwM2MClient.getRegistration().getSupportedVersion(SW_ID) != null) {  
1374 - SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient);  
1375 - if (sessionInfo != null) {  
1376 - DefaultLwM2MTransportMsgHandler handler = this;  
1377 - transportService.process(sessionInfo, createOtaPackageRequestMsg(sessionInfo, OtaPackageType.SOFTWARE.name()),  
1378 - new TransportServiceCallback<>() {  
1379 - @Override  
1380 - public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) {  
1381 - if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())  
1382 - && response.getType().equals(OtaPackageType.SOFTWARE.name())) {  
1383 - lwM2MClient.getSwUpdate().setRpcRequest(rpcRequest);  
1384 - lwM2MClient.getSwUpdate().setCurrentVersion(response.getVersion());  
1385 - lwM2MClient.getSwUpdate().setCurrentTitle(response.getTitle());  
1386 - lwM2MClient.getSwUpdate().setCurrentId(new OtaPackageId(new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB())).getId());  
1387 - lwM2MClient.getSwUpdate().sendReadObserveInfo(lwM2mTransportRequest);  
1388 - if (rpcRequest == null) {  
1389 - lwM2MClient.getSwUpdate().sendReadObserveInfo(lwM2mTransportRequest);  
1390 - } else {  
1391 - lwM2MClient.getSwUpdate().writeFwSwWare(handler, lwM2mTransportRequest);  
1392 - }  
1393 - } else {  
1394 - log.trace("Software [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());  
1395 - }  
1396 - }  
1397 -  
1398 - @Override  
1399 - public void onError(Throwable e) {  
1400 - log.trace("Failed to process softwareUpdate ", e);  
1401 - }  
1402 - });  
1403 - }  
1404 - }  
1405 - }  
1406 -  
1407 - private TransportProtos.GetOtaPackageRequestMsg createOtaPackageRequestMsg(SessionInfoProto sessionInfo, String nameFwSW) {  
1408 - return TransportProtos.GetOtaPackageRequestMsg.newBuilder()  
1409 - .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())  
1410 - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())  
1411 - .setTenantIdMSB(sessionInfo.getTenantIdMSB())  
1412 - .setTenantIdLSB(sessionInfo.getTenantIdLSB())  
1413 - .setType(nameFwSW)  
1414 - .build();  
1415 - }  
1416 -  
1417 - /**  
1418 - * !!! sharedAttr === profileAttr !!!  
1419 - * Get names or keyNames from profile: resources IsWritable  
1420 - *  
1421 - * @param lwM2MClient -  
1422 - * @return ArrayList keyNames from profile profileAttr && IsWritable  
1423 - */  
1424 - private ConcurrentMap<String, String> getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) {  
1425 -  
1426 - LwM2mClientProfile profile = clientContext.getProfile(lwM2MClient.getProfileId());  
1427 - return new Gson().fromJson(profile.getPostKeyNameProfile().toString(),  
1428 - new TypeToken<ConcurrentHashMap<String, String>>() {  
1429 - }.getType());  
1430 - }  
1431 -  
1432 - private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) {  
1433 - ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer, this.config  
1434 - .getModelProvider());  
1435 - Integer objectId = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)).getObjectId();  
1436 - String objectVer = validateObjectVerFromKey(pathIdVer);  
1437 - return resourceModel != null && (isWritableNotOptional ?  
1438 - objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() :  
1439 - objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)));  
1440 - }  
1441 -  
1442 - public LwM2MTransportServerConfig getConfig() {  
1443 - return this.config;  
1444 - }  
1445 -  
1446 - private void reportActivitySubscription(TransportProtos.SessionInfoProto sessionInfo) {  
1447 - transportService.process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder()  
1448 - .setAttributeSubscription(true)  
1449 - .setRpcSubscription(true)  
1450 - .setLastActivityTime(System.currentTimeMillis())  
1451 - .build(), TransportServiceCallback.EMPTY);  
1452 - }  
1453 -}  
@@ -26,8 +26,8 @@ import org.eclipse.leshan.server.californium.LeshanServer; @@ -26,8 +26,8 @@ import org.eclipse.leshan.server.californium.LeshanServer;
26 import org.eclipse.leshan.server.californium.LeshanServerBuilder; 26 import org.eclipse.leshan.server.californium.LeshanServerBuilder;
27 import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; 27 import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
28 import org.eclipse.leshan.server.model.LwM2mModelProvider; 28 import org.eclipse.leshan.server.model.LwM2mModelProvider;
29 -import org.eclipse.leshan.server.security.EditableSecurityStore;  
30 import org.springframework.stereotype.Component; 29 import org.springframework.stereotype.Component;
  30 +import org.thingsboard.server.cache.ota.OtaPackageDataCache;
31 import org.thingsboard.server.common.data.StringUtils; 31 import org.thingsboard.server.common.data.StringUtils;
32 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 32 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
33 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; 33 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
@@ -35,8 +35,8 @@ import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC; @@ -35,8 +35,8 @@ import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC;
35 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; 35 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer;
36 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier; 36 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier;
37 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; 37 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
38 -import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore;  
39 import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; 38 import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore;
  39 +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
40 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; 40 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
41 41
42 import javax.annotation.PostConstruct; 42 import javax.annotation.PostConstruct;
@@ -81,7 +81,8 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { @@ -81,7 +81,8 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
81 private final LwM2mTransportContext context; 81 private final LwM2mTransportContext context;
82 private final LwM2MTransportServerConfig config; 82 private final LwM2MTransportServerConfig config;
83 private final LwM2mTransportServerHelper helper; 83 private final LwM2mTransportServerHelper helper;
84 - private final DefaultLwM2MTransportMsgHandler handler; 84 + private final OtaPackageDataCache otaPackageDataCache;
  85 + private final DefaultLwM2MUplinkMsgHandler handler;
85 private final CaliforniumRegistrationStore registrationStore; 86 private final CaliforniumRegistrationStore registrationStore;
86 private final TbSecurityStore securityStore; 87 private final TbSecurityStore securityStore;
87 private final LwM2mClientContext lwM2mClientContext; 88 private final LwM2mClientContext lwM2mClientContext;
@@ -104,8 +105,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { @@ -104,8 +105,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
104 * "coap://host:port/{path}/{token}/{nameFile}" 105 * "coap://host:port/{path}/{token}/{nameFile}"
105 */ 106 */
106 107
107 -  
108 - LwM2mTransportCoapResource otaCoapResource = new LwM2mTransportCoapResource(handler, FIRMWARE_UPDATE_COAP_RECOURSE); 108 + LwM2mTransportCoapResource otaCoapResource = new LwM2mTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RECOURSE);
109 this.server.coap().getServer().add(otaCoapResource); 109 this.server.coap().getServer().add(otaCoapResource);
110 this.startLhServer(); 110 this.startLhServer();
111 this.context.setServer(server); 111 this.context.setServer(server);
  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;
  17 +
  18 +public enum LwM2MFirmwareUpdateStrategy {
  19 + OBJ_5_BINARY(1, "ObjectId 5, Binary"),
  20 + OBJ_5_TEMP_URL(2, "ObjectId 5, URI"),
  21 + OBJ_19_BINARY(3, "ObjectId 19, Binary");
  22 +
  23 + public int code;
  24 + public String type;
  25 +
  26 + LwM2MFirmwareUpdateStrategy(int code, String type) {
  27 + this.code = code;
  28 + this.type = type;
  29 + }
  30 +
  31 + public static LwM2MFirmwareUpdateStrategy fromStrategyFwByType(String type) {
  32 + for (LwM2MFirmwareUpdateStrategy to : LwM2MFirmwareUpdateStrategy.values()) {
  33 + if (to.type.equals(type)) {
  34 + return to;
  35 + }
  36 + }
  37 + throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type));
  38 + }
  39 +
  40 + public static LwM2MFirmwareUpdateStrategy fromStrategyFwByCode(int code) {
  41 + for (LwM2MFirmwareUpdateStrategy to : LwM2MFirmwareUpdateStrategy.values()) {
  42 + if (to.code == code) {
  43 + return to;
  44 + }
  45 + }
  46 + throw new IllegalArgumentException(String.format("Unsupported FW Strategy code : %s", code));
  47 + }
  48 +}
  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;
  17 +
  18 +public enum LwM2MSoftwareUpdateStrategy {
  19 + BINARY(1, "ObjectId 9, Binary"),
  20 + TEMP_URL(2, "ObjectId 9, URI");
  21 +
  22 + public int code;
  23 + public String type;
  24 +
  25 + LwM2MSoftwareUpdateStrategy(int code, String type) {
  26 + this.code = code;
  27 + this.type = type;
  28 + }
  29 +
  30 + public static LwM2MSoftwareUpdateStrategy fromStrategySwByType(String type) {
  31 + for (LwM2MSoftwareUpdateStrategy to : LwM2MSoftwareUpdateStrategy.values()) {
  32 + if (to.type.equals(type)) {
  33 + return to;
  34 + }
  35 + }
  36 + throw new IllegalArgumentException(String.format("Unsupported SW Strategy type : %s", type));
  37 + }
  38 +
  39 + public static LwM2MSoftwareUpdateStrategy fromStrategySwByCode(int code) {
  40 + for (LwM2MSoftwareUpdateStrategy to : LwM2MSoftwareUpdateStrategy.values()) {
  41 + if (to.code == code) {
  42 + return to;
  43 + }
  44 + }
  45 + throw new IllegalArgumentException(String.format("Unsupported SW Strategy code : %s", code));
  46 + }
  47 +
  48 +}
@@ -84,10 +84,10 @@ public class LwM2mNetworkConfig { @@ -84,10 +84,10 @@ public class LwM2mNetworkConfig {
84 Create new instance of udp endpoint context matcher. 84 Create new instance of udp endpoint context matcher.
85 Params: 85 Params:
86 checkAddress 86 checkAddress
87 - – true with address check, (STRICT, UDP) 87 + – true with address check, (STRICT, UDP) - if port Registration of client is changed - it is bad
88 - false, without 88 - false, without
89 */ 89 */
90 - coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "STRICT"); 90 + coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED");
91 /** 91 /**
92 https://tools.ietf.org/html/rfc7959#section-2.9.3 92 https://tools.ietf.org/html/rfc7959#section-2.9.3
93 The block size (number of bytes) to use when doing a blockwise transfer. \ 93 The block size (number of bytes) to use when doing a blockwise transfer. \
@@ -103,7 +103,7 @@ public class LwM2mNetworkConfig { @@ -103,7 +103,7 @@ public class LwM2mNetworkConfig {
103 */ 103 */
104 coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024); 104 coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024);
105 105
106 - coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 4); 106 + coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 10);
107 107
108 return coapConfig; 108 return coapConfig;
109 } 109 }
  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;
  17 +
  18 +import lombok.Getter;
  19 +
  20 +/**
  21 + * Define the behavior of a write request.
  22 + */
  23 +public enum LwM2mOperationType {
  24 +
  25 + READ(0, "Read", true),
  26 + DISCOVER(1, "Discover", true),
  27 + DISCOVER_ALL(2, "DiscoverAll", false),
  28 + OBSERVE_READ_ALL(3, "ObserveReadAll", false),
  29 +
  30 + OBSERVE(4, "Observe", true),
  31 + OBSERVE_CANCEL(5, "ObserveCancel", true),
  32 + OBSERVE_CANCEL_ALL(6, "ObserveCancelAll", false),
  33 + EXECUTE(7, "Execute", true),
  34 + /**
  35 + * 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).
  37 + * if all resources are to be replaced
  38 + */
  39 + WRITE_REPLACE(8, "WriteReplace", true),
  40 +
  41 + /**
  42 + * 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).
  44 + * if this is a partial update request
  45 + */
  46 + WRITE_UPDATE(9, "WriteUpdate", true),
  47 + WRITE_ATTRIBUTES(10, "WriteAttributes", true),
  48 + DELETE(11, "Delete", true),
  49 +
  50 + // only for RPC
  51 + FW_UPDATE(12, "FirmwareUpdate", false);
  52 +
  53 +// FW_READ_INFO(12, "FirmwareReadInfo"),
  54 +// SW_READ_INFO(15, "SoftwareReadInfo"),
  55 +// SW_UPDATE(16, "SoftwareUpdate"),
  56 +// SW_UNINSTALL(18, "SoftwareUninstall");
  57 +
  58 + @Getter
  59 + private final int code;
  60 + @Getter
  61 + private final String type;
  62 + @Getter
  63 + private final boolean hasObjectId;
  64 +
  65 + LwM2mOperationType(int code, String type, boolean hasObjectId) {
  66 + this.code = code;
  67 + this.type = type;
  68 + this.hasObjectId = hasObjectId;
  69 + }
  70 +
  71 + public static LwM2mOperationType fromType(String type) {
  72 + for (LwM2mOperationType to : LwM2mOperationType.values()) {
  73 + if (to.type.equals(type)) {
  74 + return to;
  75 + }
  76 + }
  77 + return null;
  78 + }
  79 +}
@@ -23,18 +23,18 @@ import org.eclipse.leshan.server.queue.PresenceListener; @@ -23,18 +23,18 @@ import org.eclipse.leshan.server.queue.PresenceListener;
23 import org.eclipse.leshan.server.registration.Registration; 23 import org.eclipse.leshan.server.registration.Registration;
24 import org.eclipse.leshan.server.registration.RegistrationListener; 24 import org.eclipse.leshan.server.registration.RegistrationListener;
25 import org.eclipse.leshan.server.registration.RegistrationUpdate; 25 import org.eclipse.leshan.server.registration.RegistrationUpdate;
  26 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
26 27
27 import java.util.Collection; 28 import java.util.Collection;
28 29
29 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;  
30 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; 30 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
31 31
32 @Slf4j 32 @Slf4j
33 public class LwM2mServerListener { 33 public class LwM2mServerListener {
34 34
35 - private final LwM2mTransportMsgHandler service; 35 + private final LwM2mUplinkMsgHandler service;
36 36
37 - public LwM2mServerListener(LwM2mTransportMsgHandler service) { 37 + public LwM2mServerListener(LwM2mUplinkMsgHandler service) {
38 this.service = service; 38 this.service = service;
39 } 39 }
40 40
@@ -86,30 +86,24 @@ public class LwM2mServerListener { @@ -86,30 +86,24 @@ public class LwM2mServerListener {
86 86
87 @Override 87 @Override
88 public void cancelled(Observation observation) { 88 public void cancelled(Observation observation) {
89 - String msg = String.format("%s: Canceled Observation %s.", LOG_LW2M_INFO, observation.getPath());  
90 - service.sendLogsToThingsboard(observation.getRegistrationId(), msg);  
91 - log.warn(msg); 89 + log.trace("Canceled Observation {}.", observation.getPath());
92 } 90 }
93 91
94 @Override 92 @Override
95 public void onResponse(Observation observation, Registration registration, ObserveResponse response) { 93 public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
96 if (registration != null) { 94 if (registration != null) {
97 - service.onUpdateValueAfterReadResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(),  
98 - registration), response, null); 95 + service.onUpdateValueAfterReadResponse(registration, convertObjectIdToVersionedId(observation.getPath().toString(), registration), response);
99 } 96 }
100 } 97 }
101 98
102 @Override 99 @Override
103 public void onError(Observation observation, Registration registration, Exception error) { 100 public void onError(Observation observation, Registration registration, Exception error) {
104 - log.error(String.format("Unable to handle notification of [%s:%s]", observation.getRegistrationId(), observation.getPath()), error); 101 + log.error("Unable to handle notification of [{}:{}]", observation.getRegistrationId(), observation.getPath(), error);
105 } 102 }
106 103
107 @Override 104 @Override
108 public void newObservation(Observation observation, Registration registration) { 105 public void newObservation(Observation observation, Registration registration) {
109 - String msg = String.format("%s: Successful start newObservation %s.", LOG_LW2M_INFO,  
110 - observation.getPath());  
111 - log.warn(msg);  
112 - service.sendLogsToThingsboard(registration.getId(), msg); 106 + log.trace("Successful start newObservation {}.", observation.getPath());
113 } 107 }
114 }; 108 };
115 } 109 }
@@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server; @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server;
17 17
18 import io.netty.util.concurrent.Future; 18 import io.netty.util.concurrent.Future;
19 import io.netty.util.concurrent.GenericFutureListener; 19 import io.netty.util.concurrent.GenericFutureListener;
  20 +import lombok.RequiredArgsConstructor;
20 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
21 import org.jetbrains.annotations.NotNull; 22 import org.jetbrains.annotations.NotNull;
22 import org.thingsboard.server.common.data.Device; 23 import org.thingsboard.server.common.data.Device;
@@ -30,28 +31,29 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotifica @@ -30,28 +31,29 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotifica
30 import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; 31 import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg;
31 import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; 32 import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg;
32 import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; 33 import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto;
  34 +import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService;
  35 +import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler;
  36 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
33 37
34 import java.util.Optional; 38 import java.util.Optional;
35 import java.util.UUID; 39 import java.util.UUID;
36 40
37 @Slf4j 41 @Slf4j
  42 +@RequiredArgsConstructor
38 public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? super Void>>, SessionMsgListener { 43 public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? super Void>>, SessionMsgListener {
39 - private DefaultLwM2MTransportMsgHandler handler;  
40 - private TransportProtos.SessionInfoProto sessionInfo;  
41 -  
42 - public LwM2mSessionMsgListener(DefaultLwM2MTransportMsgHandler handler, TransportProtos.SessionInfoProto sessionInfo) {  
43 - this.handler = handler;  
44 - this.sessionInfo = sessionInfo;  
45 - } 44 + private final LwM2mUplinkMsgHandler handler;
  45 + private final LwM2MAttributesService attributesService;
  46 + private final LwM2MRpcRequestHandler rpcHandler;
  47 + private final TransportProtos.SessionInfoProto sessionInfo;
46 48
47 @Override 49 @Override
48 public void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse) { 50 public void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse) {
49 - this.handler.onGetAttributesResponse(getAttributesResponse, this.sessionInfo); 51 + this.attributesService.onGetAttributesResponse(getAttributesResponse, this.sessionInfo);
50 } 52 }
51 53
52 @Override 54 @Override
53 public void onAttributeUpdate(AttributeUpdateNotificationMsg attributeUpdateNotification) { 55 public void onAttributeUpdate(AttributeUpdateNotificationMsg attributeUpdateNotification) {
54 - this.handler.onAttributeUpdate(attributeUpdateNotification, this.sessionInfo); 56 + this.attributesService.onAttributesUpdate(attributeUpdateNotification, this.sessionInfo);
55 } 57 }
56 58
57 @Override 59 @Override
@@ -76,12 +78,12 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s @@ -76,12 +78,12 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s
76 78
77 @Override 79 @Override
78 public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) { 80 public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) {
79 - this.handler.onToDeviceRpcRequest(toDeviceRequest,this.sessionInfo); 81 + this.rpcHandler.onToDeviceRpcRequest(toDeviceRequest,this.sessionInfo);
80 } 82 }
81 83
82 @Override 84 @Override
83 public void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse) { 85 public void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse) {
84 - this.handler.onToServerRpcResponse(toServerResponse); 86 + this.rpcHandler.onToServerRpcResponse(toServerResponse);
85 } 87 }
86 88
87 @Override 89 @Override
@@ -24,6 +24,9 @@ import org.eclipse.californium.core.observe.ObserveRelation; @@ -24,6 +24,9 @@ import org.eclipse.californium.core.observe.ObserveRelation;
24 import org.eclipse.californium.core.server.resources.CoapExchange; 24 import org.eclipse.californium.core.server.resources.CoapExchange;
25 import org.eclipse.californium.core.server.resources.Resource; 25 import org.eclipse.californium.core.server.resources.Resource;
26 import org.eclipse.californium.core.server.resources.ResourceObserver; 26 import org.eclipse.californium.core.server.resources.ResourceObserver;
  27 +import org.thingsboard.server.cache.ota.OtaPackageDataCache;
  28 +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
  29 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
27 30
28 import java.util.UUID; 31 import java.util.UUID;
29 import java.util.concurrent.ConcurrentHashMap; 32 import java.util.concurrent.ConcurrentHashMap;
@@ -37,11 +40,11 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.S @@ -37,11 +40,11 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.S
37 public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { 40 public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
38 private final ConcurrentMap<String, ObserveRelation> tokenToObserveRelationMap = new ConcurrentHashMap<>(); 41 private final ConcurrentMap<String, ObserveRelation> tokenToObserveRelationMap = new ConcurrentHashMap<>();
39 private final ConcurrentMap<String, AtomicInteger> tokenToObserveNotificationSeqMap = new ConcurrentHashMap<>(); 42 private final ConcurrentMap<String, AtomicInteger> tokenToObserveNotificationSeqMap = new ConcurrentHashMap<>();
40 - private final LwM2mTransportMsgHandler handler; 43 + private final OtaPackageDataCache otaPackageDataCache;
41 44
42 - public LwM2mTransportCoapResource(LwM2mTransportMsgHandler handler, String name) { 45 + public LwM2mTransportCoapResource(OtaPackageDataCache otaPackageDataCache, String name) {
43 super(name); 46 super(name);
44 - this.handler = handler; 47 + this.otaPackageDataCache = otaPackageDataCache;
45 this.setObservable(true); // enable observing 48 this.setObservable(true); // enable observing
46 this.addObserver(new CoapResourceObserver()); 49 this.addObserver(new CoapResourceObserver());
47 } 50 }
@@ -140,9 +143,9 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { @@ -140,9 +143,9 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
140 response.setPayload(fwData); 143 response.setPayload(fwData);
141 if (exchange.getRequestOptions().getBlock2() != null) { 144 if (exchange.getRequestOptions().getBlock2() != null) {
142 int chunkSize = exchange.getRequestOptions().getBlock2().getSzx(); 145 int chunkSize = exchange.getRequestOptions().getBlock2().getSzx();
143 - boolean moreFlag = fwData.length > chunkSize;  
144 - response.getOptions().setBlock2(chunkSize, moreFlag, 0);  
145 - log.warn("92) with blokc2 Send currentId: [{}], length: [{}], chunkSize [{}], moreFlag [{}]", currentId.toString(), fwData.length, chunkSize, moreFlag); 146 + boolean lastFlag = fwData.length > chunkSize;
  147 + response.getOptions().setBlock2(chunkSize, lastFlag, 0);
  148 + log.warn("92) with blokc2 Send currentId: [{}], length: [{}], chunkSize [{}], moreFlag [{}]", currentId.toString(), fwData.length, chunkSize, lastFlag);
146 } 149 }
147 else { 150 else {
148 log.warn("92) with block1 Send currentId: [{}], length: [{}], ", currentId.toString(), fwData.length); 151 log.warn("92) with block1 Send currentId: [{}], length: [{}], ", currentId.toString(), fwData.length);
@@ -152,7 +155,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { @@ -152,7 +155,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
152 } 155 }
153 156
154 private byte[] getOtaData(UUID currentId) { 157 private byte[] getOtaData(UUID currentId) {
155 - return ((DefaultLwM2MTransportMsgHandler) handler).otaPackageDataCache.get(currentId.toString()); 158 + return otaPackageDataCache.get(currentId.toString());
156 } 159 }
157 160
158 } 161 }
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;  
17 -  
18 -import lombok.RequiredArgsConstructor;  
19 -import lombok.extern.slf4j.Slf4j;  
20 -import org.eclipse.californium.core.coap.CoAP;  
21 -import org.eclipse.californium.core.coap.Response;  
22 -import org.eclipse.leshan.core.Link;  
23 -import org.eclipse.leshan.core.model.ResourceModel;  
24 -import org.eclipse.leshan.core.node.LwM2mNode;  
25 -import org.eclipse.leshan.core.node.LwM2mObject;  
26 -import org.eclipse.leshan.core.node.LwM2mObjectInstance;  
27 -import org.eclipse.leshan.core.node.LwM2mPath;  
28 -import org.eclipse.leshan.core.node.LwM2mResource;  
29 -import org.eclipse.leshan.core.node.LwM2mSingleResource;  
30 -import org.eclipse.leshan.core.node.ObjectLink;  
31 -import org.eclipse.leshan.core.observation.Observation;  
32 -import org.eclipse.leshan.core.request.ContentFormat;  
33 -import org.eclipse.leshan.core.request.DeleteRequest;  
34 -import org.eclipse.leshan.core.request.DiscoverRequest;  
35 -import org.eclipse.leshan.core.request.ExecuteRequest;  
36 -import org.eclipse.leshan.core.request.ObserveRequest;  
37 -import org.eclipse.leshan.core.request.ReadRequest;  
38 -import org.eclipse.leshan.core.request.SimpleDownlinkRequest;  
39 -import org.eclipse.leshan.core.request.WriteAttributesRequest;  
40 -import org.eclipse.leshan.core.request.WriteRequest;  
41 -import org.eclipse.leshan.core.request.exception.ClientSleepingException;  
42 -import org.eclipse.leshan.core.response.DeleteResponse;  
43 -import org.eclipse.leshan.core.response.DiscoverResponse;  
44 -import org.eclipse.leshan.core.response.ExecuteResponse;  
45 -import org.eclipse.leshan.core.response.LwM2mResponse;  
46 -import org.eclipse.leshan.core.response.ReadResponse;  
47 -import org.eclipse.leshan.core.response.ResponseCallback;  
48 -import org.eclipse.leshan.core.response.WriteAttributesResponse;  
49 -import org.eclipse.leshan.core.response.WriteResponse;  
50 -import org.eclipse.leshan.core.util.Hex;  
51 -import org.eclipse.leshan.core.util.NamedThreadFactory;  
52 -import org.eclipse.leshan.server.registration.Registration;  
53 -import org.springframework.stereotype.Service;  
54 -import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;  
55 -import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;  
56 -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;  
57 -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;  
58 -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientRpcRequest;  
59 -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;  
60 -  
61 -import javax.annotation.PostConstruct;  
62 -import java.util.Arrays;  
63 -import java.util.Collection;  
64 -import java.util.Date;  
65 -import java.util.Set;  
66 -import java.util.concurrent.ConcurrentHashMap;  
67 -import java.util.concurrent.ExecutorService;  
68 -import java.util.concurrent.Executors;  
69 -import java.util.stream.Collectors;  
70 -  
71 -import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT;  
72 -import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST;  
73 -import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND;  
74 -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED;  
75 -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED;  
76 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getContentFormatByResourceModelType;  
77 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEFAULT_TIMEOUT;  
78 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_5_ID;  
79 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_UPDATE_ID;  
80 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR;  
81 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;  
82 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE;  
83 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;  
84 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER;  
85 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;  
86 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;  
87 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_READ_ALL;  
88 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;  
89 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;  
90 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_UPDATE;  
91 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.RESPONSE_REQUEST_CHANNEL;  
92 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_INSTALL_ID;  
93 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_PACKAGE_ID;  
94 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;  
95 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;  
96 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.createWriteAttributeRequest;  
97 -  
98 -@Slf4j  
99 -@Service  
100 -@TbLwM2mTransportComponent  
101 -@RequiredArgsConstructor  
102 -public class LwM2mTransportRequest {  
103 - private ExecutorService responseRequestExecutor;  
104 -  
105 - public LwM2mValueConverterImpl converter;  
106 -  
107 - private final LwM2mTransportContext context;  
108 - private final LwM2MTransportServerConfig config;  
109 - private final LwM2mClientContext lwM2mClientContext;  
110 - private final DefaultLwM2MTransportMsgHandler handler;  
111 -  
112 - @PostConstruct  
113 - public void init() {  
114 - this.converter = LwM2mValueConverterImpl.getInstance();  
115 - responseRequestExecutor = Executors.newFixedThreadPool(this.config.getResponsePoolSize(),  
116 - new NamedThreadFactory(String.format("LwM2M %s channel response after request", RESPONSE_REQUEST_CHANNEL)));  
117 - }  
118 -  
119 - public void sendAllRequest(LwM2mClient lwM2MClient, String targetIdVer, LwM2mTypeOper typeOper, Object params, long timeoutInMs, LwM2mClientRpcRequest lwm2mClientRpcRequest) {  
120 - sendAllRequest(lwM2MClient, targetIdVer, typeOper, lwM2MClient.getDefaultContentFormat(), params, timeoutInMs, lwm2mClientRpcRequest);  
121 - }  
122 -  
123 -  
124 - public void sendAllRequest(LwM2mClient lwM2MClient, String targetIdVer, LwM2mTypeOper typeOper,  
125 - ContentFormat contentFormat, Object params, long timeoutInMs, LwM2mClientRpcRequest lwm2mClientRpcRequest) {  
126 - Registration registration = lwM2MClient.getRegistration();  
127 - try {  
128 - String target = convertPathFromIdVerToObjectId(targetIdVer);  
129 - if(contentFormat == null){  
130 - contentFormat = ContentFormat.DEFAULT;  
131 - }  
132 - LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null;  
133 - if (!OBSERVE_CANCEL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) {  
134 - if (lwM2MClient.isValidObjectVersion(targetIdVer)) {  
135 - timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT;  
136 - SimpleDownlinkRequest request = createRequest(registration, lwM2MClient, typeOper, contentFormat, target,  
137 - targetIdVer, resultIds, params, lwm2mClientRpcRequest);  
138 - if (request != null) {  
139 - try {  
140 - this.sendRequest(registration, lwM2MClient, request, timeoutInMs, lwm2mClientRpcRequest);  
141 - } catch (ClientSleepingException e) {  
142 - SimpleDownlinkRequest finalRequest = request;  
143 - long finalTimeoutInMs = timeoutInMs;  
144 - LwM2mClientRpcRequest finalRpcRequest = lwm2mClientRpcRequest;  
145 - lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, finalRpcRequest));  
146 - } catch (Exception e) {  
147 - log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper.name(), e);  
148 - }  
149 - } else if (WRITE_UPDATE.name().equals(typeOper.name())) {  
150 - if (lwm2mClientRpcRequest != null) {  
151 - String errorMsg = String.format("Path %s params is not valid", targetIdVer);  
152 - handler.sentRpcResponse(lwm2mClientRpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);  
153 - }  
154 - } else if (WRITE_REPLACE.name().equals(typeOper.name()) || EXECUTE.name().equals(typeOper.name())) {  
155 - if (lwm2mClientRpcRequest != null) {  
156 - String errorMsg = String.format("Path %s object model is absent", targetIdVer);  
157 - handler.sentRpcResponse(lwm2mClientRpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);  
158 - }  
159 - } else if (!OBSERVE_CANCEL.name().equals(typeOper.name())) {  
160 - log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer);  
161 - if (lwm2mClientRpcRequest != null) {  
162 - ResourceModel resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider());  
163 - String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null";  
164 - handler.sentRpcResponse(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);  
165 - }  
166 - }  
167 - } else if (lwm2mClientRpcRequest != null) {  
168 - String errorMsg = String.format("Path %s not found in object version", targetIdVer);  
169 - handler.sentRpcResponse(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);  
170 - }  
171 - } else {  
172 - switch (typeOper) {  
173 - case OBSERVE_READ_ALL:  
174 - case DISCOVER_ALL:  
175 - Set<String> paths;  
176 - if (OBSERVE_READ_ALL.name().equals(typeOper.name())) {  
177 - Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);  
178 - paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet());  
179 - } else {  
180 - assert registration != null;  
181 - Link[] objectLinks = registration.getSortedObjectLinks();  
182 - paths = Arrays.stream(objectLinks).map(Link::toString).collect(Collectors.toUnmodifiableSet());  
183 - }  
184 - String msg = String.format("%s: type operation %s paths - %s", LOG_LW2M_INFO,  
185 - typeOper.name(), paths);  
186 - this.handler.sendLogsToThingsboard(lwM2MClient, msg);  
187 - if (lwm2mClientRpcRequest != null) {  
188 - String valueMsg = String.format("Paths - %s", paths);  
189 - handler.sentRpcResponse(lwm2mClientRpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE);  
190 - }  
191 - break;  
192 - case OBSERVE_CANCEL:  
193 - case OBSERVE_CANCEL_ALL:  
194 - int observeCancelCnt = 0;  
195 - String observeCancelMsg = null;  
196 - if (OBSERVE_CANCEL.name().equals(typeOper)) {  
197 - observeCancelCnt = context.getServer().getObservationService().cancelObservations(registration, target);  
198 - observeCancelMsg = String.format("%s: type operation %s paths: %s count: %d", LOG_LW2M_INFO,  
199 - OBSERVE_CANCEL.name(), target, observeCancelCnt);  
200 - } else {  
201 - observeCancelCnt = context.getServer().getObservationService().cancelObservations(registration);  
202 - observeCancelMsg = String.format("%s: type operation %s paths: All count: %d", LOG_LW2M_INFO,  
203 - OBSERVE_CANCEL.name(), observeCancelCnt);  
204 - }  
205 - this.afterObserveCancel(lwM2MClient, observeCancelCnt, observeCancelMsg, lwm2mClientRpcRequest);  
206 - break;  
207 - // lwm2mClientRpcRequest != null  
208 - case FW_UPDATE:  
209 - handler.getInfoFirmwareUpdate(lwM2MClient, lwm2mClientRpcRequest);  
210 - break;  
211 - }  
212 - }  
213 - } catch (Exception e) {  
214 - String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR,  
215 - typeOper.name(), e.getMessage());  
216 - handler.sendLogsToThingsboard(lwM2MClient, msg);  
217 - if (lwm2mClientRpcRequest != null) {  
218 - String errorMsg = String.format("Path %s type operation %s %s", targetIdVer, typeOper.name(), e.getMessage());  
219 - handler.sentRpcResponse(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);  
220 - }  
221 - }  
222 - }  
223 -  
224 - private SimpleDownlinkRequest createRequest(Registration registration, LwM2mClient lwM2MClient, LwM2mTypeOper typeOper,  
225 - ContentFormat contentFormat, String target, String targetIdVer,  
226 - LwM2mPath resultIds, Object params, LwM2mClientRpcRequest rpcRequest) {  
227 - SimpleDownlinkRequest request = null;  
228 - switch (typeOper) {  
229 - case READ:  
230 - request = new ReadRequest(contentFormat, target);  
231 - break;  
232 - case DISCOVER:  
233 - request = new DiscoverRequest(target);  
234 - break;  
235 - case OBSERVE:  
236 - String msg = String.format("%s: Send Observation %s.", LOG_LW2M_INFO, targetIdVer);  
237 - log.warn(msg);  
238 - if (resultIds.isResource()) {  
239 - Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);  
240 - Set<Observation> paths = observations.stream().filter(observation -> observation.getPath().equals(resultIds)).collect(Collectors.toSet());  
241 - if (paths.size() == 0) {  
242 - request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());  
243 - } else {  
244 - request = new ReadRequest(contentFormat, target);  
245 - }  
246 - } else if (resultIds.isObjectInstance()) {  
247 - request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId());  
248 - } else if (resultIds.getObjectId() >= 0) {  
249 - request = new ObserveRequest(contentFormat, resultIds.getObjectId());  
250 - }  
251 - break;  
252 - case EXECUTE:  
253 - ResourceModel resourceModelExecute = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider());  
254 - if (resourceModelExecute != null) {  
255 - if (params != null && !resourceModelExecute.multiple) {  
256 - request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resourceModelExecute.type, ResourceModel.Type.STRING, resultIds));  
257 - } else {  
258 - request = new ExecuteRequest(target);  
259 - }  
260 - }  
261 - break;  
262 - case WRITE_REPLACE:  
263 - /**  
264 - * Request to write a <b>String Single-Instance Resource</b> using the TLV content format.  
265 - * Type from resourceModel -> STRING, INTEGER, FLOAT, BOOLEAN, OPAQUE, TIME, OBJLNK  
266 - * contentFormat -> TLV, TLV, TLV, TLV, OPAQUE, TLV, LINK  
267 - * JSON, TEXT;  
268 - **/  
269 - ResourceModel resourceModelWrite = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider());  
270 - if (resourceModelWrite != null) {  
271 - contentFormat = getContentFormatByResourceModelType(resourceModelWrite, contentFormat);  
272 - request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(),  
273 - resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModelWrite.type,  
274 - lwM2MClient, rpcRequest);  
275 - }  
276 - break;  
277 - case WRITE_UPDATE:  
278 - if (resultIds.isResource()) {  
279 - /**  
280 - * send request: path = '/3/0' node == wM2mObjectInstance  
281 - * with params == "\"resources\": {15: resource:{id:15. value:'+01'...}}  
282 - **/  
283 - Collection<LwM2mResource> resources = lwM2MClient.getNewResourceForInstance(  
284 - targetIdVer, params,  
285 - this.config.getModelProvider(),  
286 - this.converter);  
287 - contentFormat = getContentFormatByResourceModelType(lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider()),  
288 - contentFormat);  
289 - request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(),  
290 - resultIds.getObjectInstanceId(), resources);  
291 - }  
292 - /**  
293 - * params = "{\"id\":0,\"resources\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}"  
294 - * int rscId = resultIds.getObjectInstanceId();  
295 - * contentFormat – Format of the payload (TLV or JSON).  
296 - */  
297 - else if (resultIds.isObjectInstance()) {  
298 - if (((ConcurrentHashMap) params).size() > 0) {  
299 - Collection<LwM2mResource> resources = lwM2MClient.getNewResourcesForInstance(  
300 - targetIdVer, params,  
301 - this.config.getModelProvider(),  
302 - this.converter);  
303 - if (resources.size() > 0) {  
304 - contentFormat = contentFormat.equals(ContentFormat.JSON) ? contentFormat : ContentFormat.TLV;  
305 - request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(),  
306 - resultIds.getObjectInstanceId(), resources);  
307 - }  
308 - }  
309 - } else if (resultIds.getObjectId() >= 0) {  
310 - request = new ObserveRequest(resultIds.getObjectId());  
311 - }  
312 - break;  
313 - case WRITE_ATTRIBUTES:  
314 - request = createWriteAttributeRequest(target, params, this.handler);  
315 - break;  
316 - case DELETE:  
317 - request = new DeleteRequest(target);  
318 - break;  
319 - }  
320 - return request;  
321 - }  
322 -  
323 - /**  
324 - * @param registration -  
325 - * @param request -  
326 - * @param timeoutInMs -  
327 - */  
328 -  
329 - @SuppressWarnings({"error sendRequest"})  
330 - private void sendRequest(Registration registration, LwM2mClient lwM2MClient, SimpleDownlinkRequest request,  
331 - long timeoutInMs, LwM2mClientRpcRequest rpcRequest) {  
332 - context.getServer().send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {  
333 -  
334 - if (!lwM2MClient.isInit()) {  
335 - lwM2MClient.initReadValue(this.handler, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));  
336 - }  
337 - if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) {  
338 - this.handleResponse(lwM2MClient, request.getPath().toString(), response, request, rpcRequest);  
339 - } else {  
340 - String msg = String.format("%s: SendRequest %s: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s", LOG_LW2M_ERROR, request.getClass().getName().toString(),  
341 - ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString());  
342 - handler.sendLogsToThingsboard(lwM2MClient, msg);  
343 - log.error("[{}] [{}], [{}] - [{}] [{}] error SendRequest", request.getClass().getName().toString(), registration.getEndpoint(),  
344 - ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString());  
345 - if (!lwM2MClient.isInit()) {  
346 - lwM2MClient.initReadValue(this.handler, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));  
347 - }  
348 - /** Not Found */  
349 - if (rpcRequest != null) {  
350 - handler.sentRpcResponse(rpcRequest, response.getCode().getName(), response.getErrorMessage(), LOG_LW2M_ERROR);  
351 - }  
352 - /** Not Found  
353 - set setClient_fw_info... = empty  
354 - **/  
355 - if (lwM2MClient.getFwUpdate() != null && lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {  
356 - lwM2MClient.getFwUpdate().initReadValue(handler, this, request.getPath().toString());  
357 - }  
358 - if (lwM2MClient.getSwUpdate() != null && lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {  
359 - lwM2MClient.getSwUpdate().initReadValue(handler, this, request.getPath().toString());  
360 - }  
361 - if (request.getPath().toString().equals(FW_PACKAGE_5_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) {  
362 - this.afterWriteFwSWUpdateError(registration, request, response.getErrorMessage());  
363 - }  
364 - if (request.getPath().toString().equals(FW_UPDATE_ID) || request.getPath().toString().equals(SW_INSTALL_ID)) {  
365 - this.afterExecuteFwSwUpdateError(registration, request, response.getErrorMessage());  
366 - }  
367 - }  
368 - }, e -> {  
369 - /** version == null  
370 - set setClient_fw_info... = empty  
371 - **/  
372 - if (lwM2MClient.getFwUpdate() != null && lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {  
373 - lwM2MClient.getFwUpdate().initReadValue(handler, this, request.getPath().toString());  
374 - }  
375 - if (lwM2MClient.getSwUpdate() != null && lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {  
376 - lwM2MClient.getSwUpdate().initReadValue(handler, this, request.getPath().toString());  
377 - }  
378 - if (request.getPath().toString().equals(FW_PACKAGE_5_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) {  
379 - this.afterWriteFwSWUpdateError(registration, request, e.getMessage());  
380 - }  
381 - if (request.getPath().toString().equals(FW_UPDATE_ID) || request.getPath().toString().equals(SW_INSTALL_ID)) {  
382 - this.afterExecuteFwSwUpdateError(registration, request, e.getMessage());  
383 - }  
384 - if (!lwM2MClient.isInit()) {  
385 - lwM2MClient.initReadValue(this.handler, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));  
386 - }  
387 - String msg = String.format("%s: SendRequest %s: Resource path - %s msg error - %s",  
388 - LOG_LW2M_ERROR, request.getClass().getName().toString(), request.getPath().toString(), e.getMessage());  
389 - handler.sendLogsToThingsboard(lwM2MClient, msg);  
390 - log.error("[{}] [{}] - [{}] error SendRequest", request.getClass().getName().toString(), request.getPath().toString(), e.toString());  
391 - if (rpcRequest != null) {  
392 - handler.sentRpcResponse(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR);  
393 - }  
394 - });  
395 - }  
396 -  
397 - private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId,  
398 - Integer resourceId, Object value, ResourceModel.Type type,  
399 - LwM2mClient client, LwM2mClientRpcRequest rpcRequest) {  
400 - try {  
401 - if (type != null) {  
402 - switch (type) {  
403 - case STRING: // String  
404 - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, value.toString()) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, value.toString());  
405 - case INTEGER: // Long  
406 - final long valueInt = Integer.toUnsignedLong(Integer.parseInt(value.toString()));  
407 - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, valueInt) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, valueInt);  
408 - case OBJLNK: // ObjectLink  
409 - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, ObjectLink.fromPath(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, ObjectLink.fromPath(value.toString()));  
410 - case BOOLEAN: // Boolean  
411 - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Boolean.parseBoolean(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Boolean.parseBoolean(value.toString()));  
412 - case FLOAT: // Double  
413 - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Double.parseDouble(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Double.parseDouble(value.toString()));  
414 - case TIME: // Date  
415 - Date date = new Date(Long.decode(value.toString()));  
416 - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, date) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, date);  
417 - case OPAQUE: // byte[] value, base64  
418 - byte[] valueRequest = value instanceof byte[] ? (byte[]) value : Hex.decodeHex(value.toString().toCharArray());  
419 - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, valueRequest) :  
420 - new WriteRequest(contentFormat, objectId, instanceId, resourceId, valueRequest);  
421 - default:  
422 - }  
423 - }  
424 - if (rpcRequest != null) {  
425 - String patn = "/" + objectId + "/" + instanceId + "/" + resourceId;  
426 - String errorMsg = String.format("Bad ResourceModel Operations (E): Resource path - %s ResourceModel type - %s", patn, type);  
427 - rpcRequest.setErrorMsg(errorMsg);  
428 - }  
429 - return null;  
430 - } catch (NumberFormatException e) {  
431 - String patn = "/" + objectId + "/" + instanceId + "/" + resourceId;  
432 - String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client",  
433 - patn, type, value, e.toString());  
434 - handler.sendLogsToThingsboard(client, msg);  
435 - log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString());  
436 - if (rpcRequest != null) {  
437 - String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value);  
438 - handler.sentRpcResponse(rpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);  
439 - }  
440 - return null;  
441 - }  
442 - }  
443 -  
444 - private void handleResponse(LwM2mClient lwM2mClient, final String path, LwM2mResponse response,  
445 - SimpleDownlinkRequest request, LwM2mClientRpcRequest rpcRequest) {  
446 - responseRequestExecutor.submit(() -> {  
447 - try {  
448 - this.sendResponse(lwM2mClient, path, response, request, rpcRequest);  
449 - } catch (Exception e) {  
450 - log.error("[{}] endpoint [{}] path [{}] Exception Unable to after send response.", lwM2mClient.getRegistration().getEndpoint(), path, e);  
451 - }  
452 - });  
453 - }  
454 -  
455 - /**  
456 - * processing a response from a client  
457 - *  
458 - * @param path -  
459 - * @param response -  
460 - */  
461 - private void sendResponse(LwM2mClient lwM2mClient, String path, LwM2mResponse response,  
462 - SimpleDownlinkRequest request, LwM2mClientRpcRequest rpcRequest) {  
463 - Registration registration = lwM2mClient.getRegistration();  
464 - String pathIdVer = convertPathFromObjectIdToIdVer(path, registration);  
465 - String msgLog = "";  
466 - if (response instanceof ReadResponse) {  
467 - handler.onUpdateValueAfterReadResponse(registration, pathIdVer, (ReadResponse) response, rpcRequest);  
468 - } else if (response instanceof DeleteResponse) {  
469 - log.warn("11) [{}] Path [{}] DeleteResponse", pathIdVer, response);  
470 - if (rpcRequest != null) {  
471 - rpcRequest.setInfoMsg(null);  
472 - handler.sentRpcResponse(rpcRequest, response.getCode().getName(), null, null);  
473 - }  
474 - } else if (response instanceof DiscoverResponse) {  
475 - String discoverValue = Link.serialize(((DiscoverResponse) response).getObjectLinks());  
476 - msgLog = String.format("%s: type operation: %s path: %s value: %s",  
477 - LOG_LW2M_INFO, DISCOVER.name(), request.getPath().toString(), discoverValue);  
478 - handler.sendLogsToThingsboard(lwM2mClient, msgLog);  
479 - log.warn("DiscoverResponse: [{}]", (DiscoverResponse) response);  
480 - if (rpcRequest != null) {  
481 - handler.sentRpcResponse(rpcRequest, response.getCode().getName(), discoverValue, LOG_LW2M_VALUE);  
482 - }  
483 - } else if (response instanceof ExecuteResponse) {  
484 - msgLog = String.format("%s: type operation: %s path: %s",  
485 - LOG_LW2M_INFO, EXECUTE.name(), request.getPath().toString());  
486 - log.warn("9) [{}] ", msgLog);  
487 - handler.sendLogsToThingsboard(lwM2mClient, msgLog);  
488 - if (rpcRequest != null) {  
489 - msgLog = String.format("Start %s path: %S. Preparation finished: %s", EXECUTE.name(), path, rpcRequest.getInfoMsg());  
490 - rpcRequest.setInfoMsg(msgLog);  
491 - handler.sentRpcResponse(rpcRequest, response.getCode().getName(), path, LOG_LW2M_INFO);  
492 - }  
493 -  
494 - } else if (response instanceof WriteAttributesResponse) {  
495 - msgLog = String.format("%s: type operation: %s path: %s value: %s",  
496 - LOG_LW2M_INFO, WRITE_ATTRIBUTES.name(), request.getPath().toString(), ((WriteAttributesRequest) request).getAttributes().toString());  
497 - handler.sendLogsToThingsboard(lwM2mClient, msgLog);  
498 - log.warn("12) [{}] Path [{}] WriteAttributesResponse", pathIdVer, response);  
499 - if (rpcRequest != null) {  
500 - handler.sentRpcResponse(rpcRequest, response.getCode().getName(), response.toString(), LOG_LW2M_VALUE);  
501 - }  
502 - } else if (response instanceof WriteResponse) {  
503 - msgLog = String.format("Type operation: Write path: %s", pathIdVer);  
504 - log.warn("10) [{}] response: [{}]", msgLog, response);  
505 - this.infoWriteResponse(lwM2mClient, response, request, rpcRequest);  
506 - handler.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request);  
507 - }  
508 - }  
509 -  
510 - private void infoWriteResponse(LwM2mClient lwM2mClient, LwM2mResponse response, SimpleDownlinkRequest request, LwM2mClientRpcRequest rpcRequest) {  
511 - try {  
512 - Registration registration = lwM2mClient.getRegistration();  
513 - LwM2mNode node = ((WriteRequest) request).getNode();  
514 - String msg = null;  
515 - Object value;  
516 - if (node instanceof LwM2mObject) {  
517 - msg = String.format("%s: Update finished successfully: Lwm2m code - %d Source path: %s value: %s",  
518 - LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), ((LwM2mObject) node).toString());  
519 - } else if (node instanceof LwM2mObjectInstance) {  
520 - msg = String.format("%s: Update finished successfully: Lwm2m code - %d Source path: %s value: %s",  
521 - LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), ((LwM2mObjectInstance) node).prettyPrint());  
522 - } else if (node instanceof LwM2mSingleResource) {  
523 - LwM2mSingleResource singleResource = (LwM2mSingleResource) node;  
524 - if (singleResource.getType() == ResourceModel.Type.STRING || singleResource.getType() == ResourceModel.Type.OPAQUE) {  
525 - int valueLength;  
526 - if (singleResource.getType() == ResourceModel.Type.STRING) {  
527 - valueLength = ((String) singleResource.getValue()).length();  
528 - value = ((String) singleResource.getValue())  
529 - .substring(Math.min(valueLength, config.getLogMaxLength())).trim();  
530 -  
531 - } else {  
532 - valueLength = ((byte[]) singleResource.getValue()).length;  
533 - value = new String(Arrays.copyOf(((byte[]) singleResource.getValue()),  
534 - Math.min(valueLength, config.getLogMaxLength()))).trim();  
535 - }  
536 - value = valueLength > config.getLogMaxLength() ? value + "..." : value;  
537 - msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path: %s length: %s value: %s",  
538 - LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), valueLength, value);  
539 - } else {  
540 - value = this.converter.convertValue(singleResource.getValue(),  
541 - singleResource.getType(), ResourceModel.Type.STRING, request.getPath());  
542 - msg = String.format("%s: Update finished successfully. Lwm2m code: %d Resource path: %s value: %s",  
543 - LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), value);  
544 - }  
545 - }  
546 - if (msg != null) {  
547 - handler.sendLogsToThingsboard(lwM2mClient, msg);  
548 - if (request.getPath().toString().equals(FW_PACKAGE_5_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) {  
549 - this.afterWriteSuccessFwSwUpdate(registration, request);  
550 - if (rpcRequest != null) {  
551 - rpcRequest.setInfoMsg(msg);  
552 - }  
553 - }  
554 - else if (rpcRequest != null) {  
555 - handler.sentRpcResponse(rpcRequest, response.getCode().getName(), msg, LOG_LW2M_INFO);  
556 - }  
557 - }  
558 - } catch (Exception e) {  
559 - log.trace("Fail convert value from request to string. ", e);  
560 - }  
561 - }  
562 -  
563 - /**  
564 - * After finish operation FwSwUpdate Write (success):  
565 - * fw_state/sw_state = DOWNLOADED  
566 - * send operation Execute  
567 - */  
568 - private void afterWriteSuccessFwSwUpdate(Registration registration, SimpleDownlinkRequest request) {  
569 - LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());  
570 - if (request.getPath().toString().equals(FW_PACKAGE_5_ID) && lwM2MClient.getFwUpdate() != null) {  
571 - lwM2MClient.getFwUpdate().setStateUpdate(DOWNLOADED.name());  
572 - lwM2MClient.getFwUpdate().sendLogs(this.handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null);  
573 - }  
574 - if (request.getPath().toString().equals(SW_PACKAGE_ID) && lwM2MClient.getSwUpdate() != null) {  
575 - lwM2MClient.getSwUpdate().setStateUpdate(DOWNLOADED.name());  
576 - lwM2MClient.getSwUpdate().sendLogs(this.handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null);  
577 - }  
578 - }  
579 -  
580 - /**  
581 - * After finish operation FwSwUpdate Write (error): fw_state = FAILED  
582 - */  
583 - private void afterWriteFwSWUpdateError(Registration registration, SimpleDownlinkRequest request, String msgError) {  
584 - LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());  
585 - if (request.getPath().toString().equals(FW_PACKAGE_5_ID) && lwM2MClient.getFwUpdate() != null) {  
586 - lwM2MClient.getFwUpdate().setStateUpdate(FAILED.name());  
587 - lwM2MClient.getFwUpdate().sendLogs(this.handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError);  
588 - }  
589 - if (request.getPath().toString().equals(SW_PACKAGE_ID) && lwM2MClient.getSwUpdate() != null) {  
590 - lwM2MClient.getSwUpdate().setStateUpdate(FAILED.name());  
591 - lwM2MClient.getSwUpdate().sendLogs(this.handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError);  
592 - }  
593 - }  
594 -  
595 - private void afterExecuteFwSwUpdateError(Registration registration, SimpleDownlinkRequest request, String msgError) {  
596 - LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());  
597 - if (request.getPath().toString().equals(FW_UPDATE_ID) && lwM2MClient.getFwUpdate() != null) {  
598 - lwM2MClient.getFwUpdate().sendLogs(this.handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError);  
599 - }  
600 - if (request.getPath().toString().equals(SW_INSTALL_ID) && lwM2MClient.getSwUpdate() != null) {  
601 - lwM2MClient.getSwUpdate().sendLogs(this.handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError);  
602 - }  
603 - }  
604 -  
605 - private void afterObserveCancel(LwM2mClient lwM2mClient, int observeCancelCnt, String observeCancelMsg, LwM2mClientRpcRequest rpcRequest) {  
606 - handler.sendLogsToThingsboard(lwM2mClient, observeCancelMsg);  
607 - log.warn("[{}]", observeCancelMsg);  
608 - if (rpcRequest != null) {  
609 - rpcRequest.setInfoMsg(String.format("Count: %d", observeCancelCnt));  
610 - handler.sentRpcResponse(rpcRequest, CONTENT.name(), null, LOG_LW2M_INFO);  
611 - }  
612 - }  
613 -}  
@@ -37,6 +37,8 @@ import org.eclipse.leshan.core.model.DefaultDDFFileValidator; @@ -37,6 +37,8 @@ import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
37 import org.eclipse.leshan.core.model.InvalidDDFFileException; 37 import org.eclipse.leshan.core.model.InvalidDDFFileException;
38 import org.eclipse.leshan.core.model.ObjectModel; 38 import org.eclipse.leshan.core.model.ObjectModel;
39 import org.eclipse.leshan.core.model.ResourceModel; 39 import org.eclipse.leshan.core.model.ResourceModel;
  40 +import org.eclipse.leshan.core.node.LwM2mPath;
  41 +import org.eclipse.leshan.core.node.LwM2mResource;
40 import org.eclipse.leshan.core.node.codec.CodecException; 42 import org.eclipse.leshan.core.node.codec.CodecException;
41 import org.eclipse.leshan.core.request.ContentFormat; 43 import org.eclipse.leshan.core.request.ContentFormat;
42 import org.springframework.stereotype.Component; 44 import org.springframework.stereotype.Component;
@@ -48,6 +50,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; @@ -48,6 +50,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
48 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; 50 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
49 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 51 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
50 import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor; 52 import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
  53 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  54 +import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
51 55
52 import java.io.ByteArrayInputStream; 56 import java.io.ByteArrayInputStream;
53 import java.io.IOException; 57 import java.io.IOException;
@@ -57,6 +61,7 @@ import java.util.concurrent.TimeUnit; @@ -57,6 +61,7 @@ import java.util.concurrent.TimeUnit;
57 import java.util.concurrent.atomic.AtomicInteger; 61 import java.util.concurrent.atomic.AtomicInteger;
58 62
59 import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType.BOOLEAN_V; 63 import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType.BOOLEAN_V;
  64 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
60 65
61 @Slf4j 66 @Slf4j
62 @Component 67 @Component
@@ -67,37 +72,15 @@ public class LwM2mTransportServerHelper { @@ -67,37 +72,15 @@ public class LwM2mTransportServerHelper {
67 private final LwM2mTransportContext context; 72 private final LwM2mTransportContext context;
68 private final AtomicInteger atomicTs = new AtomicInteger(0); 73 private final AtomicInteger atomicTs = new AtomicInteger(0);
69 74
70 -  
71 public long getTS() { 75 public long getTS() {
72 return TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) * 1000L + (atomicTs.getAndIncrement() % 1000); 76 return TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) * 1000L + (atomicTs.getAndIncrement() % 1000);
73 } 77 }
74 78
75 - /**  
76 - * send to Thingsboard Attribute || Telemetry  
77 - *  
78 - * @param msg - JsonObject: [{name: value}]  
79 - * @return - dummyWriteReplace {\"targetIdVer\":\"/19_1.0/0/0\",\"value\":0082}  
80 - */  
81 - private <T> TransportServiceCallback<Void> getPubAckCallbackSendAttrTelemetry(final T msg) {  
82 - return new TransportServiceCallback<>() {  
83 - @Override  
84 - public void onSuccess(Void dummy) {  
85 - log.trace("Success to publish msg: {}, dummy: {}", msg, dummy);  
86 - }  
87 -  
88 - @Override  
89 - public void onError(Throwable e) {  
90 - log.trace("[{}] Failed to publish msg: {}", msg, e);  
91 - }  
92 - };  
93 - }  
94 -  
95 public void sendParametersOnThingsboardAttribute(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) { 79 public void sendParametersOnThingsboardAttribute(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
96 PostAttributeMsg.Builder request = PostAttributeMsg.newBuilder(); 80 PostAttributeMsg.Builder request = PostAttributeMsg.newBuilder();
97 request.addAllKv(result); 81 request.addAllKv(result);
98 PostAttributeMsg postAttributeMsg = request.build(); 82 PostAttributeMsg postAttributeMsg = request.build();
99 - TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postAttributeMsg);  
100 - context.getTransportService().process(sessionInfo, postAttributeMsg, this.getPubAckCallbackSendAttrTelemetry(call)); 83 + context.getTransportService().process(sessionInfo, postAttributeMsg, TransportServiceCallback.EMPTY);
101 } 84 }
102 85
103 public void sendParametersOnThingsboardTelemetry(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) { 86 public void sendParametersOnThingsboardTelemetry(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
@@ -107,8 +90,7 @@ public class LwM2mTransportServerHelper { @@ -107,8 +90,7 @@ public class LwM2mTransportServerHelper {
107 builder.addAllKv(result); 90 builder.addAllKv(result);
108 request.addTsKvList(builder.build()); 91 request.addTsKvList(builder.build());
109 PostTelemetryMsg postTelemetryMsg = request.build(); 92 PostTelemetryMsg postTelemetryMsg = request.build();
110 - TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postTelemetryMsg);  
111 - context.getTransportService().process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSendAttrTelemetry(call)); 93 + context.getTransportService().process(sessionInfo, postTelemetryMsg, TransportServiceCallback.EMPTY);
112 } 94 }
113 95
114 /** 96 /**
@@ -210,28 +192,6 @@ public class LwM2mTransportServerHelper { @@ -210,28 +192,6 @@ public class LwM2mTransportServerHelper {
210 throw new CodecException("Invalid ResourceModel_Type for resource %s, got %s", resourcePath, currentType); 192 throw new CodecException("Invalid ResourceModel_Type for resource %s, got %s", resourcePath, currentType);
211 } 193 }
212 194
213 - public static ContentFormat convertResourceModelTypeToContentFormat(ResourceModel.Type type) {  
214 - switch (type) {  
215 - case BOOLEAN:  
216 - case STRING:  
217 - case TIME:  
218 - case INTEGER:  
219 - case FLOAT:  
220 - return ContentFormat.TLV;  
221 - case OPAQUE:  
222 - return ContentFormat.OPAQUE;  
223 - case OBJLNK:  
224 - return ContentFormat.LINK;  
225 - default:  
226 - }  
227 - throw new CodecException("Invalid ResourceModel_Type for %s ContentFormat.", type);  
228 - }  
229 -  
230 - public static ContentFormat getContentFormatByResourceModelType(ResourceModel resourceModel, ContentFormat contentFormat) {  
231 - return contentFormat.equals(ContentFormat.TLV) ? convertResourceModelTypeToContentFormat(resourceModel.type) :  
232 - contentFormat;  
233 - }  
234 -  
235 public static Object getValueFromKvProto(TransportProtos.KeyValueProto kv) { 195 public static Object getValueFromKvProto(TransportProtos.KeyValueProto kv) {
236 switch (kv.getType()) { 196 switch (kv.getType()) {
237 case BOOLEAN_V: 197 case BOOLEAN_V:
@@ -247,4 +207,5 @@ public class LwM2mTransportServerHelper { @@ -247,4 +207,5 @@ public class LwM2mTransportServerHelper {
247 } 207 }
248 return null; 208 return null;
249 } 209 }
  210 +
250 } 211 }
@@ -16,13 +16,9 @@ @@ -16,13 +16,9 @@
16 package org.thingsboard.server.transport.lwm2m.server; 16 package org.thingsboard.server.transport.lwm2m.server;
17 17
18 import com.fasterxml.jackson.databind.ObjectMapper; 18 import com.fasterxml.jackson.databind.ObjectMapper;
19 -import com.google.common.collect.Sets;  
20 -import com.google.gson.Gson;  
21 -import com.google.gson.JsonArray;  
22 import com.google.gson.JsonObject; 19 import com.google.gson.JsonObject;
23 import com.google.gson.JsonParser; 20 import com.google.gson.JsonParser;
24 import com.google.gson.JsonSyntaxException; 21 import com.google.gson.JsonSyntaxException;
25 -import com.google.gson.reflect.TypeToken;  
26 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
27 import org.apache.commons.lang3.StringUtils; 23 import org.apache.commons.lang3.StringUtils;
28 import org.eclipse.leshan.core.attributes.Attribute; 24 import org.eclipse.leshan.core.attributes.Attribute;
@@ -34,6 +30,7 @@ import org.eclipse.leshan.core.node.LwM2mNode; @@ -34,6 +30,7 @@ import org.eclipse.leshan.core.node.LwM2mNode;
34 import org.eclipse.leshan.core.node.LwM2mObject; 30 import org.eclipse.leshan.core.node.LwM2mObject;
35 import org.eclipse.leshan.core.node.LwM2mObjectInstance; 31 import org.eclipse.leshan.core.node.LwM2mObjectInstance;
36 import org.eclipse.leshan.core.node.LwM2mPath; 32 import org.eclipse.leshan.core.node.LwM2mPath;
  33 +import org.eclipse.leshan.core.node.LwM2mResource;
37 import org.eclipse.leshan.core.node.LwM2mSingleResource; 34 import org.eclipse.leshan.core.node.LwM2mSingleResource;
38 import org.eclipse.leshan.core.node.codec.CodecException; 35 import org.eclipse.leshan.core.node.codec.CodecException;
39 import org.eclipse.leshan.core.request.SimpleDownlinkRequest; 36 import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
@@ -42,17 +39,19 @@ import org.eclipse.leshan.core.util.Hex; @@ -42,17 +39,19 @@ import org.eclipse.leshan.core.util.Hex;
42 import org.eclipse.leshan.server.registration.Registration; 39 import org.eclipse.leshan.server.registration.Registration;
43 import org.nustaq.serialization.FSTConfiguration; 40 import org.nustaq.serialization.FSTConfiguration;
44 import org.thingsboard.server.common.data.DeviceProfile; 41 import org.thingsboard.server.common.data.DeviceProfile;
  42 +import org.thingsboard.server.common.data.DeviceTransportType;
  43 +import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration;
  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.data.id.TenantId;  
47 import org.thingsboard.server.common.data.ota.OtaPackageKey; 46 import org.thingsboard.server.common.data.ota.OtaPackageKey;
48 import org.thingsboard.server.common.data.ota.OtaPackageType; 47 import org.thingsboard.server.common.data.ota.OtaPackageType;
49 import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; 48 import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
50 import org.thingsboard.server.common.data.ota.OtaPackageUtil; 49 import org.thingsboard.server.common.data.ota.OtaPackageUtil;
51 import org.thingsboard.server.common.transport.TransportServiceCallback; 50 import org.thingsboard.server.common.transport.TransportServiceCallback;
52 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 51 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
53 -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; 52 +import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
  53 +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
54 54
55 -import java.io.IOException;  
56 import java.util.ArrayList; 55 import java.util.ArrayList;
57 import java.util.Arrays; 56 import java.util.Arrays;
58 import java.util.Date; 57 import java.util.Date;
@@ -60,7 +59,6 @@ import java.util.LinkedList; @@ -60,7 +59,6 @@ import java.util.LinkedList;
60 import java.util.List; 59 import java.util.List;
61 import java.util.Map; 60 import java.util.Map;
62 import java.util.Optional; 61 import java.util.Optional;
63 -import java.util.Set;  
64 import java.util.concurrent.ConcurrentHashMap; 62 import java.util.concurrent.ConcurrentHashMap;
65 63
66 import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION; 64 import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION;
@@ -115,33 +113,17 @@ public class LwM2mTransportUtil { @@ -115,33 +113,17 @@ public class LwM2mTransportUtil {
115 113
116 public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms 114 public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms
117 115
118 - public static final String LOG_LW2M_TELEMETRY = "logLwm2m";  
119 - public static final String LOG_LW2M_INFO = "info";  
120 - public static final String LOG_LW2M_ERROR = "error";  
121 - public static final String LOG_LW2M_WARN = "warn";  
122 - public static final String LOG_LW2M_VALUE = "value"; 116 + public static final String LOG_LWM2M_TELEMETRY = "logLwm2m";
  117 + public static final String LOG_LWM2M_INFO = "info";
  118 + public static final String LOG_LWM2M_ERROR = "error";
  119 + public static final String LOG_LWM2M_WARN = "warn";
  120 + public static final String LOG_LWM2M_VALUE = "value";
123 121
124 public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized"; 122 public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized";
125 public static final String LWM2M_VERSION_DEFAULT = "1.0"; 123 public static final String LWM2M_VERSION_DEFAULT = "1.0";
126 124
127 - // RPC  
128 - public static final String TYPE_OPER_KEY = "typeOper";  
129 - public static final String TARGET_ID_VER_KEY = "targetIdVer";  
130 - public static final String KEY_NAME_KEY = "key";  
131 - public static final String VALUE_KEY = "value";  
132 - public static final String PARAMS_KEY = "params";  
133 - public static final String SEPARATOR_KEY = ":";  
134 - public static final String FINISH_VALUE_KEY = ",";  
135 - public static final String START_JSON_KEY = "{";  
136 - public static final String FINISH_JSON_KEY = "}";  
137 - public static final String INFO_KEY = "info";  
138 - public static final String RESULT_KEY = "result";  
139 - public static final String ERROR_KEY = "error";  
140 - public static final String METHOD_KEY = "methodName";  
141 -  
142 -  
143 // Firmware 125 // Firmware
144 - public static final String FIRMWARE_UPDATE_COAP_RECOURSE = "firmwareUpdateCoapRecourse"; 126 + public static final String FIRMWARE_UPDATE_COAP_RECOURSE = "tbfw";
145 public static final String FW_UPDATE = "Firmware update"; 127 public static final String FW_UPDATE = "Firmware update";
146 public static final Integer FW_5_ID = 5; 128 public static final Integer FW_5_ID = 5;
147 public static final Integer FW_19_ID = 19; 129 public static final Integer FW_19_ID = 19;
@@ -155,10 +137,14 @@ public class LwM2mTransportUtil { @@ -155,10 +137,14 @@ public class LwM2mTransportUtil {
155 public static final String FW_STATE_ID = "/5/0/3"; 137 public static final String FW_STATE_ID = "/5/0/3";
156 // Update Result R 138 // Update Result R
157 public static final String FW_RESULT_ID = "/5/0/5"; 139 public static final String FW_RESULT_ID = "/5/0/5";
  140 +
  141 + public static final String FW_DELIVERY_METHOD = "/5/0/9";
  142 +
158 // PkgName R 143 // PkgName R
159 public static final String FW_NAME_ID = "/5/0/6"; 144 public static final String FW_NAME_ID = "/5/0/6";
160 // PkgVersion R 145 // PkgVersion R
161 public static final String FW_5_VER_ID = "/5/0/7"; 146 public static final String FW_5_VER_ID = "/5/0/7";
  147 +
162 /** 148 /**
163 * Quectel@Hi15RM1-HLB_V1.0@BC68JAR01A10,V150R100C20B300SP7,V150R100C20B300SP7@8 149 * Quectel@Hi15RM1-HLB_V1.0@BC68JAR01A10,V150R100C20B300SP7,V150R100C20B300SP7@8
164 * BC68JAR01A10 150 * BC68JAR01A10
@@ -215,192 +201,12 @@ public class LwM2mTransportUtil { @@ -215,192 +201,12 @@ public class LwM2mTransportUtil {
215 } 201 }
216 } 202 }
217 203
218 - /**  
219 - * Define the behavior of a write request.  
220 - */  
221 - public enum LwM2mTypeOper {  
222 - /**  
223 - * GET  
224 - */  
225 - READ(0, "Read"),  
226 - DISCOVER(1, "Discover"),  
227 - DISCOVER_ALL(2, "DiscoverAll"),  
228 - OBSERVE_READ_ALL(3, "ObserveReadAll"),  
229 - /**  
230 - * POST  
231 - */  
232 - OBSERVE(4, "Observe"),  
233 - OBSERVE_CANCEL(5, "ObserveCancel"),  
234 - OBSERVE_CANCEL_ALL(6, "ObserveCancelAll"),  
235 - EXECUTE(7, "Execute"),  
236 - /**  
237 - * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see  
238 - * section 5.3.3 of the LW M2M spec).  
239 - * if all resources are to be replaced  
240 - */  
241 - WRITE_REPLACE(8, "WriteReplace"),  
242 - /*  
243 - PUT  
244 - */  
245 - /**  
246 - * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section  
247 - * 5.3.3 of the LW M2M spec).  
248 - * if this is a partial update request  
249 - */  
250 - WRITE_UPDATE(9, "WriteUpdate"),  
251 - WRITE_ATTRIBUTES(10, "WriteAttributes"),  
252 - DELETE(11, "Delete"),  
253 -  
254 - // only for RPC  
255 - FW_UPDATE(12, "FirmwareUpdate");  
256 -// FW_READ_INFO(12, "FirmwareReadInfo"),  
257 -  
258 -// SW_READ_INFO(15, "SoftwareReadInfo"),  
259 -// SW_UPDATE(16, "SoftwareUpdate"),  
260 -// SW_UNINSTALL(18, "SoftwareUninstall");  
261 -  
262 - public int code;  
263 - public String type;  
264 -  
265 - LwM2mTypeOper(int code, String type) {  
266 - this.code = code;  
267 - this.type = type;  
268 - }  
269 -  
270 - public static LwM2mTypeOper fromLwLwM2mTypeOper(String type) {  
271 - for (LwM2mTypeOper to : LwM2mTypeOper.values()) {  
272 - if (to.type.equals(type)) {  
273 - return to;  
274 - }  
275 - }  
276 - throw new IllegalArgumentException(String.format("Unsupported typeOper type : %s", type));  
277 - }  
278 - }  
279 -  
280 - /**  
281 - * /** State R  
282 - * 0: Idle (before downloading or after successful updating)  
283 - * 1: Downloading (The data sequence is on the way)  
284 - * 2: Downloaded  
285 - * 3: Updating  
286 - */  
287 - public enum StateFw {  
288 - IDLE(0, "Idle"),  
289 - DOWNLOADING(1, "Downloading"),  
290 - DOWNLOADED(2, "Downloaded"),  
291 - UPDATING(3, "Updating");  
292 -  
293 - public int code;  
294 - public String type;  
295 -  
296 - StateFw(int code, String type) {  
297 - this.code = code;  
298 - this.type = type;  
299 - }  
300 -  
301 - public static StateFw fromStateFwByType(String type) {  
302 - for (StateFw to : StateFw.values()) {  
303 - if (to.type.equals(type)) {  
304 - return to;  
305 - }  
306 - }  
307 - throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type));  
308 - }  
309 -  
310 - public static StateFw fromStateFwByCode(int code) {  
311 - for (StateFw to : StateFw.values()) {  
312 - if (to.code == code) {  
313 - return to;  
314 - }  
315 - }  
316 - throw new IllegalArgumentException(String.format("Unsupported FW State code : %s", code));  
317 - }  
318 - }  
319 -  
320 - /**  
321 - * FW Update Result  
322 - * 0: Initial value. Once the updating process is initiated (Download /Update), this Resource MUST be reset to Initial value.  
323 - * 1: Firmware updated successfully.  
324 - * 2: Not enough flash memory for the new firmware package.  
325 - * 3: Out of RAM during downloading process.  
326 - * 4: Connection lost during downloading process.  
327 - * 5: Integrity check failure for new downloaded package.  
328 - * 6: Unsupported package type.  
329 - * 7: Invalid URI.  
330 - * 8: Firmware update failed.  
331 - * 9: Unsupported protocol.  
332 - */  
333 - public enum UpdateResultFw {  
334 - INITIAL(0, "Initial value", false),  
335 - UPDATE_SUCCESSFULLY(1, "Firmware updated successfully", false),  
336 - NOT_ENOUGH(2, "Not enough flash memory for the new firmware package", false),  
337 - OUT_OFF_MEMORY(3, "Out of RAM during downloading process", false),  
338 - CONNECTION_LOST(4, "Connection lost during downloading process", true),  
339 - INTEGRITY_CHECK_FAILURE(5, "Integrity check failure for new downloaded package", true),  
340 - UNSUPPORTED_TYPE(6, "Unsupported package type", false),  
341 - INVALID_URI(7, "Invalid URI", false),  
342 - UPDATE_FAILED(8, "Firmware update failed", false),  
343 - UNSUPPORTED_PROTOCOL(9, "Unsupported protocol", false);  
344 -  
345 - public int code;  
346 - public String type;  
347 - public boolean isAgain;  
348 -  
349 - UpdateResultFw(int code, String type, boolean isAgain) {  
350 - this.code = code;  
351 - this.type = type;  
352 - this.isAgain = isAgain;  
353 - }  
354 -  
355 - public static UpdateResultFw fromUpdateResultFwByType(String type) {  
356 - for (UpdateResultFw to : UpdateResultFw.values()) {  
357 - if (to.type.equals(type)) {  
358 - return to;  
359 - }  
360 - }  
361 - throw new IllegalArgumentException(String.format("Unsupported FW Update Result type : %s", type));  
362 - }  
363 -  
364 - public static UpdateResultFw fromUpdateResultFwByCode(int code) {  
365 - for (UpdateResultFw to : UpdateResultFw.values()) {  
366 - if (to.code == code) {  
367 - return to;  
368 - }  
369 - }  
370 - throw new IllegalArgumentException(String.format("Unsupported FW Update Result code : %s", code));  
371 - }  
372 - }  
373 -  
374 - /**  
375 - * FirmwareUpdateStatus {  
376 - * DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED  
377 - */  
378 - public static OtaPackageUpdateStatus equalsFwSateFwResultToFirmwareUpdateStatus(StateFw stateFw, UpdateResultFw updateResultFw) {  
379 - switch (updateResultFw) {  
380 - case INITIAL:  
381 - return equalsFwSateToFirmwareUpdateStatus(stateFw);  
382 - case UPDATE_SUCCESSFULLY:  
383 - return UPDATED;  
384 - case NOT_ENOUGH:  
385 - case OUT_OFF_MEMORY:  
386 - case CONNECTION_LOST:  
387 - case INTEGRITY_CHECK_FAILURE:  
388 - case UNSUPPORTED_TYPE:  
389 - case INVALID_URI:  
390 - case UPDATE_FAILED:  
391 - case UNSUPPORTED_PROTOCOL:  
392 - return FAILED;  
393 - default:  
394 - throw new CodecException("Invalid value stateFw %s %s for FirmwareUpdateStatus.", stateFw.name(), updateResultFw.name());  
395 - }  
396 - }  
397 -  
398 - public static OtaPackageUpdateStatus equalsFwResultToFirmwareUpdateStatus(UpdateResultFw updateResultFw) { 204 + public static Optional<OtaPackageUpdateStatus> toOtaPackageUpdateStatus(UpdateResultFw updateResultFw) {
399 switch (updateResultFw) { 205 switch (updateResultFw) {
400 case INITIAL: 206 case INITIAL:
401 - return VERIFIED;  
402 - case UPDATE_SUCCESSFULLY:  
403 - return UPDATED; 207 + return Optional.empty();
  208 + case UPDATE_SUCCESSFULLY:
  209 + return Optional.of(UPDATED);
404 case NOT_ENOUGH: 210 case NOT_ENOUGH:
405 case OUT_OFF_MEMORY: 211 case OUT_OFF_MEMORY:
406 case CONNECTION_LOST: 212 case CONNECTION_LOST:
@@ -409,24 +215,24 @@ public class LwM2mTransportUtil { @@ -409,24 +215,24 @@ public class LwM2mTransportUtil {
409 case INVALID_URI: 215 case INVALID_URI:
410 case UPDATE_FAILED: 216 case UPDATE_FAILED:
411 case UNSUPPORTED_PROTOCOL: 217 case UNSUPPORTED_PROTOCOL:
412 - return FAILED; 218 + return Optional.of(FAILED);
413 default: 219 default:
414 throw new CodecException("Invalid value stateFw %s for FirmwareUpdateStatus.", updateResultFw.name()); 220 throw new CodecException("Invalid value stateFw %s for FirmwareUpdateStatus.", updateResultFw.name());
415 } 221 }
416 } 222 }
417 223
418 - public static OtaPackageUpdateStatus equalsFwSateToFirmwareUpdateStatus(StateFw stateFw) {  
419 - switch (stateFw) { 224 + public static Optional<OtaPackageUpdateStatus> toOtaPackageUpdateStatus(UpdateStateFw updateStateFw) {
  225 + switch (updateStateFw) {
420 case IDLE: 226 case IDLE:
421 - return VERIFIED; 227 + return Optional.empty();
422 case DOWNLOADING: 228 case DOWNLOADING:
423 - return DOWNLOADING; 229 + return Optional.of(DOWNLOADING);
424 case DOWNLOADED: 230 case DOWNLOADED:
425 - return DOWNLOADED; 231 + return Optional.of(DOWNLOADED);
426 case UPDATING: 232 case UPDATING:
427 - return UPDATING; 233 + return Optional.of(UPDATING);
428 default: 234 default:
429 - throw new CodecException("Invalid value stateFw %d for FirmwareUpdateStatus.", stateFw); 235 + throw new CodecException("Invalid value stateFw %d for FirmwareUpdateStatus.", updateStateFw);
430 } 236 }
431 } 237 }
432 238
@@ -574,70 +380,6 @@ public class LwM2mTransportUtil { @@ -574,70 +380,6 @@ public class LwM2mTransportUtil {
574 } 380 }
575 } 381 }
576 382
577 - public enum LwM2MFirmwareUpdateStrategy {  
578 - OBJ_5_BINARY(1, "ObjectId 5, Binary"),  
579 - OBJ_5_TEMP_URL(2, "ObjectId 5, URI"),  
580 - OBJ_19_BINARY(3, "ObjectId 19, Binary");  
581 -  
582 - public int code;  
583 - public String type;  
584 -  
585 - LwM2MFirmwareUpdateStrategy(int code, String type) {  
586 - this.code = code;  
587 - this.type = type;  
588 - }  
589 -  
590 - public static LwM2MFirmwareUpdateStrategy fromStrategyFwByType(String type) {  
591 - for (LwM2MFirmwareUpdateStrategy to : LwM2MFirmwareUpdateStrategy.values()) {  
592 - if (to.type.equals(type)) {  
593 - return to;  
594 - }  
595 - }  
596 - throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type));  
597 - }  
598 -  
599 - public static LwM2MFirmwareUpdateStrategy fromStrategyFwByCode(int code) {  
600 - for (LwM2MFirmwareUpdateStrategy to : LwM2MFirmwareUpdateStrategy.values()) {  
601 - if (to.code == code) {  
602 - return to;  
603 - }  
604 - }  
605 - throw new IllegalArgumentException(String.format("Unsupported FW Strategy code : %s", code));  
606 - }  
607 - }  
608 -  
609 - public enum LwM2MSoftwareUpdateStrategy {  
610 - BINARY(1, "ObjectId 9, Binary"),  
611 - TEMP_URL(2, "ObjectId 9, URI");  
612 -  
613 - public int code;  
614 - public String type;  
615 -  
616 - LwM2MSoftwareUpdateStrategy(int code, String type) {  
617 - this.code = code;  
618 - this.type = type;  
619 - }  
620 -  
621 - public static LwM2MSoftwareUpdateStrategy fromStrategySwByType(String type) {  
622 - for (LwM2MSoftwareUpdateStrategy to : LwM2MSoftwareUpdateStrategy.values()) {  
623 - if (to.type.equals(type)) {  
624 - return to;  
625 - }  
626 - }  
627 - throw new IllegalArgumentException(String.format("Unsupported SW Strategy type : %s", type));  
628 - }  
629 -  
630 - public static LwM2MSoftwareUpdateStrategy fromStrategySwByCode(int code) {  
631 - for (LwM2MSoftwareUpdateStrategy to : LwM2MSoftwareUpdateStrategy.values()) {  
632 - if (to.code == code) {  
633 - return to;  
634 - }  
635 - }  
636 - throw new IllegalArgumentException(String.format("Unsupported SW Strategy code : %s", code));  
637 - }  
638 -  
639 - }  
640 -  
641 /** 383 /**
642 * FirmwareUpdateStatus { 384 * FirmwareUpdateStatus {
643 * DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED 385 * DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
@@ -695,26 +437,23 @@ public class LwM2mTransportUtil { @@ -695,26 +437,23 @@ public class LwM2mTransportUtil {
695 } 437 }
696 } 438 }
697 439
698 - public static LwM2mOtaConvert convertOtaUpdateValueToString (String pathIdVer, Object value, ResourceModel.Type currentType) {  
699 - String path = convertPathFromIdVerToObjectId(pathIdVer); 440 + public static LwM2mOtaConvert convertOtaUpdateValueToString(String pathIdVer, Object value, ResourceModel.Type currentType) {
  441 + String path = fromVersionedIdToObjectId(pathIdVer);
700 LwM2mOtaConvert lwM2mOtaConvert = new LwM2mOtaConvert(); 442 LwM2mOtaConvert lwM2mOtaConvert = new LwM2mOtaConvert();
701 if (path != null) { 443 if (path != null) {
702 if (FW_STATE_ID.equals(path)) { 444 if (FW_STATE_ID.equals(path)) {
703 lwM2mOtaConvert.setCurrentType(STRING); 445 lwM2mOtaConvert.setCurrentType(STRING);
704 - lwM2mOtaConvert.setValue(StateFw.fromStateFwByCode(((Long) value).intValue()).type); 446 + lwM2mOtaConvert.setValue(UpdateStateFw.fromStateFwByCode(((Long) value).intValue()).type);
705 return lwM2mOtaConvert; 447 return lwM2mOtaConvert;
706 - }  
707 - else if (FW_RESULT_ID.equals(path)) { 448 + } else if (FW_RESULT_ID.equals(path)) {
708 lwM2mOtaConvert.setCurrentType(STRING); 449 lwM2mOtaConvert.setCurrentType(STRING);
709 - lwM2mOtaConvert.setValue(UpdateResultFw.fromUpdateResultFwByCode(((Long) value).intValue()).type); 450 + lwM2mOtaConvert.setValue(UpdateResultFw.fromUpdateResultFwByCode(((Long) value).intValue()).getType());
710 return lwM2mOtaConvert; 451 return lwM2mOtaConvert;
711 - }  
712 - else if (SW_UPDATE_STATE_ID.equals(path)) { 452 + } else if (SW_UPDATE_STATE_ID.equals(path)) {
713 lwM2mOtaConvert.setCurrentType(STRING); 453 lwM2mOtaConvert.setCurrentType(STRING);
714 lwM2mOtaConvert.setValue(UpdateStateSw.fromUpdateStateSwByCode(((Long) value).intValue()).type); 454 lwM2mOtaConvert.setValue(UpdateStateSw.fromUpdateStateSwByCode(((Long) value).intValue()).type);
715 return lwM2mOtaConvert; 455 return lwM2mOtaConvert;
716 - }  
717 - else if (SW_RESULT_ID.equals(path)) { 456 + } else if (SW_RESULT_ID.equals(path)) {
718 lwM2mOtaConvert.setCurrentType(STRING); 457 lwM2mOtaConvert.setCurrentType(STRING);
719 lwM2mOtaConvert.setValue(UpdateResultSw.fromUpdateResultSwByCode(((Long) value).intValue()).type); 458 lwM2mOtaConvert.setValue(UpdateResultSw.fromUpdateResultSwByCode(((Long) value).intValue()).type);
720 return lwM2mOtaConvert; 459 return lwM2mOtaConvert;
@@ -738,112 +477,32 @@ public class LwM2mTransportUtil { @@ -738,112 +477,32 @@ public class LwM2mTransportUtil {
738 return null; 477 return null;
739 } 478 }
740 479
741 -  
742 - public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, TenantId tenantId) {  
743 - LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile();  
744 - lwM2MClientProfile.setTenantId(tenantId);  
745 - lwM2MClientProfile.setPostClientLwM2mSettings(profilesConfigData.get(CLIENT_LWM2M_SETTINGS).getAsJsonObject());  
746 - lwM2MClientProfile.setPostKeyNameProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).getAsJsonObject());  
747 - lwM2MClientProfile.setPostAttributeProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).getAsJsonArray());  
748 - lwM2MClientProfile.setPostTelemetryProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).getAsJsonArray());  
749 - lwM2MClientProfile.setPostObserveProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).getAsJsonArray());  
750 - lwM2MClientProfile.setPostAttributeLwm2mProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).getAsJsonObject());  
751 - return lwM2MClientProfile;  
752 - }  
753 -  
754 - /**  
755 - * @return deviceProfileBody with Observe&Attribute&Telemetry From Thingsboard  
756 - * Example:  
757 - * property: {"clientLwM2mSettings": {  
758 - * clientUpdateValueAfterConnect: false;  
759 - * }  
760 - * property: "observeAttr"  
761 - * {"keyName": {  
762 - * "/3/0/1": "modelNumber",  
763 - * "/3/0/0": "manufacturer",  
764 - * "/3/0/2": "serialNumber"  
765 - * },  
766 - * "attribute":["/2/0/1","/3/0/9"],  
767 - * "telemetry":["/1/0/1","/2/0/1","/6/0/1"],  
768 - * "observe":["/2/0","/2/0/0","/4/0/2"]}  
769 - * "attributeLwm2m": {"/3_1.0": {"ver": "currentTimeTest11"},  
770 - * "/3_1.0/0": {"gt": 17},  
771 - * "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}}  
772 - */  
773 - public static LwM2mClientProfile toLwM2MClientProfile(DeviceProfile deviceProfile) {  
774 - if (((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {  
775 - Object profile = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties();  
776 - try {  
777 - ObjectMapper mapper = new ObjectMapper();  
778 - String profileStr = mapper.writeValueAsString(profile);  
779 - JsonObject profileJson = (profileStr != null) ? validateJson(profileStr) : null;  
780 - return getValidateCredentialsBodyFromThingsboard(profileJson) ? LwM2mTransportUtil.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null;  
781 - } catch (IOException e) {  
782 - log.error("", e);  
783 - }  
784 - }  
785 - return null;  
786 - }  
787 -  
788 - public static JsonObject getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) {  
789 - if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {  
790 - Object bootstrap = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties();  
791 - try {  
792 - ObjectMapper mapper = new ObjectMapper();  
793 - String bootstrapStr = mapper.writeValueAsString(bootstrap);  
794 - JsonObject objectMsg = (bootstrapStr != null) ? validateJson(bootstrapStr) : null;  
795 - return (getValidateBootstrapProfileFromThingsboard(objectMsg)) ? objectMsg.get(BOOTSTRAP).getAsJsonObject() : null;  
796 - } catch (IOException e) {  
797 - log.error("", e);  
798 - } 480 +// public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, TenantId tenantId) {
  481 +// LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile();
  482 +// lwM2MClientProfile.setTenantId(tenantId);
  483 +// lwM2MClientProfile.setPostClientLwM2mSettings(profilesConfigData.get(CLIENT_LWM2M_SETTINGS).getAsJsonObject());
  484 +// lwM2MClientProfile.setPostKeyNameProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).getAsJsonObject());
  485 +// lwM2MClientProfile.setPostAttributeProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).getAsJsonArray());
  486 +// lwM2MClientProfile.setPostTelemetryProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).getAsJsonArray());
  487 +// lwM2MClientProfile.setPostObserveProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).getAsJsonArray());
  488 +// lwM2MClientProfile.setPostAttributeLwm2mProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).getAsJsonObject());
  489 +// return lwM2MClientProfile;
  490 +// }
  491 +
  492 + public static Lwm2mDeviceProfileTransportConfiguration toLwM2MClientProfile(DeviceProfile deviceProfile) {
  493 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  494 + if (transportConfiguration.getType().equals(DeviceTransportType.LWM2M)) {
  495 + return (Lwm2mDeviceProfileTransportConfiguration) transportConfiguration;
  496 + } else {
  497 + log.warn("[{}] Received profile with invalid transport configuration: {}", deviceProfile.getId(), deviceProfile.getProfileData().getTransportConfiguration());
  498 + throw new IllegalArgumentException("Received profile with invalid transport configuration: " + transportConfiguration.getType());
799 } 499 }
800 - return null;  
801 - }  
802 -  
803 - private static boolean getValidateCredentialsBodyFromThingsboard(JsonObject objectMsg) {  
804 - return (objectMsg != null &&  
805 - !objectMsg.isJsonNull() &&  
806 - objectMsg.has(CLIENT_LWM2M_SETTINGS) &&  
807 - !objectMsg.get(CLIENT_LWM2M_SETTINGS).isJsonNull() &&  
808 - objectMsg.get(CLIENT_LWM2M_SETTINGS).isJsonObject() &&  
809 - objectMsg.has(OBSERVE_ATTRIBUTE_TELEMETRY) &&  
810 - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).isJsonNull() &&  
811 - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).isJsonObject() &&  
812 - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(KEY_NAME) &&  
813 - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).isJsonNull() &&  
814 - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).isJsonObject() &&  
815 - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(ATTRIBUTE) &&  
816 - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).isJsonNull() &&  
817 - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).isJsonArray() &&  
818 - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(TELEMETRY) &&  
819 - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).isJsonNull() &&  
820 - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).isJsonArray() &&  
821 - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(OBSERVE_LWM2M) &&  
822 - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).isJsonNull() &&  
823 - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).isJsonArray() &&  
824 - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(ATTRIBUTE_LWM2M) &&  
825 - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).isJsonNull() &&  
826 - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).isJsonObject());  
827 } 500 }
828 501
829 - private static boolean getValidateBootstrapProfileFromThingsboard(JsonObject objectMsg) {  
830 - return (objectMsg != null &&  
831 - !objectMsg.isJsonNull() &&  
832 - objectMsg.has(BOOTSTRAP) &&  
833 - objectMsg.get(BOOTSTRAP).isJsonObject() &&  
834 - !objectMsg.get(BOOTSTRAP).isJsonNull() &&  
835 - objectMsg.get(BOOTSTRAP).getAsJsonObject().has(SERVERS) &&  
836 - !objectMsg.get(BOOTSTRAP).getAsJsonObject().get(SERVERS).isJsonNull() &&  
837 - objectMsg.get(BOOTSTRAP).getAsJsonObject().get(SERVERS).isJsonObject() &&  
838 - objectMsg.get(BOOTSTRAP).getAsJsonObject().has(BOOTSTRAP_SERVER) &&  
839 - !objectMsg.get(BOOTSTRAP).getAsJsonObject().get(BOOTSTRAP_SERVER).isJsonNull() &&  
840 - objectMsg.get(BOOTSTRAP).getAsJsonObject().get(BOOTSTRAP_SERVER).isJsonObject() &&  
841 - objectMsg.get(BOOTSTRAP).getAsJsonObject().has(LWM2M_SERVER) &&  
842 - !objectMsg.get(BOOTSTRAP).getAsJsonObject().get(LWM2M_SERVER).isJsonNull() &&  
843 - objectMsg.get(BOOTSTRAP).getAsJsonObject().get(LWM2M_SERVER).isJsonObject()); 502 + public static BootstrapConfiguration getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) {
  503 + return toLwM2MClientProfile(deviceProfile).getBootstrap();
844 } 504 }
845 505
846 -  
847 public static JsonObject validateJson(String jsonStr) { 506 public static JsonObject validateJson(String jsonStr) {
848 JsonObject object = null; 507 JsonObject object = null;
849 if (jsonStr != null && !jsonStr.isEmpty()) { 508 if (jsonStr != null && !jsonStr.isEmpty()) {
@@ -900,8 +559,11 @@ public class LwM2mTransportUtil { @@ -900,8 +559,11 @@ public class LwM2mTransportUtil {
900 }; 559 };
901 } 560 }
902 561
903 - public static String convertPathFromIdVerToObjectId(String pathIdVer) { 562 + public static String fromVersionedIdToObjectId(String pathIdVer) {
904 try { 563 try {
  564 + if (pathIdVer == null) {
  565 + return null;
  566 + }
905 String[] keyArray = pathIdVer.split(LWM2M_SEPARATOR_PATH); 567 String[] keyArray = pathIdVer.split(LWM2M_SEPARATOR_PATH);
906 if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) { 568 if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) {
907 keyArray[1] = keyArray[1].split(LWM2M_SEPARATOR_KEY)[0]; 569 keyArray[1] = keyArray[1].split(LWM2M_SEPARATOR_KEY)[0];
@@ -910,7 +572,8 @@ public class LwM2mTransportUtil { @@ -910,7 +572,8 @@ public class LwM2mTransportUtil {
910 return pathIdVer; 572 return pathIdVer;
911 } 573 }
912 } catch (Exception e) { 574 } catch (Exception e) {
913 - return null; 575 + log.warn("Issue converting path with version [{}] to path without version: ", pathIdVer, e);
  576 + throw new RuntimeException(e);
914 } 577 }
915 } 578 }
916 579
@@ -941,12 +604,12 @@ public class LwM2mTransportUtil { @@ -941,12 +604,12 @@ public class LwM2mTransportUtil {
941 return pathIdVer; 604 return pathIdVer;
942 } else { 605 } else {
943 LwM2mPath pathObjId = new LwM2mPath(pathIdVer); 606 LwM2mPath pathObjId = new LwM2mPath(pathIdVer);
944 - return convertPathFromObjectIdToIdVer(pathIdVer, registration); 607 + return convertObjectIdToVersionedId(pathIdVer, registration);
945 } 608 }
946 } 609 }
947 } 610 }
948 611
949 - public static String convertPathFromObjectIdToIdVer(String path, Registration registration) { 612 + public static String convertObjectIdToVersionedId(String path, Registration registration) {
950 String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId()); 613 String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
951 ver = ver != null ? ver : LWM2M_VERSION_DEFAULT; 614 ver = ver != null ? ver : LWM2M_VERSION_DEFAULT;
952 try { 615 try {
@@ -1001,12 +664,12 @@ public class LwM2mTransportUtil { @@ -1001,12 +664,12 @@ public class LwM2mTransportUtil {
1001 * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60"); 664 * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60");
1002 * Attribute [] attrs = {gt, st}; 665 * Attribute [] attrs = {gt, st};
1003 */ 666 */
1004 - public static SimpleDownlinkRequest createWriteAttributeRequest(String target, Object params, DefaultLwM2MTransportMsgHandler serviceImpl) { 667 + public static SimpleDownlinkRequest createWriteAttributeRequest(String target, Object params, DefaultLwM2MUplinkMsgHandler serviceImpl) {
1005 AttributeSet attrSet = new AttributeSet(createWriteAttributes(params, serviceImpl, target)); 668 AttributeSet attrSet = new AttributeSet(createWriteAttributes(params, serviceImpl, target));
1006 return attrSet.getAttributes().size() > 0 ? new WriteAttributesRequest(target, attrSet) : null; 669 return attrSet.getAttributes().size() > 0 ? new WriteAttributesRequest(target, attrSet) : null;
1007 } 670 }
1008 671
1009 - private static Attribute[] createWriteAttributes(Object params, DefaultLwM2MTransportMsgHandler serviceImpl, String target) { 672 + private static Attribute[] createWriteAttributes(Object params, DefaultLwM2MUplinkMsgHandler serviceImpl, String target) {
1010 List<Attribute> attributeLists = new ArrayList<>(); 673 List<Attribute> attributeLists = new ArrayList<>();
1011 ObjectMapper oMapper = new ObjectMapper(); 674 ObjectMapper oMapper = new ObjectMapper();
1012 Map<String, Object> map = oMapper.convertValue(params, ConcurrentHashMap.class); 675 Map<String, Object> map = oMapper.convertValue(params, ConcurrentHashMap.class);
@@ -1024,12 +687,6 @@ public class LwM2mTransportUtil { @@ -1024,12 +687,6 @@ public class LwM2mTransportUtil {
1024 return attributeLists.toArray(Attribute[]::new); 687 return attributeLists.toArray(Attribute[]::new);
1025 } 688 }
1026 689
1027 - public static Set<String> convertJsonArrayToSet(JsonArray jsonArray) {  
1028 - List<String> attributeListOld = new Gson().fromJson(jsonArray, new TypeToken<List<String>>() {  
1029 - }.getType());  
1030 - return Sets.newConcurrentHashSet(attributeListOld);  
1031 - }  
1032 -  
1033 public static ResourceModel.Type equalsResourceTypeGetSimpleName(Object value) { 690 public static ResourceModel.Type equalsResourceTypeGetSimpleName(Object value) {
1034 switch (value.getClass().getSimpleName()) { 691 switch (value.getClass().getSimpleName()) {
1035 case "Double": 692 case "Double":
@@ -1051,15 +708,7 @@ public class LwM2mTransportUtil { @@ -1051,15 +708,7 @@ public class LwM2mTransportUtil {
1051 } 708 }
1052 } 709 }
1053 710
1054 - public static LwM2mTypeOper setValidTypeOper(String typeOper) {  
1055 - try {  
1056 - return LwM2mTransportUtil.LwM2mTypeOper.fromLwLwM2mTypeOper(typeOper);  
1057 - } catch (Exception e) {  
1058 - return null;  
1059 - }  
1060 - }  
1061 -  
1062 - public static Object convertWriteAttributes(String type, Object value, DefaultLwM2MTransportMsgHandler serviceImpl, String target) { 711 + public static Object convertWriteAttributes(String type, Object value, DefaultLwM2MUplinkMsgHandler serviceImpl, String target) {
1063 switch (type) { 712 switch (type) {
1064 /** Integer [0:255]; */ 713 /** Integer [0:255]; */
1065 case DIMENSION: 714 case DIMENSION:
@@ -1106,4 +755,20 @@ public class LwM2mTransportUtil { @@ -1106,4 +755,20 @@ public class LwM2mTransportUtil {
1106 || OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM_ALGORITHM).equals(pathName) 755 || OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM_ALGORITHM).equals(pathName)
1107 || OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.SIZE).equals(pathName); 756 || OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.SIZE).equals(pathName);
1108 } 757 }
  758 +
  759 + /**
  760 + * @param lwM2MClient -
  761 + * @param path -
  762 + * @return - return value of Resource by idPath
  763 + */
  764 + public static LwM2mResource getResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) {
  765 + LwM2mResource lwm2mResourceValue = null;
  766 + ResourceValue resourceValue = lwM2MClient.getResources().get(path);
  767 + if (resourceValue != null) {
  768 + if (new LwM2mPath(fromVersionedIdToObjectId(path)).isResource()) {
  769 + lwm2mResourceValue = lwM2MClient.getResources().get(path).getLwM2mResource();
  770 + }
  771 + }
  772 + return lwm2mResourceValue;
  773 + }
1109 } 774 }
@@ -72,7 +72,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider { @@ -72,7 +72,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
72 72
73 public DynamicModel(Registration registration) { 73 public DynamicModel(Registration registration) {
74 this.registration = registration; 74 this.registration = registration;
75 - this.tenantId = lwM2mClientContext.getProfile(registration).getTenantId(); 75 + this.tenantId = lwM2mClientContext.getClientByEndpoint(registration.getEndpoint()).getTenantId();
76 } 76 }
77 77
78 @Override 78 @Override
  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;
  17 +
  18 +import lombok.Getter;
  19 +
  20 +/**
  21 + * FW Update Result
  22 + * 0: Initial value. Once the updating process is initiated (Download /Update), this Resource MUST be reset to Initial value.
  23 + * 1: Firmware updated successfully.
  24 + * 2: Not enough flash memory for the new firmware package.
  25 + * 3: Out of RAM during downloading process.
  26 + * 4: Connection lost during downloading process.
  27 + * 5: Integrity check failure for new downloaded package.
  28 + * 6: Unsupported package type.
  29 + * 7: Invalid URI.
  30 + * 8: Firmware update failed.
  31 + * 9: Unsupported protocol.
  32 + */
  33 +public enum UpdateResultFw {
  34 + INITIAL(0, "Initial value", false),
  35 + UPDATE_SUCCESSFULLY(1, "Firmware updated successfully", false),
  36 + NOT_ENOUGH(2, "Not enough flash memory for the new firmware package", false),
  37 + OUT_OFF_MEMORY(3, "Out of RAM during downloading process", false),
  38 + CONNECTION_LOST(4, "Connection lost during downloading process", true),
  39 + INTEGRITY_CHECK_FAILURE(5, "Integrity check failure for new downloaded package", true),
  40 + UNSUPPORTED_TYPE(6, "Unsupported package type", false),
  41 + INVALID_URI(7, "Invalid URI", false),
  42 + UPDATE_FAILED(8, "Firmware update failed", false),
  43 + UNSUPPORTED_PROTOCOL(9, "Unsupported protocol", false);
  44 +
  45 + @Getter
  46 + private int code;
  47 + @Getter
  48 + private String type;
  49 + @Getter
  50 + private boolean again;
  51 +
  52 + UpdateResultFw(int code, String type, boolean isAgain) {
  53 + this.code = code;
  54 + this.type = type;
  55 + this.again = isAgain;
  56 + }
  57 +
  58 + public static UpdateResultFw fromUpdateResultFwByType(String type) {
  59 + for (UpdateResultFw to : UpdateResultFw.values()) {
  60 + if (to.type.equals(type)) {
  61 + return to;
  62 + }
  63 + }
  64 + throw new IllegalArgumentException(String.format("Unsupported FW Update Result type : %s", type));
  65 + }
  66 +
  67 + public static UpdateResultFw fromUpdateResultFwByCode(int code) {
  68 + for (UpdateResultFw to : UpdateResultFw.values()) {
  69 + if (to.code == code) {
  70 + return to;
  71 + }
  72 + }
  73 + throw new IllegalArgumentException(String.format("Unsupported FW Update Result code : %s", code));
  74 + }
  75 +}
  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;
  17 +
  18 +/**
  19 + * /** State R
  20 + * 0: Idle (before downloading or after successful updating)
  21 + * 1: Downloading (The data sequence is on the way)
  22 + * 2: Downloaded
  23 + * 3: Updating
  24 + */
  25 +public enum UpdateStateFw {
  26 + IDLE(0, "Idle"),
  27 + DOWNLOADING(1, "Downloading"),
  28 + DOWNLOADED(2, "Downloaded"),
  29 + UPDATING(3, "Updating");
  30 +
  31 + public int code;
  32 + public String type;
  33 +
  34 + UpdateStateFw(int code, String type) {
  35 + this.code = code;
  36 + this.type = type;
  37 + }
  38 +
  39 + public static UpdateStateFw fromStateFwByType(String type) {
  40 + for (UpdateStateFw to : UpdateStateFw.values()) {
  41 + if (to.type.equals(type)) {
  42 + return to;
  43 + }
  44 + }
  45 + throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type));
  46 + }
  47 +
  48 + public static UpdateStateFw fromStateFwByCode(int code) {
  49 + for (UpdateStateFw to : UpdateStateFw.values()) {
  50 + if (to.code == code) {
  51 + return to;
  52 + }
  53 + }
  54 + throw new IllegalArgumentException(String.format("Unsupported FW State code : %s", code));
  55 + }
  56 +}
  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.attributes;
  17 +
  18 +import com.google.common.util.concurrent.ListenableFuture;
  19 +import com.google.common.util.concurrent.SettableFuture;
  20 +import lombok.RequiredArgsConstructor;
  21 +import lombok.extern.slf4j.Slf4j;
  22 +import org.eclipse.leshan.core.model.ResourceModel;
  23 +import org.eclipse.leshan.core.node.LwM2mPath;
  24 +import org.eclipse.leshan.core.node.LwM2mResource;
  25 +import org.springframework.stereotype.Service;
  26 +import org.thingsboard.server.common.data.ota.OtaPackageKey;
  27 +import org.thingsboard.server.common.data.ota.OtaPackageType;
  28 +import org.thingsboard.server.common.data.ota.OtaPackageUtil;
  29 +import org.thingsboard.server.common.transport.TransportService;
  30 +import org.thingsboard.server.common.transport.TransportServiceCallback;
  31 +import org.thingsboard.server.gen.transport.TransportProtos;
  32 +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg;
  33 +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
  34 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
  35 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
  36 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
  37 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  38 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
  39 +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler;
  40 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest;
  41 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback;
  42 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  43 +import org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService;
  44 +import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
  45 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  46 +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
  47 +
  48 +import java.util.ArrayList;
  49 +import java.util.Collection;
  50 +import java.util.List;
  51 +import java.util.Map;
  52 +import java.util.Optional;
  53 +import java.util.concurrent.atomic.AtomicInteger;
  54 +
  55 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto;
  56 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR;
  57 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
  58 +
  59 +@Slf4j
  60 +@Service
  61 +@TbLwM2mTransportComponent
  62 +@RequiredArgsConstructor
  63 +public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
  64 +
  65 + //TODO: add timeout logic
  66 + private final AtomicInteger reqIdSeq = new AtomicInteger();
  67 + private final Map<Integer, SettableFuture<List<TransportProtos.TsKvProto>>> futures;
  68 +
  69 + private final TransportService transportService;
  70 + private final LwM2mTransportServerHelper helper;
  71 + private final LwM2mClientContext clientContext;
  72 + private final LwM2MTransportServerConfig config;
  73 + private final LwM2mUplinkMsgHandler uplinkHandler;
  74 + private final LwM2mDownlinkMsgHandler downlinkHandler;
  75 + private final LwM2MTelemetryLogService logService;
  76 + private final LwM2MOtaUpdateService otaUpdateService;
  77 +
  78 + @Override
  79 + public ListenableFuture<List<TransportProtos.TsKvProto>> getSharedAttributes(LwM2mClient client, Collection<String> keys) {
  80 + SettableFuture<List<TransportProtos.TsKvProto>> future = SettableFuture.create();
  81 + int requestId = reqIdSeq.incrementAndGet();
  82 + futures.put(requestId, future);
  83 + transportService.process(client.getSession(), TransportProtos.GetAttributeRequestMsg.newBuilder().setRequestId(requestId).
  84 + addAllSharedAttributeNames(keys).build(), new TransportServiceCallback<Void>() {
  85 + @Override
  86 + public void onSuccess(Void msg) {
  87 +
  88 + }
  89 +
  90 + @Override
  91 + public void onError(Throwable e) {
  92 + SettableFuture<List<TransportProtos.TsKvProto>> callback = futures.remove(requestId);
  93 + if (callback != null) {
  94 + callback.setException(e);
  95 + }
  96 + }
  97 + });
  98 + return future;
  99 + }
  100 +
  101 + @Override
  102 + public void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse, TransportProtos.SessionInfoProto sessionInfo) {
  103 + var callback = futures.remove(getAttributesResponse.getRequestId());
  104 + if (callback != null) {
  105 + callback.set(getAttributesResponse.getSharedAttributeListList());
  106 + }
  107 + }
  108 +
  109 + /**
  110 + * Update - send request in change value resources in Client
  111 + * 1. FirmwareUpdate:
  112 + * - If msg.getSharedUpdatedList().forEach(tsKvProto -> {tsKvProto.getKv().getKey().indexOf(FIRMWARE_UPDATE_PREFIX, 0) == 0
  113 + * 2. Shared Other AttributeUpdate
  114 + * -- Path to resources from profile equal keyName or from ModelObject equal name
  115 + * -- Only for resources: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase)
  116 + * 3. Delete - nothing
  117 + *
  118 + * @param msg -
  119 + */
  120 + @Override
  121 + public void onAttributesUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
  122 + LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo);
  123 + if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) {
  124 + String newFirmwareTitle = null;
  125 + String newFirmwareVersion = null;
  126 + String newFirmwareUrl = null;
  127 + String newSoftwareTitle = null;
  128 + String newSoftwareVersion = null;
  129 + List<TransportProtos.TsKvProto> otherAttributes = new ArrayList<>();
  130 + for (TransportProtos.TsKvProto tsKvProto : msg.getSharedUpdatedList()) {
  131 + String attrName = tsKvProto.getKv().getKey();
  132 + if (DefaultLwM2MOtaUpdateService.FIRMWARE_TITLE.equals(attrName)) {
  133 + newFirmwareTitle = getStrValue(tsKvProto);
  134 + } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_VERSION.equals(attrName)) {
  135 + newFirmwareVersion = getStrValue(tsKvProto);
  136 + } else if (DefaultLwM2MOtaUpdateService.FIRMWARE_URL.equals(attrName)) {
  137 + newFirmwareUrl = getStrValue(tsKvProto);
  138 + } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_TITLE.equals(attrName)) {
  139 + newSoftwareTitle = getStrValue(tsKvProto);
  140 + } else if (DefaultLwM2MOtaUpdateService.SOFTWARE_VERSION.equals(attrName)) {
  141 + newSoftwareVersion = getStrValue(tsKvProto);
  142 + } else {
  143 + otherAttributes.add(tsKvProto);
  144 + }
  145 + }
  146 + if (newFirmwareTitle != null || newFirmwareVersion != null) {
  147 + otaUpdateService.onTargetFirmwareUpdate(lwM2MClient, newFirmwareTitle, newFirmwareVersion, Optional.ofNullable(newFirmwareUrl));
  148 + }
  149 + if (newSoftwareTitle != null || newSoftwareVersion != null) {
  150 + otaUpdateService.onTargetSoftwareUpdate(lwM2MClient, newSoftwareTitle, newSoftwareVersion);
  151 + }
  152 + if (!otherAttributes.isEmpty()) {
  153 + onAttributesUpdate(lwM2MClient, otherAttributes);
  154 + }
  155 + } else if (lwM2MClient == null) {
  156 + log.error("OnAttributeUpdate, lwM2MClient is null");
  157 + }
  158 + }
  159 +
  160 + /**
  161 + * #1.1 If two names have equal path => last time attribute
  162 + * #2.1 if there is a difference in values between the current resource values and the shared attribute values
  163 + * => send to client Request Update of value (new value from shared attribute)
  164 + * and LwM2MClient.delayedRequests.add(path)
  165 + * #2.1 if there is not a difference in values between the current resource values and the shared attribute values
  166 + *
  167 + */
  168 + @Override
  169 + public void onAttributesUpdate(LwM2mClient lwM2MClient, List<TransportProtos.TsKvProto> tsKvProtos) {
  170 + log.trace("[{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), tsKvProtos);
  171 + tsKvProtos.forEach(tsKvProto -> {
  172 + String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey());
  173 + if (pathIdVer != null) {
  174 + // #1.1
  175 + if (lwM2MClient.getSharedAttributes().containsKey(pathIdVer)) {
  176 + if (tsKvProto.getTs() > lwM2MClient.getSharedAttributes().get(pathIdVer).getTs()) {
  177 + lwM2MClient.getSharedAttributes().put(pathIdVer, tsKvProto);
  178 + }
  179 + } else {
  180 + lwM2MClient.getSharedAttributes().put(pathIdVer, tsKvProto);
  181 + }
  182 + }
  183 + });
  184 + // #2.1
  185 + lwM2MClient.getSharedAttributes().forEach((pathIdVer, tsKvProto) -> {
  186 + this.pushUpdateToClientIfNeeded(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer),
  187 + getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
  188 + });
  189 + }
  190 +
  191 + private void pushUpdateToClientIfNeeded(LwM2mClient lwM2MClient, Object valueOld, Object newValue, String versionedId) {
  192 + if (newValue != null && (valueOld == null || !newValue.toString().equals(valueOld.toString()))) {
  193 + TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValue).timeout(this.config.getTimeout()).build();
  194 + downlinkHandler.sendWriteReplaceRequest(lwM2MClient, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, lwM2MClient, versionedId));
  195 + } else {
  196 + log.error("Failed update resource [{}] [{}]", versionedId, newValue);
  197 + String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. Value is not changed or bad",
  198 + LOG_LWM2M_ERROR, versionedId, newValue);
  199 + logService.log(lwM2MClient, logMsg);
  200 + log.info("Failed update resource [{}] [{}]", versionedId, newValue);
  201 + }
  202 + }
  203 +
  204 + /**
  205 + * @param pathIdVer - path resource
  206 + * @return - value of Resource into format KvProto or null
  207 + */
  208 + private Object getResourceValueFormatKv(LwM2mClient lwM2MClient, String pathIdVer) {
  209 + LwM2mResource resourceValue = LwM2mTransportUtil.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);
  210 + if (resourceValue != null) {
  211 + ResourceModel.Type currentType = resourceValue.getType();
  212 + ResourceModel.Type expectedType = helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
  213 + return LwM2mValueConverterImpl.getInstance().convertValue(resourceValue.getValue(), currentType, expectedType,
  214 + new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)));
  215 + } else {
  216 + return null;
  217 + }
  218 + }
  219 +
  220 + private String getStrValue(TransportProtos.TsKvProto tsKvProto) {
  221 + return tsKvProto.getKv().getStringV();
  222 + }
  223 +}
  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.attributes;
  17 +
  18 +import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.gen.transport.TransportProtos;
  20 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  21 +
  22 +import java.util.Collection;
  23 +import java.util.List;
  24 +
  25 +public interface LwM2MAttributesService {
  26 +
  27 + ListenableFuture<List<TransportProtos.TsKvProto>> getSharedAttributes(LwM2mClient client, Collection<String> keys);
  28 +
  29 + void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg getAttributesResponse, TransportProtos.SessionInfoProto sessionInfo);
  30 +
  31 + void onAttributesUpdate(TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotification, TransportProtos.SessionInfoProto sessionInfo);
  32 +
  33 + void onAttributesUpdate(LwM2mClient lwM2MClient, List<TransportProtos.TsKvProto> tsKvProtos);
  34 +}
@@ -20,28 +20,27 @@ import lombok.Setter; @@ -20,28 +20,27 @@ import lombok.Setter;
20 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
21 import org.eclipse.leshan.core.model.ObjectModel; 21 import org.eclipse.leshan.core.model.ObjectModel;
22 import org.eclipse.leshan.core.model.ResourceModel; 22 import org.eclipse.leshan.core.model.ResourceModel;
23 -import org.eclipse.leshan.core.node.LwM2mMultipleResource;  
24 import org.eclipse.leshan.core.node.LwM2mObject; 23 import org.eclipse.leshan.core.node.LwM2mObject;
25 import org.eclipse.leshan.core.node.LwM2mObjectInstance; 24 import org.eclipse.leshan.core.node.LwM2mObjectInstance;
26 import org.eclipse.leshan.core.node.LwM2mPath; 25 import org.eclipse.leshan.core.node.LwM2mPath;
27 import org.eclipse.leshan.core.node.LwM2mResource; 26 import org.eclipse.leshan.core.node.LwM2mResource;
28 import org.eclipse.leshan.core.node.LwM2mSingleResource; 27 import org.eclipse.leshan.core.node.LwM2mSingleResource;
  28 +import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
29 import org.eclipse.leshan.core.request.ContentFormat; 29 import org.eclipse.leshan.core.request.ContentFormat;
30 import org.eclipse.leshan.server.model.LwM2mModelProvider; 30 import org.eclipse.leshan.server.model.LwM2mModelProvider;
31 import org.eclipse.leshan.server.registration.Registration; 31 import org.eclipse.leshan.server.registration.Registration;
32 import org.eclipse.leshan.server.security.SecurityInfo; 32 import org.eclipse.leshan.server.security.SecurityInfo;
33 import org.thingsboard.server.common.data.Device; 33 import org.thingsboard.server.common.data.Device;
34 import org.thingsboard.server.common.data.DeviceProfile; 34 import org.thingsboard.server.common.data.DeviceProfile;
  35 +import org.thingsboard.server.common.data.id.TenantId;
35 import org.thingsboard.server.common.data.ota.OtaPackageType; 36 import org.thingsboard.server.common.data.ota.OtaPackageType;
36 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 37 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
37 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; 38 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
38 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; 39 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
39 -import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;  
40 import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest; 40 import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest;
41 -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; 41 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
42 42
43 import java.util.Collection; 43 import java.util.Collection;
44 -import java.util.List;  
45 import java.util.Map; 44 import java.util.Map;
46 import java.util.Optional; 45 import java.util.Optional;
47 import java.util.Queue; 46 import java.util.Queue;
@@ -49,18 +48,15 @@ import java.util.Set; @@ -49,18 +48,15 @@ import java.util.Set;
49 import java.util.UUID; 48 import java.util.UUID;
50 import java.util.concurrent.ConcurrentHashMap; 49 import java.util.concurrent.ConcurrentHashMap;
51 import java.util.concurrent.ConcurrentLinkedQueue; 50 import java.util.concurrent.ConcurrentLinkedQueue;
52 -import java.util.concurrent.CopyOnWriteArrayList;  
53 import java.util.concurrent.locks.Lock; 51 import java.util.concurrent.locks.Lock;
54 import java.util.concurrent.locks.ReentrantLock; 52 import java.util.concurrent.locks.ReentrantLock;
55 import java.util.stream.Collectors; 53 import java.util.stream.Collectors;
56 54
57 -import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;  
58 -import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING;  
59 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;
60 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TRANSPORT_DEFAULT_LWM2M_VERSION; 56 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TRANSPORT_DEFAULT_LWM2M_VERSION;
61 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;  
62 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; 57 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
63 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; 58 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName;
  59 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
64 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId; 60 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId;
65 61
66 @Slf4j 62 @Slf4j
@@ -76,9 +72,7 @@ public class LwM2mClient implements Cloneable { @@ -76,9 +72,7 @@ public class LwM2mClient implements Cloneable {
76 @Getter 72 @Getter
77 private final Map<String, ResourceValue> resources; 73 private final Map<String, ResourceValue> resources;
78 @Getter 74 @Getter
79 - private final Map<String, TsKvProto> delayedRequests;  
80 - @Getter  
81 - private final List<String> pendingReadRequests; 75 + private final Map<String, TsKvProto> sharedAttributes;
82 @Getter 76 @Getter
83 private final Queue<LwM2mQueuedRequest> queuedRequests; 77 private final Queue<LwM2mQueuedRequest> queuedRequests;
84 78
@@ -92,6 +86,8 @@ public class LwM2mClient implements Cloneable { @@ -92,6 +86,8 @@ public class LwM2mClient implements Cloneable {
92 @Getter 86 @Getter
93 private SecurityInfo securityInfo; 87 private SecurityInfo securityInfo;
94 @Getter 88 @Getter
  89 + private TenantId tenantId;
  90 + @Getter
95 private UUID deviceId; 91 private UUID deviceId;
96 @Getter 92 @Getter
97 private SessionInfoProto session; 93 private SessionInfoProto session;
@@ -99,19 +95,10 @@ public class LwM2mClient implements Cloneable { @@ -99,19 +95,10 @@ public class LwM2mClient implements Cloneable {
99 private UUID profileId; 95 private UUID profileId;
100 @Getter 96 @Getter
101 @Setter 97 @Setter
102 - private volatile LwM2mFwSwUpdate fwUpdate;  
103 - @Getter  
104 - @Setter  
105 - private volatile LwM2mFwSwUpdate swUpdate;  
106 - @Getter  
107 - @Setter  
108 private Registration registration; 98 private Registration registration;
109 99
110 private ValidateDeviceCredentialsResponse credentials; 100 private ValidateDeviceCredentialsResponse credentials;
111 101
112 - @Getter  
113 - private boolean init;  
114 -  
115 public Object clone() throws CloneNotSupportedException { 102 public Object clone() throws CloneNotSupportedException {
116 return super.clone(); 103 return super.clone();
117 } 104 }
@@ -120,26 +107,22 @@ public class LwM2mClient implements Cloneable { @@ -120,26 +107,22 @@ public class LwM2mClient implements Cloneable {
120 this.nodeId = nodeId; 107 this.nodeId = nodeId;
121 this.endpoint = endpoint; 108 this.endpoint = endpoint;
122 this.lock = new ReentrantLock(); 109 this.lock = new ReentrantLock();
123 - this.delayedRequests = new ConcurrentHashMap<>();  
124 - this.pendingReadRequests = new CopyOnWriteArrayList<>(); 110 + this.sharedAttributes = new ConcurrentHashMap<>();
125 this.resources = new ConcurrentHashMap<>(); 111 this.resources = new ConcurrentHashMap<>();
126 this.queuedRequests = new ConcurrentLinkedQueue<>(); 112 this.queuedRequests = new ConcurrentLinkedQueue<>();
127 this.state = LwM2MClientState.CREATED; 113 this.state = LwM2MClientState.CREATED;
128 } 114 }
129 115
130 - public void init(String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID profileId, UUID sessionId) { 116 + public void init(String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID sessionId) {
131 this.identity = identity; 117 this.identity = identity;
132 this.securityInfo = securityInfo; 118 this.securityInfo = securityInfo;
133 this.credentials = credentials; 119 this.credentials = credentials;
134 - this.profileId = profileId;  
135 - this.init = false;  
136 - if (this.credentials != null && this.credentials.hasDeviceInfo()) {  
137 - this.session = createSession(nodeId, sessionId, credentials);  
138 - this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB());  
139 - this.profileId = new UUID(session.getDeviceProfileIdMSB(), session.getDeviceProfileIdLSB());  
140 - this.deviceName = session.getDeviceName();  
141 - this.deviceProfileName = session.getDeviceType();  
142 - } 120 + this.session = createSession(nodeId, sessionId, credentials);
  121 + this.tenantId = new TenantId(new UUID(session.getTenantIdMSB(), session.getTenantIdLSB()));
  122 + this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB());
  123 + this.profileId = new UUID(session.getDeviceProfileIdMSB(), session.getDeviceProfileIdLSB());
  124 + this.deviceName = session.getDeviceName();
  125 + this.deviceProfileName = session.getDeviceType();
143 } 126 }
144 127
145 public void lock() { 128 public void lock() {
@@ -198,7 +181,7 @@ public class LwM2mClient implements Cloneable { @@ -198,7 +181,7 @@ public class LwM2mClient implements Cloneable {
198 this.resources.get(pathRezIdVer).setLwM2mResource(rez); 181 this.resources.get(pathRezIdVer).setLwM2mResource(rez);
199 return true; 182 return true;
200 } else { 183 } else {
201 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); 184 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer));
202 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); 185 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
203 if (resourceModel != null) { 186 if (resourceModel != null) {
204 this.resources.put(pathRezIdVer, new ResourceValue(rez, resourceModel)); 187 this.resources.put(pathRezIdVer, new ResourceValue(rez, resourceModel));
@@ -210,7 +193,7 @@ public class LwM2mClient implements Cloneable { @@ -210,7 +193,7 @@ public class LwM2mClient implements Cloneable {
210 } 193 }
211 194
212 public Object getResourceValue(String pathRezIdVer, String pathRezId) { 195 public Object getResourceValue(String pathRezIdVer, String pathRezId) {
213 - String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer; 196 + String pathRez = pathRezIdVer == null ? convertObjectIdToVersionedId(pathRezId, this.registration) : pathRezIdVer;
214 if (this.resources.get(pathRez) != null) { 197 if (this.resources.get(pathRez) != null) {
215 return this.resources.get(pathRez).getLwM2mResource().getValue(); 198 return this.resources.get(pathRez).getLwM2mResource().getValue();
216 } 199 }
@@ -218,7 +201,7 @@ public class LwM2mClient implements Cloneable { @@ -218,7 +201,7 @@ public class LwM2mClient implements Cloneable {
218 } 201 }
219 202
220 public Object getResourceNameByRezId(String pathRezIdVer, String pathRezId) { 203 public Object getResourceNameByRezId(String pathRezIdVer, String pathRezId) {
221 - String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer; 204 + String pathRez = pathRezIdVer == null ? convertObjectIdToVersionedId(pathRezId, this.registration) : pathRezIdVer;
222 if (this.resources.get(pathRez) != null) { 205 if (this.resources.get(pathRez) != null) {
223 return this.resources.get(pathRez).getResourceModel().name; 206 return this.resources.get(pathRez).getResourceModel().name;
224 } 207 }
@@ -226,7 +209,7 @@ public class LwM2mClient implements Cloneable { @@ -226,7 +209,7 @@ public class LwM2mClient implements Cloneable {
226 } 209 }
227 210
228 public String getRezIdByResourceNameAndObjectInstanceId(String resourceName, String pathObjectInstanceIdVer, LwM2mModelProvider modelProvider) { 211 public String getRezIdByResourceNameAndObjectInstanceId(String resourceName, String pathObjectInstanceIdVer, LwM2mModelProvider modelProvider) {
229 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathObjectInstanceIdVer)); 212 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathObjectInstanceIdVer));
230 if (pathIds.isObjectInstance()) { 213 if (pathIds.isObjectInstance()) {
231 Set<Integer> rezIds = modelProvider.getObjectModel(registration) 214 Set<Integer> rezIds = modelProvider.getObjectModel(registration)
232 .getObjectModel(pathIds.getObjectId()).resources.entrySet() 215 .getObjectModel(pathIds.getObjectId()).resources.entrySet()
@@ -240,7 +223,7 @@ public class LwM2mClient implements Cloneable { @@ -240,7 +223,7 @@ public class LwM2mClient implements Cloneable {
240 } 223 }
241 224
242 public ResourceModel getResourceModel(String pathIdVer, LwM2mModelProvider modelProvider) { 225 public ResourceModel getResourceModel(String pathIdVer, LwM2mModelProvider modelProvider) {
243 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)); 226 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer));
244 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); 227 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
245 String verRez = getVerFromPathIdVerOrId(pathIdVer); 228 String verRez = getVerFromPathIdVerOrId(pathIdVer);
246 return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) 229 return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
@@ -248,14 +231,14 @@ public class LwM2mClient implements Cloneable { @@ -248,14 +231,14 @@ public class LwM2mClient implements Cloneable {
248 } 231 }
249 232
250 public ObjectModel getObjectModel(String pathIdVer, LwM2mModelProvider modelProvider) { 233 public ObjectModel getObjectModel(String pathIdVer, LwM2mModelProvider modelProvider) {
251 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)); 234 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer));
252 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); 235 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
253 String verRez = getVerFromPathIdVerOrId(pathIdVer); 236 String verRez = getVerFromPathIdVerOrId(pathIdVer);
254 return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) 237 return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
255 .getObjectModel(pathIds.getObjectId()) : null; 238 .getObjectModel(pathIds.getObjectId()) : null;
256 } 239 }
257 240
258 - public String objectToString(LwM2mObject lwM2mObject, LwM2mValueConverterImpl converter, String pathIdVer) { 241 + public String objectToString(LwM2mObject lwM2mObject, LwM2mValueConverter converter, String pathIdVer) {
259 StringBuilder builder = new StringBuilder(); 242 StringBuilder builder = new StringBuilder();
260 builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={"); 243 builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={");
261 lwM2mObject.getInstances().forEach((instId, inst) -> { 244 lwM2mObject.getInstances().forEach((instId, inst) -> {
@@ -269,7 +252,7 @@ public class LwM2mClient implements Cloneable { @@ -269,7 +252,7 @@ public class LwM2mClient implements Cloneable {
269 return builder.toString(); 252 return builder.toString();
270 } 253 }
271 254
272 - public String instanceToString(LwM2mObjectInstance objectInstance, LwM2mValueConverterImpl converter, String pathIdVer) { 255 + public String instanceToString(LwM2mObjectInstance objectInstance, LwM2mValueConverter converter, String pathIdVer) {
273 StringBuilder builder = new StringBuilder(); 256 StringBuilder builder = new StringBuilder();
274 builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={"); 257 builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={");
275 objectInstance.getResources().forEach((resId, res) -> { 258 objectInstance.getResources().forEach((resId, res) -> {
@@ -283,25 +266,18 @@ public class LwM2mClient implements Cloneable { @@ -283,25 +266,18 @@ public class LwM2mClient implements Cloneable {
283 return builder.toString(); 266 return builder.toString();
284 } 267 }
285 268
286 - public String resourceToString(LwM2mResource lwM2mResource, LwM2mValueConverterImpl converter, String pathIdVer) {  
287 - if (!OPAQUE.equals(lwM2mResource.getType())) {  
288 - return lwM2mResource.isMultiInstances() ? ((LwM2mMultipleResource) lwM2mResource).toString() :  
289 - ((LwM2mSingleResource) lwM2mResource).toString();  
290 - } else {  
291 - return String.format("LwM2mSingleResource [id=%s, value=%s, type=%s]", lwM2mResource.getId(),  
292 - converter.convertValue(lwM2mResource.getValue(),  
293 - OPAQUE, STRING, new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))), lwM2mResource.getType().name());  
294 - } 269 + public String resourceToString(LwM2mResource lwM2mResource, LwM2mValueConverter converter, String pathIdVer) {
  270 + return lwM2mResource.getValue().toString();
295 } 271 }
296 272
297 public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider, 273 public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
298 - LwM2mValueConverterImpl converter) {  
299 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); 274 + LwM2mValueConverter converter) {
  275 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer));
300 Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet(); 276 Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
301 Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration) 277 Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
302 .getObjectModel(pathIds.getObjectId()).resources; 278 .getObjectModel(pathIds.getObjectId()).resources;
303 resourceModels.forEach((resId, resourceModel) -> { 279 resourceModels.forEach((resId, resourceModel) -> {
304 - if (resId == pathIds.getResourceId()) { 280 + if (resId.equals(pathIds.getResourceId())) {
305 resources.add(LwM2mSingleResource.newResource(resId, converter.convertValue(params, 281 resources.add(LwM2mSingleResource.newResource(resId, converter.convertValue(params,
306 equalsResourceTypeGetSimpleName(params), resourceModel.type, pathIds), resourceModel.type)); 282 equalsResourceTypeGetSimpleName(params), resourceModel.type, pathIds), resourceModel.type));
307 283
@@ -311,14 +287,14 @@ public class LwM2mClient implements Cloneable { @@ -311,14 +287,14 @@ public class LwM2mClient implements Cloneable {
311 } 287 }
312 288
313 public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider, 289 public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
314 - LwM2mValueConverterImpl converter) {  
315 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); 290 + LwM2mValueConverter converter) {
  291 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer));
316 Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet(); 292 Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
317 Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration) 293 Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
318 .getObjectModel(pathIds.getObjectId()).resources; 294 .getObjectModel(pathIds.getObjectId()).resources;
319 resourceModels.forEach((resId, resourceModel) -> { 295 resourceModels.forEach((resId, resourceModel) -> {
320 - if (((ConcurrentHashMap) params).containsKey(String.valueOf(resId))) {  
321 - Object value = ((ConcurrentHashMap) params).get((String.valueOf(resId))); 296 + if (((Map) params).containsKey(String.valueOf(resId))) {
  297 + Object value = ((Map) params).get((String.valueOf(resId)));
322 resources.add(LwM2mSingleResource.newResource(resId, 298 resources.add(LwM2mSingleResource.newResource(resId,
323 converter.convertValue(value, equalsResourceTypeGetSimpleName(value), resourceModel.type, pathIds), resourceModel.type)); 299 converter.convertValue(value, equalsResourceTypeGetSimpleName(value), resourceModel.type, pathIds), resourceModel.type));
324 300
@@ -328,7 +304,7 @@ public class LwM2mClient implements Cloneable { @@ -328,7 +304,7 @@ public class LwM2mClient implements Cloneable {
328 } 304 }
329 305
330 public boolean isValidObjectVersion(String path) { 306 public boolean isValidObjectVersion(String path) {
331 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(path)); 307 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path));
332 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); 308 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
333 String verRez = getVerFromPathIdVerOrId(path); 309 String verRez = getVerFromPathIdVerOrId(path);
334 return verRez == null ? TRANSPORT_DEFAULT_LWM2M_VERSION.equals(verSupportedObject) : verRez.equals(verSupportedObject); 310 return verRez == null ? TRANSPORT_DEFAULT_LWM2M_VERSION.equals(verSupportedObject) : verRez.equals(verSupportedObject);
@@ -341,7 +317,7 @@ public class LwM2mClient implements Cloneable { @@ -341,7 +317,7 @@ public class LwM2mClient implements Cloneable {
341 public void deleteResources(String pathIdVer, LwM2mModelProvider modelProvider) { 317 public void deleteResources(String pathIdVer, LwM2mModelProvider modelProvider) {
342 Set<String> key = getKeysEqualsIdVer(pathIdVer); 318 Set<String> key = getKeysEqualsIdVer(pathIdVer);
343 key.forEach(pathRez -> { 319 key.forEach(pathRez -> {
344 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez)); 320 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRez));
345 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); 321 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
346 if (resourceModel != null) { 322 if (resourceModel != null) {
347 this.resources.get(pathRez).setResourceModel(resourceModel); 323 this.resources.get(pathRez).setResourceModel(resourceModel);
@@ -361,7 +337,7 @@ public class LwM2mClient implements Cloneable { @@ -361,7 +337,7 @@ public class LwM2mClient implements Cloneable {
361 } 337 }
362 338
363 private void saveResourceModel(String pathRez, LwM2mModelProvider modelProvider) { 339 private void saveResourceModel(String pathRez, LwM2mModelProvider modelProvider) {
364 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez)); 340 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRez));
365 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); 341 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
366 this.resources.get(pathRez).setResourceModel(resourceModel); 342 this.resources.get(pathRez).setResourceModel(resourceModel);
367 } 343 }
@@ -373,16 +349,6 @@ public class LwM2mClient implements Cloneable { @@ -373,16 +349,6 @@ public class LwM2mClient implements Cloneable {
373 .collect(Collectors.toSet()); 349 .collect(Collectors.toSet());
374 } 350 }
375 351
376 - public void initReadValue(DefaultLwM2MTransportMsgHandler serviceImpl, String path) {  
377 - if (path != null) {  
378 - this.pendingReadRequests.remove(path);  
379 - }  
380 - if (this.pendingReadRequests.size() == 0) {  
381 - this.init = true;  
382 - serviceImpl.putDelayedUpdateResourcesThingsboard(this);  
383 - }  
384 - }  
385 -  
386 public ContentFormat getDefaultContentFormat() { 352 public ContentFormat getDefaultContentFormat() {
387 if (registration == null) { 353 if (registration == null) {
388 return ContentFormat.DEFAULT; 354 return ContentFormat.DEFAULT;
@@ -393,21 +359,5 @@ public class LwM2mClient implements Cloneable { @@ -393,21 +359,5 @@ public class LwM2mClient implements Cloneable {
393 } 359 }
394 } 360 }
395 361
396 - public LwM2mFwSwUpdate getFwUpdate (LwM2mClientContext clientContext) {  
397 - if (this.fwUpdate == null) {  
398 - LwM2mClientProfile lwM2mClientProfile = clientContext.getProfile(this.getProfileId());  
399 - this.fwUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.FIRMWARE, lwM2mClientProfile.getFwUpdateStrategy());  
400 - }  
401 - return this.fwUpdate;  
402 - }  
403 -  
404 - public LwM2mFwSwUpdate getSwUpdate (LwM2mClientContext clientContext) {  
405 - if (this.swUpdate == null) {  
406 - LwM2mClientProfile lwM2mClientProfile = clientContext.getProfile(this.getProfileId());  
407 - this.swUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.SOFTWARE, lwM2mClientProfile.getSwUpdateStrategy());  
408 - }  
409 - return this.fwUpdate;  
410 - }  
411 -  
412 } 362 }
413 363
@@ -17,11 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.client; @@ -17,11 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.client;
17 17
18 import org.eclipse.leshan.server.registration.Registration; 18 import org.eclipse.leshan.server.registration.Registration;
19 import org.thingsboard.server.common.data.DeviceProfile; 19 import org.thingsboard.server.common.data.DeviceProfile;
  20 +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
20 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 21 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
21 import org.thingsboard.server.gen.transport.TransportProtos; 22 import org.thingsboard.server.gen.transport.TransportProtos;
22 23
23 import java.util.Collection; 24 import java.util.Collection;
24 -import java.util.Map; 25 +import java.util.Optional;
25 import java.util.Set; 26 import java.util.Set;
26 import java.util.UUID; 27 import java.util.UUID;
27 28
@@ -33,7 +34,7 @@ public interface LwM2mClientContext { @@ -33,7 +34,7 @@ public interface LwM2mClientContext {
33 34
34 LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo); 35 LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo);
35 36
36 - void register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException; 37 + Optional<TransportProtos.SessionInfoProto> register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException;
37 38
38 void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException; 39 void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException;
39 40
@@ -41,21 +42,21 @@ public interface LwM2mClientContext { @@ -41,21 +42,21 @@ public interface LwM2mClientContext {
41 42
42 Collection<LwM2mClient> getLwM2mClients(); 43 Collection<LwM2mClient> getLwM2mClients();
43 44
44 - Map<UUID, LwM2mClientProfile> getProfiles(); 45 + //TODO: replace UUID with DeviceProfileId
  46 + Lwm2mDeviceProfileTransportConfiguration getProfile(UUID profileUuId);
45 47
46 - LwM2mClientProfile getProfile(UUID profileUuId); 48 + Lwm2mDeviceProfileTransportConfiguration getProfile(Registration registration);
47 49
48 - LwM2mClientProfile getProfile(Registration registration);  
49 -  
50 - Map<UUID, LwM2mClientProfile> setProfiles(Map<UUID, LwM2mClientProfile> profiles);  
51 -  
52 - LwM2mClientProfile profileUpdate(DeviceProfile deviceProfile); 50 + Lwm2mDeviceProfileTransportConfiguration profileUpdate(DeviceProfile deviceProfile);
53 51
54 Set<String> getSupportedIdVerInClient(LwM2mClient registration); 52 Set<String> getSupportedIdVerInClient(LwM2mClient registration);
55 53
56 LwM2mClient getClientByDeviceId(UUID deviceId); 54 LwM2mClient getClientByDeviceId(UUID deviceId);
57 55
58 - void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials); 56 + String getObjectIdByKeyNameFromProfile(TransportProtos.SessionInfoProto sessionInfo, String keyName);
59 57
  58 + String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName);
  59 +
  60 + void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials);
60 61
61 } 62 }
@@ -17,13 +17,16 @@ package org.thingsboard.server.transport.lwm2m.server.client; @@ -17,13 +17,16 @@ package org.thingsboard.server.transport.lwm2m.server.client;
17 17
18 import lombok.RequiredArgsConstructor; 18 import lombok.RequiredArgsConstructor;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.leshan.core.model.ResourceModel;
20 import org.eclipse.leshan.core.node.LwM2mPath; 21 import org.eclipse.leshan.core.node.LwM2mPath;
21 import org.eclipse.leshan.server.registration.Registration; 22 import org.eclipse.leshan.server.registration.Registration;
22 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
23 import org.thingsboard.server.common.data.DeviceProfile; 24 import org.thingsboard.server.common.data.DeviceProfile;
  25 +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
24 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 26 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
25 import org.thingsboard.server.gen.transport.TransportProtos; 27 import org.thingsboard.server.gen.transport.TransportProtos;
26 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 28 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
  29 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
27 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; 30 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
28 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; 31 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
29 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; 32 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
@@ -39,7 +42,9 @@ import java.util.concurrent.ConcurrentHashMap; @@ -39,7 +42,9 @@ import java.util.concurrent.ConcurrentHashMap;
39 import java.util.function.Predicate; 42 import java.util.function.Predicate;
40 43
41 import static org.eclipse.leshan.core.SecurityMode.NO_SEC; 44 import static org.eclipse.leshan.core.SecurityMode.NO_SEC;
42 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; 45 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
  46 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
  47 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validateObjectVerFromKey;
43 48
44 @Slf4j 49 @Slf4j
45 @Service 50 @Service
@@ -48,10 +53,11 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c @@ -48,10 +53,11 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c
48 public class LwM2mClientContextImpl implements LwM2mClientContext { 53 public class LwM2mClientContextImpl implements LwM2mClientContext {
49 54
50 private final LwM2mTransportContext context; 55 private final LwM2mTransportContext context;
  56 + private final LwM2MTransportServerConfig config;
51 private final TbEditableSecurityStore securityStore; 57 private final TbEditableSecurityStore securityStore;
52 private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); 58 private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>();
53 private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); 59 private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>();
54 - private Map<UUID, LwM2mClientProfile> profiles = new ConcurrentHashMap<>(); 60 + private final Map<UUID, Lwm2mDeviceProfileTransportConfiguration> profiles = new ConcurrentHashMap<>();
55 61
56 @Override 62 @Override
57 public LwM2mClient getClientByEndpoint(String endpoint) { 63 public LwM2mClient getClientByEndpoint(String endpoint) {
@@ -59,20 +65,22 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -59,20 +65,22 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
59 } 65 }
60 66
61 @Override 67 @Override
62 - public void register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException { 68 + public Optional<TransportProtos.SessionInfoProto> register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException {
  69 + TransportProtos.SessionInfoProto oldSession = null;
63 lwM2MClient.lock(); 70 lwM2MClient.lock();
64 try { 71 try {
65 if (LwM2MClientState.UNREGISTERED.equals(lwM2MClient.getState())) { 72 if (LwM2MClientState.UNREGISTERED.equals(lwM2MClient.getState())) {
66 throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); 73 throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state.");
67 } 74 }
  75 + oldSession = lwM2MClient.getSession();
68 TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(lwM2MClient.getEndpoint()); 76 TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(lwM2MClient.getEndpoint());
69 if (securityInfo.getSecurityMode() != null) { 77 if (securityInfo.getSecurityMode() != null) {
70 if (securityInfo.getDeviceProfile() != null) { 78 if (securityInfo.getDeviceProfile() != null) {
71 - UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile()) != null ? securityInfo.getDeviceProfile().getUuidId() : null; 79 + profileUpdate(securityInfo.getDeviceProfile());
72 if (securityInfo.getSecurityInfo() != null) { 80 if (securityInfo.getSecurityInfo() != null) {
73 - lwM2MClient.init(securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(), securityInfo.getMsg(), profileUuid, UUID.randomUUID()); 81 + lwM2MClient.init(securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(), securityInfo.getMsg(), UUID.randomUUID());
74 } else if (NO_SEC.equals(securityInfo.getSecurityMode())) { 82 } else if (NO_SEC.equals(securityInfo.getSecurityMode())) {
75 - lwM2MClient.init(null, null, securityInfo.getMsg(), profileUuid, UUID.randomUUID()); 83 + lwM2MClient.init(null, null, securityInfo.getMsg(), UUID.randomUUID());
76 } else { 84 } else {
77 throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint())); 85 throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint()));
78 } 86 }
@@ -88,6 +96,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -88,6 +96,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
88 } finally { 96 } finally {
89 lwM2MClient.unlock(); 97 lwM2MClient.unlock();
90 } 98 }
  99 + return Optional.ofNullable(oldSession);
91 } 100 }
92 101
93 @Override 102 @Override
@@ -156,6 +165,28 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -156,6 +165,28 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
156 return lwM2mClient; 165 return lwM2mClient;
157 } 166 }
158 167
  168 + /**
  169 + * Get path to resource from profile equal keyName
  170 + *
  171 + * @param sessionInfo -
  172 + * @param keyName -
  173 + * @return -
  174 + */
  175 + @Override
  176 + public String getObjectIdByKeyNameFromProfile(TransportProtos.SessionInfoProto sessionInfo, String keyName) {
  177 + return getObjectIdByKeyNameFromProfile(getClientBySessionInfo(sessionInfo), keyName);
  178 + }
  179 +
  180 + @Override
  181 + public String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName) {
  182 + Lwm2mDeviceProfileTransportConfiguration profile = getProfile(lwM2mClient.getProfileId());
  183 +
  184 + return profile.getObserveAttr().getKeyName().entrySet().stream()
  185 + .filter(e -> e.getValue().equals(keyName) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().orElseThrow(
  186 + () -> new IllegalArgumentException(keyName + " is not configured in the device profile!")
  187 + ).getKey();
  188 + }
  189 +
159 public Registration getRegistration(String registrationId) { 190 public Registration getRegistration(String registrationId) {
160 return this.lwM2mClientsByRegistrationId.get(registrationId).getRegistration(); 191 return this.lwM2mClientsByRegistrationId.get(registrationId).getRegistration();
161 } 192 }
@@ -163,7 +194,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -163,7 +194,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
163 @Override 194 @Override
164 public void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials) { 195 public void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials) {
165 LwM2mClient client = getClientByEndpoint(registration.getEndpoint()); 196 LwM2mClient client = getClientByEndpoint(registration.getEndpoint());
166 - client.init(null, null, credentials, credentials.getDeviceProfile().getUuidId(), UUID.randomUUID()); 197 + client.init(null, null, credentials, UUID.randomUUID());
167 lwM2mClientsByRegistrationId.put(registration.getId(), client); 198 lwM2mClientsByRegistrationId.put(registration.getId(), client);
168 profileUpdate(credentials.getDeviceProfile()); 199 profileUpdate(credentials.getDeviceProfile());
169 } 200 }
@@ -174,35 +205,20 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -174,35 +205,20 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
174 } 205 }
175 206
176 @Override 207 @Override
177 - public Map<UUID, LwM2mClientProfile> getProfiles() {  
178 - return profiles;  
179 - }  
180 -  
181 - @Override  
182 - public LwM2mClientProfile getProfile(UUID profileId) { 208 + public Lwm2mDeviceProfileTransportConfiguration getProfile(UUID profileId) {
183 return profiles.get(profileId); 209 return profiles.get(profileId);
184 } 210 }
185 211
186 @Override 212 @Override
187 - public LwM2mClientProfile getProfile(Registration registration) {  
188 - return this.getProfiles().get(getClientByEndpoint(registration.getEndpoint()).getProfileId());  
189 - }  
190 -  
191 - @Override  
192 - public Map<UUID, LwM2mClientProfile> setProfiles(Map<UUID, LwM2mClientProfile> profiles) {  
193 - return this.profiles = profiles; 213 + public Lwm2mDeviceProfileTransportConfiguration getProfile(Registration registration) {
  214 + return profiles.get(getClientByEndpoint(registration.getEndpoint()).getProfileId());
194 } 215 }
195 216
196 @Override 217 @Override
197 - public LwM2mClientProfile profileUpdate(DeviceProfile deviceProfile) {  
198 - LwM2mClientProfile lwM2MClientProfile = deviceProfile != null ?  
199 - LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile) : null;  
200 - if (lwM2MClientProfile != null) {  
201 - profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile);  
202 - return lwM2MClientProfile;  
203 - } else {  
204 - return null;  
205 - } 218 + public Lwm2mDeviceProfileTransportConfiguration profileUpdate(DeviceProfile deviceProfile) {
  219 + Lwm2mDeviceProfileTransportConfiguration lwM2MClientProfile = LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile);
  220 + profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile);
  221 + return lwM2MClientProfile;
206 } 222 }
207 223
208 @Override 224 @Override
@@ -211,7 +227,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -211,7 +227,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
211 Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> { 227 Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> {
212 LwM2mPath pathIds = new LwM2mPath(link.getUrl()); 228 LwM2mPath pathIds = new LwM2mPath(link.getUrl());
213 if (!pathIds.isRoot()) { 229 if (!pathIds.isRoot()) {
214 - clientObjects.add(convertPathFromObjectIdToIdVer(link.getUrl(), client.getRegistration())); 230 + clientObjects.add(convertObjectIdToVersionedId(link.getUrl(), client.getRegistration()));
215 } 231 }
216 }); 232 });
217 return (clientObjects.size() > 0) ? clientObjects : null; 233 return (clientObjects.size() > 0) ? clientObjects : null;
@@ -222,4 +238,14 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -222,4 +238,14 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
222 return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null); 238 return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null);
223 } 239 }
224 240
  241 + private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) {
  242 + ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer, this.config
  243 + .getModelProvider());
  244 + Integer objectId = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)).getObjectId();
  245 + String objectVer = validateObjectVerFromKey(pathIdVer);
  246 + return resourceModel != null && (isWritableNotOptional ?
  247 + objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() :
  248 + objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)));
  249 + }
  250 +
225 } 251 }
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.client;  
17 -  
18 -import com.google.gson.Gson;  
19 -import com.google.gson.JsonArray;  
20 -import com.google.gson.JsonObject;  
21 -import lombok.Data;  
22 -import org.thingsboard.server.common.data.id.TenantId;  
23 -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MClientStrategy;  
24 -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy;  
25 -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MSoftwareUpdateStrategy;  
26 -  
27 -@Data  
28 -public class LwM2mClientProfile {  
29 - private final String clientStrategyStr = "clientStrategy";  
30 - private final String fwUpdateStrategyStr = "fwUpdateStrategy";  
31 - private final String swUpdateStrategyStr = "swUpdateStrategy";  
32 -  
33 - private TenantId tenantId;  
34 - /**  
35 - * "clientLwM2mSettings": {  
36 - * "fwUpdateStrategy": "1",  
37 - * "swUpdateStrategy": "1",  
38 - * "clientStrategy": "1"  
39 - * }  
40 - **/  
41 - private JsonObject postClientLwM2mSettings;  
42 -  
43 - /**  
44 - * {"keyName": {  
45 - * "/3_1.0/0/1": "modelNumber",  
46 - * "/3_1.0/0/0": "manufacturer",  
47 - * "/3_1.0/0/2": "serialNumber"  
48 - * }  
49 - **/  
50 - private JsonObject postKeyNameProfile;  
51 -  
52 - /**  
53 - * [ "/3_1.0/0/0", "/3_1.0/0/1"]  
54 - */  
55 - private JsonArray postAttributeProfile;  
56 -  
57 - /**  
58 - * [ "/3_1.0/0/0", "/3_1.0/0/2"]  
59 - */  
60 - private JsonArray postTelemetryProfile;  
61 -  
62 - /**  
63 - * [ "/3_1.0/0", "/3_1.0/0/1, "/3_1.0/0/2"]  
64 - */  
65 - private JsonArray postObserveProfile;  
66 -  
67 - /**  
68 - * "attributeLwm2m": {"/3_1.0": {"ver": "currentTimeTest11"},  
69 - * "/3_1.0/0": {"gt": 17},  
70 - * "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}}  
71 - */  
72 - private JsonObject postAttributeLwm2mProfile;  
73 -  
74 - public LwM2mClientProfile clone() {  
75 - LwM2mClientProfile lwM2mClientProfile = new LwM2mClientProfile();  
76 - lwM2mClientProfile.postClientLwM2mSettings = this.deepCopy(this.postClientLwM2mSettings, JsonObject.class);  
77 - lwM2mClientProfile.postKeyNameProfile = this.deepCopy(this.postKeyNameProfile, JsonObject.class);  
78 - lwM2mClientProfile.postAttributeProfile = this.deepCopy(this.postAttributeProfile, JsonArray.class);  
79 - lwM2mClientProfile.postTelemetryProfile = this.deepCopy(this.postTelemetryProfile, JsonArray.class);  
80 - lwM2mClientProfile.postObserveProfile = this.deepCopy(this.postObserveProfile, JsonArray.class);  
81 - lwM2mClientProfile.postAttributeLwm2mProfile = this.deepCopy(this.postAttributeLwm2mProfile, JsonObject.class);  
82 - return lwM2mClientProfile;  
83 - }  
84 -  
85 -  
86 - private <T> T deepCopy(T elements, Class<T> type) {  
87 - try {  
88 - Gson gson = new Gson();  
89 - return gson.fromJson(gson.toJson(elements), type);  
90 - } catch (Exception e) {  
91 - e.printStackTrace();  
92 - return null;  
93 - }  
94 - }  
95 -  
96 - public int getClientStrategy() {  
97 - return this.postClientLwM2mSettings.getAsJsonObject().has(this.clientStrategyStr) ?  
98 - Integer.parseInt(this.postClientLwM2mSettings.getAsJsonObject().get(this.clientStrategyStr).getAsString()) :  
99 - LwM2MClientStrategy.CLIENT_STRATEGY_1.code;  
100 - }  
101 -  
102 - public int getFwUpdateStrategy() {  
103 - return this.postClientLwM2mSettings.getAsJsonObject().has(this.fwUpdateStrategyStr) ?  
104 - Integer.parseInt(this.postClientLwM2mSettings.getAsJsonObject().get(this.fwUpdateStrategyStr).getAsString()) :  
105 - LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code;  
106 - }  
107 -  
108 - public int getSwUpdateStrategy() {  
109 - return this.postClientLwM2mSettings.getAsJsonObject().has(this.swUpdateStrategyStr) ?  
110 - Integer.parseInt(this.postClientLwM2mSettings.getAsJsonObject().get(this.swUpdateStrategyStr).getAsString()) :  
111 - LwM2MSoftwareUpdateStrategy.BINARY.code;  
112 - }  
113 -}