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 97 changed files with 5038 additions and 3674 deletions
... ... @@ -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   -}
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.JsonObject;
20   -import com.google.gson.reflect.TypeToken;
21   -import lombok.Data;
22   -import lombok.extern.slf4j.Slf4j;
23   -import org.apache.commons.lang3.StringUtils;
24   -import org.eclipse.leshan.core.node.LwM2mPath;
25   -import org.eclipse.leshan.server.registration.Registration;
26   -import org.thingsboard.server.gen.transport.TransportProtos;
27   -import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;
28   -
29   -import java.util.Map;
30   -import java.util.Objects;
31   -import java.util.concurrent.ConcurrentHashMap;
32   -import java.util.concurrent.TimeoutException;
33   -
34   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.ERROR_KEY;
35   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FINISH_JSON_KEY;
36   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FINISH_VALUE_KEY;
37   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.INFO_KEY;
38   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.KEY_NAME_KEY;
39   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;
40   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER_ALL;
41   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
42   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.FW_UPDATE;
43   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;
44   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_READ_ALL;
45   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;
46   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
47   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_UPDATE;
48   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.METHOD_KEY;
49   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.PARAMS_KEY;
50   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.RESULT_KEY;
51   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SEPARATOR_KEY;
52   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.START_JSON_KEY;
53   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TARGET_ID_VER_KEY;
54   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.VALUE_KEY;
55   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
56   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validPathIdVer;
57   -
58   -@Slf4j
59   -@Data
60   -public class LwM2mClientRpcRequest {
61   -
62   - private Registration registration;
63   - private TransportProtos.SessionInfoProto sessionInfo;
64   - private String bodyParams;
65   - private int requestId;
66   -
67   - private LwM2mTypeOper typeOper;
68   - private String key;
69   - private String targetIdVer;
70   - private Object value;
71   - private Map<String, Object> params;
72   -
73   - private String errorMsg;
74   - private String valueMsg;
75   - private String infoMsg;
76   - private String responseCode;
77   -
78   - public LwM2mClientRpcRequest() {
79   - }
80   -
81   - public LwM2mClientRpcRequest(LwM2mTypeOper lwM2mTypeOper, String bodyParams, int requestId,
82   - TransportProtos.SessionInfoProto sessionInfo, Registration registration, DefaultLwM2MTransportMsgHandler handler) {
83   - this.registration = registration;
84   - this.sessionInfo = sessionInfo;
85   - this.requestId = requestId;
86   - if (lwM2mTypeOper != null) {
87   - this.typeOper = lwM2mTypeOper;
88   - } else {
89   - this.errorMsg = METHOD_KEY + " - " + typeOper + " is not valid.";
90   - }
91   - if (this.errorMsg == null && !bodyParams.equals("null")) {
92   - this.bodyParams = bodyParams;
93   - this.init(handler);
94   - }
95   - }
96   -
97   - public TransportProtos.ToDeviceRpcResponseMsg getDeviceRpcResponseResultMsg() {
98   - JsonObject payloadResp = new JsonObject();
99   - payloadResp.addProperty(RESULT_KEY, this.responseCode);
100   - if (this.errorMsg != null) {
101   - payloadResp.addProperty(ERROR_KEY, this.errorMsg);
102   - } else if (this.valueMsg != null) {
103   - payloadResp.addProperty(VALUE_KEY, this.valueMsg);
104   - } else if (this.infoMsg != null) {
105   - payloadResp.addProperty(INFO_KEY, this.infoMsg);
106   - }
107   - return TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
108   - .setPayload(payloadResp.getAsJsonObject().toString())
109   - .setRequestId(this.requestId)
110   - .build();
111   - }
112   -
113   - private void init(DefaultLwM2MTransportMsgHandler handler) {
114   - try {
115   - // #1
116   - if (this.bodyParams.contains(KEY_NAME_KEY)) {
117   - String targetIdVerStr = this.getValueKeyFromBody(KEY_NAME_KEY);
118   - if (targetIdVerStr != null) {
119   - String targetIdVer = handler.getPresentPathIntoProfile(sessionInfo, targetIdVerStr);
120   - if (targetIdVer != null) {
121   - this.targetIdVer = targetIdVer;
122   - this.setInfoMsg(String.format("Changed by: key - %s, pathIdVer - %s",
123   - targetIdVerStr, targetIdVer));
124   - }
125   - }
126   - }
127   - if (this.getTargetIdVer() == null && this.bodyParams.contains(TARGET_ID_VER_KEY)) {
128   - this.setValidTargetIdVerKey();
129   - }
130   - if (this.bodyParams.contains(VALUE_KEY)) {
131   - this.value = this.getValueKeyFromBody(VALUE_KEY);
132   - }
133   - try {
134   - if (this.bodyParams.contains(PARAMS_KEY)) {
135   - this.setValidParamsKey(handler);
136   - }
137   - } catch (Exception e) {
138   - this.setErrorMsg(String.format("Params of request is bad Json format. %s", e.getMessage()));
139   - }
140   -
141   - if (this.getTargetIdVer() == null
142   - && !(OBSERVE_READ_ALL == this.getTypeOper()
143   - || DISCOVER_ALL == this.getTypeOper()
144   - || OBSERVE_CANCEL == this.getTypeOper()
145   - || FW_UPDATE == this.getTypeOper())) {
146   - this.setErrorMsg(TARGET_ID_VER_KEY + " and " +
147   - KEY_NAME_KEY + " is null or bad format");
148   - }
149   - /**
150   - * EXECUTE && WRITE_REPLACE - only for Resource or ResourceInstance
151   - */
152   - else if (this.getTargetIdVer() != null
153   - && (EXECUTE == this.getTypeOper()
154   - || WRITE_REPLACE == this.getTypeOper())
155   - && !(new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(this.getTargetIdVer()))).isResource()
156   - || new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(this.getTargetIdVer()))).isResourceInstance())) {
157   - this.setErrorMsg("Invalid parameter " + TARGET_ID_VER_KEY
158   - + ". Only Resource or ResourceInstance can be this operation");
159   - }
160   - } catch (Exception e) {
161   - this.setErrorMsg(String.format("Bad format request. %s", e.getMessage()));
162   - }
163   -
164   - }
165   -
166   - private void setValidTargetIdVerKey() {
167   - String targetIdVerStr = this.getValueKeyFromBody(TARGET_ID_VER_KEY);
168   - // targetIdVer without ver - ok
169   - try {
170   - // targetIdVer with/without ver - ok
171   - this.targetIdVer = validPathIdVer(targetIdVerStr, this.registration);
172   - if (this.targetIdVer != null) {
173   - this.infoMsg = String.format("Changed by: pathIdVer - %s", this.targetIdVer);
174   - }
175   - } catch (Exception e) {
176   - if (this.targetIdVer == null) {
177   - this.errorMsg = TARGET_ID_VER_KEY + " - " + targetIdVerStr + " is not valid.";
178   - }
179   - }
180   - }
181   -
182   - private void setValidParamsKey(DefaultLwM2MTransportMsgHandler handler) {
183   - String paramsStr = this.getValueKeyFromBody(PARAMS_KEY);
184   - if (paramsStr != null) {
185   - String params2Json =
186   - START_JSON_KEY
187   - + "\""
188   - + paramsStr
189   - .replaceAll(SEPARATOR_KEY, "\"" + SEPARATOR_KEY + "\"")
190   - .replaceAll(FINISH_VALUE_KEY, "\"" + FINISH_VALUE_KEY + "\"")
191   - + "\""
192   - + FINISH_JSON_KEY;
193   - // jsonObject
194   - Map<String, Object> params = new Gson().fromJson(params2Json, new TypeToken<ConcurrentHashMap<String, Object>>() {
195   - }.getType());
196   - if (WRITE_UPDATE == this.getTypeOper()) {
197   - if (this.targetIdVer != null) {
198   - Map<String, Object> paramsResourceId = this.convertParamsToResourceId((ConcurrentHashMap<String, Object>) params, handler);
199   - if (paramsResourceId.size() > 0) {
200   - this.setParams(paramsResourceId);
201   - }
202   - }
203   - } else if (WRITE_ATTRIBUTES == this.getTypeOper()) {
204   - this.setParams(params);
205   - }
206   - }
207   - }
208   -
209   - private String getValueKeyFromBody(String key) {
210   - String valueKey = null;
211   - int startInd = -1;
212   - int finishInd = -1;
213   - try {
214   - switch (key) {
215   - case KEY_NAME_KEY:
216   - case TARGET_ID_VER_KEY:
217   - case VALUE_KEY:
218   - startInd = this.bodyParams.indexOf(SEPARATOR_KEY, this.bodyParams.indexOf(key));
219   - finishInd = this.bodyParams.indexOf(FINISH_VALUE_KEY, this.bodyParams.indexOf(key));
220   - if (startInd >= 0 && finishInd < 0) {
221   - finishInd = this.bodyParams.indexOf(FINISH_JSON_KEY, this.bodyParams.indexOf(key));
222   - }
223   - break;
224   - case PARAMS_KEY:
225   - startInd = this.bodyParams.indexOf(START_JSON_KEY, this.bodyParams.indexOf(key));
226   - finishInd = this.bodyParams.indexOf(FINISH_JSON_KEY, this.bodyParams.indexOf(key));
227   - }
228   - if (startInd >= 0 && finishInd > 0) {
229   - valueKey = this.bodyParams.substring(startInd + 1, finishInd);
230   - }
231   - } catch (Exception e) {
232   - log.error("", new TimeoutException());
233   - }
234   - /**
235   - * ReplaceAll "\""
236   - */
237   - if (StringUtils.trimToNull(valueKey) != null) {
238   - char[] chars = valueKey.toCharArray();
239   - for (int i = 0; i < chars.length; i++) {
240   - if (chars[i] == 92 || chars[i] == 34) chars[i] = 32;
241   - }
242   - return key.equals(PARAMS_KEY) ? String.valueOf(chars) : String.valueOf(chars).replaceAll(" ", "");
243   - }
244   - return null;
245   - }
246   -
247   - private ConcurrentHashMap<String, Object> convertParamsToResourceId(ConcurrentHashMap<String, Object> params,
248   - DefaultLwM2MTransportMsgHandler serviceImpl) {
249   - Map<String, Object> paramsIdVer = new ConcurrentHashMap<>();
250   - LwM2mPath targetId = new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(this.targetIdVer)));
251   - if (targetId.isObjectInstance()) {
252   - params.forEach((k, v) -> {
253   - try {
254   - int id = Integer.parseInt(k);
255   - paramsIdVer.put(String.valueOf(id), v);
256   - } catch (NumberFormatException e) {
257   - String targetIdVer = serviceImpl.getPresentPathIntoProfile(sessionInfo, k);
258   - if (targetIdVer != null) {
259   - LwM2mPath lwM2mPath = new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(targetIdVer)));
260   - paramsIdVer.put(String.valueOf(lwM2mPath.getResourceId()), v);
261   - }
262   - /** WRITE_UPDATE*/
263   - else {
264   - String rezId = this.getRezIdByResourceNameAndObjectInstanceId(k, serviceImpl);
265   - if (rezId != null) {
266   - paramsIdVer.put(rezId, v);
267   - }
268   - }
269   - }
270   - });
271   - }
272   - return (ConcurrentHashMap<String, Object>) paramsIdVer;
273   - }
274   -
275   - private String getRezIdByResourceNameAndObjectInstanceId(String resourceName, DefaultLwM2MTransportMsgHandler handler) {
276   - LwM2mClient lwM2mClient = handler.clientContext.getClientBySessionInfo(this.sessionInfo);
277   - return lwM2mClient != null ?
278   - lwM2mClient.getRezIdByResourceNameAndObjectInstanceId(resourceName, this.targetIdVer, handler.config.getModelProvider()) :
279   - null;
280   - }
281   -}
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 lombok.Getter;
19   -import lombok.Setter;
20   -import lombok.extern.slf4j.Slf4j;
21   -import org.apache.commons.lang3.StringUtils;
22   -import org.eclipse.leshan.core.request.ContentFormat;
23   -import org.eclipse.leshan.server.registration.Registration;
24   -import org.thingsboard.server.common.data.ota.OtaPackageType;
25   -import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
26   -import org.thingsboard.server.gen.transport.TransportProtos;
27   -import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;
28   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportRequest;
29   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
30   -
31   -import java.util.ArrayList;
32   -import java.util.List;
33   -import java.util.UUID;
34   -import java.util.concurrent.CopyOnWriteArrayList;
35   -
36   -import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT;
37   -import static org.thingsboard.server.common.data.ota.OtaPackageKey.STATE;
38   -import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
39   -import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE;
40   -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED;
41   -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED;
42   -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.INITIATED;
43   -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATED;
44   -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING;
45   -import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey;
46   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FIRMWARE_UPDATE_COAP_RECOURSE;
47   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_3_VER_ID;
48   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_5_VER_ID;
49   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_NAME_ID;
50   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_19_ID;
51   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_5_ID;
52   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_URI_ID;
53   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID;
54   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_STATE_ID;
55   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_UPDATE;
56   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_UPDATE_ID;
57   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR;
58   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;
59   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY;
60   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY;
61   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL;
62   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
63   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE;
64   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
65   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_INSTALL_ID;
66   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_NAME_ID;
67   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_PACKAGE_ID;
68   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_RESULT_ID;
69   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UN_INSTALL_ID;
70   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UPDATE;
71   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UPDATE_STATE_ID;
72   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_VER_ID;
73   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
74   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsFwSateToFirmwareUpdateStatus;
75   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.splitCamelCaseString;
76   -
77   -@Slf4j
78   -public class LwM2mFwSwUpdate {
79   - // 5/0/6 PkgName
80   - // 9/0/0 PkgName
81   - @Getter
82   - @Setter
83   - private volatile String currentTitle;
84   - // 5/0/7 PkgVersion
85   - // 9/0/1 PkgVersion
86   - @Getter
87   - @Setter
88   - private volatile String currentVersion;
89   - @Getter
90   - @Setter
91   - private volatile UUID currentId;
92   - @Getter
93   - @Setter
94   - private volatile String stateUpdate;
95   - @Getter
96   - private String pathPackageId;
97   - @Getter
98   - private String pathStateId;
99   - @Getter
100   - private String pathResultId;
101   - @Getter
102   - private String pathNameId;
103   - @Getter
104   - private String pathVerId;
105   - @Getter
106   - private String pathInstallId;
107   - @Getter
108   - private String pathUnInstallId;
109   - @Getter
110   - private String wUpdate;
111   - @Getter
112   - @Setter
113   - private volatile boolean infoFwSwUpdate = false;
114   - private final OtaPackageType type;
115   - @Getter
116   - LwM2mClient lwM2MClient;
117   - @Getter
118   - @Setter
119   - private final List<String> pendingInfoRequestsStart;
120   - @Getter
121   - @Setter
122   - private volatile LwM2mClientRpcRequest rpcRequest;
123   - @Getter
124   - @Setter
125   - private volatile int updateStrategy;
126   -
127   - public LwM2mFwSwUpdate(LwM2mClient lwM2MClient, OtaPackageType type, int updateStrategy) {
128   - this.lwM2MClient = lwM2MClient;
129   - this.pendingInfoRequestsStart = new CopyOnWriteArrayList<>();
130   - this.type = type;
131   - this.stateUpdate = null;
132   - this.updateStrategy = updateStrategy;
133   - this.initPathId();
134   - }
135   -
136   - private void initPathId() {
137   - if (FIRMWARE.equals(this.type)) {
138   - this.pathPackageId = LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy ?
139   - FW_PACKAGE_5_ID : LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL.code == this.updateStrategy ?
140   - FW_PACKAGE_URI_ID : FW_PACKAGE_19_ID;
141   - this.pathStateId = FW_STATE_ID;
142   - this.pathResultId = FW_RESULT_ID;
143   - this.pathNameId = FW_NAME_ID;
144   - this.pathVerId = FW_5_VER_ID;
145   - this.pathInstallId = FW_UPDATE_ID;
146   - this.wUpdate = FW_UPDATE;
147   - } else if (SOFTWARE.equals(this.type)) {
148   - this.pathPackageId = SW_PACKAGE_ID;
149   - this.pathStateId = SW_UPDATE_STATE_ID;
150   - this.pathResultId = SW_RESULT_ID;
151   - this.pathNameId = SW_NAME_ID;
152   - this.pathVerId = SW_VER_ID;
153   - this.pathInstallId = SW_INSTALL_ID;
154   - this.pathUnInstallId = SW_UN_INSTALL_ID;
155   - this.wUpdate = SW_UPDATE;
156   - }
157   - }
158   -
159   - public void initReadValue(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request, String pathIdVer) {
160   - if (pathIdVer != null) {
161   - this.pendingInfoRequestsStart.remove(pathIdVer);
162   - }
163   - if (this.pendingInfoRequestsStart.size() == 0) {
164   - this.infoFwSwUpdate = false;
165   -// if (!FAILED.name().equals(this.stateUpdate)) {
166   - boolean conditionalStart = this.type.equals(FIRMWARE) ? this.conditionalFwUpdateStart(handler) :
167   - this.conditionalSwUpdateStart(handler);
168   - if (conditionalStart) {
169   - this.writeFwSwWare(handler, request);
170   - }
171   -// }
172   - }
173   - }
174   -
175   - /**
176   - * Send FsSw to Lwm2mClient:
177   - * before operation Write: fw_state = DOWNLOADING
178   - */
179   - public void writeFwSwWare(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) {
180   - if (this.currentId != null) {
181   - this.stateUpdate = OtaPackageUpdateStatus.INITIATED.name();
182   - this.sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null);
183   - String targetIdVer = convertPathFromObjectIdToIdVer(this.pathPackageId, this.lwM2MClient.getRegistration());
184   - String fwMsg = String.format("%s: Start type operation %s paths: %s", LOG_LW2M_INFO,
185   - LwM2mTransportUtil.LwM2mTypeOper.FW_UPDATE.name(), this.pathPackageId);
186   - handler.sendLogsToThingsboard(fwMsg, lwM2MClient.getRegistration().getId());
187   - log.warn("8) Start firmware Update. Send save to: [{}] ver: [{}] path: [{}]", this.lwM2MClient.getDeviceName(), this.currentVersion, targetIdVer);
188   - if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy) {
189   - int chunkSize = 0;
190   - int chunk = 0;
191   - byte[] firmwareChunk = handler.otaPackageDataCache.get(this.currentId.toString(), chunkSize, chunk);
192   - request.sendAllRequest(this.lwM2MClient, targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE,
193   - firmwareChunk, handler.config.getTimeout(), this.rpcRequest);
194   - } else if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL.code == this.updateStrategy) {
195   - String apiFont = "coap://176.36.143.9:5685";
196   - String uri = apiFont + "/" + FIRMWARE_UPDATE_COAP_RECOURSE + "/" + this.currentId.toString();
197   - log.warn("89) coapUri: [{}]", uri);
198   - request.sendAllRequest(this.lwM2MClient, targetIdVer, WRITE_REPLACE, null,
199   - uri, handler.config.getTimeout(), this.rpcRequest);
200   - } else if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY.code == this.updateStrategy) {
201   -
202   - }
203   - } else {
204   - String msgError = "FirmWareId is null.";
205   - log.warn("6) [{}]", msgError);
206   - if (this.rpcRequest != null) {
207   - handler.sentRpcResponse(this.rpcRequest, CONTENT.name(), msgError, LOG_LW2M_ERROR);
208   - }
209   - log.error(msgError);
210   - this.sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError);
211   - }
212   - }
213   -
214   - public void sendLogs(DefaultLwM2MTransportMsgHandler handler, String typeOper, String typeInfo, String msgError) {
215   -// this.sendSateOnThingsBoard(handler);
216   - String msg = String.format("%s: %s, %s, pkgVer: %s: pkgName - %s state - %s.",
217   - typeInfo, this.wUpdate, typeOper, this.currentVersion, this.currentTitle, this.stateUpdate);
218   - if (LOG_LW2M_ERROR.equals(typeInfo)) {
219   - msg = String.format("%s Error: %s", msg, msgError);
220   - }
221   - handler.sendLogsToThingsboard(lwM2MClient, msg);
222   - }
223   -
224   -
225   - /**
226   - * After inspection Update Result
227   - * fw_state/sw_state = UPDATING
228   - * send execute
229   - */
230   - public void executeFwSwWare(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) {
231   - this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_INFO, null);
232   - request.sendAllRequest(this.lwM2MClient, this.pathInstallId, EXECUTE, null, 0, this.rpcRequest);
233   - }
234   -
235   - /**
236   - * Firmware start: Check if the version has changed and launch a new update.
237   - * -ObjectId 5, Binary or ObjectId 5, URI
238   - * -- If the result of the update - errors (more than 1) - This means that the previous. the update failed.
239   - * - We launch the update regardless of the state of the firmware and its version.
240   - * -- If the result of the update - errors (more than 1) - This means that the previous. the update failed.
241   - * * ObjectId 5, Binary
242   - * -- If the result of the update is not errors (equal to 1 or 0) and ver in Object 5 is not empty - it means that the previous update has passed.
243   - * Compare current versions by equals.
244   - * * ObjectId 5, URI
245   - * -- If the result of the update is not errors (equal to 1 or 0) and ver in Object 5 is not empty - it means that the previous update has passed.
246   - * Compare current versions by contains.
247   - */
248   - private boolean conditionalFwUpdateStart(DefaultLwM2MTransportMsgHandler handler) {
249   - Long updateResultFw = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
250   - String ver5 = (String) this.lwM2MClient.getResourceValue(null, this.pathVerId);
251   - String pathName = (String) this.lwM2MClient.getResourceValue(null, this.pathNameId);
252   - String ver3 = (String) this.lwM2MClient.getResourceValue(null, FW_3_VER_ID);
253   - // #1/#2
254   - String fwMsg = null;
255   - if ((this.currentVersion != null && (
256   - ver5 != null && ver5.equals(this.currentVersion) ||
257   - ver3 != null && ver3.contains(this.currentVersion)
258   - )) ||
259   - (this.currentTitle != null && pathName != null && this.currentTitle.equals(pathName))) {
260   - fwMsg = String.format("%s: The update was interrupted. The device has the same version: %s.", LOG_LW2M_ERROR,
261   - this.currentVersion);
262   - }
263   - else if (updateResultFw != null && updateResultFw > LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code) {
264   - fwMsg = String.format("%s: The update was interrupted. The device has the status UpdateResult: error (%d).", LOG_LW2M_ERROR,
265   - updateResultFw);
266   - }
267   - if (fwMsg != null) {
268   - handler.sendLogsToThingsboard(fwMsg, lwM2MClient.getRegistration().getId());
269   - return false;
270   - }
271   - else {
272   - return true;
273   - }
274   - }
275   -
276   -
277   - /**
278   - * Before operation Execute inspection Update Result :
279   - * 0 - Initial value
280   - */
281   - public boolean conditionalFwExecuteStart() {
282   - Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
283   - return LwM2mTransportUtil.UpdateResultFw.INITIAL.code == updateResult;
284   - }
285   -
286   - /**
287   - * After operation Execute success inspection Update Result :
288   - * 1 - "Firmware updated successfully"
289   - */
290   - public boolean conditionalFwExecuteAfterSuccess() {
291   - Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
292   - return LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code == updateResult;
293   - }
294   -
295   - /**
296   - * After operation Execute success inspection Update Result :
297   - * > 1 error: "Firmware updated successfully"
298   - */
299   - public boolean conditionalFwExecuteAfterError() {
300   - Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
301   - return LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code < updateResult;
302   - }
303   -
304   - /**
305   - * Software start
306   - * - If Update Result -errors (equal or more than 50) - This means that the previous. the update failed.
307   - * * - We launch the update regardless of the state of the firmware and its version.
308   - * - If Update Result is not errors (less than 50) and ver is not empty - This means that before. the update has passed.
309   - * - If Update Result is not errors and ver is empty - This means that there was no update yet or before. UnInstall update
310   - * - If Update Result is not errors and ver is not empty - This means that before unInstall update
311   - * * - Check if the version has changed and launch a new update.
312   - */
313   - private boolean conditionalSwUpdateStart(DefaultLwM2MTransportMsgHandler handler) {
314   - Long updateResultSw = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
315   - // #1/#2
316   - return updateResultSw >= LwM2mTransportUtil.UpdateResultSw.NOT_ENOUGH_STORAGE.code ||
317   - (
318   - (updateResultSw <= LwM2mTransportUtil.UpdateResultSw.NOT_ENOUGH_STORAGE.code
319   - ) &&
320   - (
321   - (this.currentVersion != null && !this.currentVersion.equals(this.lwM2MClient.getResourceValue(null, this.pathVerId))) ||
322   - (this.currentTitle != null && !this.currentTitle.equals(this.lwM2MClient.getResourceValue(null, this.pathNameId)))
323   - )
324   - );
325   - }
326   -
327   - /**
328   - * Before operation Execute inspection Update Result :
329   - * 3 - Successfully Downloaded and package integrity verified
330   - */
331   - public boolean conditionalSwUpdateExecute() {
332   - Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
333   - return LwM2mTransportUtil.UpdateResultSw.SUCCESSFULLY_DOWNLOADED_VERIFIED.code == updateResult;
334   - }
335   -
336   - /**
337   - * After finish operation Execute (success):
338   - * -- inspection Update Result:
339   - * ---- FW если Update Result == 1 ("Firmware updated successfully") или SW если Update Result == 2 ("Software successfully installed.")
340   - * -- fw_state/sw_state = UPDATED
341   - * <p>
342   - * After finish operation Execute (error):
343   - * -- inspection updateResult and send to thingsboard info about error
344   - * --- send to telemetry ( key - this is name Update Result in model) (
345   - * -- fw_state/sw_state = FAILED
346   - */
347   - public void finishFwSwUpdate(DefaultLwM2MTransportMsgHandler handler, boolean success) {
348   - Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
349   - String value = FIRMWARE.equals(this.type) ? LwM2mTransportUtil.UpdateResultFw.fromUpdateResultFwByCode(updateResult.intValue()).type :
350   - LwM2mTransportUtil.UpdateResultSw.fromUpdateResultSwByCode(updateResult.intValue()).type;
351   - String key = splitCamelCaseString((String) this.lwM2MClient.getResourceNameByRezId(null, this.pathResultId));
352   - if (success) {
353   - this.stateUpdate = OtaPackageUpdateStatus.UPDATED.name();
354   - this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_INFO, null);
355   - } else {
356   - this.stateUpdate = OtaPackageUpdateStatus.FAILED.name();
357   - this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_ERROR, value);
358   - }
359   - handler.helper.sendParametersOnThingsboardTelemetry(
360   - handler.helper.getKvStringtoThingsboard(key, value), this.lwM2MClient.getSession());
361   - }
362   -
363   - /**
364   - * After operation Execute success inspection Update Result :
365   - * 2 - "Software successfully installed."
366   - */
367   - public boolean conditionalSwExecuteAfterSuccess() {
368   - Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
369   - return LwM2mTransportUtil.UpdateResultSw.SUCCESSFULLY_INSTALLED.code == updateResult;
370   - }
371   -
372   - /**
373   - * After operation Execute success inspection Update Result :
374   - * >= 50 - error "NOT_ENOUGH_STORAGE"
375   - */
376   - public boolean conditionalSwExecuteAfterError() {
377   - Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
378   - return LwM2mTransportUtil.UpdateResultSw.NOT_ENOUGH_STORAGE.code <= updateResult;
379   - }
380   -
381   - private void observeStateUpdate(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) {
382   - request.sendAllRequest(lwM2MClient,
383   - convertPathFromObjectIdToIdVer(this.pathStateId, this.lwM2MClient.getRegistration()), OBSERVE,
384   - null, null, 0, null);
385   - request.sendAllRequest(lwM2MClient,
386   - convertPathFromObjectIdToIdVer(this.pathResultId, this.lwM2MClient.getRegistration()), OBSERVE,
387   - null, null, 0, null);
388   - }
389   -
390   - public void sendSateOnThingsBoard(DefaultLwM2MTransportMsgHandler handler) {
391   - if (StringUtils.trimToNull(this.stateUpdate) != null) {
392   - List<TransportProtos.KeyValueProto> result = new ArrayList<>();
393   - TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(getAttributeKey(this.type, STATE));
394   - kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV(stateUpdate);
395   - result.add(kvProto.build());
396   - handler.helper.sendParametersOnThingsboardTelemetry(result,
397   - handler.getSessionInfoOrCloseSession(this.lwM2MClient.getRegistration()));
398   - }
399   - }
400   -
401   - public void sendReadObserveInfo(LwM2mTransportRequest request) {
402   - this.infoFwSwUpdate = true;
403   - this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
404   - this.pathStateId, this.lwM2MClient.getRegistration()));
405   - this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
406   - this.pathResultId, this.lwM2MClient.getRegistration()));
407   - this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
408   - FW_3_VER_ID, this.lwM2MClient.getRegistration()));
409   - if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy ||
410   - LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY.code == this.updateStrategy ||
411   - SOFTWARE.equals(this.type)) {
412   - this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
413   - this.pathVerId, this.lwM2MClient.getRegistration()));
414   - this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
415   - this.pathNameId, this.lwM2MClient.getRegistration()));
416   - }
417   - this.pendingInfoRequestsStart.forEach(pathIdVer -> {
418   - request.sendAllRequest(this.lwM2MClient, pathIdVer, OBSERVE, null, 0, this.rpcRequest);
419   - });
420   -
421   - }
422   -
423   - /**
424   - * Before operation Execute (FwUpdate) inspection Update Result :
425   - * - after finished operation Write result: success (FwUpdate): fw_state = DOWNLOADED
426   - * - before start operation Execute (FwUpdate) Update Result = 0 - Initial value
427   - * - start Execute (FwUpdate)
428   - * After finished operation Execute (FwUpdate) inspection Update Result :
429   - * - after start operation Execute (FwUpdate): fw_state = UPDATING
430   - * - after success finished operation Execute (FwUpdate) Update Result == 1 ("Firmware updated successfully")
431   - * - finished operation Execute (FwUpdate)
432   - */
433   - public void updateStateOta(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request,
434   - Registration registration, String path, int value) {
435   - if (OBJ_5_BINARY.code == this.getUpdateStrategy()) {
436   - if ((convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path))) {
437   - if (DOWNLOADED.name().equals(this.getStateUpdate())
438   - && this.conditionalFwExecuteStart()) {
439   - this.executeFwSwWare(handler, request);
440   - } else if (UPDATING.name().equals(this.getStateUpdate())
441   - && this.conditionalFwExecuteAfterSuccess()) {
442   - this.finishFwSwUpdate(handler, true);
443   - } else if (UPDATING.name().equals(this.getStateUpdate())
444   - && this.conditionalFwExecuteAfterError()) {
445   - this.finishFwSwUpdate(handler, false);
446   - }
447   - }
448   - } else if (OBJ_5_TEMP_URL.code == this.getUpdateStrategy()) {
449   - if (this.currentId != null && (convertPathFromObjectIdToIdVer(FW_STATE_ID, registration).equals(path))) {
450   - String state = equalsFwSateToFirmwareUpdateStatus(LwM2mTransportUtil.StateFw.fromStateFwByCode(value)).name();
451   - if (StringUtils.isNotEmpty(state) && !FAILED.name().equals(this.stateUpdate) && !state.equals(this.stateUpdate)) {
452   - this.stateUpdate = state;
453   - this.sendSateOnThingsBoard(handler);
454   - }
455   - if (value == LwM2mTransportUtil.StateFw.DOWNLOADED.code) {
456   - this.executeFwSwWare(handler, request);
457   - }
458   - handler.firmwareUpdateState.put(lwM2MClient.getEndpoint(), value);
459   - }
460   - if ((convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path))) {
461   - if (this.currentId != null && value == LwM2mTransportUtil.UpdateResultFw.INITIAL.code) {
462   - this.setStateUpdate(INITIATED.name());
463   - } else if (this.currentId != null && value == LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code) {
464   - this.setStateUpdate(UPDATED.name());
465   - } else if (value > LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code) {
466   - this.setStateUpdate(FAILED.name());
467   - }
468   - this.sendSateOnThingsBoard(handler);
469   - }
470   - } else if (OBJ_19_BINARY.code == this.getUpdateStrategy()) {
471   -
472   - }
473   - }
474   -}
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ParametersAnalyzeResult.java renamed from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResultsAnalyzerParameters.java
... ... @@ -21,11 +21,11 @@ import java.util.Set;
21 21 import java.util.concurrent.ConcurrentHashMap;
22 22
23 23 @Data
24   -public class ResultsAnalyzerParameters {
  24 +public class ParametersAnalyzeResult {
25 25 Set<String> pathPostParametersAdd;
26 26 Set<String> pathPostParametersDel;
27 27
28   - public ResultsAnalyzerParameters() {
  28 + public ParametersAnalyzeResult() {
29 29 this.pathPostParametersAdd = ConcurrentHashMap.newKeySet();
30 30 this.pathPostParametersDel = ConcurrentHashMap.newKeySet();
31 31 }
... ...
  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.common;
  17 +
  18 +import org.thingsboard.common.util.ThingsBoardExecutors;
  19 +
  20 +import javax.annotation.PreDestroy;
  21 +import java.util.concurrent.ExecutorService;
  22 +
  23 +public abstract class LwM2MExecutorAwareService {
  24 +
  25 + protected ExecutorService executor;
  26 +
  27 + protected abstract int getExecutorSize();
  28 +
  29 + protected abstract String getExecutorName();
  30 +
  31 + protected void init() {
  32 + this.executor = ThingsBoardExecutors.newWorkStealingPool(getExecutorSize(), getExecutorName());
  33 + }
  34 +
  35 + public void destroy() {
  36 + if (executor != null) {
  37 + executor.shutdownNow();
  38 + }
  39 + }
  40 +
  41 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  20 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  21 +
  22 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_WARN;
  23 +
  24 +@Slf4j
  25 +public abstract class AbstractTbLwM2MRequestCallback<R, T> implements DownlinkRequestCallback<R, T> {
  26 +
  27 + protected final LwM2MTelemetryLogService logService;
  28 + protected final LwM2mClient client;
  29 +
  30 + protected AbstractTbLwM2MRequestCallback(LwM2MTelemetryLogService logService, LwM2mClient client) {
  31 + this.logService = logService;
  32 + this.client = client;
  33 + }
  34 +
  35 + @Override
  36 + public void onValidationError(String params, String msg) {
  37 + log.trace("[{}] Request [{}] validation failed. Reason: {}", client.getEndpoint(), params, msg);
  38 + logService.log(client, String.format("[%s]: Request [%s] validation failed. Reason: %s", LOG_LWM2M_WARN, params, msg));
  39 + }
  40 +
  41 + @Override
  42 + public void onError(String params, Exception e) {
  43 + log.trace("[{}] Request [{}] processing failed", client.getEndpoint(), params, e);
  44 + logService.log(client, String.format("[%s]: Request [%s] processing failed. Reason: %s", LOG_LWM2M_WARN, params, e));
  45 + }
  46 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Getter;
  19 +
  20 +public abstract class AbstractTbLwM2MTargetedDownlinkRequest<T> implements TbLwM2MDownlinkRequest<T>, HasVersionedId {
  21 +
  22 + @Getter
  23 + private final String versionedId;
  24 + @Getter
  25 + private final long timeout;
  26 +
  27 + public AbstractTbLwM2MTargetedDownlinkRequest(String versionedId, long timeout) {
  28 + this.versionedId = versionedId;
  29 + this.timeout = timeout;
  30 + }
  31 +
  32 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.RequiredArgsConstructor;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.leshan.core.Link;
  21 +import org.eclipse.leshan.core.attributes.Attribute;
  22 +import org.eclipse.leshan.core.attributes.AttributeSet;
  23 +import org.eclipse.leshan.core.model.ResourceModel;
  24 +import org.eclipse.leshan.core.node.LwM2mPath;
  25 +import org.eclipse.leshan.core.node.LwM2mResource;
  26 +import org.eclipse.leshan.core.node.ObjectLink;
  27 +import org.eclipse.leshan.core.node.codec.CodecException;
  28 +import org.eclipse.leshan.core.observation.Observation;
  29 +import org.eclipse.leshan.core.request.ContentFormat;
  30 +import org.eclipse.leshan.core.request.DeleteRequest;
  31 +import org.eclipse.leshan.core.request.DiscoverRequest;
  32 +import org.eclipse.leshan.core.request.ExecuteRequest;
  33 +import org.eclipse.leshan.core.request.ObserveRequest;
  34 +import org.eclipse.leshan.core.request.ReadRequest;
  35 +import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
  36 +import org.eclipse.leshan.core.request.WriteAttributesRequest;
  37 +import org.eclipse.leshan.core.request.WriteRequest;
  38 +import org.eclipse.leshan.core.response.DeleteResponse;
  39 +import org.eclipse.leshan.core.response.DiscoverResponse;
  40 +import org.eclipse.leshan.core.response.ExecuteResponse;
  41 +import org.eclipse.leshan.core.response.LwM2mResponse;
  42 +import org.eclipse.leshan.core.response.ObserveResponse;
  43 +import org.eclipse.leshan.core.response.ReadResponse;
  44 +import org.eclipse.leshan.core.response.WriteAttributesResponse;
  45 +import org.eclipse.leshan.core.response.WriteResponse;
  46 +import org.eclipse.leshan.core.util.Hex;
  47 +import org.eclipse.leshan.server.registration.Registration;
  48 +import org.springframework.stereotype.Service;
  49 +import org.thingsboard.common.util.JacksonUtil;
  50 +import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes;
  51 +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
  52 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
  53 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
  54 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  55 +import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService;
  56 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  57 +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
  58 +
  59 +import javax.annotation.PostConstruct;
  60 +import javax.annotation.PreDestroy;
  61 +import java.util.Arrays;
  62 +import java.util.Collection;
  63 +import java.util.Date;
  64 +import java.util.LinkedList;
  65 +import java.util.List;
  66 +import java.util.Set;
  67 +import java.util.function.Function;
  68 +import java.util.function.Predicate;
  69 +import java.util.stream.Collectors;
  70 +
  71 +import static org.eclipse.leshan.core.attributes.Attribute.GREATER_THAN;
  72 +import static org.eclipse.leshan.core.attributes.Attribute.LESSER_THAN;
  73 +import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD;
  74 +import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD;
  75 +import static org.eclipse.leshan.core.attributes.Attribute.STEP;
  76 +
  77 +@Slf4j
  78 +@Service
  79 +@TbLwM2mTransportComponent
  80 +@RequiredArgsConstructor
  81 +public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService implements LwM2mDownlinkMsgHandler {
  82 +
  83 + public LwM2mValueConverterImpl converter;
  84 +
  85 + private final LwM2mTransportContext context;
  86 + private final LwM2MTransportServerConfig config;
  87 + private final LwM2MTelemetryLogService logService;
  88 +
  89 + @PostConstruct
  90 + public void init() {
  91 + super.init();
  92 + this.converter = LwM2mValueConverterImpl.getInstance();
  93 + }
  94 +
  95 + @PreDestroy
  96 + public void destroy() {
  97 + super.destroy();
  98 + }
  99 +
  100 + @Override
  101 + protected int getExecutorSize() {
  102 + return config.getDownlinkPoolSize();
  103 + }
  104 +
  105 + @Override
  106 + protected String getExecutorName() {
  107 + return "LwM2M Downlink";
  108 + }
  109 +
  110 + @Override
  111 + public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback) {
  112 + validateVersionedId(client, request);
  113 + ReadRequest downlink = new ReadRequest(getContentFormat(client, request), request.getObjectId());
  114 + sendRequest(client, downlink, request.getTimeout(), callback);
  115 + }
  116 +
  117 + @Override
  118 + public void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback) {
  119 + validateVersionedId(client, request);
  120 + LwM2mPath resultIds = new LwM2mPath(request.getObjectId());
  121 + Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration());
  122 + if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) {
  123 + ObserveRequest downlink;
  124 + ContentFormat contentFormat = getContentFormat(client, request);
  125 + if (resultIds.isResource()) {
  126 + downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
  127 + } else if (resultIds.isObjectInstance()) {
  128 + downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId());
  129 + } else {
  130 + downlink = new ObserveRequest(contentFormat, resultIds.getObjectId());
  131 + }
  132 + log.info("[{}] Send observation: {}.", client.getEndpoint(), request.getVersionedId());
  133 + sendRequest(client, downlink, request.getTimeout(), callback);
  134 + } else {
  135 + throw new IllegalArgumentException("Observation is already registered!");
  136 + }
  137 + }
  138 +
  139 + @Override
  140 + public void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback<TbLwM2MObserveAllRequest, Set<String>> callback) {
  141 + Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration());
  142 + Set<String> paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet());
  143 + callback.onSuccess(request, paths);
  144 + }
  145 +
  146 + @Override
  147 + public void sendDiscoverAllRequest(LwM2mClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback<TbLwM2MDiscoverAllRequest, List<Link>> callback) {
  148 + callback.onSuccess(request, Arrays.asList(client.getRegistration().getSortedObjectLinks()));
  149 + }
  150 +
  151 + @Override
  152 + public void sendExecuteRequest(LwM2mClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback<ExecuteRequest, ExecuteResponse> callback) {
  153 + ResourceModel resourceModelExecute = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider());
  154 + if (resourceModelExecute != null) {
  155 + ExecuteRequest downlink;
  156 + if (request.getParams() != null && !resourceModelExecute.multiple) {
  157 + downlink = new ExecuteRequest(request.getVersionedId(), (String) this.converter.convertValue(request.getParams(), resourceModelExecute.type, ResourceModel.Type.STRING, new LwM2mPath(request.getObjectId())));
  158 + } else {
  159 + downlink = new ExecuteRequest(request.getVersionedId());
  160 + }
  161 + sendRequest(client, downlink, request.getTimeout(), callback);
  162 + }
  163 + }
  164 +
  165 + @Override
  166 + public void sendDeleteRequest(LwM2mClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback<DeleteRequest, DeleteResponse> callback) {
  167 + sendRequest(client, new DeleteRequest(request.getObjectId()), request.getTimeout(), callback);
  168 + }
  169 +
  170 + @Override
  171 + public void sendCancelObserveRequest(LwM2mClient client, TbLwM2MCancelObserveRequest request, DownlinkRequestCallback<TbLwM2MCancelObserveRequest, Integer> callback) {
  172 + int observeCancelCnt = context.getServer().getObservationService().cancelObservations(client.getRegistration(), request.getObjectId());
  173 + callback.onSuccess(request, observeCancelCnt);
  174 + }
  175 +
  176 + @Override
  177 + public void sendCancelAllRequest(LwM2mClient client, TbLwM2MCancelAllRequest request, DownlinkRequestCallback<TbLwM2MCancelAllRequest, Integer> callback) {
  178 + int observeCancelCnt = context.getServer().getObservationService().cancelObservations(client.getRegistration());
  179 + callback.onSuccess(request, observeCancelCnt);
  180 + }
  181 +
  182 + @Override
  183 + public void sendDiscoverRequest(LwM2mClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback<DiscoverRequest, DiscoverResponse> callback) {
  184 + validateVersionedId(client, request);
  185 + sendRequest(client, new DiscoverRequest(request.getObjectId()), request.getTimeout(), callback);
  186 + }
  187 +
  188 + @Override
  189 + public void sendWriteAttributesRequest(LwM2mClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback<WriteAttributesRequest, WriteAttributesResponse> callback) {
  190 + validateVersionedId(client, request);
  191 + if (request.getAttributes() == null) {
  192 + throw new IllegalArgumentException("Attributes to write are not specified!");
  193 + }
  194 + ObjectAttributes params = request.getAttributes();
  195 + List<Attribute> attributes = new LinkedList<>();
  196 +// Dimension and Object version are read only attributes.
  197 +// addAttribute(attributes, DIMENSION, params.getDim(), dim -> dim >= 0 && dim <= 255);
  198 +// addAttribute(attributes, OBJECT_VERSION, params.getVer(), StringUtils::isNotEmpty, Function.identity());
  199 + addAttribute(attributes, MAXIMUM_PERIOD, params.getPmax());
  200 + addAttribute(attributes, MINIMUM_PERIOD, params.getPmin());
  201 + addAttribute(attributes, GREATER_THAN, params.getGt());
  202 + addAttribute(attributes, LESSER_THAN, params.getLt());
  203 + addAttribute(attributes, STEP, params.getSt());
  204 + AttributeSet attributeSet = new AttributeSet(attributes);
  205 + sendRequest(client, new WriteAttributesRequest(request.getObjectId(), attributeSet), request.getTimeout(), callback);
  206 + }
  207 +
  208 + @Override
  209 + public void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback) {
  210 + ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider());
  211 + if (resourceModelWrite != null) {
  212 + ContentFormat contentFormat = convertResourceModelTypeToContentFormat(client, resourceModelWrite.type);
  213 + try {
  214 + LwM2mPath path = new LwM2mPath(request.getObjectId());
  215 + WriteRequest downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat,
  216 + path.getObjectId(), path.getObjectInstanceId(), path.getResourceId(), request.getValue());
  217 + sendRequest(client, downlink, request.getTimeout(), callback);
  218 + } catch (Exception e) {
  219 + callback.onError(JacksonUtil.toString(request), e);
  220 + }
  221 + } else {
  222 + callback.onValidationError(JacksonUtil.toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!");
  223 + }
  224 + }
  225 +
  226 + @Override
  227 + public void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback) {
  228 + LwM2mPath resultIds = new LwM2mPath(request.getObjectId());
  229 + if (resultIds.isResource()) {
  230 + /*
  231 + * send request: path = '/3/0' node == wM2mObjectInstance
  232 + * with params == "\"resources\": {15: resource:{id:15. value:'+01'...}}
  233 + **/
  234 + Collection<LwM2mResource> resources = client.getNewResourceForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter);
  235 + ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider());
  236 + ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : convertResourceModelTypeToContentFormat(client, resourceModelWrite.type);
  237 + WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(),
  238 + resultIds.getObjectInstanceId(), resources);
  239 + sendRequest(client, downlink, request.getTimeout(), callback);
  240 + } else if (resultIds.isObjectInstance()) {
  241 + /*
  242 + * params = "{\"id\":0,\"resources\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}"
  243 + * int rscId = resultIds.getObjectInstanceId();
  244 + * contentFormat – Format of the payload (TLV or JSON).
  245 + */
  246 + Collection<LwM2mResource> resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter);
  247 + if (resources.size() > 0) {
  248 + ContentFormat contentFormat = request.getObjectContentFormat() != null ? request.getObjectContentFormat() : client.getDefaultContentFormat();
  249 + WriteRequest downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resources);
  250 + sendRequest(client, downlink, request.getTimeout(), callback);
  251 + } else {
  252 + callback.onValidationError(JacksonUtil.toString(request), "No resources to update!");
  253 + }
  254 + } else {
  255 + callback.onValidationError(JacksonUtil.toString(request), "Update of the root level object is not supported yet!");
  256 + }
  257 + }
  258 +
  259 + private <R extends SimpleDownlinkRequest<T>, T extends LwM2mResponse> void sendRequest(LwM2mClient client, R request, long timeoutInMs, DownlinkRequestCallback<R, T> callback) {
  260 + Registration registration = client.getRegistration();
  261 + try {
  262 + logService.log(client, String.format("[%s][%s] Sending request: %s to %s", registration.getId(), registration.getSocketAddress(), request.getClass().getSimpleName(), request.getPath()));
  263 + context.getServer().send(registration, request, timeoutInMs, response -> {
  264 + executor.submit(() -> {
  265 + try {
  266 + callback.onSuccess(request, response);
  267 + } catch (Exception e) {
  268 + log.error("[{}] failed to process successful response [{}] ", registration.getEndpoint(), response, e);
  269 + }
  270 + });
  271 + }, e -> {
  272 + executor.submit(() -> {
  273 + callback.onError(JacksonUtil.toString(request), e);
  274 + });
  275 + });
  276 + } catch (Exception e) {
  277 + callback.onError(JacksonUtil.toString(request), e);
  278 + }
  279 + }
  280 +
  281 + private WriteRequest getWriteRequestSingleResource(ResourceModel.Type type, ContentFormat contentFormat, int objectId, int instanceId, int resourceId, Object value) {
  282 + switch (type) {
  283 + case STRING: // String
  284 + return new WriteRequest(contentFormat, objectId, instanceId, resourceId, value.toString());
  285 + case INTEGER: // Long
  286 + final long valueInt = Integer.toUnsignedLong(Integer.parseInt(value.toString()));
  287 + return new WriteRequest(contentFormat, objectId, instanceId, resourceId, valueInt);
  288 + case OBJLNK: // ObjectLink
  289 + return new WriteRequest(contentFormat, objectId, instanceId, resourceId, ObjectLink.fromPath(value.toString()));
  290 + case BOOLEAN: // Boolean
  291 + return new WriteRequest(contentFormat, objectId, instanceId, resourceId, Boolean.parseBoolean(value.toString()));
  292 + case FLOAT: // Double
  293 + return new WriteRequest(contentFormat, objectId, instanceId, resourceId, Double.parseDouble(value.toString()));
  294 + case TIME: // Date
  295 + Date date = new Date(Long.decode(value.toString()));
  296 + return new WriteRequest(contentFormat, objectId, instanceId, resourceId, date);
  297 + case OPAQUE: // byte[] value, base64
  298 + byte[] valueRequest;
  299 + if (value instanceof byte[]) {
  300 + valueRequest = (byte[]) value;
  301 + } else {
  302 + valueRequest = Hex.decodeHex(value.toString().toCharArray());
  303 + }
  304 + return new WriteRequest(contentFormat, objectId, instanceId, resourceId, valueRequest);
  305 + default:
  306 + throw new IllegalArgumentException("Not supported type:" + type.name());
  307 + }
  308 + }
  309 +
  310 + private void validateVersionedId(LwM2mClient client, HasVersionedId request) {
  311 + if (!client.isValidObjectVersion(request.getVersionedId())) {
  312 + throw new IllegalArgumentException("Specified resource id is not configured in the device profile!");
  313 + }
  314 + if (request.getObjectId() == null) {
  315 + throw new IllegalArgumentException("Specified object id is null!");
  316 + }
  317 + }
  318 +
  319 + private static <T> void addAttribute(List<Attribute> attributes, String attributeName, T value) {
  320 + addAttribute(attributes, attributeName, value, null, null);
  321 + }
  322 +
  323 + private static <T> void addAttribute(List<Attribute> attributes, String attributeName, T value, Function<T, ?> converter) {
  324 + addAttribute(attributes, attributeName, value, null, converter);
  325 + }
  326 +
  327 + private static <T> void addAttribute(List<Attribute> attributes, String attributeName, T value, Predicate<T> filter, Function<T, ?> converter) {
  328 + if (value != null && ((filter == null) || filter.test(value))) {
  329 + attributes.add(new Attribute(attributeName, converter != null ? converter.apply(value) : value));
  330 + }
  331 + }
  332 +
  333 + private static ContentFormat convertResourceModelTypeToContentFormat(LwM2mClient client, ResourceModel.Type type) {
  334 + switch (type) {
  335 + case BOOLEAN:
  336 + case STRING:
  337 + case TIME:
  338 + case INTEGER:
  339 + case FLOAT:
  340 + return client.getDefaultContentFormat();
  341 + case OPAQUE:
  342 + return ContentFormat.OPAQUE;
  343 + case OBJLNK:
  344 + return ContentFormat.LINK;
  345 + default:
  346 + }
  347 + throw new CodecException("Invalid ResourceModel_Type for %s ContentFormat.", type);
  348 + }
  349 +
  350 + private static ContentFormat getContentFormat(LwM2mClient client, HasContentFormat request) {
  351 + return request.getContentFormat() != null ? request.getContentFormat() : client.getDefaultContentFormat();
  352 + }
  353 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +public interface DownlinkRequestCallback<R, T> {
  19 +
  20 + void onSuccess(R request, T response);
  21 +
  22 + void onValidationError(String params, String msg);
  23 +
  24 + void onError(String params, Exception e);
  25 +
  26 + static <R, T> DownlinkRequestCallback<R, T> doNothing() {
  27 + return new DownlinkRequestCallback<>() {
  28 +
  29 + @Override
  30 + public void onSuccess(R request, T response) {
  31 +
  32 + }
  33 +
  34 + @Override
  35 + public void onValidationError(String params, String msg) {
  36 +
  37 + }
  38 +
  39 + @Override
  40 + public void onError(String params, Exception e) {
  41 +
  42 + }
  43 + };
  44 + }
  45 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import org.eclipse.leshan.core.request.ContentFormat;
  19 +
  20 +public interface HasContentFormat {
  21 +
  22 + ContentFormat getContentFormat();
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
  19 +
  20 +public interface HasVersionedId {
  21 +
  22 + String getVersionedId();
  23 +
  24 + default String getObjectId(){
  25 + return LwM2mTransportUtil.fromVersionedIdToObjectId(getVersionedId());
  26 + }
  27 +
  28 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import org.eclipse.leshan.core.Link;
  19 +import org.eclipse.leshan.core.request.DeleteRequest;
  20 +import org.eclipse.leshan.core.request.DiscoverRequest;
  21 +import org.eclipse.leshan.core.request.ExecuteRequest;
  22 +import org.eclipse.leshan.core.request.ObserveRequest;
  23 +import org.eclipse.leshan.core.request.ReadRequest;
  24 +import org.eclipse.leshan.core.request.WriteAttributesRequest;
  25 +import org.eclipse.leshan.core.request.WriteRequest;
  26 +import org.eclipse.leshan.core.response.DeleteResponse;
  27 +import org.eclipse.leshan.core.response.DiscoverResponse;
  28 +import org.eclipse.leshan.core.response.ExecuteResponse;
  29 +import org.eclipse.leshan.core.response.ObserveResponse;
  30 +import org.eclipse.leshan.core.response.ReadResponse;
  31 +import org.eclipse.leshan.core.response.WriteAttributesResponse;
  32 +import org.eclipse.leshan.core.response.WriteResponse;
  33 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  34 +
  35 +import java.util.List;
  36 +import java.util.Set;
  37 +
  38 +public interface LwM2mDownlinkMsgHandler {
  39 +
  40 + void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback);
  41 +
  42 + void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback);
  43 +
  44 + void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback<TbLwM2MObserveAllRequest, Set<String>> callback);
  45 +
  46 + void sendExecuteRequest(LwM2mClient client, TbLwM2MExecuteRequest request, DownlinkRequestCallback<ExecuteRequest, ExecuteResponse> callback);
  47 +
  48 + void sendDeleteRequest(LwM2mClient client, TbLwM2MDeleteRequest request, DownlinkRequestCallback<DeleteRequest, DeleteResponse> callback);
  49 +
  50 + void sendCancelObserveRequest(LwM2mClient client, TbLwM2MCancelObserveRequest request, DownlinkRequestCallback<TbLwM2MCancelObserveRequest, Integer> callback);
  51 +
  52 + void sendCancelAllRequest(LwM2mClient client, TbLwM2MCancelAllRequest request, DownlinkRequestCallback<TbLwM2MCancelAllRequest, Integer> callback);
  53 +
  54 + void sendDiscoverRequest(LwM2mClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback<DiscoverRequest, DiscoverResponse> callback);
  55 +
  56 + void sendDiscoverAllRequest(LwM2mClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback<TbLwM2MDiscoverAllRequest, List<Link>> callback);
  57 +
  58 + void sendWriteAttributesRequest(LwM2mClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback<WriteAttributesRequest, WriteAttributesResponse> callback);
  59 +
  60 + void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback);
  61 +
  62 + void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback);
  63 +
  64 +
  65 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  20 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  21 +
  22 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO;
  23 +
  24 +@Slf4j
  25 +public class TbLwM2MCancelAllObserveCallback extends AbstractTbLwM2MRequestCallback<TbLwM2MCancelAllRequest, Integer> {
  26 +
  27 + public TbLwM2MCancelAllObserveCallback(LwM2MTelemetryLogService logService, LwM2mClient client) {
  28 + super(logService, client);
  29 + }
  30 +
  31 + @Override
  32 + public void onSuccess(TbLwM2MCancelAllRequest request, Integer canceledSubscriptionsCount) {
  33 + log.trace("[{}] Cancel of all observations was successful: {}", client.getEndpoint(), canceledSubscriptionsCount);
  34 + logService.log(client, String.format("[%s]: Cancel of all observations was successful. Result: [%s]", LOG_LWM2M_INFO, canceledSubscriptionsCount));
  35 + }
  36 +
  37 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Getter;
  20 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  21 +
  22 +public class TbLwM2MCancelAllRequest implements TbLwM2MDownlinkRequest<Integer> {
  23 +
  24 + @Getter
  25 + private final long timeout;
  26 +
  27 + @Builder
  28 + private TbLwM2MCancelAllRequest(long timeout) {
  29 + this.timeout = timeout;
  30 + }
  31 +
  32 + @Override
  33 + public LwM2mOperationType getType() {
  34 + return LwM2mOperationType.OBSERVE_CANCEL_ALL;
  35 + }
  36 +
  37 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  20 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  21 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  22 +
  23 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO;
  24 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType.OBSERVE_CANCEL;
  25 +
  26 +@Slf4j
  27 +public class TbLwM2MCancelObserveCallback extends AbstractTbLwM2MRequestCallback<TbLwM2MCancelObserveRequest, Integer> {
  28 +
  29 + private final String versionedId;
  30 +
  31 + public TbLwM2MCancelObserveCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) {
  32 + super(logService, client);
  33 + this.versionedId = versionedId;
  34 + }
  35 +
  36 + @Override
  37 + public void onSuccess(TbLwM2MCancelObserveRequest request, Integer canceledSubscriptionsCount) {
  38 + log.trace("[{}] Cancel observation of [{}] successful: {}", client.getEndpoint(), versionedId, canceledSubscriptionsCount);
  39 + logService.log(client, String.format("[%s]: Cancel Observe for [%s] successful. Result: [%s]", LOG_LWM2M_INFO, versionedId, canceledSubscriptionsCount));
  40 + }
  41 +
  42 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  20 +
  21 +public class TbLwM2MCancelObserveRequest extends AbstractTbLwM2MTargetedDownlinkRequest<Integer> {
  22 +
  23 + @Builder
  24 + private TbLwM2MCancelObserveRequest(String versionedId, long timeout) {
  25 + super(versionedId, timeout);
  26 + }
  27 +
  28 + @Override
  29 + public LwM2mOperationType getType() {
  30 + return LwM2mOperationType.OBSERVE_CANCEL;
  31 + }
  32 +
  33 +
  34 +
  35 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import org.eclipse.leshan.core.request.DeleteRequest;
  19 +import org.eclipse.leshan.core.response.DeleteResponse;
  20 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  21 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  22 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  23 +
  24 +public class TbLwM2MDeleteCallback extends TbLwM2MTargetedCallback<DeleteRequest, DeleteResponse> {
  25 +
  26 + public TbLwM2MDeleteCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) {
  27 + super(logService, client, targetId);
  28 + }
  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.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import org.eclipse.leshan.core.response.ReadResponse;
  20 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  21 +
  22 +public class TbLwM2MDeleteRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ReadResponse> {
  23 +
  24 + @Builder
  25 + private TbLwM2MDeleteRequest(String versionedId, long timeout) {
  26 + super(versionedId, timeout);
  27 + }
  28 +
  29 + @Override
  30 + public LwM2mOperationType getType() {
  31 + return LwM2mOperationType.DELETE;
  32 + }
  33 +
  34 +
  35 +
  36 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Getter;
  20 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  21 +
  22 +public class TbLwM2MDiscoverAllRequest implements TbLwM2MDownlinkRequest<String> {
  23 +
  24 + @Getter
  25 + private final long timeout;
  26 +
  27 + @Builder
  28 + private TbLwM2MDiscoverAllRequest(long timeout) {
  29 + this.timeout = timeout;
  30 + }
  31 +
  32 + @Override
  33 + public LwM2mOperationType getType() {
  34 + return LwM2mOperationType.DISCOVER_ALL;
  35 + }
  36 +
  37 +
  38 +
  39 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import org.eclipse.leshan.core.request.DiscoverRequest;
  19 +import org.eclipse.leshan.core.response.DiscoverResponse;
  20 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  21 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  22 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  23 +
  24 +public class TbLwM2MDiscoverCallback extends TbLwM2MTargetedCallback<DiscoverRequest, DiscoverResponse> {
  25 +
  26 + public TbLwM2MDiscoverCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) {
  27 + super(logService, client, targetId);
  28 + }
  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.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import org.eclipse.leshan.core.response.DiscoverResponse;
  20 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  21 +
  22 +public class TbLwM2MDiscoverRequest extends AbstractTbLwM2MTargetedDownlinkRequest<DiscoverResponse> {
  23 +
  24 + @Builder
  25 + private TbLwM2MDiscoverRequest(String versionedId, long timeout) {
  26 + super(versionedId, timeout);
  27 + }
  28 +
  29 + @Override
  30 + public LwM2mOperationType getType() {
  31 + return LwM2mOperationType.DISCOVER;
  32 + }
  33 +
  34 +
  35 +
  36 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  19 +
  20 +public interface TbLwM2MDownlinkRequest<T> {
  21 +
  22 + LwM2mOperationType getType();
  23 +
  24 + long getTimeout();
  25 +
  26 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import org.eclipse.leshan.core.request.ExecuteRequest;
  19 +import org.eclipse.leshan.core.response.ExecuteResponse;
  20 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  21 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  22 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  23 +
  24 +public class TbLwM2MExecuteCallback extends TbLwM2MTargetedCallback<ExecuteRequest, ExecuteResponse> {
  25 +
  26 + public TbLwM2MExecuteCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) {
  27 + super(logService, client, targetId);
  28 + }
  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.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Getter;
  20 +import org.eclipse.leshan.core.response.ReadResponse;
  21 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  22 +
  23 +public class TbLwM2MExecuteRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ReadResponse> {
  24 +
  25 + @Getter
  26 + private final Object params;
  27 +
  28 + @Builder
  29 + private TbLwM2MExecuteRequest(String versionedId, long timeout, Object params) {
  30 + super(versionedId, timeout);
  31 + this.params = params;
  32 + }
  33 +
  34 + @Override
  35 + public LwM2mOperationType getType() {
  36 + return LwM2mOperationType.EXECUTE;
  37 + }
  38 +
  39 +
  40 +
  41 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.RequiredArgsConstructor;
  19 +
  20 +import java.util.concurrent.CountDownLatch;
  21 +
  22 +@RequiredArgsConstructor
  23 +public class TbLwM2MLatchCallback<R, T> implements DownlinkRequestCallback<R, T> {
  24 +
  25 + private final CountDownLatch countDownLatch;
  26 + private final DownlinkRequestCallback<R, T> callback;
  27 +
  28 + @Override
  29 + public void onSuccess(R request, T response) {
  30 + callback.onSuccess(request, response);
  31 + countDownLatch.countDown();
  32 + }
  33 +
  34 + @Override
  35 + public void onValidationError(String params, String msg) {
  36 + callback.onValidationError(params, msg);
  37 + countDownLatch.countDown();
  38 + }
  39 +
  40 + @Override
  41 + public void onError(String params, Exception e) {
  42 + callback.onError(params, e);
  43 + countDownLatch.countDown();
  44 + }
  45 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Getter;
  20 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  21 +
  22 +import java.util.Set;
  23 +
  24 +public class TbLwM2MObserveAllRequest implements TbLwM2MDownlinkRequest<Set<String>> {
  25 +
  26 + @Getter
  27 + private final long timeout;
  28 +
  29 + @Builder
  30 + private TbLwM2MObserveAllRequest(long timeout) {
  31 + this.timeout = timeout;
  32 + }
  33 +
  34 + @Override
  35 + public LwM2mOperationType getType() {
  36 + return LwM2mOperationType.OBSERVE_READ_ALL;
  37 + }
  38 +
  39 +
  40 +
  41 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.leshan.core.request.ObserveRequest;
  20 +import org.eclipse.leshan.core.response.ObserveResponse;
  21 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  22 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  23 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  24 +
  25 +@Slf4j
  26 +public class TbLwM2MObserveCallback extends TbLwM2MUplinkTargetedCallback<ObserveRequest, ObserveResponse> {
  27 +
  28 + public TbLwM2MObserveCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) {
  29 + super(handler, logService, client, targetId);
  30 + }
  31 +
  32 + @Override
  33 + public void onSuccess(ObserveRequest request, ObserveResponse response) {
  34 + super.onSuccess(request, response);
  35 + handler.onUpdateValueAfterReadResponse(client.getRegistration(), versionedId, response);
  36 + }
  37 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Getter;
  20 +import org.eclipse.leshan.core.request.ContentFormat;
  21 +import org.eclipse.leshan.core.response.ObserveResponse;
  22 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  23 +
  24 +public class TbLwM2MObserveRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ObserveResponse> implements HasContentFormat {
  25 +
  26 + @Getter
  27 + private final ContentFormat contentFormat;
  28 +
  29 + @Builder
  30 + private TbLwM2MObserveRequest(String versionedId, long timeout, ContentFormat contentFormat) {
  31 + super(versionedId, timeout);
  32 + this.contentFormat = contentFormat;
  33 + }
  34 +
  35 + @Override
  36 + public LwM2mOperationType getType() {
  37 + return LwM2mOperationType.OBSERVE;
  38 + }
  39 +
  40 +
  41 +
  42 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.leshan.core.request.ReadRequest;
  20 +import org.eclipse.leshan.core.response.ReadResponse;
  21 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  22 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  23 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  24 +
  25 +@Slf4j
  26 +public class TbLwM2MReadCallback extends TbLwM2MUplinkTargetedCallback<ReadRequest, ReadResponse> {
  27 +
  28 + public TbLwM2MReadCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) {
  29 + super(handler, logService, client, targetId);
  30 + }
  31 +
  32 + @Override
  33 + public void onSuccess(ReadRequest request, ReadResponse response) {
  34 + super.onSuccess(request, response);
  35 + handler.onUpdateValueAfterReadResponse(client.getRegistration(), versionedId, response);
  36 + }
  37 +
  38 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Getter;
  20 +import org.eclipse.leshan.core.request.ContentFormat;
  21 +import org.eclipse.leshan.core.response.ReadResponse;
  22 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  23 +
  24 +public class TbLwM2MReadRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ReadResponse> implements HasContentFormat {
  25 +
  26 + @Getter
  27 + private final ContentFormat contentFormat;
  28 +
  29 + @Builder
  30 + private TbLwM2MReadRequest(String versionedId, long timeout, ContentFormat contentFormat) {
  31 + super(versionedId, timeout);
  32 + this.contentFormat = contentFormat;
  33 + }
  34 +
  35 + @Override
  36 + public LwM2mOperationType getType() {
  37 + return LwM2mOperationType.READ;
  38 + }
  39 +
  40 +
  41 +
  42 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  20 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  21 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  22 +
  23 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO;
  24 +
  25 +@Slf4j
  26 +public abstract class TbLwM2MTargetedCallback<R, T> extends AbstractTbLwM2MRequestCallback<R, T> {
  27 +
  28 + protected final String versionedId;
  29 +
  30 + public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) {
  31 + super(logService, client);
  32 + this.versionedId = versionedId;
  33 + }
  34 +
  35 + @Override
  36 + public void onSuccess(R request, T response) {
  37 + //TODO convert camelCase to "camel case" using .split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])")
  38 + String requestName = request.getClass().getSimpleName();
  39 + log.trace("[{}] {} [{}] successful: {}", client.getEndpoint(), requestName, versionedId, response);
  40 + logService.log(client, String.format("[%s]: %s [%s] successful. Result: [%s]", LOG_LWM2M_INFO, requestName, versionedId, response));
  41 + }
  42 +
  43 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  20 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  21 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  22 +
  23 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO;
  24 +
  25 +@Slf4j
  26 +public abstract class TbLwM2MUplinkTargetedCallback<R, T> extends TbLwM2MTargetedCallback<R, T> {
  27 +
  28 + protected LwM2mUplinkMsgHandler handler;
  29 +
  30 + public TbLwM2MUplinkTargetedCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String versionedId) {
  31 + super(logService, client, versionedId);
  32 + this.handler = handler;
  33 + }
  34 +
  35 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import org.eclipse.leshan.core.request.WriteAttributesRequest;
  19 +import org.eclipse.leshan.core.response.WriteAttributesResponse;
  20 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  21 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  22 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  23 +
  24 +public class TbLwM2MWriteAttributesCallback extends TbLwM2MTargetedCallback<WriteAttributesRequest, WriteAttributesResponse> {
  25 +
  26 + public TbLwM2MWriteAttributesCallback(LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) {
  27 + super(logService, client, targetId);
  28 + }
  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.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Getter;
  20 +import org.eclipse.leshan.core.response.WriteAttributesResponse;
  21 +import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes;
  22 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  23 +
  24 +public class TbLwM2MWriteAttributesRequest extends AbstractTbLwM2MTargetedDownlinkRequest<WriteAttributesResponse> {
  25 +
  26 + @Getter
  27 + private final ObjectAttributes attributes;
  28 +
  29 + @Builder
  30 + private TbLwM2MWriteAttributesRequest(String versionedId, long timeout, ObjectAttributes attributes) {
  31 + super(versionedId, timeout);
  32 + this.attributes = attributes;
  33 + }
  34 +
  35 + @Override
  36 + public LwM2mOperationType getType() {
  37 + return LwM2mOperationType.WRITE_ATTRIBUTES;
  38 + }
  39 +
  40 +
  41 +
  42 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Getter;
  20 +import org.eclipse.leshan.core.request.ContentFormat;
  21 +import org.eclipse.leshan.core.response.WriteResponse;
  22 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  23 +
  24 +public class TbLwM2MWriteReplaceRequest extends AbstractTbLwM2MTargetedDownlinkRequest<WriteResponse> {
  25 +
  26 + @Getter
  27 + private final ContentFormat contentFormat;
  28 + @Getter
  29 + private final Object value;
  30 +
  31 + @Builder
  32 + private TbLwM2MWriteReplaceRequest(String versionedId, long timeout, ContentFormat contentFormat, Object value) {
  33 + super(versionedId, timeout);
  34 + this.contentFormat = contentFormat;
  35 + this.value = value;
  36 + }
  37 +
  38 + @Override
  39 + public LwM2mOperationType getType() {
  40 + return LwM2mOperationType.WRITE_REPLACE;
  41 + }
  42 +
  43 +
  44 +
  45 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import org.eclipse.leshan.core.request.WriteRequest;
  19 +import org.eclipse.leshan.core.response.WriteResponse;
  20 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  21 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  22 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  23 +
  24 +public class TbLwM2MWriteResponseCallback extends TbLwM2MUplinkTargetedCallback<WriteRequest, WriteResponse> {
  25 +
  26 + public TbLwM2MWriteResponseCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) {
  27 + super(handler, logService, client, targetId);
  28 + }
  29 +
  30 + @Override
  31 + public void onSuccess(WriteRequest request, WriteResponse response) {
  32 + super.onSuccess(request, response);
  33 + handler.onWriteResponseOk(client, versionedId, request);
  34 + }
  35 +
  36 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Getter;
  20 +import org.eclipse.leshan.core.request.ContentFormat;
  21 +import org.eclipse.leshan.core.response.WriteResponse;
  22 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  23 +
  24 +public class TbLwM2MWriteUpdateRequest extends AbstractTbLwM2MTargetedDownlinkRequest<WriteResponse> {
  25 +
  26 + @Getter
  27 + private final Object value;
  28 + @Getter
  29 + private final ContentFormat objectContentFormat;
  30 +
  31 + @Builder
  32 + private TbLwM2MWriteUpdateRequest(String versionedId, long timeout, Object value, ContentFormat objectContentFormat) {
  33 + super(versionedId, timeout);
  34 + this.value = value;
  35 + this.objectContentFormat = objectContentFormat;
  36 + }
  37 +
  38 + @Override
  39 + public LwM2mOperationType getType() {
  40 + return LwM2mOperationType.WRITE_UPDATE;
  41 + }
  42 +
  43 +
  44 +
  45 +}
... ...
  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.log;
  17 +
  18 +import lombok.RequiredArgsConstructor;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.stereotype.Service;
  21 +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
  22 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
  23 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  24 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
  25 +
  26 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY;
  27 +
  28 +@Slf4j
  29 +@Service
  30 +@TbLwM2mTransportComponent
  31 +@RequiredArgsConstructor
  32 +public class DefaultLwM2MTelemetryLogService implements LwM2MTelemetryLogService {
  33 +
  34 + private final LwM2mClientContext clientContext;
  35 + private final LwM2mTransportServerHelper helper;
  36 +
  37 + /**
  38 + * @param logMsg - text msg
  39 + * @param registrationId - Id of Registration LwM2M Client
  40 + */
  41 + @Override
  42 + public void log(String registrationId, String logMsg) {
  43 + log(clientContext.getClientByRegistrationId(registrationId), logMsg);
  44 + }
  45 +
  46 + @Override
  47 + public void log(LwM2mClient client, String logMsg) {
  48 + if (logMsg != null && client != null && client.getSession() != null) {
  49 + if (logMsg.length() > 1024) {
  50 + logMsg = logMsg.substring(0, 1024);
  51 + }
  52 + this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), client.getSession());
  53 + }
  54 + }
  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.log;
  17 +
  18 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  19 +
  20 +public interface LwM2MTelemetryLogService {
  21 +
  22 + void log(LwM2mClient client, String msg);
  23 +
  24 + void log(String registrationId, String msg);
  25 +
  26 +}
... ...
  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.ota;
  17 +
  18 +import lombok.RequiredArgsConstructor;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.leshan.core.request.ContentFormat;
  21 +import org.springframework.beans.factory.annotation.Autowired;
  22 +import org.springframework.context.annotation.Lazy;
  23 +import org.springframework.stereotype.Service;
  24 +import org.thingsboard.common.util.DonAsynchron;
  25 +import org.thingsboard.server.cache.ota.OtaPackageDataCache;
  26 +import org.thingsboard.server.common.data.StringUtils;
  27 +import org.thingsboard.server.common.data.ota.OtaPackageKey;
  28 +import org.thingsboard.server.common.data.ota.OtaPackageType;
  29 +import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
  30 +import org.thingsboard.server.common.transport.TransportService;
  31 +import org.thingsboard.server.common.transport.TransportServiceCallback;
  32 +import org.thingsboard.server.gen.transport.TransportProtos;
  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.LwM2MFirmwareUpdateStrategy;
  36 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
  37 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
  38 +import org.thingsboard.server.transport.lwm2m.server.UpdateResultFw;
  39 +import org.thingsboard.server.transport.lwm2m.server.UpdateStateFw;
  40 +import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService;
  41 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  42 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
  43 +import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService;
  44 +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler;
  45 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteCallback;
  46 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequest;
  47 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest;
  48 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback;
  49 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  50 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  51 +
  52 +import javax.annotation.PostConstruct;
  53 +import javax.annotation.PreDestroy;
  54 +import java.util.ArrayList;
  55 +import java.util.List;
  56 +import java.util.Map;
  57 +import java.util.Optional;
  58 +import java.util.UUID;
  59 +import java.util.concurrent.ConcurrentHashMap;
  60 +
  61 +import static org.thingsboard.server.common.data.ota.OtaPackageKey.STATE;
  62 +import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey;
  63 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FIRMWARE_UPDATE_COAP_RECOURSE;
  64 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY;
  65 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
  66 +
  67 +@Slf4j
  68 +@Service
  69 +@TbLwM2mTransportComponent
  70 +@RequiredArgsConstructor
  71 +public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService implements LwM2MOtaUpdateService {
  72 +
  73 + public static final String FIRMWARE_VERSION = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION);
  74 + public static final String FIRMWARE_TITLE = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE);
  75 + public static final String FIRMWARE_URL = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.URL);
  76 + public static final String SOFTWARE_VERSION = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION);
  77 + public static final String SOFTWARE_TITLE = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE);
  78 + public static final String SOFTWARE_URL = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.URL);
  79 +
  80 + private static final String FW_PACKAGE_5_ID = "/5/0/0";
  81 + private static final String FW_URL_ID = "/5/0/1";
  82 + private static final String FW_EXECUTE_ID = "/5/0/2";
  83 + private static final String FW_NAME_ID = "/5/0/6";
  84 + private static final String FW_VER_ID = "/5/0/7";
  85 + private static final String SW_NAME_ID = "/9/0/0";
  86 + private static final String SW_VER_ID = "/9/0/1";
  87 +
  88 + private final Map<String, LwM2MClientOtaInfo> fwStates = new ConcurrentHashMap<>();
  89 + private final Map<String, LwM2MClientOtaInfo> swStates = new ConcurrentHashMap<>();
  90 +
  91 + private final TransportService transportService;
  92 + private final LwM2mClientContext clientContext;
  93 + private final LwM2MTransportServerConfig config;
  94 + private final LwM2mUplinkMsgHandler uplinkHandler;
  95 + private final LwM2mDownlinkMsgHandler downlinkHandler;
  96 + private final OtaPackageDataCache otaPackageDataCache;
  97 + private final LwM2MTelemetryLogService logService;
  98 + private final LwM2mTransportServerHelper helper;
  99 +
  100 + @Autowired
  101 + @Lazy
  102 + private LwM2MAttributesService attributesService;
  103 +
  104 + @PostConstruct
  105 + public void init() {
  106 + super.init();
  107 + }
  108 +
  109 + @PreDestroy
  110 + public void destroy() {
  111 + super.destroy();
  112 + }
  113 +
  114 + @Override
  115 + protected int getExecutorSize() {
  116 + return config.getOtaPoolSize();
  117 + }
  118 +
  119 + @Override
  120 + protected String getExecutorName() {
  121 + return "LwM2M OTA";
  122 + }
  123 +
  124 + @Override
  125 + public void init(LwM2mClient client) {
  126 + //TODO: add locks by client fwInfo.
  127 + //TODO: check that the client supports FW and SW by checking the supported objects in the model.
  128 + List<String> attributesToFetch = new ArrayList<>();
  129 + LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
  130 + if (fwInfo.isSupported()) {
  131 + attributesToFetch.add(FIRMWARE_TITLE);
  132 + attributesToFetch.add(FIRMWARE_VERSION);
  133 + attributesToFetch.add(FIRMWARE_URL);
  134 + }
  135 +
  136 + if (!attributesToFetch.isEmpty()) {
  137 + var future = attributesService.getSharedAttributes(client, attributesToFetch);
  138 + DonAsynchron.withCallback(future, attrs -> {
  139 + if (fwInfo.isSupported()) {
  140 + Optional<String> newFirmwareTitle = getAttributeValue(attrs, FIRMWARE_TITLE);
  141 + Optional<String> newFirmwareVersion = getAttributeValue(attrs, FIRMWARE_VERSION);
  142 + Optional<String> newFirmwareUrl = getAttributeValue(attrs, FIRMWARE_URL);
  143 + if (newFirmwareTitle.isPresent() && newFirmwareVersion.isPresent()) {
  144 + onTargetFirmwareUpdate(client, newFirmwareTitle.get(), newFirmwareVersion.get(), newFirmwareUrl);
  145 + }
  146 + }
  147 + }, throwable -> {
  148 + if (fwInfo.isSupported()) {
  149 + fwInfo.setTargetFetchFailure(true);
  150 + }
  151 + }, executor);
  152 + }
  153 + }
  154 +
  155 + @Override
  156 + public void forceFirmwareUpdate(LwM2mClient client) {
  157 + LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
  158 + fwInfo.setRetryAttempts(0);
  159 + fwInfo.setFailedPackageId(null);
  160 + startFirmwareUpdateIfNeeded(client, fwInfo);
  161 + }
  162 +
  163 + @Override
  164 + public void onTargetFirmwareUpdate(LwM2mClient client, String newFirmwareTitle, String newFirmwareVersion, Optional<String> newFirmwareUrl) {
  165 + LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
  166 + fwInfo.updateTarget(newFirmwareTitle, newFirmwareVersion, newFirmwareUrl);
  167 + startFirmwareUpdateIfNeeded(client, fwInfo);
  168 + }
  169 +
  170 + @Override
  171 + public void onCurrentFirmwareNameUpdate(LwM2mClient client, String name) {
  172 + log.debug("[{}] Current fw name: {}", client.getEndpoint(), name);
  173 + LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
  174 + fwInfo.setCurrentName(name);
  175 + }
  176 +
  177 + @Override
  178 + public void onCurrentFirmwareVersion3Update(LwM2mClient client, String version) {
  179 + log.debug("[{}] Current fw version: {}", client.getEndpoint(), version);
  180 + LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
  181 + fwInfo.setCurrentVersion3(version);
  182 + }
  183 +
  184 + @Override
  185 + public void onCurrentFirmwareVersion5Update(LwM2mClient client, String version) {
  186 + log.debug("[{}] Current fw version: {}", client.getEndpoint(), version);
  187 + LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
  188 + fwInfo.setCurrentVersion5(version);
  189 + }
  190 +
  191 + @Override
  192 + public void onCurrentFirmwareStateUpdate(LwM2mClient client, Long stateCode) {
  193 + log.debug("[{}] Current fw state: {}", client.getEndpoint(), stateCode);
  194 + LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
  195 + UpdateStateFw state = UpdateStateFw.fromStateFwByCode(stateCode.intValue());
  196 + if (UpdateStateFw.DOWNLOADED.equals(state)) {
  197 + executeFwUpdate(client);
  198 + }
  199 + fwInfo.setUpdateState(state);
  200 + Optional<OtaPackageUpdateStatus> status = LwM2mTransportUtil.toOtaPackageUpdateStatus(state);
  201 + status.ifPresent(otaStatus -> sendStateUpdateToTelemetry(client, fwInfo,
  202 + otaStatus, "Firmware Update State: " + state.name()));
  203 + }
  204 +
  205 + @Override
  206 + public void onCurrentFirmwareResultUpdate(LwM2mClient client, Long code) {
  207 + log.debug("[{}] Current fw result: {}", client.getEndpoint(), code);
  208 + LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
  209 + UpdateResultFw result = UpdateResultFw.fromUpdateResultFwByCode(code.intValue());
  210 + Optional<OtaPackageUpdateStatus> status = LwM2mTransportUtil.toOtaPackageUpdateStatus(result);
  211 + status.ifPresent(otaStatus -> sendStateUpdateToTelemetry(client, fwInfo,
  212 + otaStatus, "Firmware Update Result: " + result.name()));
  213 + if (result.isAgain() && fwInfo.getRetryAttempts() <= 2) {
  214 + fwInfo.setRetryAttempts(fwInfo.getRetryAttempts() + 1);
  215 + startFirmwareUpdateIfNeeded(client, fwInfo);
  216 + } else {
  217 + fwInfo.setUpdateResult(result);
  218 + }
  219 + }
  220 +
  221 + @Override
  222 + public void onCurrentFirmwareDeliveryMethodUpdate(LwM2mClient client, Long value) {
  223 + log.debug("[{}] Current fw delivery method: {}", client.getEndpoint(), value);
  224 + LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
  225 + fwInfo.setDeliveryMethod(value.intValue());
  226 + }
  227 +
  228 + @Override
  229 + public void onTargetSoftwareUpdate(LwM2mClient client, String newSoftwareTitle, String newSoftwareVersion) {
  230 +
  231 + }
  232 +
  233 + private void startFirmwareUpdateIfNeeded(LwM2mClient client, LwM2MClientOtaInfo fwInfo) {
  234 + try {
  235 + if (!fwInfo.isSupported()) {
  236 + log.debug("[{}] Fw update is not supported: {}", client.getEndpoint(), fwInfo);
  237 + sendStateUpdateToTelemetry(client, fwInfo, OtaPackageUpdateStatus.FAILED, "Client does not support firmware update or profile misconfiguration!");
  238 + } else if (fwInfo.isUpdateRequired()) {
  239 + if (StringUtils.isNotEmpty(fwInfo.getTargetUrl())) {
  240 + log.debug("[{}] Starting update to [{}{}] using URL: {}", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion(), fwInfo.getTargetUrl());
  241 + startFirmwareUpdateUsingUrl(client, fwInfo.getTargetUrl());
  242 + } else {
  243 + log.debug("[{}] Starting update to [{}{}] using binary", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion());
  244 + startFirmwareUpdateUsingBinary(client, fwInfo);
  245 + }
  246 + }
  247 + } catch (Exception e) {
  248 + log.warn("[{}] failed to update client: {}", client.getEndpoint(), fwInfo, e);
  249 + sendStateUpdateToTelemetry(client, fwInfo, OtaPackageUpdateStatus.FAILED, "Internal server error: " + e.getMessage());
  250 + }
  251 + }
  252 +
  253 + private void startFirmwareUpdateUsingUrl(LwM2mClient client, String url) {
  254 + String targetIdVer = convertObjectIdToVersionedId(FW_URL_ID, client.getRegistration());
  255 + TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(url).timeout(config.getTimeout()).build();
  256 + downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, targetIdVer));
  257 + }
  258 +
  259 + public void startFirmwareUpdateUsingBinary(LwM2mClient client, LwM2MClientOtaInfo fwInfo) {
  260 + String versionedId = convertObjectIdToVersionedId(FW_PACKAGE_5_ID, client.getRegistration());
  261 + this.transportService.process(client.getSession(), createOtaPackageRequestMsg(client.getSession(), OtaPackageType.FIRMWARE.name()),
  262 + new TransportServiceCallback<>() {
  263 + @Override
  264 + public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) {
  265 + executor.submit(() -> doUpdateFirmwareUsingBinary(response, fwInfo, versionedId, client));
  266 + }
  267 +
  268 + @Override
  269 + public void onError(Throwable e) {
  270 + logService.log(client, "Failed to process firmware update: " + e.getMessage());
  271 + }
  272 + });
  273 + }
  274 +
  275 + private void doUpdateFirmwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientOtaInfo fwInfo, String versionedId, LwM2mClient client) {
  276 + if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) {
  277 + UUID otaPackageId = new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB());
  278 + LwM2MFirmwareUpdateStrategy strategy;
  279 + if (fwInfo.getDeliveryMethod() == null || fwInfo.getDeliveryMethod() == 2) {
  280 + strategy = fwInfo.getStrategy();
  281 + } else {
  282 + strategy = fwInfo.getDeliveryMethod() == 0 ? LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL : LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY;
  283 + }
  284 + switch (strategy) {
  285 + case OBJ_5_BINARY:
  286 + byte[] firmwareChunk = otaPackageDataCache.get(otaPackageId.toString(), 0, 0);
  287 + TbLwM2MWriteReplaceRequest writeRequest = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId)
  288 + .value(firmwareChunk).contentFormat(ContentFormat.OPAQUE)
  289 + .timeout(config.getTimeout()).build();
  290 + downlinkHandler.sendWriteReplaceRequest(client, writeRequest, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId));
  291 + break;
  292 + case OBJ_5_TEMP_URL:
  293 + startFirmwareUpdateUsingUrl(client, fwInfo.getBaseUrl() + "/" + FIRMWARE_UPDATE_COAP_RECOURSE + "/" + otaPackageId.toString());
  294 + break;
  295 + default:
  296 + sendStateUpdateToTelemetry(client, fwInfo, OtaPackageUpdateStatus.FAILED, "Unsupported strategy: " + strategy.name());
  297 + }
  298 + } else {
  299 + sendStateUpdateToTelemetry(client, fwInfo, OtaPackageUpdateStatus.FAILED, "Failed to fetch OTA package: " + response.getResponseStatus());
  300 + }
  301 + }
  302 +
  303 + private TransportProtos.GetOtaPackageRequestMsg createOtaPackageRequestMsg(TransportProtos.SessionInfoProto sessionInfo, String nameFwSW) {
  304 + return TransportProtos.GetOtaPackageRequestMsg.newBuilder()
  305 + .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
  306 + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
  307 + .setTenantIdMSB(sessionInfo.getTenantIdMSB())
  308 + .setTenantIdLSB(sessionInfo.getTenantIdLSB())
  309 + .setType(nameFwSW)
  310 + .build();
  311 + }
  312 +
  313 + private void executeFwUpdate(LwM2mClient client) {
  314 + TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(FW_EXECUTE_ID).timeout(config.getTimeout()).build();
  315 + downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, FW_EXECUTE_ID));
  316 + }
  317 +
  318 + private Optional<String> getAttributeValue(List<TransportProtos.TsKvProto> attrs, String keyName) {
  319 + for (TransportProtos.TsKvProto attr : attrs) {
  320 + if (keyName.equals(attr.getKv().getKey())) {
  321 + if (attr.getKv().getType().equals(TransportProtos.KeyValueType.STRING_V)) {
  322 + return Optional.of(attr.getKv().getStringV());
  323 + } else {
  324 + return Optional.empty();
  325 + }
  326 + }
  327 + }
  328 + return Optional.empty();
  329 + }
  330 +
  331 + private LwM2MClientOtaInfo getOrInitFwInfo(LwM2mClient client) {
  332 + //TODO: fetch state from the cache or DB.
  333 + return fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> {
  334 + var profile = clientContext.getProfile(client.getProfileId());
  335 + return new LwM2MClientOtaInfo(endpoint, OtaPackageType.FIRMWARE, profile.getClientLwM2mSettings().getFwUpdateStrategy(),
  336 + profile.getClientLwM2mSettings().getFwUpdateRecourse());
  337 + });
  338 + }
  339 +
  340 + private LwM2MClientOtaInfo getOrInitSwInfo(LwM2mClient client) {
  341 + //TODO: fetch state from the cache or DB.
  342 + return swStates.computeIfAbsent(client.getEndpoint(), endpoint -> {
  343 + var profile = clientContext.getProfile(client.getProfileId());
  344 + return new LwM2MClientOtaInfo(endpoint, OtaPackageType.SOFTWARE, profile.getClientLwM2mSettings().getSwUpdateStrategy(), profile.getClientLwM2mSettings().getSwUpdateRecourse());
  345 + });
  346 +
  347 + }
  348 +
  349 + private void sendStateUpdateToTelemetry(LwM2mClient client, LwM2MClientOtaInfo fwInfo, OtaPackageUpdateStatus status, String log) {
  350 + List<TransportProtos.KeyValueProto> result = new ArrayList<>();
  351 + TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(getAttributeKey(fwInfo.getType(), STATE));
  352 + kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV(status.name());
  353 + result.add(kvProto.build());
  354 + kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(LOG_LWM2M_TELEMETRY);
  355 + kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV(log);
  356 + result.add(kvProto.build());
  357 + helper.sendParametersOnThingsboardTelemetry(result, client.getSession());
  358 + }
  359 +
  360 +}
