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 677 timeout: "${LWM2M_TIMEOUT:120000}"
678 678 recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
679 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 683 registration_store_pool_size: "${LWM2M_REGISTRATION_STORE_POOL_SIZE:100}"
683 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 685 log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}"
687 686 # Use redis for Security and Registration stores
688 687 redis.enabled: "${LWM2M_REDIS_ENABLED:false}"
... ...
... ... @@ -103,7 +103,9 @@ public class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest {
103 103 " }\n" +
104 104 " },\n" +
105 105 " \"clientLwM2mSettings\": {\n" +
106   - " \"clientOnlyObserveAfterConnect\": 1\n" +
  106 + " \"clientOnlyObserveAfterConnect\": 1,\n" +
  107 + " \"fwUpdateStrategy\": 1,\n" +
  108 + " \"swUpdateStrategy\": 1\n" +
107 109 " }\n" +
108 110 "}";
109 111
... ...
... ... @@ -17,11 +17,14 @@ package org.thingsboard.server.transport.lwm2m;
17 17
18 18 import org.eclipse.californium.core.network.config.NetworkConfig;
19 19 import org.eclipse.leshan.client.object.Security;
20   -import org.jetbrains.annotations.NotNull;
21 20 import org.junit.Assert;
22 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 25 import org.thingsboard.common.util.JacksonUtil;
24 26 import org.thingsboard.server.common.data.Device;
  27 +import org.thingsboard.server.common.data.OtaPackageInfo;
25 28 import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials;
26 29 import org.thingsboard.server.common.data.query.EntityData;
27 30 import org.thingsboard.server.common.data.query.EntityDataPageLink;
... ... @@ -43,6 +46,7 @@ import java.util.List;
43 46
44 47 import static org.eclipse.leshan.client.object.Security.noSec;
45 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 51 public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
48 52
... ... @@ -51,7 +55,6 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
51 55 private final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT));
52 56 private final String ENDPOINT = "deviceAEndpoint";
53 57
54   - @NotNull
55 58 private Device createDevice() throws Exception {
56 59 Device device = new Device();
57 60 device.setName("Device A");
... ... @@ -74,6 +77,29 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
74 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 103 @Test
78 104 public void testConnectAndObserveTelemetry() throws Exception {
79 105 createDeviceProfile(TRANSPORT_CONFIGURATION);
... ... @@ -111,4 +137,53 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
111 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 52 private final String endpoint = "deviceAEndpoint";
53 53 private final String serverUri = "coaps://localhost:" + port;
54 54
55   - @NotNull
56 55 private Device createDevice(X509ClientCredentials clientCredentials) throws Exception {
57 56 Device device = new Device();
58 57 device.setName("Device A");
... ...
... ... @@ -19,8 +19,10 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter;
19 19 import com.fasterxml.jackson.annotation.JsonAnySetter;
20 20 import com.fasterxml.jackson.annotation.JsonIgnore;
21 21 import lombok.Data;
22   -import org.thingsboard.server.common.data.DeviceProfileType;
23 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 27 import java.util.HashMap;
26 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 15 */
16 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 18 import lombok.Data;
22   -import org.thingsboard.server.common.data.DeviceProfileType;
23 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 24 @Data
29 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 33 @Override
45 34 public DeviceTransportType getType() {
... ...
... ... @@ -134,8 +134,8 @@ public class OtaPackageTransportResource extends AbstractCoapTransportResource {
134 134 response.setPayload(data);
135 135 if (exchange.getRequestOptions().getBlock2() != null) {
136 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 140 exchange.respond(response);
141 141 }
... ...
... ... @@ -15,9 +15,6 @@
15 15 */
16 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 18 import lombok.extern.slf4j.Slf4j;
22 19 import org.eclipse.leshan.core.SecurityMode;
23 20 import org.eclipse.leshan.core.util.Hex;
... ... @@ -29,6 +26,8 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore;
29 26 import org.eclipse.leshan.server.security.SecurityInfo;
30 27 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
31 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 31 import org.thingsboard.server.gen.transport.TransportProtos;
33 32 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
34 33 import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
... ... @@ -43,12 +42,9 @@ import java.util.Collections;
43 42 import java.util.Iterator;
44 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 48 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getBootstrapParametersFromThingsboard;
53 49
54 50 @Slf4j
... ... @@ -151,35 +147,30 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
151 147 }
152 148
153 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 174 log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint());
184 175 return null;
185 176 }
... ...
... ... @@ -57,30 +57,22 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
57 57 private boolean recommendedSupportedGroups;
58 58
59 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 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 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 71 @Getter
72 72 @Value("${transport.lwm2m.clean_period_in_sec:}")
73 73 private int cleanPeriodInSec;
74 74
75 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 76 @Value("${transport.lwm2m.security.key_store_type:}")
85 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 26 import org.eclipse.leshan.server.californium.LeshanServerBuilder;
27 27 import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
28 28 import org.eclipse.leshan.server.model.LwM2mModelProvider;
29   -import org.eclipse.leshan.server.security.EditableSecurityStore;
30 29 import org.springframework.stereotype.Component;
  30 +import org.thingsboard.server.cache.ota.OtaPackageDataCache;
31 31 import org.thingsboard.server.common.data.StringUtils;
32 32 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
33 33 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
... ... @@ -35,8 +35,8 @@ import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC;
35 35 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer;
36 36 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier;
37 37 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
38   -import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore;
39 38 import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore;
  39 +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
40 40 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
41 41
42 42 import javax.annotation.PostConstruct;
... ... @@ -81,7 +81,8 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
81 81 private final LwM2mTransportContext context;
82 82 private final LwM2MTransportServerConfig config;
83 83 private final LwM2mTransportServerHelper helper;
84   - private final DefaultLwM2MTransportMsgHandler handler;
  84 + private final OtaPackageDataCache otaPackageDataCache;
  85 + private final DefaultLwM2MUplinkMsgHandler handler;
85 86 private final CaliforniumRegistrationStore registrationStore;
86 87 private final TbSecurityStore securityStore;
87 88 private final LwM2mClientContext lwM2mClientContext;
... ... @@ -104,8 +105,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
104 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 109 this.server.coap().getServer().add(otaCoapResource);
110 110 this.startLhServer();
111 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 84 Create new instance of udp endpoint context matcher.
85 85 Params:
86 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 88 - false, without
89 89 */
90   - coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "STRICT");
  90 + coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED");
91 91 /**
92 92 https://tools.ietf.org/html/rfc7959#section-2.9.3
93 93 The block size (number of bytes) to use when doing a blockwise transfer. \
... ... @@ -103,7 +103,7 @@ public class LwM2mNetworkConfig {
103 103 */
104 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 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 23 import org.eclipse.leshan.server.registration.Registration;
24 24 import org.eclipse.leshan.server.registration.RegistrationListener;
25 25 import org.eclipse.leshan.server.registration.RegistrationUpdate;
  26 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
26 27
27 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 32 @Slf4j
33 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 38 this.service = service;
39 39 }
40 40
... ... @@ -86,30 +86,24 @@ public class LwM2mServerListener {
86 86
87 87 @Override
88 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 92 @Override
95 93 public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
96 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 99 @Override
103 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 104 @Override
108 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 17
18 18 import io.netty.util.concurrent.Future;
19 19 import io.netty.util.concurrent.GenericFutureListener;
  20 +import lombok.RequiredArgsConstructor;
20 21 import lombok.extern.slf4j.Slf4j;
21 22 import org.jetbrains.annotations.NotNull;
22 23 import org.thingsboard.server.common.data.Device;
... ... @@ -30,28 +31,29 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotifica
30 31 import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg;
31 32 import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg;
32 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 38 import java.util.Optional;
35 39 import java.util.UUID;
36 40
37 41 @Slf4j
  42 +@RequiredArgsConstructor
38 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 49 @Override
48 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 54 @Override
53 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 59 @Override
... ... @@ -76,12 +78,12 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s
76 78
77 79 @Override
78 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 84 @Override
83 85 public void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse) {
84   - this.handler.onToServerRpcResponse(toServerResponse);
  86 + this.rpcHandler.onToServerRpcResponse(toServerResponse);
85 87 }
86 88
87 89 @Override
... ...
... ... @@ -24,6 +24,9 @@ import org.eclipse.californium.core.observe.ObserveRelation;
24 24 import org.eclipse.californium.core.server.resources.CoapExchange;
25 25 import org.eclipse.californium.core.server.resources.Resource;
26 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 31 import java.util.UUID;
29 32 import java.util.concurrent.ConcurrentHashMap;
... ... @@ -37,11 +40,11 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.S
37 40 public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
38 41 private final ConcurrentMap<String, ObserveRelation> tokenToObserveRelationMap = new ConcurrentHashMap<>();
39 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 46 super(name);
44   - this.handler = handler;
  47 + this.otaPackageDataCache = otaPackageDataCache;