... ...
  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.ota;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.StringUtils;
  20 +import org.thingsboard.server.common.data.ota.OtaPackageType;
  21 +import org.thingsboard.server.transport.lwm2m.server.LwM2MFirmwareUpdateStrategy;
  22 +import org.thingsboard.server.transport.lwm2m.server.UpdateStateFw;
  23 +import org.thingsboard.server.transport.lwm2m.server.UpdateResultFw;
  24 +
  25 +import java.util.Optional;
  26 +
  27 +@Data
  28 +public class LwM2MClientOtaInfo {
  29 +
  30 + private final String endpoint;
  31 + private final OtaPackageType type;
  32 +
  33 + private String baseUrl;
  34 +
  35 + private boolean targetFetchFailure;
  36 + private String targetName;
  37 + private String targetVersion;
  38 + private String targetUrl;
  39 +
  40 + private boolean currentFetchFailure;
  41 + private String currentName;
  42 + private String currentVersion3;
  43 + private String currentVersion5;
  44 + private Integer deliveryMethod;
  45 +
  46 + //TODO: use value from device if applicable;
  47 + private LwM2MFirmwareUpdateStrategy strategy;
  48 + private UpdateStateFw updateState;
  49 + private UpdateResultFw updateResult;
  50 +
  51 + private String failedPackageId;
  52 + private int retryAttempts;
  53 +
  54 + public LwM2MClientOtaInfo(String endpoint, OtaPackageType type, Integer strategyCode, String baseUrl) {
  55 + this.endpoint = endpoint;
  56 + this.type = type;
  57 + this.strategy = LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(strategyCode);
  58 + this.baseUrl = baseUrl;
  59 + }
  60 +
  61 + public void updateTarget(String targetName, String targetVersion, Optional<String> newFirmwareUrl) {
  62 + this.targetName = targetName;
  63 + this.targetVersion = targetVersion;
  64 + this.targetUrl = newFirmwareUrl.orElse(null);
  65 + }
  66 +
  67 + public boolean isUpdateRequired() {
  68 + if (StringUtils.isEmpty(targetName) || StringUtils.isEmpty(targetVersion) || !isSupported()) {
  69 + return false;
  70 + } else {
  71 + String targetPackageId = getPackageId(targetName, targetVersion);
  72 + String currentPackageIdUsingObject5 = getPackageId(currentName, currentVersion5);
  73 + if (StringUtils.isNotEmpty(failedPackageId) && failedPackageId.equals(targetPackageId)) {
  74 + return false;
  75 + } else {
  76 + if (targetPackageId.equals(currentPackageIdUsingObject5)) {
  77 + return false;
  78 + } else if (StringUtils.isNotEmpty(currentVersion3)) {
  79 + return !currentVersion3.contains(targetPackageId);
  80 + } else {
  81 + return true;
  82 + }
  83 + }
  84 + }
  85 + }
  86 +
  87 + public boolean isSupported() {
  88 + return StringUtils.isNotEmpty(currentName) || StringUtils.isNotEmpty(currentVersion5) || StringUtils.isNotEmpty(currentVersion3);
  89 + }
  90 +
  91 + public void setUpdateResult(UpdateResultFw updateResult) {
  92 + this.updateResult = updateResult;
  93 + switch (updateResult) {
  94 + case INITIAL:
  95 + break;
  96 + case UPDATE_SUCCESSFULLY:
  97 + retryAttempts = 0;
  98 + break;
  99 + default:
  100 + failedPackageId = getPackageId(targetName, targetVersion);
  101 + break;
  102 + }
  103 + }
  104 +
  105 + private static String getPackageId(String name, String version) {
  106 + return (StringUtils.isNotEmpty(name) ? name : "") + (StringUtils.isNotEmpty(version) ? version : "");
  107 + }
  108 +
  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.ota;
  17 +
  18 +public enum LwM2MClientOtaState {
  19 +
  20 + IDLE, IN_PROGRESS, SUCCESS, FAILED
  21 +
  22 +}
... ...
  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.ota;
  17 +
  18 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  19 +
  20 +import java.util.Optional;
  21 +
  22 +public interface LwM2MOtaUpdateService {
  23 +
  24 + void init(LwM2mClient client);
  25 +
  26 + void forceFirmwareUpdate(LwM2mClient client);
  27 +
  28 + void onTargetFirmwareUpdate(LwM2mClient client, String newFirmwareTitle, String newFirmwareVersion, Optional<String> newFirmwareUrl);
  29 +
  30 + void onTargetSoftwareUpdate(LwM2mClient client, String newSoftwareTitle, String newSoftwareVersion);
  31 +
  32 + void onCurrentFirmwareNameUpdate(LwM2mClient client, String name);
  33 +
  34 + void onCurrentFirmwareVersion3Update(LwM2mClient client, String version);
  35 +
  36 + void onCurrentFirmwareVersion5Update(LwM2mClient client, String version);
  37 +
  38 + void onCurrentFirmwareStateUpdate(LwM2mClient client, Long state);
  39 +
  40 + void onCurrentFirmwareResultUpdate(LwM2mClient client, Long result);
  41 +
  42 + void onCurrentFirmwareDeliveryMethodUpdate(LwM2mClient lwM2MClient, Long value);
  43 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import lombok.RequiredArgsConstructor;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.leshan.core.ResponseCode;
  21 +import org.springframework.stereotype.Service;
  22 +import org.thingsboard.common.util.JacksonUtil;
  23 +import org.thingsboard.server.common.data.StringUtils;
  24 +import org.thingsboard.server.common.transport.TransportService;
  25 +import org.thingsboard.server.gen.transport.TransportProtos;
  26 +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
  27 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
  28 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  29 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  30 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
  31 +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler;
  32 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllObserveCallback;
  33 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllRequest;
  34 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveCallback;
  35 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest;
  36 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDeleteCallback;
  37 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDeleteRequest;
  38 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverAllRequest;
  39 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverCallback;
  40 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverRequest;
  41 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteCallback;
  42 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequest;
  43 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveAllRequest;
  44 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveCallback;
  45 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveRequest;
  46 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadCallback;
  47 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadRequest;
  48 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesCallback;
  49 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest;
  50 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest;
  51 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback;
  52 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteUpdateRequest;
  53 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  54 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  55 +
  56 +import java.util.Map;
  57 +import java.util.Set;
  58 +import java.util.UUID;
  59 +import java.util.concurrent.ConcurrentHashMap;
  60 +import java.util.stream.Collectors;
  61 +
  62 +@Slf4j
  63 +@Service
  64 +@TbLwM2mTransportComponent
  65 +@RequiredArgsConstructor
  66 +public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
  67 +
  68 + private final TransportService transportService;
  69 + private final LwM2mClientContext clientContext;
  70 + private final LwM2MTransportServerConfig config;
  71 + private final LwM2mUplinkMsgHandler uplinkHandler;
  72 + private final LwM2mDownlinkMsgHandler downlinkHandler;
  73 + private final LwM2MTelemetryLogService logService;
  74 + private final Map<UUID, Long> rpcSubscriptions = new ConcurrentHashMap<>();
  75 +
  76 + @Override
  77 + public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg rpcRequst, TransportProtos.SessionInfoProto sessionInfo) {
  78 + this.cleanupOldSessions();
  79 + UUID requestUUID = new UUID(rpcRequst.getRequestIdMSB(), rpcRequst.getRequestIdLSB());
  80 + log.warn("Received params: {}", rpcRequst.getParams());
  81 + // We use this map to protect from browser issue that the same command is sent twice.
  82 + // TODO: This is probably not the best place and should be moved to DeviceActor
  83 + if (!this.rpcSubscriptions.containsKey(requestUUID)) {
  84 + LwM2mOperationType operationType = LwM2mOperationType.fromType(rpcRequst.getMethodName());
  85 + if (operationType == null) {
  86 + this.sendErrorRpcResponse(sessionInfo, rpcRequst.getRequestId(), ResponseCode.METHOD_NOT_ALLOWED.getName(), "Unsupported operation type: " + rpcRequst.getMethodName());
  87 + return;
  88 + }
  89 + LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo);
  90 + if (client.getRegistration() == null) {
  91 + this.sendErrorRpcResponse(sessionInfo, rpcRequst.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR.getName(), "Registration is empty");
  92 + return;
  93 + }
  94 + try {
  95 + if (operationType.isHasObjectId()) {
  96 + String objectId = getIdFromParameters(client, rpcRequst);
  97 + switch (operationType) {
  98 + case READ:
  99 + sendReadRequest(client, rpcRequst, objectId);
  100 + break;
  101 + case OBSERVE:
  102 + sendObserveRequest(client, rpcRequst, objectId);
  103 + break;
  104 + case DISCOVER:
  105 + sendDiscoverRequest(client, rpcRequst, objectId);
  106 + break;
  107 + case EXECUTE:
  108 + sendExecuteRequest(client, rpcRequst, objectId);
  109 + break;
  110 + case WRITE_ATTRIBUTES:
  111 + sendWriteAttributesRequest(client, rpcRequst, objectId);
  112 + break;
  113 + case OBSERVE_CANCEL:
  114 + sendCancelObserveRequest(client, rpcRequst, objectId);
  115 + break;
  116 + case DELETE:
  117 + sendDeleteRequest(client, rpcRequst, objectId);
  118 + break;
  119 + case WRITE_UPDATE:
  120 + sendWriteUpdateRequest(client, rpcRequst, objectId);
  121 + break;
  122 + case WRITE_REPLACE:
  123 + sendWriteReplaceRequest(client, rpcRequst, objectId);
  124 + break;
  125 + default:
  126 + throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
  127 + }
  128 + } else {
  129 + switch (operationType) {
  130 + case OBSERVE_CANCEL_ALL:
  131 + sendCancelAllObserveRequest(client, rpcRequst);
  132 + break;
  133 + case OBSERVE_READ_ALL:
  134 + sendObserveAllRequest(client, rpcRequst);
  135 + break;
  136 + case DISCOVER_ALL:
  137 + sendDiscoverAllRequest(client, rpcRequst);
  138 + break;
  139 + case FW_UPDATE:
  140 + //TODO: implement and add break statement
  141 + default:
  142 + throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
  143 + }
  144 + }
  145 + } catch (IllegalArgumentException e) {
  146 + this.sendErrorRpcResponse(sessionInfo, rpcRequst.getRequestId(), ResponseCode.BAD_REQUEST.getName(), e.getMessage());
  147 + }
  148 + }
  149 + }
  150 +
  151 + private void sendReadRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
  152 + TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
  153 + var mainCallback = new TbLwM2MReadCallback(uplinkHandler, logService, client, versionedId);
  154 + var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, versionedId, mainCallback);
  155 + downlinkHandler.sendReadRequest(client, request, rpcCallback);
  156 + }
  157 +
  158 + private void sendObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
  159 + TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
  160 + var mainCallback = new TbLwM2MObserveCallback(uplinkHandler, logService, client, versionedId);
  161 + var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, versionedId, mainCallback);
  162 + downlinkHandler.sendObserveRequest(client, request, rpcCallback);
  163 + }
  164 +
  165 + private void sendObserveAllRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) {
  166 + TbLwM2MObserveAllRequest request = TbLwM2MObserveAllRequest.builder().timeout(this.config.getTimeout()).build();
  167 + downlinkHandler.sendObserveAllRequest(client, request, new RpcLinkSetCallback<>(transportService, client, requestMsg, null));
  168 + }
  169 +
  170 + private void sendDiscoverAllRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) {
  171 + TbLwM2MDiscoverAllRequest request = TbLwM2MDiscoverAllRequest.builder().timeout(this.config.getTimeout()).build();
  172 + downlinkHandler.sendDiscoverAllRequest(client, request, new RpcLinkSetCallback<>(transportService, client, requestMsg, null));
  173 + }
  174 +
  175 + private void sendDiscoverRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
  176 + TbLwM2MDiscoverRequest request = TbLwM2MDiscoverRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
  177 + var mainCallback = new TbLwM2MDiscoverCallback(logService, client, versionedId);
  178 + var rpcCallback = new RpcDiscoverCallback(transportService, client, requestMsg, mainCallback);
  179 + downlinkHandler.sendDiscoverRequest(client, request, rpcCallback);
  180 + }
  181 +
  182 + private void sendExecuteRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
  183 + TbLwM2MExecuteRequest downlink = TbLwM2MExecuteRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
  184 + var mainCallback = new TbLwM2MExecuteCallback(logService, client, versionedId);
  185 + var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
  186 + downlinkHandler.sendExecuteRequest(client, downlink, rpcCallback);
  187 + }
  188 +
  189 + private void sendWriteAttributesRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
  190 + RpcWriteAttributesRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteAttributesRequest.class);
  191 + TbLwM2MWriteAttributesRequest request = TbLwM2MWriteAttributesRequest.builder().versionedId(versionedId)
  192 + .attributes(requestBody.getAttributes())
  193 + .timeout(this.config.getTimeout()).build();
  194 + var mainCallback = new TbLwM2MWriteAttributesCallback(logService, client, versionedId);
  195 + var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
  196 + downlinkHandler.sendWriteAttributesRequest(client, request, rpcCallback);
  197 + }
  198 +
  199 + private void sendWriteUpdateRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
  200 + RpcWriteUpdateRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteUpdateRequest.class);
  201 + TbLwM2MWriteUpdateRequest.TbLwM2MWriteUpdateRequestBuilder builder = TbLwM2MWriteUpdateRequest.builder().versionedId(versionedId);
  202 + builder.value(requestBody.getValue()).timeout(this.config.getTimeout());
  203 + var mainCallback = new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId);
  204 + var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
  205 + downlinkHandler.sendWriteUpdateRequest(client, builder.build(), rpcCallback);
  206 + }
  207 +
  208 + private void sendWriteReplaceRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
  209 + RpcWriteUpdateRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteUpdateRequest.class);
  210 + TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId)
  211 + .value(requestBody.getValue())
  212 + .timeout(this.config.getTimeout()).build();
  213 + var mainCallback = new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId);
  214 + var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
  215 + downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback);
  216 + }
  217 +
  218 + private void sendCancelObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
  219 + TbLwM2MCancelObserveRequest downlink = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
  220 + var mainCallback = new TbLwM2MCancelObserveCallback(logService, client, versionedId);
  221 + var rpcCallback = new RpcCancelObserveCallback(transportService, client, requestMsg, mainCallback);
  222 + downlinkHandler.sendCancelObserveRequest(client, downlink, rpcCallback);
  223 + }
  224 +
  225 + private void sendDeleteRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
  226 + TbLwM2MDeleteRequest downlink = TbLwM2MDeleteRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
  227 + var mainCallback = new TbLwM2MDeleteCallback(logService, client, versionedId);
  228 + var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
  229 + downlinkHandler.sendDeleteRequest(client, downlink, rpcCallback);
  230 + }
  231 +
  232 + private void sendCancelAllObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) {
  233 + TbLwM2MCancelAllRequest downlink = TbLwM2MCancelAllRequest.builder().timeout(this.config.getTimeout()).build();
  234 + var mainCallback = new TbLwM2MCancelAllObserveCallback(logService, client);
  235 + var rpcCallback = new RpcCancelAllObserveCallback(transportService, client, requestMsg, mainCallback);
  236 + downlinkHandler.sendCancelAllRequest(client, downlink, rpcCallback);
  237 + }
  238 +
  239 + private String getIdFromParameters(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequst) {
  240 + IdOrKeyRequest requestParams = JacksonUtil.fromString(rpcRequst.getParams(), IdOrKeyRequest.class);
  241 + String targetId;
  242 + if (StringUtils.isNotEmpty(requestParams.getKey())) {
  243 + targetId = clientContext.getObjectIdByKeyNameFromProfile(client, requestParams.getKey());
  244 + } else if (StringUtils.isNotEmpty(requestParams.getId())) {
  245 + targetId = requestParams.getId();
  246 + } else {
  247 + throw new IllegalArgumentException("Can't find 'key' or 'id' in the requestParams parameters!");
  248 + }
  249 + return targetId;
  250 + }
  251 +
  252 + private void sendErrorRpcResponse(TransportProtos.SessionInfoProto sessionInfo, int requestId, String result, String error) {
  253 + String payload = JacksonUtil.toString(JacksonUtil.newObjectNode().put("result", result).put("error", error));
  254 + TransportProtos.ToDeviceRpcResponseMsg msg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId).setPayload(payload).build();
  255 + transportService.process(sessionInfo, msg, null);
  256 + }
  257 +
  258 + private void cleanupOldSessions() {
  259 + log.warn("4.1) before rpcSubscriptions.size(): [{}]", rpcSubscriptions.size());
  260 + if (rpcSubscriptions.size() > 0) {
  261 + long currentTime = System.currentTimeMillis();
  262 + Set<UUID> rpcSubscriptionsToRemove = rpcSubscriptions.entrySet().stream().filter(kv -> currentTime > kv.getValue()).map(Map.Entry::getKey).collect(Collectors.toSet());
  263 + log.warn("4.2) System.currentTimeMillis(): [{}]", System.currentTimeMillis());
  264 + log.warn("4.3) rpcSubscriptionsToRemove: [{}]", rpcSubscriptionsToRemove);
  265 + rpcSubscriptionsToRemove.forEach(rpcSubscriptions::remove);
  266 + }
  267 + log.warn("4.4) after rpcSubscriptions.size(): [{}]", rpcSubscriptions.size());
  268 + }
  269 +
  270 + @Override
  271 + public void onToDeviceRpcResponse(TransportProtos.ToDeviceRpcResponseMsg toDeviceResponse, TransportProtos.SessionInfoProto sessionInfo) {
  272 + log.warn("5) onToDeviceRpcResponse: [{}], sessionUUID: [{}]", toDeviceResponse, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
  273 + transportService.process(sessionInfo, toDeviceResponse, null);
  274 + }
  275 +
  276 + public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) {
  277 + log.info("[{}] toServerRpcResponse", toServerResponse);
  278 + }
  279 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class IdOrKeyRequest {
  22 +
  23 + private String key;
  24 + private String id;
  25 +
  26 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import org.thingsboard.server.gen.transport.TransportProtos;
  19 +
  20 +public interface LwM2MRpcRequestHandler {
  21 +
  22 + void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest, TransportProtos.SessionInfoProto sessionInfo);
  23 +
  24 + void onToDeviceRpcResponse(TransportProtos.ToDeviceRpcResponseMsg toDeviceRpcResponse, TransportProtos.SessionInfoProto sessionInfo);
  25 +
  26 + void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse);
  27 +
  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.transport.lwm2m.server.rpc;
  17 +
  18 +import com.fasterxml.jackson.annotation.JsonInclude;
  19 +import lombok.Builder;
  20 +import lombok.Data;
  21 +
  22 +@Data
  23 +@Builder
  24 +@JsonInclude(JsonInclude.Include.NON_NULL)
  25 +public class LwM2MRpcResponseBody {
  26 +
  27 + private String result;
  28 + private String value;
  29 + private String error;
  30 + private String info;
  31 +
  32 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import org.eclipse.leshan.core.ResponseCode;
  19 +import org.thingsboard.server.common.transport.TransportService;
  20 +import org.thingsboard.server.gen.transport.TransportProtos;
  21 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  22 +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
  23 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllRequest;
  24 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest;
  25 +
  26 +public class RpcCancelAllObserveCallback extends RpcDownlinkRequestCallbackProxy<TbLwM2MCancelAllRequest, Integer> {
  27 +
  28 + public RpcCancelAllObserveCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<TbLwM2MCancelAllRequest, Integer> callback) {
  29 + super(transportService, client, requestMsg, callback);
  30 + }
  31 +
  32 + @Override
  33 + protected void sendRpcReplyOnSuccess(Integer response) {
  34 + reply(LwM2MRpcResponseBody.builder().result(ResponseCode.CONTENT.getName()).value(response.toString()).build());
  35 + }
  36 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import org.eclipse.leshan.core.ResponseCode;
  19 +import org.eclipse.leshan.core.node.LwM2mObject;
  20 +import org.eclipse.leshan.core.node.LwM2mObjectInstance;
  21 +import org.eclipse.leshan.core.node.LwM2mResource;
  22 +import org.eclipse.leshan.core.response.ReadResponse;
  23 +import org.thingsboard.server.common.data.StringUtils;
  24 +import org.thingsboard.server.common.transport.TransportService;
  25 +import org.thingsboard.server.gen.transport.TransportProtos;
  26 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  27 +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
  28 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest;
  29 +
  30 +import java.util.Optional;
  31 +
  32 +public class RpcCancelObserveCallback extends RpcDownlinkRequestCallbackProxy<TbLwM2MCancelObserveRequest, Integer> {
  33 +
  34 + public RpcCancelObserveCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<TbLwM2MCancelObserveRequest, Integer> callback) {
  35 + super(transportService, client, requestMsg, callback);
  36 + }
  37 +
  38 + @Override
  39 + protected void sendRpcReplyOnSuccess(Integer response) {
  40 + reply(LwM2MRpcResponseBody.builder().result(ResponseCode.CONTENT.getName()).value(response.toString()).build());
  41 + }
  42 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import org.eclipse.leshan.core.Link;
  19 +import org.eclipse.leshan.core.node.LwM2mObject;
  20 +import org.eclipse.leshan.core.node.LwM2mObjectInstance;
  21 +import org.eclipse.leshan.core.node.LwM2mResource;
  22 +import org.eclipse.leshan.core.request.DiscoverRequest;
  23 +import org.eclipse.leshan.core.response.DiscoverResponse;
  24 +import org.eclipse.leshan.core.response.ReadResponse;
  25 +import org.jetbrains.annotations.NotNull;
  26 +import org.thingsboard.server.common.data.StringUtils;
  27 +import org.thingsboard.server.common.transport.TransportService;
  28 +import org.thingsboard.server.gen.transport.TransportProtos;
  29 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  30 +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
  31 +
  32 +import java.util.Optional;
  33 +
  34 +public class RpcDiscoverCallback extends RpcLwM2MDownlinkCallback<DiscoverRequest, DiscoverResponse> {
  35 +
  36 + public RpcDiscoverCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<DiscoverRequest, DiscoverResponse> callback) {
  37 + super(transportService, client, requestMsg, callback);
  38 + }
  39 +
  40 + protected Optional<String> serializeSuccessfulResponse(DiscoverResponse response) {
  41 + return Optional.of(Link.serialize(response.getObjectLinks()));
  42 + }
  43 +
  44 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import org.eclipse.leshan.core.ResponseCode;
  19 +import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
  20 +import org.thingsboard.common.util.JacksonUtil;
  21 +import org.thingsboard.server.common.transport.TransportService;
  22 +import org.thingsboard.server.gen.transport.TransportProtos;
  23 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  24 +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
  25 +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
  26 +
  27 +public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkRequestCallback<R, T> {
  28 +
  29 + private final TransportService transportService;
  30 + private final TransportProtos.ToDeviceRpcRequestMsg request;
  31 + private final DownlinkRequestCallback<R, T> callback;
  32 +
  33 + protected final LwM2mClient client;
  34 + protected final LwM2mValueConverter converter;
  35 +
  36 + public RpcDownlinkRequestCallbackProxy(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) {
  37 + this.transportService = transportService;
  38 + this.client = client;
  39 + this.request = requestMsg;
  40 + this.callback = callback;
  41 + this.converter = LwM2mValueConverterImpl.getInstance();
  42 + }
  43 +
  44 + @Override
  45 + public void onSuccess(R request, T response) {
  46 + sendRpcReplyOnSuccess(response);
  47 + if (callback != null) {
  48 + callback.onSuccess(request, response);
  49 + }
  50 + }
  51 +
  52 + @Override
  53 + public void onValidationError(String params, String msg) {
  54 + sendRpcReplyOnValidationError(msg);
  55 + if (callback != null) {
  56 + callback.onValidationError(params, msg);
  57 + }
  58 + }
  59 +
  60 + @Override
  61 + public void onError(String params, Exception e) {
  62 + sendRpcReplyOnError(e);
  63 + if (callback != null) {
  64 + callback.onError(params, e);
  65 + }
  66 + }
  67 +
  68 + protected void reply(LwM2MRpcResponseBody response) {
  69 + TransportProtos.ToDeviceRpcResponseMsg msg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
  70 + .setPayload(JacksonUtil.toString(response))
  71 + .setRequestId(request.getRequestId())
  72 + .build();
  73 + transportService.process(client.getSession(), msg, null);
  74 + }
  75 +
  76 + abstract protected void sendRpcReplyOnSuccess(T response);
  77 +
  78 + protected void sendRpcReplyOnValidationError(String msg) {
  79 + reply(LwM2MRpcResponseBody.builder().result(ResponseCode.BAD_REQUEST.getName()).error(msg).build());
  80 + }
  81 +
  82 + protected void sendRpcReplyOnError(Exception e) {
  83 + reply(LwM2MRpcResponseBody.builder().result(ResponseCode.INTERNAL_SERVER_ERROR.getName()).error(e.getMessage()).build());
  84 + }
  85 +
  86 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import org.eclipse.leshan.core.request.LwM2mRequest;
  19 +import org.eclipse.leshan.core.response.LwM2mResponse;
  20 +import org.thingsboard.server.common.transport.TransportService;
  21 +import org.thingsboard.server.gen.transport.TransportProtos;
  22 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  23 +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
  24 +
  25 +import java.util.Optional;
  26 +
  27 +public class RpcEmptyResponseCallback<R extends LwM2mRequest<T>, T extends LwM2mResponse> extends RpcLwM2MDownlinkCallback<R, T> {
  28 +
  29 + public RpcEmptyResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) {
  30 + super(transportService, client, requestMsg, callback);
  31 + }
  32 +
  33 + protected Optional<String> serializeSuccessfulResponse(T response) {
  34 + return Optional.empty();
  35 + }
  36 +
  37 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import org.eclipse.leshan.core.Link;
  19 +import org.eclipse.leshan.core.ResponseCode;
  20 +import org.eclipse.leshan.core.response.DiscoverResponse;
  21 +import org.thingsboard.common.util.JacksonUtil;
  22 +import org.thingsboard.server.common.transport.TransportService;
  23 +import org.thingsboard.server.gen.transport.TransportProtos;
  24 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  25 +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
  26 +
  27 +import java.util.Optional;
  28 +import java.util.Set;
  29 +
  30 +public class RpcLinkSetCallback<R, T> extends RpcDownlinkRequestCallbackProxy<R, T> {
  31 +
  32 + public RpcLinkSetCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) {
  33 + super(transportService, client, requestMsg, callback);
  34 + }
  35 +
  36 + @Override
  37 + protected void sendRpcReplyOnSuccess(T response) {
  38 + reply(LwM2MRpcResponseBody.builder().result(ResponseCode.CONTENT.getName()).value(JacksonUtil.toString(response)).build());
  39 + }
  40 +
  41 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import org.eclipse.leshan.core.request.LwM2mRequest;
  19 +import org.eclipse.leshan.core.response.LwM2mResponse;
  20 +import org.thingsboard.server.common.data.StringUtils;
  21 +import org.thingsboard.server.common.transport.TransportService;
  22 +import org.thingsboard.server.gen.transport.TransportProtos;
  23 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  24 +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
  25 +
  26 +import java.util.Optional;
  27 +
  28 +public abstract class RpcLwM2MDownlinkCallback<R extends LwM2mRequest<T>, T extends LwM2mResponse> extends RpcDownlinkRequestCallbackProxy<R, T> {
  29 +
  30 + public RpcLwM2MDownlinkCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) {
  31 + super(transportService, client, requestMsg, callback);
  32 + }
  33 +
  34 + @Override
  35 + protected void sendRpcReplyOnSuccess(T response) {
  36 + LwM2MRpcResponseBody.LwM2MRpcResponseBodyBuilder builder = LwM2MRpcResponseBody.builder().result(response.getCode().getName());
  37 + if (response.isSuccess()) {
  38 + Optional<String> responseValue = serializeSuccessfulResponse(response);
  39 + if (responseValue.isPresent() && StringUtils.isNotEmpty(responseValue.get())) {
  40 + builder.value(responseValue.get());
  41 + }
  42 + } else {
  43 + if (StringUtils.isNotEmpty(response.getErrorMessage())) {
  44 + builder.error(response.getErrorMessage());
  45 + }
  46 + }
  47 + reply(builder.build());
  48 + }
  49 +
  50 + protected abstract Optional<String> serializeSuccessfulResponse(T response);
  51 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import org.eclipse.leshan.core.node.LwM2mObject;
  19 +import org.eclipse.leshan.core.node.LwM2mObjectInstance;
  20 +import org.eclipse.leshan.core.node.LwM2mResource;
  21 +import org.eclipse.leshan.core.request.LwM2mRequest;
  22 +import org.eclipse.leshan.core.response.ReadResponse;
  23 +import org.thingsboard.server.common.transport.TransportService;
  24 +import org.thingsboard.server.gen.transport.TransportProtos;
  25 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  26 +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
  27 +
  28 +import java.util.Optional;
  29 +
  30 +public class RpcReadResponseCallback<R extends LwM2mRequest<T>, T extends ReadResponse> extends RpcLwM2MDownlinkCallback<R, T> {
  31 +
  32 + private final String versionedId;
  33 +
  34 + public RpcReadResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId, DownlinkRequestCallback<R, T> callback) {
  35 + super(transportService, client, requestMsg, callback);
  36 + this.versionedId = versionedId;
  37 + }
  38 +
  39 + @Override
  40 + protected Optional<String> serializeSuccessfulResponse(T response) {
  41 + Object value = null;
  42 + if (response.getContent() instanceof LwM2mObject) {
  43 + value = client.objectToString((LwM2mObject) response.getContent(), this.converter, versionedId);
  44 + } else if (response.getContent() instanceof LwM2mObjectInstance) {
  45 + value = client.instanceToString((LwM2mObjectInstance) response.getContent(), this.converter, versionedId);
  46 + } else if (response.getContent() instanceof LwM2mResource) {
  47 + value = client.resourceToString((LwM2mResource) response.getContent(), this.converter, versionedId);
  48 + }
  49 + return Optional.of(String.format("%s", value));
  50 + }
  51 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import lombok.Data;
  19 +import lombok.EqualsAndHashCode;
  20 +import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes;
  21 +
  22 +@Data
  23 +@EqualsAndHashCode(callSuper = true)
  24 +public class RpcWriteAttributesRequest extends IdOrKeyRequest {
  25 +
  26 + private ObjectAttributes attributes;
  27 +
  28 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import lombok.Data;
  19 +import lombok.EqualsAndHashCode;
  20 +
  21 +@Data
  22 +@EqualsAndHashCode(callSuper = true)
  23 +public class RpcWriteReplaceRequest extends IdOrKeyRequest {
  24 +
  25 + private Object value;
  26 +
  27 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.rpc;
  17 +
  18 +import lombok.Data;
  19 +import lombok.EqualsAndHashCode;
  20 +import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes;
  21 +
  22 +@Data
  23 +@EqualsAndHashCode(callSuper = true)
  24 +public class RpcWriteUpdateRequest extends IdOrKeyRequest {
  25 +
  26 + private Object value;
  27 + private String contentFormat;
  28 +
  29 +}
... ...
... ... @@ -85,6 +85,7 @@ public class TbLwM2mSecurityStore implements TbEditableSecurityStore {
85 85
86 86 @Override
87 87 public void remove(String endpoint) {
88   - securityStore.remove(endpoint);
  88 + //TODO: Make sure we delay removal of security store from endpoint due to reg/unreg race condition.
  89 +// securityStore.remove(endpoint);
89 90 }
90 91 }
... ...
  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.uplink;
  17 +
  18 +import com.google.gson.Gson;
  19 +import com.google.gson.GsonBuilder;
  20 +import com.google.gson.JsonElement;
  21 +import com.google.gson.JsonObject;
  22 +import com.google.gson.reflect.TypeToken;
  23 +import lombok.extern.slf4j.Slf4j;
  24 +import org.eclipse.leshan.core.model.ObjectModel;
  25 +import org.eclipse.leshan.core.model.ResourceModel;
  26 +import org.eclipse.leshan.core.node.LwM2mObject;
  27 +import org.eclipse.leshan.core.node.LwM2mObjectInstance;
  28 +import org.eclipse.leshan.core.node.LwM2mPath;
  29 +import org.eclipse.leshan.core.node.LwM2mResource;
  30 +import org.eclipse.leshan.core.observation.Observation;
  31 +import org.eclipse.leshan.core.request.ObserveRequest;
  32 +import org.eclipse.leshan.core.request.ReadRequest;
  33 +import org.eclipse.leshan.core.request.WriteRequest;
  34 +import org.eclipse.leshan.core.response.ObserveResponse;
  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.DonAsynchron;
  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.device.data.lwm2m.ObjectAttributes;
  45 +import org.thingsboard.server.common.data.device.data.lwm2m.TelemetryMappingConfiguration;
  46 +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
  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.service.DefaultTransportService;
  51 +import org.thingsboard.server.gen.transport.TransportProtos;
  52 +import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent;
  53 +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
  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.LwM2mOtaConvert;
  57 +import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest;
  58 +import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener;
  59 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
  60 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
  61 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
  62 +import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService;
  63 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState;
  64 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientStateException;
  65 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  66 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
  67 +import org.thingsboard.server.transport.lwm2m.server.client.ParametersAnalyzeResult;
  68 +import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto;
  69 +import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService;
  70 +import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
  71 +import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler;
  72 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveCallback;
  73 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest;
  74 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverCallback;
  75 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverRequest;
  76 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MLatchCallback;
  77 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveCallback;
  78 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveRequest;
  79 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadCallback;
  80 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadRequest;
  81 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesCallback;
  82 +import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest;
  83 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  84 +import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
  85 +import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler;
  86 +import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
  87 +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
  88 +
  89 +import javax.annotation.PostConstruct;
  90 +import javax.annotation.PreDestroy;
  91 +import java.util.ArrayList;
  92 +import java.util.Collection;
  93 +import java.util.Collections;
  94 +import java.util.HashSet;
  95 +import java.util.List;
  96 +import java.util.Map;
  97 +import java.util.Optional;
  98 +import java.util.Random;
  99 +import java.util.Set;
  100 +import java.util.UUID;
  101 +import java.util.concurrent.ConcurrentHashMap;
  102 +import java.util.concurrent.CountDownLatch;
  103 +import java.util.concurrent.ExecutorService;
  104 +import java.util.concurrent.TimeUnit;
  105 +import java.util.stream.Collectors;
  106 +
  107 +import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
  108 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_3_VER_ID;
  109 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_5_VER_ID;
  110 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_DELIVERY_METHOD;
  111 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_NAME_ID;
  112 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID;
  113 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_STATE_ID;
  114 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR;
  115 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO;
  116 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_WARN;
  117 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
  118 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertOtaUpdateValueToString;
  119 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
  120 +
  121 +
  122 +@Slf4j
  123 +@Service
  124 +@TbLwM2mTransportComponent
  125 +public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService implements LwM2mUplinkMsgHandler {
  126 +
  127 + public LwM2mValueConverterImpl converter;
  128 +
  129 + private final TransportService transportService;
  130 + private final LwM2mTransportContext context;
  131 + private final LwM2MAttributesService attributesService;
  132 + private final LwM2MOtaUpdateService otaService;
  133 + public final LwM2MTransportServerConfig config;
  134 + private final LwM2MTelemetryLogService logService;
  135 + public final OtaPackageDataCache otaPackageDataCache;
  136 + public final LwM2mTransportServerHelper helper;
  137 + private final TbLwM2MDtlsSessionStore sessionStore;
  138 + public final LwM2mClientContext clientContext;
  139 + private final LwM2MRpcRequestHandler rpcHandler;
  140 + public final LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler;
  141 +
  142 + public final Map<String, Integer> firmwareUpdateState;
  143 +
  144 + public DefaultLwM2MUplinkMsgHandler(TransportService transportService,
  145 + LwM2MTransportServerConfig config,
  146 + LwM2mTransportServerHelper helper,
  147 + LwM2mClientContext clientContext,
  148 + LwM2MTelemetryLogService logService,
  149 + @Lazy LwM2MOtaUpdateService otaService,
  150 + @Lazy LwM2MAttributesService attributesService,
  151 + @Lazy LwM2MRpcRequestHandler rpcHandler,
  152 + @Lazy LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler,
  153 + OtaPackageDataCache otaPackageDataCache,
  154 + LwM2mTransportContext context, TbLwM2MDtlsSessionStore sessionStore) {
  155 + this.transportService = transportService;
  156 + this.attributesService = attributesService;
  157 + this.otaService = otaService;
  158 + this.config = config;
  159 + this.helper = helper;
  160 + this.clientContext = clientContext;
  161 + this.logService = logService;
  162 + this.rpcHandler = rpcHandler;
  163 + this.defaultLwM2MDownlinkMsgHandler = defaultLwM2MDownlinkMsgHandler;
  164 + this.otaPackageDataCache = otaPackageDataCache;
  165 + this.context = context;
  166 + this.firmwareUpdateState = new ConcurrentHashMap<>();
  167 + this.sessionStore = sessionStore;
  168 + }
  169 +
  170 + @PostConstruct
  171 + public void init() {
  172 + super.init();
  173 + this.context.getScheduler().scheduleAtFixedRate(this::reportActivity, new Random().nextInt((int) config.getSessionReportTimeout()), config.getSessionReportTimeout(), TimeUnit.MILLISECONDS);
  174 + this.converter = LwM2mValueConverterImpl.getInstance();
  175 + }
  176 +
  177 + @PreDestroy
  178 + public void destroy() {
  179 + super.destroy();
  180 + }
  181 +
  182 + @Override
  183 + protected String getExecutorName() {
  184 + return "LwM2M uplink";
  185 + }
  186 +
  187 + @Override
  188 + protected int getExecutorSize() {
  189 + return config.getUplinkPoolSize();
  190 + }
  191 +
  192 + /**
  193 + * Start registration device
  194 + * Create session: Map<String <registrationId >, LwM2MClient>
  195 + * 1. replaceNewRegistration -> (solving the problem of incorrect termination of the previous session with this endpoint)
  196 + * 1.1 When we initialize the registration, we register the session by endpoint.
  197 + * 1.2 If the server has incomplete requests (canceling the registration of the previous session),
  198 + * delete the previous session only by the previous registration.getId
  199 + * 1.2 Add Model (Entity) for client (from registration & observe) by registration.getId
  200 + * 1.2 Remove from sessions Model by enpPoint
  201 + * Next -> Create new LwM2MClient for current session -> setModelClient...
  202 + *
  203 + * @param registration - Registration LwM2M Client
  204 + * @param previousObservations - may be null
  205 + */
  206 + public void onRegistered(Registration registration, Collection<Observation> previousObservations) {
  207 + executor.submit(() -> {
  208 + LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint());
  209 + try {
  210 + log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId());
  211 + if (lwM2MClient != null) {
  212 + Optional<SessionInfoProto> oldSessionInfo = this.clientContext.register(lwM2MClient, registration);
  213 + if (oldSessionInfo.isPresent()) {
  214 + log.info("[{}] Closing old session: {}", registration.getEndpoint(), new UUID(oldSessionInfo.get().getSessionIdMSB(), oldSessionInfo.get().getSessionIdLSB()));
  215 + closeSession(oldSessionInfo.get());
  216 + }
  217 + logService.log(lwM2MClient, LOG_LWM2M_INFO + ": Client registered with registration id: " + registration.getId());
  218 + SessionInfoProto sessionInfo = lwM2MClient.getSession();
  219 + transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, attributesService, rpcHandler, sessionInfo));
  220 + log.warn("40) sessionId [{}] Registering rpc subscription after Registration client", new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
  221 + TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder()
  222 + .setSessionInfo(sessionInfo)
  223 + .setSessionEvent(DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN))
  224 + .setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build())
  225 + .setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build())
  226 + .build();
  227 + transportService.process(msg, null);
  228 + this.initClientTelemetry(lwM2MClient);
  229 + this.initAttributes(lwM2MClient);
  230 + otaService.init(lwM2MClient);
  231 + } else {
  232 + log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null);
  233 + }
  234 + } catch (LwM2MClientStateException stateException) {
  235 + if (LwM2MClientState.UNREGISTERED.equals(stateException.getState())) {
  236 + log.info("[{}] retry registration due to race condition: [{}].", registration.getEndpoint(), stateException.getState());
  237 + // Race condition detected and the client was in progress of unregistration while new registration arrived. Let's try again.
  238 + onRegistered(registration, previousObservations);
  239 + } else {
  240 + logService.log(lwM2MClient, LOG_LWM2M_WARN + ": Client registration failed due to invalid state: " + stateException.getState());
  241 + }
  242 + } catch (Throwable t) {
  243 + log.error("[{}] endpoint [{}] error Unable registration.", registration.getEndpoint(), t);
  244 + logService.log(lwM2MClient, LOG_LWM2M_WARN + ": Client registration failed due to: " + t.getMessage());
  245 + }
  246 + });
  247 + }
  248 +
  249 + /**
  250 + * if sessionInfo removed from sessions, then new registerAsyncSession
  251 + *
  252 + * @param registration - Registration LwM2M Client
  253 + */
  254 + public void updatedReg(Registration registration) {
  255 + executor.submit(() -> {
  256 + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());
  257 + try {
  258 + log.warn("[{}] [{{}] Client: update after Registration", registration.getEndpoint(), registration.getId());
  259 + clientContext.updateRegistration(lwM2MClient, registration);
  260 + TransportProtos.SessionInfoProto sessionInfo = lwM2MClient.getSession();
  261 + this.reportActivityAndRegister(sessionInfo);
  262 + if (registration.usesQueueMode()) {
  263 + LwM2mQueuedRequest request;
  264 + while ((request = lwM2MClient.getQueuedRequests().poll()) != null) {
  265 + request.send();
  266 + }
  267 + }
  268 + } catch (LwM2MClientStateException stateException) {
  269 + if (LwM2MClientState.REGISTERED.equals(stateException.getState())) {
  270 + log.info("[{}] update registration failed because client has different registration id: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage());
  271 + } else {
  272 + onRegistered(registration, Collections.emptyList());
  273 + }
  274 + } catch (Throwable t) {
  275 + log.error("[{}] endpoint [{}] error Unable update registration.", registration.getEndpoint(), t);
  276 + logService.log(lwM2MClient, LOG_LWM2M_ERROR + String.format(": Client update Registration, %s", t.getMessage()));
  277 + }
  278 + });
  279 + }
  280 +
  281 + /**
  282 + * @param registration - Registration LwM2M Client
  283 + * @param observations - !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect
  284 + */
  285 + public void unReg(Registration registration, Collection<Observation> observations) {
  286 + executor.submit(() -> {
  287 + LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint());
  288 + try {
  289 + logService.log(client, LOG_LWM2M_INFO + ": Client unRegistration");
  290 + clientContext.unregister(client, registration);
  291 + SessionInfoProto sessionInfo = client.getSession();
  292 + if (sessionInfo != null) {
  293 + closeSession(sessionInfo);
  294 + sessionStore.remove(registration.getEndpoint());
  295 + log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType());
  296 + } else {
  297 + log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
  298 + }
  299 + } catch (LwM2MClientStateException stateException) {
  300 + log.info("[{}] delete registration: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage());
  301 + } catch (Throwable t) {
  302 + log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t);
  303 + logService.log(client, LOG_LWM2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage()));
  304 + }
  305 + });
  306 + }
  307 +
  308 + public void closeSession(SessionInfoProto sessionInfo) {
  309 + transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.CLOSED), null);
  310 + transportService.deregisterSession(sessionInfo);
  311 + }
  312 +
  313 + @Override
  314 + public void onSleepingDev(Registration registration) {
  315 + log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint());
  316 + logService.log(clientContext.getClientByEndpoint(registration.getEndpoint()), LOG_LWM2M_INFO + ": Client is sleeping!");
  317 + //TODO: associate endpointId with device information.
  318 + }
  319 +
  320 +// /**
  321 +// * Cancel observation for All objects for this registration
  322 +// */
  323 +// @Override
  324 +// public void setCancelObservationsAll(Registration registration) {
  325 +// if (registration != null) {
  326 +// LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint());
  327 +// if (client != null && client.getRegistration() != null && client.getRegistration().getId().equals(registration.getId())) {
  328 +// defaultLwM2MDownlinkMsgHandler.sendCancelAllRequest(client, TbLwM2MCancelAllRequest.builder().build(), new TbLwM2MCancelAllObserveRequestCallback(this, client));
  329 +// }
  330 +// }
  331 +// }
  332 +
  333 + /**
  334 + * Sending observe value to thingsboard from ObservationListener.onResponse: object, instance, SingleResource or MultipleResource
  335 + *
  336 + * @param registration - Registration LwM2M Client
  337 + * @param path - observe
  338 + * @param response - observe
  339 + */
  340 + @Override
  341 + public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response) {
  342 + if (response.getContent() != null) {
  343 + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());
  344 + ObjectModel objectModelVersion = lwM2MClient.getObjectModel(path, this.config.getModelProvider());
  345 + if (objectModelVersion != null) {
  346 + if (response.getContent() instanceof LwM2mObject) {
  347 + LwM2mObject lwM2mObject = (LwM2mObject) response.getContent();
  348 + this.updateObjectResourceValue(lwM2MClient, lwM2mObject, path);
  349 + } else if (response.getContent() instanceof LwM2mObjectInstance) {
  350 + LwM2mObjectInstance lwM2mObjectInstance = (LwM2mObjectInstance) response.getContent();
  351 + this.updateObjectInstanceResourceValue(lwM2MClient, lwM2mObjectInstance, path);
  352 + } else if (response.getContent() instanceof LwM2mResource) {
  353 + LwM2mResource lwM2mResource = (LwM2mResource) response.getContent();
  354 + this.updateResourcesValue(lwM2MClient, lwM2mResource, path);
  355 + }
  356 + }
  357 + }
  358 + }
  359 +
  360 + /**
  361 + * @param sessionInfo -
  362 + * @param deviceProfile -
  363 + */
  364 + @Override
  365 + public void onDeviceProfileUpdate(SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {
  366 + List<LwM2mClient> clients = clientContext.getLwM2mClients()
  367 + .stream().filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toList());
  368 + clients.forEach(client -> client.onDeviceProfileUpdate(deviceProfile));
  369 + if (clients.size() > 0) {
  370 + this.onDeviceProfileUpdate(clients, deviceProfile);
  371 + }
  372 + }
  373 +
  374 + @Override
  375 + public void onDeviceUpdate(SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt) {
  376 + //TODO: check, maybe device has multiple sessions/registrations? Is this possible according to the standard.
  377 + LwM2mClient client = clientContext.getClientByDeviceId(device.getUuidId());
  378 + if (client != null) {
  379 + this.onDeviceUpdate(client, device, deviceProfileOpt);
  380 + }
  381 + }
  382 +
  383 + @Override
  384 + public void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {
  385 + String idVer = resourceUpdateMsgOpt.get().getResourceKey();
  386 + clientContext.getLwM2mClients().forEach(e -> e.updateResourceModel(idVer, this.config.getModelProvider()));
  387 + }
  388 +
  389 + @Override
  390 + public void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt) {
  391 + String pathIdVer = resourceDeleteMsgOpt.get().getResourceKey();
  392 + clientContext.getLwM2mClients().forEach(e -> e.deleteResources(pathIdVer, this.config.getModelProvider()));
  393 + }
  394 +
  395 + /**
  396 + * Deregister session in transport
  397 + *
  398 + * @param sessionInfo - lwm2m client
  399 + */
  400 + @Override
  401 + public void doDisconnect(SessionInfoProto sessionInfo) {
  402 + closeSession(sessionInfo);
  403 + }
  404 +
  405 + /**
  406 + * Those methods are called by the protocol stage thread pool, this means that execution MUST be done in a short delay,
  407 + * * if you need to do long time processing use a dedicated thread pool.
  408 + *
  409 + * @param registration -
  410 + */
  411 + @Override
  412 + public void onAwakeDev(Registration registration) {
  413 + log.trace("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint());
  414 + logService.log(clientContext.getClientByEndpoint(registration.getEndpoint()), LOG_LWM2M_INFO + ": Client is awake!");
  415 + //TODO: associate endpointId with device information.
  416 + }
  417 +
  418 + /**
  419 + * #1 clientOnlyObserveAfterConnect == true
  420 + * - Only Observe Request to the client marked as observe from the profile configuration.
  421 + * #2. clientOnlyObserveAfterConnect == false
  422 + * После регистрации отправляю запрос на read всех ресурсов, которые после регистрации есть у клиента,
  423 + * а затем запрос на observe (edited)
  424 + * - Read Request to the client after registration to read all resource values for all objects
  425 + * - then Observe Request to the client marked as observe from the profile configuration.
  426 + *
  427 + * @param lwM2MClient - object with All parameters off client
  428 + */
  429 + private void initClientTelemetry(LwM2mClient lwM2MClient) {
  430 + Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId());
  431 + Set<String> supportedObjects = clientContext.getSupportedIdVerInClient(lwM2MClient);
  432 + if (supportedObjects != null && supportedObjects.size() > 0) {
  433 + // #1
  434 + this.sendReadRequests(lwM2MClient, profile, supportedObjects);
  435 + this.sendObserveRequests(lwM2MClient, profile, supportedObjects);
  436 + this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects);
  437 +// Removed. Used only for debug.
  438 +// this.sendDiscoverRequests(lwM2MClient, profile, supportedObjects);
  439 + }
  440 + }
  441 +
  442 + private void sendReadRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set<String> supportedObjects) {
  443 + Set<String> targetIds = new HashSet<>(profile.getObserveAttr().getAttribute());
  444 + targetIds.addAll(profile.getObserveAttr().getTelemetry());
  445 + targetIds = targetIds.stream().filter(target -> isSupportedTargetId(supportedObjects, target)).collect(Collectors.toSet());
  446 +
  447 + CountDownLatch latch = new CountDownLatch(targetIds.size());
  448 + targetIds.forEach(versionedId -> sendReadRequest(lwM2MClient, versionedId,
  449 + new TbLwM2MLatchCallback<>(latch, new TbLwM2MReadCallback(this, logService, lwM2MClient, versionedId))));
  450 + try {
  451 + latch.await();
  452 + } catch (InterruptedException e) {
  453 + log.error("[{}] Failed to await Read requests!", lwM2MClient.getEndpoint());
  454 + }
  455 + }
  456 +
  457 + private void sendObserveRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set<String> supportedObjects) {
  458 + Set<String> targetIds = profile.getObserveAttr().getObserve();
  459 + targetIds = targetIds.stream().filter(target -> isSupportedTargetId(supportedObjects, target)).collect(Collectors.toSet());
  460 +
  461 + CountDownLatch latch = new CountDownLatch(targetIds.size());
  462 + targetIds.forEach(targetId -> sendObserveRequest(lwM2MClient, targetId,
  463 + new TbLwM2MLatchCallback<>(latch, new TbLwM2MObserveCallback(this, logService, lwM2MClient, targetId))));
  464 + try {
  465 + latch.await();
  466 + } catch (InterruptedException e) {
  467 + log.error("[{}] Failed to await Observe requests!", lwM2MClient.getEndpoint());
  468 + }
  469 + }
  470 +
  471 + private void sendWriteAttributeRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set<String> supportedObjects) {
  472 + Map<String, ObjectAttributes> attributesMap = profile.getObserveAttr().getAttributeLwm2m();
  473 + attributesMap = attributesMap.entrySet().stream().filter(target -> isSupportedTargetId(supportedObjects, target.getKey())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
  474 +// TODO: why do we need to put observe into pending read requests?
  475 +// lwM2MClient.getPendingReadRequests().addAll(targetIds);
  476 + attributesMap.forEach((targetId, params) -> sendWriteAttributesRequest(lwM2MClient, targetId, params));
  477 + }
  478 +
  479 + private void sendDiscoverRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set<String> supportedObjects) {
  480 + Set<String> targetIds = profile.getObserveAttr().getAttributeLwm2m().keySet();
  481 + targetIds = targetIds.stream().filter(target -> isSupportedTargetId(supportedObjects, target)).collect(Collectors.toSet());
  482 +// TODO: why do we need to put observe into pending read requests?
  483 +// lwM2MClient.getPendingReadRequests().addAll(targetIds);
  484 + targetIds.forEach(targetId -> sendDiscoverRequest(lwM2MClient, targetId));
  485 + }
  486 +
  487 + private void sendDiscoverRequest(LwM2mClient lwM2MClient, String targetId) {
  488 + TbLwM2MDiscoverRequest request = TbLwM2MDiscoverRequest.builder().versionedId(targetId).timeout(this.config.getTimeout()).build();
  489 + defaultLwM2MDownlinkMsgHandler.sendDiscoverRequest(lwM2MClient, request, new TbLwM2MDiscoverCallback(logService, lwM2MClient, targetId));
  490 + }
  491 +
  492 + private void sendReadRequest(LwM2mClient lwM2MClient, String versionedId) {
  493 + sendReadRequest(lwM2MClient, versionedId, new TbLwM2MReadCallback(this, logService, lwM2MClient, versionedId));
  494 + }
  495 +
  496 + private void sendReadRequest(LwM2mClient lwM2MClient, String versionedId, DownlinkRequestCallback<ReadRequest, ReadResponse> callback) {
  497 + TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
  498 + defaultLwM2MDownlinkMsgHandler.sendReadRequest(lwM2MClient, request, callback);
  499 + }
  500 +
  501 + private void sendObserveRequest(LwM2mClient lwM2MClient, String versionedId) {
  502 + sendObserveRequest(lwM2MClient, versionedId, new TbLwM2MObserveCallback(this, logService, lwM2MClient, versionedId));
  503 + }
  504 +
  505 + private void sendObserveRequest(LwM2mClient lwM2MClient, String versionedId, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback) {
  506 + TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
  507 + defaultLwM2MDownlinkMsgHandler.sendObserveRequest(lwM2MClient, request, callback);
  508 + }
  509 +
  510 + private void sendWriteAttributesRequest(LwM2mClient lwM2MClient, String targetId, ObjectAttributes params) {
  511 + TbLwM2MWriteAttributesRequest request = TbLwM2MWriteAttributesRequest.builder().versionedId(targetId).attributes(params).timeout(this.config.getTimeout()).build();
  512 + defaultLwM2MDownlinkMsgHandler.sendWriteAttributesRequest(lwM2MClient, request, new TbLwM2MWriteAttributesCallback(logService, lwM2MClient, targetId));
  513 + }
  514 +
  515 + private void sendCancelObserveRequest(String versionedId, LwM2mClient client) {
  516 + TbLwM2MCancelObserveRequest request = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
  517 + defaultLwM2MDownlinkMsgHandler.sendCancelObserveRequest(client, request, new TbLwM2MCancelObserveCallback(logService, client, versionedId));
  518 + }
  519 +
  520 + private void updateObjectResourceValue(LwM2mClient client, LwM2mObject lwM2mObject, String pathIdVer) {
  521 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer));
  522 + lwM2mObject.getInstances().forEach((instanceId, instance) -> {
  523 + String pathInstance = pathIds.toString() + "/" + instanceId;
  524 + this.updateObjectInstanceResourceValue(client, instance, pathInstance);
  525 + });
  526 + }
  527 +
  528 + private void updateObjectInstanceResourceValue(LwM2mClient client, LwM2mObjectInstance lwM2mObjectInstance, String pathIdVer) {
  529 + LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer));
  530 + lwM2mObjectInstance.getResources().forEach((resourceId, resource) -> {
  531 + String pathRez = pathIds.toString() + "/" + resourceId;
  532 + this.updateResourcesValue(client, resource, pathRez);
  533 + });
  534 + }
  535 +
  536 + /**
  537 + * Sending observe value of resources to thingsboard
  538 + * #1 Return old Value Resource from LwM2MClient
  539 + * #2 Update new Resources (replace old Resource Value on new Resource Value)
  540 + * #3 If fr_update -> UpdateFirmware
  541 + * #4 updateAttrTelemetry
  542 + *
  543 + * @param lwM2MClient - Registration LwM2M Client
  544 + * @param lwM2mResource - LwM2mSingleResource response.getContent()
  545 + * @param path - resource
  546 + */
  547 + private void updateResourcesValue(LwM2mClient lwM2MClient, LwM2mResource lwM2mResource, String path) {
  548 + Registration registration = lwM2MClient.getRegistration();
  549 + if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider())) {
  550 + if (path.equals(convertObjectIdToVersionedId(FW_NAME_ID, registration))) {
  551 + otaService.onCurrentFirmwareNameUpdate(lwM2MClient, (String) lwM2mResource.getValue());
  552 + } else if (path.equals(convertObjectIdToVersionedId(FW_3_VER_ID, registration))) {
  553 + otaService.onCurrentFirmwareVersion3Update(lwM2MClient, (String) lwM2mResource.getValue());
  554 + } else if (path.equals(convertObjectIdToVersionedId(FW_5_VER_ID, registration))) {
  555 + otaService.onCurrentFirmwareVersion5Update(lwM2MClient, (String) lwM2mResource.getValue());
  556 + } else if (path.equals(convertObjectIdToVersionedId(FW_STATE_ID, registration))) {
  557 + otaService.onCurrentFirmwareStateUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
  558 + } else if (path.equals(convertObjectIdToVersionedId(FW_RESULT_ID, registration))) {
  559 + otaService.onCurrentFirmwareResultUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
  560 + } else if (path.equals(convertObjectIdToVersionedId(FW_DELIVERY_METHOD, registration))) {
  561 + otaService.onCurrentFirmwareDeliveryMethodUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
  562 + }
  563 + this.updateAttrTelemetry(registration, Collections.singleton(path));
  564 + } else {
  565 + log.error("Fail update Resource [{}]", lwM2mResource);
  566 + }
  567 + }
  568 +
  569 +
  570 + /**
  571 + * send Attribute and Telemetry to Thingsboard
  572 + * #1 - get AttrName/TelemetryName with value from LwM2MClient:
  573 + * -- resourceId == path from LwM2MClientProfile.postAttributeProfile/postTelemetryProfile/postObserveProfile
  574 + * -- AttrName/TelemetryName == resourceName from ModelObject.objectModel, value from ModelObject.instance.resource(resourceId)
  575 + * #2 - set Attribute/Telemetry
  576 + *
  577 + * @param registration - Registration LwM2M Client
  578 + */
  579 + private void updateAttrTelemetry(Registration registration, Set<String> paths) {
  580 + try {
  581 + ResultsAddKeyValueProto results = this.getParametersFromProfile(registration, paths);
  582 + SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registration);
  583 + if (results != null && sessionInfo != null) {
  584 + if (results.getResultAttributes().size() > 0) {
  585 + this.helper.sendParametersOnThingsboardAttribute(results.getResultAttributes(), sessionInfo);
  586 + }
  587 + if (results.getResultTelemetries().size() > 0) {
  588 + this.helper.sendParametersOnThingsboardTelemetry(results.getResultTelemetries(), sessionInfo);
  589 + }
  590 + }
  591 + } catch (Exception e) {
  592 + log.error("UpdateAttrTelemetry", e);
  593 + }
  594 + }
  595 +
  596 + private boolean isSupportedTargetId(Set<String> supportedIds, String targetId) {
  597 + String[] targetIdParts = targetId.split(LWM2M_SEPARATOR_PATH);
  598 + if (targetIdParts.length <= 1) {
  599 + return false;
  600 + }
  601 + String targetIdSearch = targetIdParts[0];
  602 + for (int i = 1; i < targetIdParts.length; i++) {
  603 + targetIdSearch += "/" + targetIdParts[i];
  604 + if (supportedIds.contains(targetIdSearch)) {
  605 + return true;
  606 + }
  607 + }
  608 + return false;
  609 + }
  610 +
  611 + private ConcurrentHashMap<String, Object> getPathForWriteAttributes(JsonObject objectJson) {
  612 + ConcurrentHashMap<String, Object> pathAttributes = new Gson().fromJson(objectJson.toString(),
  613 + new TypeToken<ConcurrentHashMap<String, Object>>() {
  614 + }.getType());
  615 + return pathAttributes;
  616 + }
  617 +
  618 + private void onDeviceUpdate(LwM2mClient lwM2MClient, Device device, Optional<DeviceProfile> deviceProfileOpt) {
  619 + deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singletonList(lwM2MClient), deviceProfile));
  620 + lwM2MClient.onDeviceUpdate(device, deviceProfileOpt);
  621 + }
  622 +
  623 + /**
  624 + * // * @param attributes - new JsonObject
  625 + * // * @param telemetry - new JsonObject
  626 + *
  627 + * @param registration - Registration LwM2M Client
  628 + * @param path -
  629 + */
  630 + private ResultsAddKeyValueProto getParametersFromProfile(Registration registration, Set<String> path) {
  631 + if (path != null && path.size() > 0) {
  632 + ResultsAddKeyValueProto results = new ResultsAddKeyValueProto();
  633 + var profile = clientContext.getProfile(registration);
  634 + List<TransportProtos.KeyValueProto> resultAttributes = new ArrayList<>();
  635 + profile.getObserveAttr().getAttribute().forEach(pathIdVer -> {
  636 + if (path.contains(pathIdVer)) {
  637 + TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer, registration);
  638 + if (kvAttr != null) {
  639 + resultAttributes.add(kvAttr);
  640 + }
  641 + }
  642 + });
  643 + List<TransportProtos.KeyValueProto> resultTelemetries = new ArrayList<>();
  644 + profile.getObserveAttr().getTelemetry().forEach(pathIdVer -> {
  645 + if (path.contains(pathIdVer)) {
  646 + TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer, registration);
  647 + if (kvAttr != null) {
  648 + resultTelemetries.add(kvAttr);
  649 + }
  650 + }
  651 + });
  652 + if (resultAttributes.size() > 0) {
  653 + results.setResultAttributes(resultAttributes);
  654 + }
  655 + if (resultTelemetries.size() > 0) {
  656 + results.setResultTelemetries(resultTelemetries);
  657 + }
  658 + return results;
  659 + }
  660 + return null;
  661 + }
  662 +
  663 + private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) {
  664 + LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint());
  665 + Map<String, String> names = clientContext.getProfile(lwM2MClient.getProfileId()).getObserveAttr().getKeyName();
  666 + if (names != null && names.containsKey(pathIdVer)) {
  667 + String resourceName = names.get(pathIdVer);
  668 + if (resourceName != null && !resourceName.isEmpty()) {
  669 + try {
  670 + LwM2mResource resourceValue = LwM2mTransportUtil.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);
  671 + if (resourceValue != null) {
  672 + ResourceModel.Type currentType = resourceValue.getType();
  673 + ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
  674 + Object valueKvProto = null;
  675 + if (resourceValue.isMultiInstances()) {
  676 + valueKvProto = new JsonObject();
  677 + Object finalvalueKvProto = valueKvProto;
  678 + Gson gson = new GsonBuilder().create();
  679 + ResourceModel.Type finalCurrentType = currentType;
  680 + resourceValue.getInstances().forEach((k, v) -> {
  681 + Object val = this.converter.convertValue(v, finalCurrentType, expectedType,
  682 + new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)));
  683 + JsonElement element = gson.toJsonTree(val, val.getClass());
  684 + ((JsonObject) finalvalueKvProto).add(String.valueOf(k), element);
  685 + });
  686 + valueKvProto = gson.toJson(valueKvProto);
  687 + } else {
  688 + valueKvProto = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
  689 + new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)));
  690 + }
  691 + LwM2mOtaConvert lwM2mOtaConvert = convertOtaUpdateValueToString(pathIdVer, valueKvProto, currentType);
  692 + valueKvProto = lwM2mOtaConvert.getValue();
  693 + currentType = lwM2mOtaConvert.getCurrentType();
  694 + return valueKvProto != null ? this.helper.getKvAttrTelemetryToThingsboard(currentType, resourceName, valueKvProto, resourceValue.isMultiInstances()) : null;
  695 + }
  696 + } catch (Exception e) {
  697 + log.error("Failed to add parameters.", e);
  698 + }
  699 + }
  700 + } else {
  701 + log.error("Failed to add parameters. path: [{}], names: [{}]", pathIdVer, names);
  702 + }
  703 + return null;
  704 + }
  705 +
  706 + @Override
  707 + public void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request) {
  708 + if (request.getNode() instanceof LwM2mResource) {
  709 + this.updateResourcesValue(client, ((LwM2mResource) request.getNode()), path);
  710 + } else if (request.getNode() instanceof LwM2mObjectInstance) {
  711 + ((LwM2mObjectInstance) request.getNode()).getResources().forEach((resId, resource) -> {
  712 + this.updateResourcesValue(client, resource, path + "/" + resId);
  713 + });
  714 + }
  715 +
  716 + }
  717 +
  718 + //TODO: review and optimize the logic to minimize number of the requests to device.
  719 + private void onDeviceProfileUpdate(List<LwM2mClient> clients, DeviceProfile deviceProfile) {
  720 + var oldProfile = clientContext.getProfile(deviceProfile.getUuidId());
  721 + if (clientContext.profileUpdate(deviceProfile) != null) {
  722 + // #1
  723 + TelemetryMappingConfiguration oldTelemetryParams = oldProfile.getObserveAttr();
  724 + Set<String> attributeSetOld = oldTelemetryParams.getAttribute();
  725 + Set<String> telemetrySetOld = oldTelemetryParams.getTelemetry();
  726 + Set<String> observeOld = oldTelemetryParams.getObserve();
  727 + Map<String, String> keyNameOld = oldTelemetryParams.getKeyName();
  728 + Map<String, ObjectAttributes> attributeLwm2mOld = oldTelemetryParams.getAttributeLwm2m();
  729 +
  730 + var newProfile = clientContext.getProfile(deviceProfile.getUuidId());
  731 + TelemetryMappingConfiguration newTelemetryParams = newProfile.getObserveAttr();
  732 + Set<String> attributeSetNew = newTelemetryParams.getAttribute();
  733 + Set<String> telemetrySetNew = newTelemetryParams.getTelemetry();
  734 + Set<String> observeNew = newTelemetryParams.getObserve();
  735 + Map<String, String> keyNameNew = newTelemetryParams.getKeyName();
  736 + Map<String, ObjectAttributes> attributeLwm2mNew = newTelemetryParams.getAttributeLwm2m();
  737 +
  738 + Set<String> observeToAdd = diffSets(observeOld, observeNew);
  739 + Set<String> observeToRemove = diffSets(observeNew, observeOld);
  740 +
  741 + Set<String> newObjectsToRead = new HashSet<>();
  742 +
  743 + // #3.1
  744 + if (!attributeSetOld.equals(attributeSetNew)) {
  745 + newObjectsToRead.addAll(diffSets(attributeSetOld, attributeSetNew));
  746 + }
  747 + // #3.2
  748 + if (!telemetrySetOld.equals(telemetrySetNew)) {
  749 + newObjectsToRead.addAll(diffSets(telemetrySetOld, telemetrySetNew));
  750 + }
  751 + // #3.3
  752 + if (!keyNameOld.equals(keyNameNew)) {
  753 + ParametersAnalyzeResult keyNameChange = this.getAnalyzerKeyName(keyNameOld, keyNameNew);
  754 + newObjectsToRead.addAll(keyNameChange.getPathPostParametersAdd());
  755 + }
  756 +
  757 + // #3.4, #6
  758 + if (!attributeLwm2mOld.equals(attributeLwm2mNew)) {
  759 + this.compareAndSendWriteAttributes(clients, attributeLwm2mOld, attributeLwm2mNew);
  760 + }
  761 +
  762 + // #4.1 add
  763 + if (!newObjectsToRead.isEmpty()) {
  764 + Set<String> newObjectsToReadButNotNewInObserve = diffSets(observeToAdd, newObjectsToRead);
  765 + // update value in Resources
  766 + for (String versionedId : newObjectsToReadButNotNewInObserve) {
  767 + clients.forEach(client -> sendReadRequest(client, versionedId));
  768 + }
  769 + }
  770 +
  771 + // Calculating difference between old and new flags.
  772 + if (!observeToAdd.isEmpty()) {
  773 + for (String targetId : observeToAdd) {
  774 + clients.forEach(client -> sendObserveRequest(client, targetId));
  775 + }
  776 + }
  777 + if (!observeToRemove.isEmpty()) {
  778 + for (String targetId : observeToRemove) {
  779 + clients.forEach(client -> sendCancelObserveRequest(targetId, client));
  780 + }
  781 + }
  782 + }
  783 + }
  784 +
  785 + /**
  786 + * Returns new set with elements that are present in set B(new) but absent in set A(old).
  787 + */
  788 + private static <T> Set<T> diffSets(Set<T> a, Set<T> b) {
  789 + return b.stream().filter(p -> !a.contains(p)).collect(Collectors.toSet());
  790 + }
  791 +
  792 + private ParametersAnalyzeResult getAnalyzerKeyName(Map<String, String> keyNameOld, Map<String, String> keyNameNew) {
  793 + ParametersAnalyzeResult analyzerParameters = new ParametersAnalyzeResult();
  794 + Set<String> paths = keyNameNew.entrySet()
  795 + .stream()
  796 + .filter(e -> !e.getValue().equals(keyNameOld.get(e.getKey())))
  797 + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).keySet();
  798 + analyzerParameters.setPathPostParametersAdd(paths);
  799 + return analyzerParameters;
  800 + }
  801 +
  802 + /**
  803 + * #6.1 - send update WriteAttribute
  804 + * #6.2 - send empty WriteAttribute
  805 + */
  806 + private void compareAndSendWriteAttributes(List<LwM2mClient> clients, Map<String, ObjectAttributes> lwm2mAttributesOld, Map<String, ObjectAttributes> lwm2mAttributesNew) {
  807 + ParametersAnalyzeResult analyzerParameters = new ParametersAnalyzeResult();
  808 + Set<String> pathOld = lwm2mAttributesOld.keySet();
  809 + Set<String> pathNew = lwm2mAttributesNew.keySet();
  810 + analyzerParameters.setPathPostParametersAdd(pathNew
  811 + .stream().filter(p -> !pathOld.contains(p)).collect(Collectors.toSet()));
  812 + analyzerParameters.setPathPostParametersDel(pathOld
  813 + .stream().filter(p -> !pathNew.contains(p)).collect(Collectors.toSet()));
  814 + Set<String> pathCommon = pathNew
  815 + .stream().filter(pathOld::contains).collect(Collectors.toSet());
  816 + Set<String> pathCommonChange = pathCommon
  817 + .stream().filter(p -> !lwm2mAttributesOld.get(p).equals(lwm2mAttributesNew.get(p))).collect(Collectors.toSet());
  818 + analyzerParameters.getPathPostParametersAdd().addAll(pathCommonChange);
  819 + // #6
  820 + // #6.2
  821 + if (analyzerParameters.getPathPostParametersAdd().size() > 0) {
  822 + clients.forEach(client -> {
  823 + Set<String> clientObjects = clientContext.getSupportedIdVerInClient(client);
  824 + Set<String> pathSend = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))
  825 + .collect(Collectors.toUnmodifiableSet());
  826 + if (!pathSend.isEmpty()) {
  827 + pathSend.forEach(target -> sendWriteAttributesRequest(client, target, lwm2mAttributesNew.get(target)));
  828 + }
  829 + });
  830 + }
  831 + // #6.2
  832 + if (analyzerParameters.getPathPostParametersDel().size() > 0) {
  833 + clients.forEach(client -> {
  834 + Set<String> clientObjects = clientContext.getSupportedIdVerInClient(client);
  835 + Set<String> pathSend = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))
  836 + .collect(Collectors.toUnmodifiableSet());
  837 + if (!pathSend.isEmpty()) {
  838 + pathSend.forEach(target -> sendWriteAttributesRequest(client, target, new ObjectAttributes()));
  839 + }
  840 + });
  841 + }
  842 + }
  843 +
  844 + /**
  845 + * @param updateCredentials - Credentials include config only security Client (without config attr/telemetry...)
  846 + * config attr/telemetry... in profile
  847 + */
  848 + @Override
  849 + public void onToTransportUpdateCredentials(TransportProtos.ToTransportUpdateCredentialsProto updateCredentials) {
  850 + log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList());
  851 + }
  852 +
  853 + /**
  854 + * @param lwM2MClient -
  855 + * @return SessionInfoProto -
  856 + */
  857 + private SessionInfoProto getSessionInfo(LwM2mClient lwM2MClient) {
  858 + if (lwM2MClient != null && lwM2MClient.getSession() != null) {
  859 + return lwM2MClient.getSession();
  860 + }
  861 + return null;
  862 + }
  863 +
  864 + /**
  865 + * @param registration - Registration LwM2M Client
  866 + * @return - sessionInfo after access connect client
  867 + */
  868 + public SessionInfoProto getSessionInfoOrCloseSession(Registration registration) {
  869 + return getSessionInfo(clientContext.getClientByEndpoint(registration.getEndpoint()));
  870 + }
  871 +
  872 + /**
  873 + * if sessionInfo removed from sessions, then new registerAsyncSession
  874 + *
  875 + * @param sessionInfo -
  876 + */
  877 + private void reportActivityAndRegister(SessionInfoProto sessionInfo) {
  878 + if (sessionInfo != null && transportService.reportActivity(sessionInfo) == null) {
  879 + transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, attributesService, rpcHandler, sessionInfo));
  880 + this.reportActivitySubscription(sessionInfo);
  881 + }
  882 + }
  883 +
  884 + private void reportActivity() {
  885 + clientContext.getLwM2mClients().forEach(client -> reportActivityAndRegister(client.getSession()));
  886 + }
  887 +
  888 + /**
  889 + * #1. !!! sharedAttr === profileAttr !!!
  890 + * - If there is a difference in values between the current resource values and the shared attribute values
  891 + * - when the client connects to the server
  892 + * #1.1 get attributes name from profile include name resources in ModelObject if resource isWritable
  893 + * #1.2 #1 size > 0 => send Request getAttributes to thingsboard
  894 + * #2. FirmwareAttribute subscribe:
  895 + *
  896 + * @param lwM2MClient - LwM2M Client
  897 + */
  898 + public void initAttributes(LwM2mClient lwM2MClient) {
  899 + Map<String, String> keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient);
  900 + if (!keyNamesMap.isEmpty()) {
  901 + Set<String> keysToFetch = new HashSet<>(keyNamesMap.values());
  902 + keysToFetch.removeAll(OtaPackageUtil.ALL_FW_ATTRIBUTE_KEYS);
  903 + keysToFetch.removeAll(OtaPackageUtil.ALL_SW_ATTRIBUTE_KEYS);
  904 + DonAsynchron.withCallback(attributesService.getSharedAttributes(lwM2MClient, keysToFetch),
  905 + v -> attributesService.onAttributesUpdate(lwM2MClient, v),
  906 + t -> log.error("[{}] Failed to get attributes", lwM2MClient.getEndpoint(), t),
  907 + executor);
  908 + }
  909 + }
  910 +
  911 + private TransportProtos.GetOtaPackageRequestMsg createOtaPackageRequestMsg(SessionInfoProto sessionInfo, String nameFwSW) {
  912 + return TransportProtos.GetOtaPackageRequestMsg.newBuilder()
  913 + .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
  914 + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
  915 + .setTenantIdMSB(sessionInfo.getTenantIdMSB())
  916 + .setTenantIdLSB(sessionInfo.getTenantIdLSB())
  917 + .setType(nameFwSW)
  918 + .build();
  919 + }
  920 +
  921 + private Map<String, String> getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) {
  922 + Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId());
  923 + return profile.getObserveAttr().getKeyName();
  924 + }
  925 +
  926 + public LwM2MTransportServerConfig getConfig() {
  927 + return this.config;
  928 + }
  929 +
  930 + private void reportActivitySubscription(TransportProtos.SessionInfoProto sessionInfo) {
  931 + transportService.process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder()
  932 + .setAttributeSubscription(true)
  933 + .setRpcSubscription(true)
  934 + .setLastActivityTime(System.currentTimeMillis())
  935 + .build(), TransportServiceCallback.EMPTY);
  936 + }
  937 +}
... ...
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java renamed from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java
... ... @@ -13,9 +13,10 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.transport.lwm2m.server;
  16 +package org.thingsboard.server.transport.lwm2m.server.uplink;
17 17
18 18 import org.eclipse.leshan.core.observation.Observation;
  19 +import org.eclipse.leshan.core.request.WriteRequest;
19 20 import org.eclipse.leshan.core.response.ReadResponse;
20 21 import org.eclipse.leshan.server.registration.Registration;
21 22 import org.thingsboard.server.common.data.Device;
... ... @@ -23,12 +24,11 @@ import org.thingsboard.server.common.data.DeviceProfile;
23 24 import org.thingsboard.server.gen.transport.TransportProtos;
24 25 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
25 26 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
26   -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientRpcRequest;
27 27
28 28 import java.util.Collection;
29 29 import java.util.Optional;
30 30
31   -public interface LwM2mTransportMsgHandler {
  31 +public interface LwM2mUplinkMsgHandler {
32 32
33 33 void onRegistered(Registration registration, Collection<Observation> previousObsersations);
34 34
... ... @@ -38,33 +38,23 @@ public interface LwM2mTransportMsgHandler {
38 38
39 39 void onSleepingDev(Registration registration);
40 40
41   - void setCancelObservationsAll(Registration registration);
42   -
43   - void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, LwM2mClientRpcRequest rpcRequest);
44   -
45   - void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo);
  41 + void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response);