45 48 this.setObservable(true); // enable observing
46 49 this.addObserver(new CoapResourceObserver());
47 50 }
... ... @@ -140,9 +143,9 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
140 143 response.setPayload(fwData);
141 144 if (exchange.getRequestOptions().getBlock2() != null) {
142 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 150 else {
148 151 log.warn("92) with block1 Send currentId: [{}], length: [{}], ", currentId.toString(), fwData.length);
... ... @@ -152,7 +155,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
152 155 }
153 156
154 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 37 import org.eclipse.leshan.core.model.InvalidDDFFileException;
38 38 import org.eclipse.leshan.core.model.ObjectModel;
39 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 42 import org.eclipse.leshan.core.node.codec.CodecException;
41 43 import org.eclipse.leshan.core.request.ContentFormat;
42 44 import org.springframework.stereotype.Component;
... ... @@ -48,6 +50,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
48 50 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
49 51 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
50 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 56 import java.io.ByteArrayInputStream;
53 57 import java.io.IOException;
... ... @@ -57,6 +61,7 @@ import java.util.concurrent.TimeUnit;
57 61 import java.util.concurrent.atomic.AtomicInteger;
58 62
59 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 66 @Slf4j
62 67 @Component
... ... @@ -67,37 +72,15 @@ public class LwM2mTransportServerHelper {
67 72 private final LwM2mTransportContext context;
68 73 private final AtomicInteger atomicTs = new AtomicInteger(0);
69 74
70   -
71 75 public long getTS() {
72 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 79 public void sendParametersOnThingsboardAttribute(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
96 80 PostAttributeMsg.Builder request = PostAttributeMsg.newBuilder();
97 81 request.addAllKv(result);
98 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 86 public void sendParametersOnThingsboardTelemetry(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
... ... @@ -107,8 +90,7 @@ public class LwM2mTransportServerHelper {
107 90 builder.addAllKv(result);
108 91 request.addTsKvList(builder.build());
109 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 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 195 public static Object getValueFromKvProto(TransportProtos.KeyValueProto kv) {
236 196 switch (kv.getType()) {
237 197 case BOOLEAN_V:
... ... @@ -247,4 +207,5 @@ public class LwM2mTransportServerHelper {
247 207 }
248 208 return null;
249 209 }
  210 +
250 211 }
... ...
... ... @@ -16,13 +16,9 @@
16 16 package org.thingsboard.server.transport.lwm2m.server;
17 17
18 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 19 import com.google.gson.JsonObject;
23 20 import com.google.gson.JsonParser;
24 21 import com.google.gson.JsonSyntaxException;
25   -import com.google.gson.reflect.TypeToken;
26 22 import lombok.extern.slf4j.Slf4j;
27 23 import org.apache.commons.lang3.StringUtils;
28 24 import org.eclipse.leshan.core.attributes.Attribute;
... ... @@ -34,6 +30,7 @@ import org.eclipse.leshan.core.node.LwM2mNode;
34 30 import org.eclipse.leshan.core.node.LwM2mObject;
35 31 import org.eclipse.leshan.core.node.LwM2mObjectInstance;
36 32 import org.eclipse.leshan.core.node.LwM2mPath;
  33 +import org.eclipse.leshan.core.node.LwM2mResource;
37 34 import org.eclipse.leshan.core.node.LwM2mSingleResource;
38 35 import org.eclipse.leshan.core.node.codec.CodecException;
39 36 import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
... ... @@ -42,17 +39,19 @@ import org.eclipse.leshan.core.util.Hex;
42 39 import org.eclipse.leshan.server.registration.Registration;
43 40 import org.nustaq.serialization.FSTConfiguration;
44 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 45 import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
46   -import org.thingsboard.server.common.data.id.TenantId;
47 46 import org.thingsboard.server.common.data.ota.OtaPackageKey;
48 47 import org.thingsboard.server.common.data.ota.OtaPackageType;
49 48 import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
50 49 import org.thingsboard.server.common.data.ota.OtaPackageUtil;
51 50 import org.thingsboard.server.common.transport.TransportServiceCallback;
52 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 55 import java.util.ArrayList;
57 56 import java.util.Arrays;
58 57 import java.util.Date;
... ... @@ -60,7 +59,6 @@ import java.util.LinkedList;
60 59 import java.util.List;
61 60 import java.util.Map;
62 61 import java.util.Optional;
63   -import java.util.Set;
64 62 import java.util.concurrent.ConcurrentHashMap;
65 63
66 64 import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION;
... ... @@ -115,33 +113,17 @@ public class LwM2mTransportUtil {
115 113
116 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 122 public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized";
125 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 125 // Firmware
144   - public static final String FIRMWARE_UPDATE_COAP_RECOURSE = "firmwareUpdateCoapRecourse";
  126 + public static final String FIRMWARE_UPDATE_COAP_RECOURSE = "tbfw";
145 127 public static final String FW_UPDATE = "Firmware update";
146 128 public static final Integer FW_5_ID = 5;
147 129 public static final Integer FW_19_ID = 19;
... ... @@ -155,10 +137,14 @@ public class LwM2mTransportUtil {
155 137 public static final String FW_STATE_ID = "/5/0/3";
156 138 // Update Result R
157 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 143 // PkgName R
159 144 public static final String FW_NAME_ID = "/5/0/6";
160 145 // PkgVersion R
161 146 public static final String FW_5_VER_ID = "/5/0/7";
  147 +
162 148 /**
163 149 * Quectel@Hi15RM1-HLB_V1.0@BC68JAR01A10,V150R100C20B300SP7,V150R100C20B300SP7@8
164 150 * BC68JAR01A10
... ... @@ -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 205 switch (updateResultFw) {
400 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 210 case NOT_ENOUGH:
405 211 case OUT_OFF_MEMORY:
406 212 case CONNECTION_LOST:
... ... @@ -409,24 +215,24 @@ public class LwM2mTransportUtil {
409 215 case INVALID_URI:
410 216 case UPDATE_FAILED:
411 217 case UNSUPPORTED_PROTOCOL:
412   - return FAILED;
  218 + return Optional.of(FAILED);
413 219 default:
414 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 226 case IDLE:
421   - return VERIFIED;
  227 + return Optional.empty();
422 228 case DOWNLOADING:
423   - return DOWNLOADING;
  229 + return Optional.of(DOWNLOADING);
424 230 case DOWNLOADED:
425   - return DOWNLOADED;
  231 + return Optional.of(DOWNLOADED);
426 232 case UPDATING:
427   - return UPDATING;
  233 + return Optional.of(UPDATING);
428 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 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 384 * FirmwareUpdateStatus {
643 385 * DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
... ... @@ -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 442 LwM2mOtaConvert lwM2mOtaConvert = new LwM2mOtaConvert();
701 443 if (path != null) {
702 444 if (FW_STATE_ID.equals(path)) {
703 445 lwM2mOtaConvert.setCurrentType(STRING);
704   - lwM2mOtaConvert.setValue(StateFw.fromStateFwByCode(((Long) value).intValue()).type);
  446 + lwM2mOtaConvert.setValue(UpdateStateFw.fromStateFwByCode(((Long) value).intValue()).type);
705 447 return lwM2mOtaConvert;
706   - }
707   - else if (FW_RESULT_ID.equals(path)) {
  448 + } else if (FW_RESULT_ID.equals(path)) {
708 449 lwM2mOtaConvert.setCurrentType(STRING);
709   - lwM2mOtaConvert.setValue(UpdateResultFw.fromUpdateResultFwByCode(((Long) value).intValue()).type);
  450 + lwM2mOtaConvert.setValue(UpdateResultFw.fromUpdateResultFwByCode(((Long) value).intValue()).getType());
710 451 return lwM2mOtaConvert;
711   - }
712   - else if (SW_UPDATE_STATE_ID.equals(path)) {
  452 + } else if (SW_UPDATE_STATE_ID.equals(path)) {
713 453 lwM2mOtaConvert.setCurrentType(STRING);
714 454 lwM2mOtaConvert.setValue(UpdateStateSw.fromUpdateStateSwByCode(((Long) value).intValue()).type);
715 455 return lwM2mOtaConvert;
716   - }
717   - else if (SW_RESULT_ID.equals(path)) {
  456 + } else if (SW_RESULT_ID.equals(path)) {
718 457 lwM2mOtaConvert.setCurrentType(STRING);
719 458 lwM2mOtaConvert.setValue(UpdateResultSw.fromUpdateResultSwByCode(((Long) value).intValue()).type);
720 459 return lwM2mOtaConvert;
... ... @@ -738,112 +477,32 @@ public class LwM2mTransportUtil {
738 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 506 public static JsonObject validateJson(String jsonStr) {
848 507 JsonObject object = null;
849 508 if (jsonStr != null && !jsonStr.isEmpty()) {
... ... @@ -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 563 try {
  564 + if (pathIdVer == null) {
  565 + return null;
  566 + }
905 567 String[] keyArray = pathIdVer.split(LWM2M_SEPARATOR_PATH);
906 568 if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) {
907 569 keyArray[1] = keyArray[1].split(LWM2M_SEPARATOR_KEY)[0];
... ... @@ -910,7 +572,8 @@ public class LwM2mTransportUtil {
910 572 return pathIdVer;
911 573 }
912 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 604 return pathIdVer;
942 605 } else {
943 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 613 String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
951 614 ver = ver != null ? ver : LWM2M_VERSION_DEFAULT;
952 615 try {
... ... @@ -1001,12 +664,12 @@ public class LwM2mTransportUtil {
1001 664 * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60");
1002 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 668 AttributeSet attrSet = new AttributeSet(createWriteAttributes(params, serviceImpl, target));
1006 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 673 List<Attribute> attributeLists = new ArrayList<>();
1011 674 ObjectMapper oMapper = new ObjectMapper();
1012 675 Map<String, Object> map = oMapper.convertValue(params, ConcurrentHashMap.class);
... ... @@ -1024,12 +687,6 @@ public class LwM2mTransportUtil {
1024 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 690 public static ResourceModel.Type equalsResourceTypeGetSimpleName(Object value) {
1034 691 switch (value.getClass().getSimpleName()) {
1035 692 case "Double":
... ... @@ -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 712 switch (type) {
1064 713 /** Integer [0:255]; */
1065 714 case DIMENSION:
... ... @@ -1106,4 +755,20 @@ public class LwM2mTransportUtil {
1106 755 || OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM_ALGORITHM).equals(pathName)
1107 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 72
73 73 public DynamicModel(Registration registration) {
74 74 this.registration = registration;
75   - this.tenantId = lwM2mClientContext.getProfile(registration).getTenantId();
  75 + this.tenantId = lwM2mClientContext.getClientByEndpoint(registration.getEndpoint()).getTenantId();
76 76 }
77 77
78 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 20 import lombok.extern.slf4j.Slf4j;
21 21 import org.eclipse.leshan.core.model.ObjectModel;
22 22 import org.eclipse.leshan.core.model.ResourceModel;
23   -import org.eclipse.leshan.core.node.LwM2mMultipleResource;
24 23 import org.eclipse.leshan.core.node.LwM2mObject;
25 24 import org.eclipse.leshan.core.node.LwM2mObjectInstance;
26 25 import org.eclipse.leshan.core.node.LwM2mPath;
27 26 import org.eclipse.leshan.core.node.LwM2mResource;
28 27 import org.eclipse.leshan.core.node.LwM2mSingleResource;
  28 +import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
29 29 import org.eclipse.leshan.core.request.ContentFormat;
30 30 import org.eclipse.leshan.server.model.LwM2mModelProvider;
31 31 import org.eclipse.leshan.server.registration.Registration;
32 32 import org.eclipse.leshan.server.security.SecurityInfo;
33 33 import org.thingsboard.server.common.data.Device;
34 34 import org.thingsboard.server.common.data.DeviceProfile;
  35 +import org.thingsboard.server.common.data.id.TenantId;
35 36 import org.thingsboard.server.common.data.ota.OtaPackageType;
36 37 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
37 38 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
38 39 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
39   -import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;
40 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 43 import java.util.Collection;
44   -import java.util.List;
45 44 import java.util.Map;
46 45 import java.util.Optional;
47 46 import java.util.Queue;
... ... @@ -49,18 +48,15 @@ import java.util.Set;
49 48 import java.util.UUID;
50 49 import java.util.concurrent.ConcurrentHashMap;
51 50 import java.util.concurrent.ConcurrentLinkedQueue;
52   -import java.util.concurrent.CopyOnWriteArrayList;
53 51 import java.util.concurrent.locks.Lock;
54 52 import java.util.concurrent.locks.ReentrantLock;
55 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 55 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
60 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 58 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName;
  59 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
64 60 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId;
65 61
66 62 @Slf4j
... ... @@ -76,9 +72,7 @@ public class LwM2mClient implements Cloneable {
76 72 @Getter
77 73 private final Map<String, ResourceValue> resources;
78 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 76 @Getter
83 77 private final Queue<LwM2mQueuedRequest> queuedRequests;
84 78
... ... @@ -92,6 +86,8 @@ public class LwM2mClient implements Cloneable {
92 86 @Getter
93 87 private SecurityInfo securityInfo;
94 88 @Getter
  89 + private TenantId tenantId;
  90 + @Getter
95 91 private UUID deviceId;
96 92 @Getter
97 93 private SessionInfoProto session;
... ... @@ -99,19 +95,10 @@ public class LwM2mClient implements Cloneable {
99 95 private UUID profileId;
100 96 @Getter
101 97 @Setter
102   - private volatile LwM2mFwSwUpdate fwUpdate;
103   - @Getter
104   - @Setter
105   - private volatile LwM2mFwSwUpdate swUpdate;
106   - @Getter
107   - @Setter
108 98 private Registration registration;
109 99
110 100 private ValidateDeviceCredentialsResponse credentials;
111 101
112   - @Getter
113   - private boolean init;
114   -
115 102 public Object clone() throws CloneNotSupportedException {
116 103 return super.clone();
117 104 }
... ... @@ -120,26 +107,22 @@ public class LwM2mClient implements Cloneable {
120 107 this.nodeId = nodeId;
121 108 this.endpoint = endpoint;
122 109 this.lock = new ReentrantLock();
123   - this.delayedRequests = new ConcurrentHashMap<>();
124   - this.pendingReadRequests = new CopyOnWriteArrayList<>();
  110 + this.sharedAttributes = new ConcurrentHashMap<>();
125 111 this.resources = new ConcurrentHashMap<>();
126 112 this.queuedRequests = new ConcurrentLinkedQueue<>();
127 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 117 this.identity = identity;
132 118 this.securityInfo = securityInfo;
133 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 128 public void lock() {
... ... @@ -198,7 +181,7 @@ public class LwM2mClient implements Cloneable {
198 181 this.resources.get(pathRezIdVer).setLwM2mResource(rez);
199 182 return true;
200 183 } else {
201   - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer));
  184 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer));
202 185 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
203 186 if (resourceModel != null) {
204 187 this.resources.put(pathRezIdVer, new ResourceValue(rez, resourceModel));
... ... @@ -210,7 +193,7 @@ public class LwM2mClient implements Cloneable {
210 193 }
211 194
212 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 197 if (this.resources.get(pathRez) != null) {
215 198 return this.resources.get(pathRez).getLwM2mResource().getValue();
216 199 }
... ... @@ -218,7 +201,7 @@ public class LwM2mClient implements Cloneable {
218 201 }
219 202
220 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 205 if (this.resources.get(pathRez) != null) {
223 206 return this.resources.get(pathRez).getResourceModel().name;
224 207 }
... ... @@ -226,7 +209,7 @@ public class LwM2mClient implements Cloneable {
226 209 }
227 210
228 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 213 if (pathIds.isObjectInstance()) {
231 214 Set<Integer> rezIds = modelProvider.getObjectModel(registration)
232 215 .getObjectModel(pathIds.getObjectId()).resources.entrySet()
... ... @@ -240,7 +223,7 @@ public class LwM2mClient implements Cloneable {
240 223 }
241 224
242 225 public ResourceModel getResourceModel(String pathIdVer, LwM2mModelProvider modelProvider) {
243   - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));
  226 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer));
244 227 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
245 228 String verRez = getVerFromPathIdVerOrId(pathIdVer);
246 229 return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
... ... @@ -248,14 +231,14 @@ public class LwM2mClient implements Cloneable {
248 231 }
249 232
250 233 public ObjectModel getObjectModel(String pathIdVer, LwM2mModelProvider modelProvider) {
251   - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));
  234 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer));
252 235 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
253 236 String verRez = getVerFromPathIdVerOrId(pathIdVer);
254 237 return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
255 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 242 StringBuilder builder = new StringBuilder();
260 243 builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={");
261 244 lwM2mObject.getInstances().forEach((instId, inst) -> {
... ... @@ -269,7 +252,7 @@ public class LwM2mClient implements Cloneable {
269 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 256 StringBuilder builder = new StringBuilder();
274 257 builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={");
275 258 objectInstance.getResources().forEach((resId, res) -> {
... ... @@ -283,25 +266,18 @@ public class LwM2mClient implements Cloneable {
283 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 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 276 Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
301 277 Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
302 278 .getObjectModel(pathIds.getObjectId()).resources;
303 279 resourceModels.forEach((resId, resourceModel) -> {
304   - if (resId == pathIds.getResourceId()) {
  280 + if (resId.equals(pathIds.getResourceId())) {
305 281 resources.add(LwM2mSingleResource.newResource(resId, converter.convertValue(params,
306 282 equalsResourceTypeGetSimpleName(params), resourceModel.type, pathIds), resourceModel.type));
307 283
... ... @@ -311,14 +287,14 @@ public class LwM2mClient implements Cloneable {
311 287 }
312 288
313 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 292 Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
317 293 Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
318 294 .getObjectModel(pathIds.getObjectId()).resources;
319 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 298 resources.add(LwM2mSingleResource.newResource(resId,
323 299 converter.convertValue(value, equalsResourceTypeGetSimpleName(value), resourceModel.type, pathIds), resourceModel.type));
324 300
... ... @@ -328,7 +304,7 @@ public class LwM2mClient implements Cloneable {
328 304 }
329 305
330 306 public boolean isValidObjectVersion(String path) {
331   - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(path));
  307 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path));
332 308 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
333 309 String verRez = getVerFromPathIdVerOrId(path);
334 310 return verRez == null ? TRANSPORT_DEFAULT_LWM2M_VERSION.equals(verSupportedObject) : verRez.equals(verSupportedObject);
... ... @@ -341,7 +317,7 @@ public class LwM2mClient implements Cloneable {
341 317 public void deleteResources(String pathIdVer, LwM2mModelProvider modelProvider) {
342 318 Set<String> key = getKeysEqualsIdVer(pathIdVer);
343 319 key.forEach(pathRez -> {
344   - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
  320 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRez));
345 321 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
346 322 if (resourceModel != null) {
347 323 this.resources.get(pathRez).setResourceModel(resourceModel);
... ... @@ -361,7 +337,7 @@ public class LwM2mClient implements Cloneable {
361 337 }
362 338
363 339 private void saveResourceModel(String pathRez, LwM2mModelProvider modelProvider) {
364   - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
  340 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRez));
365 341 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
366 342 this.resources.get(pathRez).setResourceModel(resourceModel);
367 343 }
... ... @@ -373,16 +349,6 @@ public class LwM2mClient implements Cloneable {
373 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 352 public ContentFormat getDefaultContentFormat() {
387 353 if (registration == null) {
388 354 return ContentFormat.DEFAULT;
... ... @@ -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 17
18 18 import org.eclipse.leshan.server.registration.Registration;
19 19 import org.thingsboard.server.common.data.DeviceProfile;
  20 +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
20 21 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
21 22 import org.thingsboard.server.gen.transport.TransportProtos;
22 23
23 24 import java.util.Collection;
24   -import java.util.Map;
  25 +import java.util.Optional;
25 26 import java.util.Set;
26 27 import java.util.UUID;
27 28
... ... @@ -33,7 +34,7 @@ public interface LwM2mClientContext {
33 34
34 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 39 void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException;
39 40
... ... @@ -41,21 +42,21 @@ public interface LwM2mClientContext {
41 42
42 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 52 Set<String> getSupportedIdVerInClient(LwM2mClient registration);
55 53
56 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 17
18 18 import lombok.RequiredArgsConstructor;
19 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.leshan.core.model.ResourceModel;
20 21 import org.eclipse.leshan.core.node.LwM2mPath;
21 22 import org.eclipse.leshan.server.registration.Registration;
22 23 import org.springframework.stereotype.Service;
23 24 import org.thingsboard.server.common.data.DeviceProfile;
  25 +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
24 26 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
25 27 import org.thingsboard.server.gen.transport.TransportProtos;
26 28 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
  29 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
27 30 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
28 31 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
29 32 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
... ... @@ -39,7 +42,9 @@ import java.util.concurrent.ConcurrentHashMap;
39 42 import java.util.function.Predicate;
40 43
41 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 49 @Slf4j
45 50 @Service
... ... @@ -48,10 +53,11 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c
48 53 public class LwM2mClientContextImpl implements LwM2mClientContext {
49 54
50 55 private final LwM2mTransportContext context;
  56 + private final LwM2MTransportServerConfig config;
51 57 private final TbEditableSecurityStore securityStore;
52 58 private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>();
53 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 62 @Override
57 63 public LwM2mClient getClientByEndpoint(String endpoint) {
... ... @@ -59,20 +65,22 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
59 65 }
60 66
61 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 70 lwM2MClient.lock();
64 71 try {
65 72 if (LwM2MClientState.UNREGISTERED.equals(lwM2MClient.getState())) {
66 73 throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state.");
67 74 }
  75 + oldSession = lwM2MClient.getSession();
68 76 TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(lwM2MClient.getEndpoint());
69 77 if (securityInfo.getSecurityMode() != null) {
70 78 if (securityInfo.getDeviceProfile() != null) {
71   - UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile()) != null ? securityInfo.getDeviceProfile().getUuidId() : null;
  79 + profileUpdate(securityInfo.getDeviceProfile());
72 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 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 84 } else {
77 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 96 } finally {
89 97 lwM2MClient.unlock();
90 98 }
  99 + return Optional.ofNullable(oldSession);
91 100 }
92 101
93 102 @Override
... ... @@ -156,6 +165,28 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
156 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 190 public Registration getRegistration(String registrationId) {
160 191 return this.lwM2mClientsByRegistrationId.get(registrationId).getRegistration();
161 192 }
... ... @@ -163,7 +194,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
163 194 @Override
164 195 public void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials) {
165 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 198 lwM2mClientsByRegistrationId.put(registration.getId(), client);
168 199 profileUpdate(credentials.getDeviceProfile());
169 200 }
... ... @@ -174,35 +205,20 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
174 205 }
175 206
176 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 209 return profiles.get(profileId);
184 210 }
185 211
186 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 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 224 @Override
... ... @@ -211,7 +227,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
211 227 Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> {
212 228 LwM2mPath pathIds = new LwM2mPath(link.getUrl());
213 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 233 return (clientObjects.size() > 0) ? clientObjects : null;
... ... @@ -222,4 +238,14 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
222 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   -}