46 42
47 43 void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile);
48 44
49 45 void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt);
50 46
51   - void onResourceUpdate (Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt);
  47 + void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt);
52 48
53 49 void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt);
54 50
55   - void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest, TransportProtos.SessionInfoProto sessionInfo);
56   -
57   - void onToDeviceRpcResponse(TransportProtos.ToDeviceRpcResponseMsg toDeviceRpcResponse, TransportProtos.SessionInfoProto sessionInfo);
58   -
59   - void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse);
60   -
61 51 void doDisconnect(TransportProtos.SessionInfoProto sessionInfo);
62 52
63 53 void onAwakeDev(Registration registration);
64 54
65   - void sendLogsToThingsboard(LwM2mClient client, String msg);
  55 + void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request);
66 56
67   - void sendLogsToThingsboard(String registrationId, String msg);
  57 + void onToTransportUpdateCredentials(TransportProtos.ToTransportUpdateCredentialsProto updateCredentials);
68 58
69 59 LwM2MTransportServerConfig getConfig();
70 60 }
... ...
... ... @@ -117,7 +117,7 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
117 117 switch (currentType) {
118 118 case INTEGER:
119 119 log.debug("Trying to convert long value {} to date", value);
120   - /** let's assume we received the millisecond since 1970/1/1 */
  120 + /* let's assume we received the millisecond since 1970/1/1 */
121 121 return new Date(((Number) value).longValue() * 1000L);
122 122 case STRING:
123 123 log.debug("Trying to convert string value {} to date", value);
... ...
... ... @@ -142,12 +142,10 @@ transport:
142 142 timeout: "${LWM2M_TIMEOUT:120000}"
143 143 recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
144 144 recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
145   - response_pool_size: "${LWM2M_RESPONSE_POOL_SIZE:100}"
146   - registered_pool_size: "${LWM2M_REGISTERED_POOL_SIZE:10}"
147   - registration_store_pool_size: "${LWM2M_REGISTRATION_STORE_POOL_SIZE:100}"
  145 + uplink_pool_size: "${LWM2M_UPLINK_POOL_SIZE:10}"
  146 + downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}"
  147 + ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}"
148 148 clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}"
149   - update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}"
150   - un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}"
151 149 log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}"
152 150 # Use redis for Security and Registration stores
153 151 redis.enabled: "${LWM2M_REDIS_ENABLED:false}"
... ...
... ... @@ -89,6 +89,13 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
89 89 objectsList: [this.objectsList],
90 90 objectLwm2m: ['']
91 91 });
  92 + this.lwm2mListFormGroup.valueChanges.subscribe((value) => {
  93 + let formValue = null;
  94 + if (this.lwm2mListFormGroup.valid) {
  95 + formValue = value;
  96 + }
  97 + this.propagateChange(formValue);
  98 + });
92 99 }
93 100
94 101 private updateValidators = (): void => {
... ... @@ -142,7 +149,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
142 149 this.objectsList = [];
143 150 this.modelValue = [];
144 151 }
145   - this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList, {emitEvents: false});
  152 + this.lwm2mListFormGroup.patchValue({objectsList: this.objectsList}, {emitEvent: false});
146 153 this.dirty = false;
147 154 }
148 155 }
... ... @@ -195,9 +202,9 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
195 202 }
196 203 }
197 204
198   - private clear = (): void => {
  205 + private clear() {
199 206 this.searchText = '';
200   - this.lwm2mListFormGroup.get('objectLwm2m').patchValue(null);
  207 + this.lwm2mListFormGroup.get('objectLwm2m').patchValue(null, {emitEvent: false});
201 208 setTimeout(() => {
202 209 this.objectInput.nativeElement.blur();
203 210 this.objectInput.nativeElement.focus();
... ...