Commit 15d725570d25ad7d81ee18435fb1c65bccba7d0f

Authored by Andrii Shvaika
2 parents ab5c803a e9f5fd27

Merge with master

Showing 59 changed files with 2035 additions and 736 deletions

Too many changes to show.

To preserve performance only 59 of 142 files are displayed.

@@ -146,6 +146,10 @@ @@ -146,6 +146,10 @@
146 <scope>runtime</scope> 146 <scope>runtime</scope>
147 </dependency> 147 </dependency>
148 <dependency> 148 <dependency>
  149 + <groupId>org.springframework.integration</groupId>
  150 + <artifactId>spring-integration-redis</artifactId>
  151 + </dependency>
  152 + <dependency>
149 <groupId>org.springframework.boot</groupId> 153 <groupId>org.springframework.boot</groupId>
150 <artifactId>spring-boot-starter-security</artifactId> 154 <artifactId>spring-boot-starter-security</artifactId>
151 </dependency> 155 </dependency>
@@ -78,14 +78,24 @@ CREATE TABLE IF NOT EXISTS firmware ( @@ -78,14 +78,24 @@ CREATE TABLE IF NOT EXISTS firmware (
78 CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version) 78 CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
79 ); 79 );
80 80
  81 +ALTER TABLE dashboard
  82 + ADD COLUMN IF NOT EXISTS image varchar(1000000);
  83 +
81 ALTER TABLE device_profile 84 ALTER TABLE device_profile
  85 + ADD COLUMN IF NOT EXISTS image varchar(1000000),
82 ADD COLUMN IF NOT EXISTS firmware_id uuid, 86 ADD COLUMN IF NOT EXISTS firmware_id uuid,
83 - ADD COLUMN IF NOT EXISTS software_id uuid; 87 + ADD COLUMN IF NOT EXISTS software_id uuid,
  88 + ADD COLUMN IF NOT EXISTS default_dashboard_id uuid;
84 89
85 ALTER TABLE device 90 ALTER TABLE device
86 ADD COLUMN IF NOT EXISTS firmware_id uuid, 91 ADD COLUMN IF NOT EXISTS firmware_id uuid,
87 ADD COLUMN IF NOT EXISTS software_id uuid; 92 ADD COLUMN IF NOT EXISTS software_id uuid;
88 93
  94 +ALTER TABLE alarm
  95 + ADD COLUMN IF NOT EXISTS customer_id uuid;
  96 +
  97 +DELETE FROM relation WHERE from_type = 'TENANT' AND relation_type_group = 'RULE_CHAIN';
  98 +
89 DO $$ 99 DO $$
90 BEGIN 100 BEGIN
91 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device_profile') THEN 101 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device_profile') THEN
@@ -100,6 +110,12 @@ DO $$ @@ -100,6 +110,12 @@ DO $$
100 FOREIGN KEY (firmware_id) REFERENCES firmware(id); 110 FOREIGN KEY (firmware_id) REFERENCES firmware(id);
101 END IF; 111 END IF;
102 112
  113 + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_default_dashboard_device_profile') THEN
  114 + ALTER TABLE device_profile
  115 + ADD CONSTRAINT fk_default_dashboard_device_profile
  116 + FOREIGN KEY (default_dashboard_id) REFERENCES dashboard(id);
  117 + END IF;
  118 +
103 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device') THEN 119 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device') THEN
104 ALTER TABLE device 120 ALTER TABLE device
105 ADD CONSTRAINT fk_firmware_device 121 ADD CONSTRAINT fk_firmware_device
@@ -114,3 +130,7 @@ DO $$ @@ -114,3 +130,7 @@ DO $$
114 END; 130 END;
115 $$; 131 $$;
116 132
  133 +
  134 +ALTER TABLE api_usage_state
  135 + ADD COLUMN IF NOT EXISTS alarm_exec VARCHAR(32);
  136 +UPDATE api_usage_state SET alarm_exec = 'ENABLED' WHERE alarm_exec IS NULL;
@@ -197,6 +197,40 @@ public class AlarmController extends BaseController { @@ -197,6 +197,40 @@ public class AlarmController extends BaseController {
197 } 197 }
198 198
199 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 199 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
  200 + @RequestMapping(value = "/alarms", method = RequestMethod.GET)
  201 + @ResponseBody
  202 + public PageData<AlarmInfo> getAllAlarms(
  203 + @RequestParam(required = false) String searchStatus,
  204 + @RequestParam(required = false) String status,
  205 + @RequestParam int pageSize,
  206 + @RequestParam int page,
  207 + @RequestParam(required = false) String textSearch,
  208 + @RequestParam(required = false) String sortProperty,
  209 + @RequestParam(required = false) String sortOrder,
  210 + @RequestParam(required = false) Long startTime,
  211 + @RequestParam(required = false) Long endTime,
  212 + @RequestParam(required = false) Boolean fetchOriginator
  213 + ) throws ThingsboardException {
  214 + AlarmSearchStatus alarmSearchStatus = StringUtils.isEmpty(searchStatus) ? null : AlarmSearchStatus.valueOf(searchStatus);
  215 + AlarmStatus alarmStatus = StringUtils.isEmpty(status) ? null : AlarmStatus.valueOf(status);
  216 + if (alarmSearchStatus != null && alarmStatus != null) {
  217 + throw new ThingsboardException("Invalid alarms search query: Both parameters 'searchStatus' " +
  218 + "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
  219 + }
  220 + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
  221 +
  222 + try {
  223 + if (getCurrentUser().isCustomerUser()) {
  224 + return checkNotNull(alarmService.findCustomerAlarms(getCurrentUser().getTenantId(), getCurrentUser().getCustomerId(), new AlarmQuery(null, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get());
  225 + } else {
  226 + return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(null, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get());
  227 + }
  228 + } catch (Exception e) {
  229 + throw handleException(e);
  230 + }
  231 + }
  232 +
  233 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
200 @RequestMapping(value = "/alarm/highestSeverity/{entityType}/{entityId}", method = RequestMethod.GET) 234 @RequestMapping(value = "/alarm/highestSeverity/{entityType}/{entityId}", method = RequestMethod.GET)
201 @ResponseBody 235 @ResponseBody
202 public AlarmSeverity getHighestAlarmSeverity( 236 public AlarmSeverity getHighestAlarmSeverity(
@@ -106,6 +106,8 @@ public abstract class BaseApiUsageState { @@ -106,6 +106,8 @@ public abstract class BaseApiUsageState {
106 return apiUsageState.getEmailExecState(); 106 return apiUsageState.getEmailExecState();
107 case SMS: 107 case SMS:
108 return apiUsageState.getSmsExecState(); 108 return apiUsageState.getSmsExecState();
  109 + case ALARM:
  110 + return apiUsageState.getAlarmExecState();
109 default: 111 default:
110 return ApiUsageStateValue.ENABLED; 112 return ApiUsageStateValue.ENABLED;
111 } 113 }
@@ -132,6 +134,9 @@ public abstract class BaseApiUsageState { @@ -132,6 +134,9 @@ public abstract class BaseApiUsageState {
132 case SMS: 134 case SMS:
133 apiUsageState.setSmsExecState(value); 135 apiUsageState.setSmsExecState(value);
134 break; 136 break;
  137 + case ALARM:
  138 + apiUsageState.setAlarmExecState(value);
  139 + break;
135 } 140 }
136 return !currentValue.equals(value); 141 return !currentValue.equals(value);
137 } 142 }
@@ -24,8 +24,9 @@ import org.thingsboard.server.common.data.DataConstants; @@ -24,8 +24,9 @@ import org.thingsboard.server.common.data.DataConstants;
24 import org.thingsboard.server.common.data.Device; 24 import org.thingsboard.server.common.data.Device;
25 import org.thingsboard.server.common.data.DeviceProfile; 25 import org.thingsboard.server.common.data.DeviceProfile;
26 import org.thingsboard.server.common.data.FirmwareInfo; 26 import org.thingsboard.server.common.data.FirmwareInfo;
27 -import org.thingsboard.server.common.data.firmware.FirmwareUtil;  
28 import org.thingsboard.server.common.data.firmware.FirmwareType; 27 import org.thingsboard.server.common.data.firmware.FirmwareType;
  28 +import org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus;
  29 +import org.thingsboard.server.common.data.firmware.FirmwareUtil;
29 import org.thingsboard.server.common.data.id.DeviceId; 30 import org.thingsboard.server.common.data.id.DeviceId;
30 import org.thingsboard.server.common.data.id.FirmwareId; 31 import org.thingsboard.server.common.data.id.FirmwareId;
31 import org.thingsboard.server.common.data.id.TenantId; 32 import org.thingsboard.server.common.data.id.TenantId;
@@ -66,11 +67,11 @@ import static org.thingsboard.server.common.data.firmware.FirmwareKey.STATE; @@ -66,11 +67,11 @@ import static org.thingsboard.server.common.data.firmware.FirmwareKey.STATE;
66 import static org.thingsboard.server.common.data.firmware.FirmwareKey.TITLE; 67 import static org.thingsboard.server.common.data.firmware.FirmwareKey.TITLE;
67 import static org.thingsboard.server.common.data.firmware.FirmwareKey.TS; 68 import static org.thingsboard.server.common.data.firmware.FirmwareKey.TS;
68 import static org.thingsboard.server.common.data.firmware.FirmwareKey.VERSION; 69 import static org.thingsboard.server.common.data.firmware.FirmwareKey.VERSION;
  70 +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
  71 +import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;
69 import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getAttributeKey; 72 import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getAttributeKey;
70 import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getTargetTelemetryKey; 73 import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getTargetTelemetryKey;
71 import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getTelemetryKey; 74 import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getTelemetryKey;
72 -import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;  
73 -import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;  
74 75
75 @Slf4j 76 @Slf4j
76 @Service 77 @Service
@@ -27,6 +27,9 @@ import org.thingsboard.rule.engine.profile.TbDeviceProfileNode; @@ -27,6 +27,9 @@ import org.thingsboard.rule.engine.profile.TbDeviceProfileNode;
27 import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration; 27 import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration;
28 import org.thingsboard.server.common.data.EntityView; 28 import org.thingsboard.server.common.data.EntityView;
29 import org.thingsboard.server.common.data.Tenant; 29 import org.thingsboard.server.common.data.Tenant;
  30 +import org.thingsboard.server.common.data.alarm.Alarm;
  31 +import org.thingsboard.server.common.data.alarm.AlarmInfo;
  32 +import org.thingsboard.server.common.data.alarm.AlarmQuery;
30 import org.thingsboard.server.common.data.id.EntityViewId; 33 import org.thingsboard.server.common.data.id.EntityViewId;
31 import org.thingsboard.server.common.data.id.TenantId; 34 import org.thingsboard.server.common.data.id.TenantId;
32 import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; 35 import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
@@ -34,9 +37,13 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery; @@ -34,9 +37,13 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
34 import org.thingsboard.server.common.data.kv.TsKvEntry; 37 import org.thingsboard.server.common.data.kv.TsKvEntry;
35 import org.thingsboard.server.common.data.page.PageData; 38 import org.thingsboard.server.common.data.page.PageData;
36 import org.thingsboard.server.common.data.page.PageLink; 39 import org.thingsboard.server.common.data.page.PageLink;
  40 +import org.thingsboard.server.common.data.page.TimePageLink;
37 import org.thingsboard.server.common.data.rule.RuleChain; 41 import org.thingsboard.server.common.data.rule.RuleChain;
38 import org.thingsboard.server.common.data.rule.RuleChainMetaData; 42 import org.thingsboard.server.common.data.rule.RuleChainMetaData;
39 import org.thingsboard.server.common.data.rule.RuleNode; 43 import org.thingsboard.server.common.data.rule.RuleNode;
  44 +import org.thingsboard.server.dao.alarm.AlarmDao;
  45 +import org.thingsboard.server.dao.alarm.AlarmService;
  46 +import org.thingsboard.server.dao.entity.EntityService;
40 import org.thingsboard.server.dao.entityview.EntityViewService; 47 import org.thingsboard.server.dao.entityview.EntityViewService;
41 import org.thingsboard.server.dao.rule.RuleChainService; 48 import org.thingsboard.server.dao.rule.RuleChainService;
42 import org.thingsboard.server.dao.tenant.TenantService; 49 import org.thingsboard.server.dao.tenant.TenantService;
@@ -72,6 +79,15 @@ public class DefaultDataUpdateService implements DataUpdateService { @@ -72,6 +79,15 @@ public class DefaultDataUpdateService implements DataUpdateService {
72 @Autowired 79 @Autowired
73 private TimeseriesService tsService; 80 private TimeseriesService tsService;
74 81
  82 + @Autowired
  83 + private AlarmService alarmService;
  84 +
  85 + @Autowired
  86 + private EntityService entityService;
  87 +
  88 + @Autowired
  89 + private AlarmDao alarmDao;
  90 +
75 @Override 91 @Override
76 public void updateData(String fromVersion) throws Exception { 92 public void updateData(String fromVersion) throws Exception {
77 switch (fromVersion) { 93 switch (fromVersion) {
@@ -90,14 +106,25 @@ public class DefaultDataUpdateService implements DataUpdateService { @@ -90,14 +106,25 @@ public class DefaultDataUpdateService implements DataUpdateService {
90 case "3.2.2": 106 case "3.2.2":
91 log.info("Updating data from version 3.2.2 to 3.3.0 ..."); 107 log.info("Updating data from version 3.2.2 to 3.3.0 ...");
92 tenantsDefaultEdgeRuleChainUpdater.updateEntities(null); 108 tenantsDefaultEdgeRuleChainUpdater.updateEntities(null);
  109 + tenantsAlarmsCustomerUpdater.updateEntities(null);
93 break; 110 break;
94 default: 111 default:
95 throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); 112 throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion);
96 } 113 }
97 } 114 }
98 115
99 - private PaginatedUpdater<String, Tenant> tenantsDefaultRuleChainUpdater =  
100 - new PaginatedUpdater<String, Tenant>() { 116 + private final PaginatedUpdater<String, Tenant> tenantsDefaultRuleChainUpdater =
  117 + new PaginatedUpdater<>() {
  118 +
  119 + @Override
  120 + protected String getName() {
  121 + return "Tenants default rule chain updater";
  122 + }
  123 +
  124 + @Override
  125 + protected boolean forceReportTotal() {
  126 + return true;
  127 + }
101 128
102 @Override 129 @Override
103 protected PageData<Tenant> findEntities(String region, PageLink pageLink) { 130 protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
@@ -117,8 +144,18 @@ public class DefaultDataUpdateService implements DataUpdateService { @@ -117,8 +144,18 @@ public class DefaultDataUpdateService implements DataUpdateService {
117 } 144 }
118 }; 145 };
119 146
120 - private PaginatedUpdater<String, Tenant> tenantsDefaultEdgeRuleChainUpdater =  
121 - new PaginatedUpdater<String, Tenant>() { 147 + private final PaginatedUpdater<String, Tenant> tenantsDefaultEdgeRuleChainUpdater =
  148 + new PaginatedUpdater<>() {
  149 +
  150 + @Override
  151 + protected String getName() {
  152 + return "Tenants default edge rule chain updater";
  153 + }
  154 +
  155 + @Override
  156 + protected boolean forceReportTotal() {
  157 + return true;
  158 + }
122 159
123 @Override 160 @Override
124 protected PageData<Tenant> findEntities(String region, PageLink pageLink) { 161 protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
@@ -138,8 +175,18 @@ public class DefaultDataUpdateService implements DataUpdateService { @@ -138,8 +175,18 @@ public class DefaultDataUpdateService implements DataUpdateService {
138 } 175 }
139 }; 176 };
140 177
141 - private PaginatedUpdater<String, Tenant> tenantsRootRuleChainUpdater =  
142 - new PaginatedUpdater<String, Tenant>() { 178 + private final PaginatedUpdater<String, Tenant> tenantsRootRuleChainUpdater =
  179 + new PaginatedUpdater<>() {
  180 +
  181 + @Override
  182 + protected String getName() {
  183 + return "Tenants root rule chain updater";
  184 + }
  185 +
  186 + @Override
  187 + protected boolean forceReportTotal() {
  188 + return true;
  189 + }
143 190
144 @Override 191 @Override
145 protected PageData<Tenant> findEntities(String region, PageLink pageLink) { 192 protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
@@ -192,8 +239,18 @@ public class DefaultDataUpdateService implements DataUpdateService { @@ -192,8 +239,18 @@ public class DefaultDataUpdateService implements DataUpdateService {
192 } 239 }
193 }; 240 };
194 241
195 - private PaginatedUpdater<String, Tenant> tenantsEntityViewsUpdater =  
196 - new PaginatedUpdater<String, Tenant>() { 242 + private final PaginatedUpdater<String, Tenant> tenantsEntityViewsUpdater =
  243 + new PaginatedUpdater<>() {
  244 +
  245 + @Override
  246 + protected String getName() {
  247 + return "Tenants entity views updater";
  248 + }
  249 +
  250 + @Override
  251 + protected boolean forceReportTotal() {
  252 + return true;
  253 + }
197 254
198 @Override 255 @Override
199 protected PageData<Tenant> findEntities(String region, PageLink pageLink) { 256 protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
@@ -261,4 +318,48 @@ public class DefaultDataUpdateService implements DataUpdateService { @@ -261,4 +318,48 @@ public class DefaultDataUpdateService implements DataUpdateService {
261 }, MoreExecutors.directExecutor()); 318 }, MoreExecutors.directExecutor());
262 } 319 }
263 320
  321 + private final PaginatedUpdater<String, Tenant> tenantsAlarmsCustomerUpdater =
  322 + new PaginatedUpdater<>() {
  323 +
  324 + @Override
  325 + protected String getName() {
  326 + return "Tenants alarms customer updater";
  327 + }
  328 +
  329 + @Override
  330 + protected boolean forceReportTotal() {
  331 + return true;
  332 + }
  333 +
  334 + @Override
  335 + protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
  336 + return tenantService.findTenants(pageLink);
  337 + }
  338 +
  339 + @Override
  340 + protected void updateEntity(Tenant tenant) {
  341 + updateTenantAlarmsCustomer(tenant.getId());
  342 + }
  343 + };
  344 +
  345 + private void updateTenantAlarmsCustomer(TenantId tenantId) {
  346 + AlarmQuery alarmQuery = new AlarmQuery(null, new TimePageLink(100), null, null, false);
  347 + PageData<AlarmInfo> alarms = alarmDao.findAlarms(tenantId, alarmQuery);
  348 + boolean hasNext = true;
  349 + while (hasNext) {
  350 + for (Alarm alarm : alarms.getData()) {
  351 + if (alarm.getCustomerId() == null && alarm.getOriginator() != null) {
  352 + alarm.setCustomerId(entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator()));
  353 + alarmDao.save(tenantId, alarm);
  354 + }
  355 + }
  356 + if (alarms.hasNext()) {
  357 + alarmQuery.setPageLink(alarmQuery.getPageLink().nextPageLink());
  358 + alarms = alarmDao.findAlarms(tenantId, alarmQuery);
  359 + } else {
  360 + hasNext = false;
  361 + }
  362 + }
  363 + }
  364 +
264 } 365 }
@@ -15,16 +15,20 @@ @@ -15,16 +15,20 @@
15 */ 15 */
16 package org.thingsboard.server.service.install.update; 16 package org.thingsboard.server.service.install.update;
17 17
  18 +import lombok.extern.slf4j.Slf4j;
18 import org.thingsboard.server.common.data.SearchTextBased; 19 import org.thingsboard.server.common.data.SearchTextBased;
19 import org.thingsboard.server.common.data.id.UUIDBased; 20 import org.thingsboard.server.common.data.id.UUIDBased;
20 import org.thingsboard.server.common.data.page.PageData; 21 import org.thingsboard.server.common.data.page.PageData;
21 import org.thingsboard.server.common.data.page.PageLink; 22 import org.thingsboard.server.common.data.page.PageLink;
22 23
  24 +@Slf4j
23 public abstract class PaginatedUpdater<I, D extends SearchTextBased<? extends UUIDBased>> { 25 public abstract class PaginatedUpdater<I, D extends SearchTextBased<? extends UUIDBased>> {
24 26
25 private static final int DEFAULT_LIMIT = 100; 27 private static final int DEFAULT_LIMIT = 100;
  28 + private int updated = 0;
26 29
27 public void updateEntities(I id) { 30 public void updateEntities(I id) {
  31 + updated = 0;
28 PageLink pageLink = new PageLink(DEFAULT_LIMIT); 32 PageLink pageLink = new PageLink(DEFAULT_LIMIT);
29 boolean hasNext = true; 33 boolean hasNext = true;
30 while (hasNext) { 34 while (hasNext) {
@@ -32,13 +36,25 @@ public abstract class PaginatedUpdater<I, D extends SearchTextBased<? extends UU @@ -32,13 +36,25 @@ public abstract class PaginatedUpdater<I, D extends SearchTextBased<? extends UU
32 for (D entity : entities.getData()) { 36 for (D entity : entities.getData()) {
33 updateEntity(entity); 37 updateEntity(entity);
34 } 38 }
  39 + updated += entities.getData().size();
35 hasNext = entities.hasNext(); 40 hasNext = entities.hasNext();
36 if (hasNext) { 41 if (hasNext) {
  42 + log.info("{}: {} entities updated so far...", getName(), updated);
37 pageLink = pageLink.nextPageLink(); 43 pageLink = pageLink.nextPageLink();
  44 + } else {
  45 + if (updated > DEFAULT_LIMIT || forceReportTotal()) {
  46 + log.info("{}: {} total entities updated.", getName(), updated);
  47 + }
38 } 48 }
39 } 49 }
40 } 50 }
41 51
  52 + protected boolean forceReportTotal() {
  53 + return false;
  54 + }
  55 +
  56 + protected abstract String getName();
  57 +
42 protected abstract PageData<D> findEntities(I id, PageLink pageLink); 58 protected abstract PageData<D> findEntities(I id, PageLink pageLink);
43 59
44 protected abstract void updateEntity(D entity); 60 protected abstract void updateEntity(D entity);
@@ -309,6 +309,8 @@ public class DefaultMailService implements MailService { @@ -309,6 +309,8 @@ public class DefaultMailService implements MailService {
309 case EMAIL: 309 case EMAIL:
310 case SMS: 310 case SMS:
311 return "send"; 311 return "send";
  312 + case ALARM:
  313 + return "create";
312 default: 314 default:
313 throw new RuntimeException("Not implemented!"); 315 throw new RuntimeException("Not implemented!");
314 } 316 }
@@ -327,6 +329,8 @@ public class DefaultMailService implements MailService { @@ -327,6 +329,8 @@ public class DefaultMailService implements MailService {
327 case EMAIL: 329 case EMAIL:
328 case SMS: 330 case SMS:
329 return "sent"; 331 return "sent";
  332 + case ALARM:
  333 + return "created";
330 default: 334 default:
331 throw new RuntimeException("Not implemented!"); 335 throw new RuntimeException("Not implemented!");
332 } 336 }
@@ -44,6 +44,7 @@ import java.util.Base64; @@ -44,6 +44,7 @@ import java.util.Base64;
44 import java.util.Comparator; 44 import java.util.Comparator;
45 import java.util.List; 45 import java.util.List;
46 import java.util.stream.Collectors; 46 import java.util.stream.Collectors;
  47 +import java.util.stream.Stream;
47 48
48 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY; 49 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
49 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_SEARCH_TEXT; 50 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_SEARCH_TEXT;
@@ -130,7 +131,7 @@ public class DefaultTbResourceService implements TbResourceService { @@ -130,7 +131,7 @@ public class DefaultTbResourceService implements TbResourceService {
130 List<TbResource> resources = resourceService.findTenantResourcesByResourceTypeAndObjectIds(tenantId, ResourceType.LWM2M_MODEL, 131 List<TbResource> resources = resourceService.findTenantResourcesByResourceTypeAndObjectIds(tenantId, ResourceType.LWM2M_MODEL,
131 objectIds); 132 objectIds);
132 return resources.stream() 133 return resources.stream()
133 - .map(this::toLwM2mObject) 134 + .flatMap(s -> Stream.ofNullable(toLwM2mObject(s)))
134 .sorted(getComparator(sortProperty, sortOrder)) 135 .sorted(getComparator(sortProperty, sortOrder))
135 .collect(Collectors.toList()); 136 .collect(Collectors.toList());
136 } 137 }
@@ -141,7 +142,7 @@ public class DefaultTbResourceService implements TbResourceService { @@ -141,7 +142,7 @@ public class DefaultTbResourceService implements TbResourceService {
141 validateId(tenantId, INCORRECT_TENANT_ID + tenantId); 142 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
142 PageData<TbResource> resourcePageData = resourceService.findTenantResourcesByResourceTypeAndPageLink(tenantId, ResourceType.LWM2M_MODEL, pageLink); 143 PageData<TbResource> resourcePageData = resourceService.findTenantResourcesByResourceTypeAndPageLink(tenantId, ResourceType.LWM2M_MODEL, pageLink);
143 return resourcePageData.getData().stream() 144 return resourcePageData.getData().stream()
144 - .map(this::toLwM2mObject) 145 + .flatMap(s -> Stream.ofNullable(toLwM2mObject(s)))
145 .sorted(getComparator(sortProperty, sortOrder)) 146 .sorted(getComparator(sortProperty, sortOrder))
146 .collect(Collectors.toList()); 147 .collect(Collectors.toList());
147 } 148 }
@@ -190,9 +191,14 @@ public class DefaultTbResourceService implements TbResourceService { @@ -190,9 +191,14 @@ public class DefaultTbResourceService implements TbResourceService {
190 resources.add(lwM2MResourceObserve); 191 resources.add(lwM2MResourceObserve);
191 } 192 }
192 }); 193 });
193 - instance.setResources(resources.toArray(LwM2mResourceObserve[]::new));  
194 - lwM2mObject.setInstances(new LwM2mInstance[]{instance});  
195 - return lwM2mObject; 194 + if (resources.size() > 0) {
  195 + instance.setResources(resources.toArray(LwM2mResourceObserve[]::new));
  196 + lwM2mObject.setInstances(new LwM2mInstance[]{instance});
  197 + return lwM2mObject;
  198 + }
  199 + else {
  200 + return null;
  201 + }
196 } 202 }
197 } catch (IOException | InvalidDDFFileException e) { 203 } catch (IOException | InvalidDDFFileException e) {
198 log.error("Could not parse the XML of objectModel with name [{}]", resource.getSearchText(), e); 204 log.error("Could not parse the XML of objectModel with name [{}]", resource.getSearchText(), e);
@@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j; @@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j;
23 import org.checkerframework.checker.nullness.qual.Nullable; 23 import org.checkerframework.checker.nullness.qual.Nullable;
24 import org.springframework.beans.factory.annotation.Autowired; 24 import org.springframework.beans.factory.annotation.Autowired;
25 import org.springframework.stereotype.Service; 25 import org.springframework.stereotype.Service;
  26 +import org.thingsboard.server.common.data.ApiUsageRecordKey;
26 import org.thingsboard.server.common.data.alarm.Alarm; 27 import org.thingsboard.server.common.data.alarm.Alarm;
27 import org.thingsboard.server.common.data.alarm.AlarmInfo; 28 import org.thingsboard.server.common.data.alarm.AlarmInfo;
28 import org.thingsboard.server.common.data.alarm.AlarmQuery; 29 import org.thingsboard.server.common.data.alarm.AlarmQuery;
@@ -43,6 +44,8 @@ import org.thingsboard.server.dao.alarm.AlarmOperationResult; @@ -43,6 +44,8 @@ import org.thingsboard.server.dao.alarm.AlarmOperationResult;
43 import org.thingsboard.server.dao.alarm.AlarmService; 44 import org.thingsboard.server.dao.alarm.AlarmService;
44 import org.thingsboard.server.gen.transport.TransportProtos; 45 import org.thingsboard.server.gen.transport.TransportProtos;
45 import org.thingsboard.server.queue.discovery.PartitionService; 46 import org.thingsboard.server.queue.discovery.PartitionService;
  47 +import org.thingsboard.server.queue.usagestats.TbApiUsageClient;
  48 +import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
46 import org.thingsboard.server.service.queue.TbClusterService; 49 import org.thingsboard.server.service.queue.TbClusterService;
47 import org.thingsboard.server.service.subscription.SubscriptionManagerService; 50 import org.thingsboard.server.service.subscription.SubscriptionManagerService;
48 import org.thingsboard.server.service.subscription.TbSubscriptionUtils; 51 import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
@@ -58,12 +61,18 @@ import java.util.Optional; @@ -58,12 +61,18 @@ import java.util.Optional;
58 public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService implements AlarmSubscriptionService { 61 public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService implements AlarmSubscriptionService {
59 62
60 private final AlarmService alarmService; 63 private final AlarmService alarmService;
  64 + private final TbApiUsageClient apiUsageClient;
  65 + private final TbApiUsageStateService apiUsageStateService;
61 66
62 public DefaultAlarmSubscriptionService(TbClusterService clusterService, 67 public DefaultAlarmSubscriptionService(TbClusterService clusterService,
63 PartitionService partitionService, 68 PartitionService partitionService,
64 - AlarmService alarmService) { 69 + AlarmService alarmService,
  70 + TbApiUsageClient apiUsageClient,
  71 + TbApiUsageStateService apiUsageStateService) {
65 super(clusterService, partitionService); 72 super(clusterService, partitionService);
66 this.alarmService = alarmService; 73 this.alarmService = alarmService;
  74 + this.apiUsageClient = apiUsageClient;
  75 + this.apiUsageStateService = apiUsageStateService;
67 } 76 }
68 77
69 @Autowired(required = false) 78 @Autowired(required = false)
@@ -78,10 +87,13 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService @@ -78,10 +87,13 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService
78 87
79 @Override 88 @Override
80 public Alarm createOrUpdateAlarm(Alarm alarm) { 89 public Alarm createOrUpdateAlarm(Alarm alarm) {
81 - AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm); 90 + AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm, apiUsageStateService.getApiUsageState(alarm.getTenantId()).isAlarmCreationEnabled());
82 if (result.isSuccessful()) { 91 if (result.isSuccessful()) {
83 onAlarmUpdated(result); 92 onAlarmUpdated(result);
84 } 93 }
  94 + if (result.isCreated()) {
  95 + apiUsageClient.report(alarm.getTenantId(), null, ApiUsageRecordKey.CREATED_ALARMS_COUNT);
  96 + }
85 return result.getAlarm(); 97 return result.getAlarm();
86 } 98 }
87 99
@@ -128,6 +140,11 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService @@ -128,6 +140,11 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService
128 } 140 }
129 141
130 @Override 142 @Override
  143 + public ListenableFuture<PageData<AlarmInfo>> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query) {
  144 + return alarmService.findCustomerAlarms(tenantId, customerId, query);
  145 + }
  146 +
  147 + @Override
131 public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus) { 148 public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus) {
132 return alarmService.findHighestAlarmSeverity(tenantId, entityId, alarmSearchStatus, alarmStatus); 149 return alarmService.findHighestAlarmSeverity(tenantId, entityId, alarmSearchStatus, alarmStatus);
133 } 150 }
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 </appender> 26 </appender>
27 27
28 <logger name="org.thingsboard.server" level="INFO" /> 28 <logger name="org.thingsboard.server" level="INFO" />
29 - <logger name="org.thingsboard.server.transport.snmp" level="TRACE" /> 29 + <logger name="org.thingsboard.server.transport.snmp" level="DEBUG" />
30 30
31 <!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />--> 31 <!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />-->
32 <!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />--> 32 <!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />-->
@@ -673,6 +673,8 @@ transport: @@ -673,6 +673,8 @@ transport:
673 recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" 673 recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
674 response_pool_size: "${LWM2M_RESPONSE_POOL_SIZE:100}" 674 response_pool_size: "${LWM2M_RESPONSE_POOL_SIZE:100}"
675 registered_pool_size: "${LWM2M_REGISTERED_POOL_SIZE:10}" 675 registered_pool_size: "${LWM2M_REGISTERED_POOL_SIZE:10}"
  676 + registration_store_pool_size: "${LWM2M_REGISTRATION_STORE_POOL_SIZE:100}"
  677 + clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}"
676 update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}" 678 update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}"
677 un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}" 679 un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}"
678 log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}" 680 log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}"
@@ -313,7 +313,8 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -313,7 +313,8 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
313 Collections.sort(loadedDeviceProfileInfos, deviceProfileInfoIdComparator); 313 Collections.sort(loadedDeviceProfileInfos, deviceProfileInfoIdComparator);
314 314
315 List<DeviceProfileInfo> deviceProfileInfos = deviceProfiles.stream().map(deviceProfile -> new DeviceProfileInfo(deviceProfile.getId(), 315 List<DeviceProfileInfo> deviceProfileInfos = deviceProfiles.stream().map(deviceProfile -> new DeviceProfileInfo(deviceProfile.getId(),
316 - deviceProfile.getName(), deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList()); 316 + deviceProfile.getName(), deviceProfile.getImage(), deviceProfile.getDefaultDashboardId(),
  317 + deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList());
317 318
318 Assert.assertEquals(deviceProfileInfos, loadedDeviceProfileInfos); 319 Assert.assertEquals(deviceProfileInfos, loadedDeviceProfileInfos);
319 320
@@ -32,7 +32,6 @@ import org.thingsboard.server.common.data.page.PageLink; @@ -32,7 +32,6 @@ import org.thingsboard.server.common.data.page.PageLink;
32 import org.thingsboard.server.common.data.security.Authority; 32 import org.thingsboard.server.common.data.security.Authority;
33 import org.thingsboard.server.controller.AbstractControllerTest; 33 import org.thingsboard.server.controller.AbstractControllerTest;
34 import org.thingsboard.server.dao.exception.DataValidationException; 34 import org.thingsboard.server.dao.exception.DataValidationException;
35 -import org.thingsboard.server.dao.service.AbstractServiceTest;  
36 import org.thingsboard.server.dao.service.DaoSqlTest; 35 import org.thingsboard.server.dao.service.DaoSqlTest;
37 36
38 import java.util.ArrayList; 37 import java.util.ArrayList;
@@ -57,7 +56,7 @@ public class BaseTbResourceServiceTest extends AbstractControllerTest { @@ -57,7 +56,7 @@ public class BaseTbResourceServiceTest extends AbstractControllerTest {
57 "<Resources>\n" + 56 "<Resources>\n" +
58 "<Item ID=\"0\">\n" + 57 "<Item ID=\"0\">\n" +
59 "<Name>LWM2M</Name>\n" + 58 "<Name>LWM2M</Name>\n" +
60 - "<Operations></Operations>\n" + 59 + "<Operations>RW</Operations>\n" +
61 "<MultipleInstances>Single</MultipleInstances>\n" + 60 "<MultipleInstances>Single</MultipleInstances>\n" +
62 "<Mandatory>Mandatory</Mandatory>\n" + 61 "<Mandatory>Mandatory</Mandatory>\n" +
63 "<Type>String</Type>\n" + 62 "<Type>String</Type>\n" +
@@ -177,7 +177,7 @@ public class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { @@ -177,7 +177,7 @@ public class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest {
177 executor = Executors.newScheduledThreadPool(10); 177 executor = Executors.newScheduledThreadPool(10);
178 loginTenantAdmin(); 178 loginTenantAdmin();
179 179
180 - String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml"}; 180 + String[] resources = new String[]{"1.xml", "2.xml", "3.xml"};
181 for (String resourceName : resources) { 181 for (String resourceName : resources) {
182 TbResource lwModel = new TbResource(); 182 TbResource lwModel = new TbResource();
183 lwModel.setResourceType(ResourceType.LWM2M_MODEL); 183 lwModel.setResourceType(ResourceType.LWM2M_MODEL);
@@ -26,17 +26,21 @@ import java.util.List; @@ -26,17 +26,21 @@ import java.util.List;
26 public class AlarmOperationResult { 26 public class AlarmOperationResult {
27 private final Alarm alarm; 27 private final Alarm alarm;
28 private final boolean successful; 28 private final boolean successful;
  29 + private final boolean created;
29 private final List<EntityId> propagatedEntitiesList; 30 private final List<EntityId> propagatedEntitiesList;
30 31
31 public AlarmOperationResult(Alarm alarm, boolean successful) { 32 public AlarmOperationResult(Alarm alarm, boolean successful) {
32 - this.alarm = alarm;  
33 - this.successful = successful;  
34 - this.propagatedEntitiesList = Collections.emptyList(); 33 + this(alarm, successful, Collections.emptyList());
35 } 34 }
36 35
37 public AlarmOperationResult(Alarm alarm, boolean successful, List<EntityId> propagatedEntitiesList) { 36 public AlarmOperationResult(Alarm alarm, boolean successful, List<EntityId> propagatedEntitiesList) {
  37 + this(alarm, successful, false, propagatedEntitiesList);
  38 + }
  39 +
  40 + public AlarmOperationResult(Alarm alarm, boolean successful, boolean created, List<EntityId> propagatedEntitiesList) {
38 this.alarm = alarm; 41 this.alarm = alarm;
39 this.successful = successful; 42 this.successful = successful;
  43 + this.created = created;
40 this.propagatedEntitiesList = propagatedEntitiesList; 44 this.propagatedEntitiesList = propagatedEntitiesList;
41 } 45 }
42 } 46 }
@@ -29,7 +29,6 @@ import org.thingsboard.server.common.data.id.EntityId; @@ -29,7 +29,6 @@ import org.thingsboard.server.common.data.id.EntityId;
29 import org.thingsboard.server.common.data.id.TenantId; 29 import org.thingsboard.server.common.data.id.TenantId;
30 import org.thingsboard.server.common.data.page.PageData; 30 import org.thingsboard.server.common.data.page.PageData;
31 import org.thingsboard.server.common.data.query.AlarmData; 31 import org.thingsboard.server.common.data.query.AlarmData;
32 -import org.thingsboard.server.common.data.query.AlarmDataPageLink;  
33 import org.thingsboard.server.common.data.query.AlarmDataQuery; 32 import org.thingsboard.server.common.data.query.AlarmDataQuery;
34 33
35 import java.util.Collection; 34 import java.util.Collection;
@@ -41,6 +40,8 @@ public interface AlarmService { @@ -41,6 +40,8 @@ public interface AlarmService {
41 40
42 AlarmOperationResult createOrUpdateAlarm(Alarm alarm); 41 AlarmOperationResult createOrUpdateAlarm(Alarm alarm);
43 42
  43 + AlarmOperationResult createOrUpdateAlarm(Alarm alarm, boolean alarmCreationEnabled);
  44 +
44 AlarmOperationResult deleteAlarm(TenantId tenantId, AlarmId alarmId); 45 AlarmOperationResult deleteAlarm(TenantId tenantId, AlarmId alarmId);
45 46
46 ListenableFuture<AlarmOperationResult> ackAlarm(TenantId tenantId, AlarmId alarmId, long ackTs); 47 ListenableFuture<AlarmOperationResult> ackAlarm(TenantId tenantId, AlarmId alarmId, long ackTs);
@@ -53,6 +54,8 @@ public interface AlarmService { @@ -53,6 +54,8 @@ public interface AlarmService {
53 54
54 ListenableFuture<PageData<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query); 55 ListenableFuture<PageData<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query);
55 56
  57 + ListenableFuture<PageData<AlarmInfo>> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query);
  58 +
56 AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, 59 AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus,
57 AlarmStatus alarmStatus); 60 AlarmStatus alarmStatus);
58 61
@@ -28,6 +28,8 @@ public interface EntityService { @@ -28,6 +28,8 @@ public interface EntityService {
28 28
29 ListenableFuture<String> fetchEntityNameAsync(TenantId tenantId, EntityId entityId); 29 ListenableFuture<String> fetchEntityNameAsync(TenantId tenantId, EntityId entityId);
30 30
  31 + CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId);
  32 +
31 void deleteEntityRelations(TenantId tenantId, EntityId entityId); 33 void deleteEntityRelations(TenantId tenantId, EntityId entityId);
32 34
33 long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); 35 long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query);
@@ -23,7 +23,8 @@ public enum ApiFeature { @@ -23,7 +23,8 @@ public enum ApiFeature {
23 RE("ruleEngineApiState", "Rule Engine execution"), 23 RE("ruleEngineApiState", "Rule Engine execution"),
24 JS("jsExecutionApiState", "JavaScript functions execution"), 24 JS("jsExecutionApiState", "JavaScript functions execution"),
25 EMAIL("emailApiState", "Email messages"), 25 EMAIL("emailApiState", "Email messages"),
26 - SMS("smsApiState", "SMS messages"); 26 + SMS("smsApiState", "SMS messages"),
  27 + ALARM("alarmApiState", "Created alarms");
27 28
28 @Getter 29 @Getter
29 private final String apiStateKey; 30 private final String apiStateKey;
@@ -25,13 +25,16 @@ public enum ApiUsageRecordKey { @@ -25,13 +25,16 @@ public enum ApiUsageRecordKey {
25 RE_EXEC_COUNT(ApiFeature.RE, "ruleEngineExecutionCount", "ruleEngineExecutionLimit"), 25 RE_EXEC_COUNT(ApiFeature.RE, "ruleEngineExecutionCount", "ruleEngineExecutionLimit"),
26 JS_EXEC_COUNT(ApiFeature.JS, "jsExecutionCount", "jsExecutionLimit"), 26 JS_EXEC_COUNT(ApiFeature.JS, "jsExecutionCount", "jsExecutionLimit"),
27 EMAIL_EXEC_COUNT(ApiFeature.EMAIL, "emailCount", "emailLimit"), 27 EMAIL_EXEC_COUNT(ApiFeature.EMAIL, "emailCount", "emailLimit"),
28 - SMS_EXEC_COUNT(ApiFeature.SMS, "smsCount", "smsLimit"); 28 + SMS_EXEC_COUNT(ApiFeature.SMS, "smsCount", "smsLimit"),
  29 + CREATED_ALARMS_COUNT(ApiFeature.ALARM, "createdAlarmsCount", "createdAlarmsLimit");
  30 +
29 private static final ApiUsageRecordKey[] JS_RECORD_KEYS = {JS_EXEC_COUNT}; 31 private static final ApiUsageRecordKey[] JS_RECORD_KEYS = {JS_EXEC_COUNT};
30 private static final ApiUsageRecordKey[] RE_RECORD_KEYS = {RE_EXEC_COUNT}; 32 private static final ApiUsageRecordKey[] RE_RECORD_KEYS = {RE_EXEC_COUNT};
31 private static final ApiUsageRecordKey[] DB_RECORD_KEYS = {STORAGE_DP_COUNT}; 33 private static final ApiUsageRecordKey[] DB_RECORD_KEYS = {STORAGE_DP_COUNT};
32 private static final ApiUsageRecordKey[] TRANSPORT_RECORD_KEYS = {TRANSPORT_MSG_COUNT, TRANSPORT_DP_COUNT}; 34 private static final ApiUsageRecordKey[] TRANSPORT_RECORD_KEYS = {TRANSPORT_MSG_COUNT, TRANSPORT_DP_COUNT};
33 private static final ApiUsageRecordKey[] EMAIL_RECORD_KEYS = {EMAIL_EXEC_COUNT}; 35 private static final ApiUsageRecordKey[] EMAIL_RECORD_KEYS = {EMAIL_EXEC_COUNT};
34 private static final ApiUsageRecordKey[] SMS_RECORD_KEYS = {SMS_EXEC_COUNT}; 36 private static final ApiUsageRecordKey[] SMS_RECORD_KEYS = {SMS_EXEC_COUNT};
  37 + private static final ApiUsageRecordKey[] ALARM_RECORD_KEYS = {CREATED_ALARMS_COUNT};
35 38
36 @Getter 39 @Getter
37 private final ApiFeature apiFeature; 40 private final ApiFeature apiFeature;
@@ -60,6 +63,8 @@ public enum ApiUsageRecordKey { @@ -60,6 +63,8 @@ public enum ApiUsageRecordKey {
60 return EMAIL_RECORD_KEYS; 63 return EMAIL_RECORD_KEYS;
61 case SMS: 64 case SMS:
62 return SMS_RECORD_KEYS; 65 return SMS_RECORD_KEYS;
  66 + case ALARM:
  67 + return ALARM_RECORD_KEYS;
63 default: 68 default:
64 return new ApiUsageRecordKey[]{}; 69 return new ApiUsageRecordKey[]{};
65 } 70 }
@@ -25,34 +25,21 @@ import org.thingsboard.server.common.data.id.ApiUsageStateId; @@ -25,34 +25,21 @@ import org.thingsboard.server.common.data.id.ApiUsageStateId;
25 25
26 @ToString 26 @ToString
27 @EqualsAndHashCode(callSuper = true) 27 @EqualsAndHashCode(callSuper = true)
  28 +@Getter
  29 +@Setter
28 public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenantId { 30 public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenantId {
29 31
30 private static final long serialVersionUID = 8250339805336035966L; 32 private static final long serialVersionUID = 8250339805336035966L;
31 33
32 - @Getter  
33 - @Setter  
34 private TenantId tenantId; 34 private TenantId tenantId;
35 - @Getter  
36 - @Setter  
37 private EntityId entityId; 35 private EntityId entityId;
38 - @Getter  
39 - @Setter  
40 private ApiUsageStateValue transportState; 36 private ApiUsageStateValue transportState;
41 - @Getter  
42 - @Setter  
43 private ApiUsageStateValue dbStorageState; 37 private ApiUsageStateValue dbStorageState;
44 - @Getter  
45 - @Setter  
46 private ApiUsageStateValue reExecState; 38 private ApiUsageStateValue reExecState;
47 - @Getter  
48 - @Setter  
49 private ApiUsageStateValue jsExecState; 39 private ApiUsageStateValue jsExecState;
50 - @Getter  
51 - @Setter  
52 private ApiUsageStateValue emailExecState; 40 private ApiUsageStateValue emailExecState;
53 - @Getter  
54 - @Setter  
55 private ApiUsageStateValue smsExecState; 41 private ApiUsageStateValue smsExecState;
  42 + private ApiUsageStateValue alarmExecState;
56 43
57 public ApiUsageState() { 44 public ApiUsageState() {
58 super(); 45 super();
@@ -72,6 +59,7 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan @@ -72,6 +59,7 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan
72 this.jsExecState = ur.getJsExecState(); 59 this.jsExecState = ur.getJsExecState();
73 this.emailExecState = ur.getEmailExecState(); 60 this.emailExecState = ur.getEmailExecState();
74 this.smsExecState = ur.getSmsExecState(); 61 this.smsExecState = ur.getSmsExecState();
  62 + this.alarmExecState = ur.getAlarmExecState();
75 } 63 }
76 64
77 public boolean isTransportEnabled() { 65 public boolean isTransportEnabled() {
@@ -97,4 +85,8 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan @@ -97,4 +85,8 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan
97 public boolean isSmsSendEnabled(){ 85 public boolean isSmsSendEnabled(){
98 return !ApiUsageStateValue.DISABLED.equals(smsExecState); 86 return !ApiUsageStateValue.DISABLED.equals(smsExecState);
99 } 87 }
  88 +
  89 + public boolean isAlarmCreationEnabled() {
  90 + return alarmExecState != ApiUsageStateValue.DISABLED;
  91 + }
100 } 92 }
@@ -30,6 +30,7 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa @@ -30,6 +30,7 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa
30 private TenantId tenantId; 30 private TenantId tenantId;
31 @NoXss 31 @NoXss
32 private String title; 32 private String title;
  33 + private String image;
33 @Valid 34 @Valid
34 private Set<ShortCustomerInfo> assignedCustomers; 35 private Set<ShortCustomerInfo> assignedCustomers;
35 36
@@ -45,6 +46,7 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa @@ -45,6 +46,7 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa
45 super(dashboardInfo); 46 super(dashboardInfo);
46 this.tenantId = dashboardInfo.getTenantId(); 47 this.tenantId = dashboardInfo.getTenantId();
47 this.title = dashboardInfo.getTitle(); 48 this.title = dashboardInfo.getTitle();
  49 + this.image = dashboardInfo.getImage();
48 this.assignedCustomers = dashboardInfo.getAssignedCustomers(); 50 this.assignedCustomers = dashboardInfo.getAssignedCustomers();
49 } 51 }
50 52
@@ -64,6 +66,14 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa @@ -64,6 +66,14 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa
64 this.title = title; 66 this.title = title;
65 } 67 }
66 68
  69 + public String getImage() {
  70 + return image;
  71 + }
  72 +
  73 + public void setImage(String image) {
  74 + this.image = image;
  75 + }
  76 +
67 public Set<ShortCustomerInfo> getAssignedCustomers() { 77 public Set<ShortCustomerInfo> getAssignedCustomers() {
68 return assignedCustomers; 78 return assignedCustomers;
69 } 79 }
@@ -92,26 +92,6 @@ public class DataConstants { @@ -92,26 +92,6 @@ public class DataConstants {
92 public static final String CLIENT_ID = "clientId"; 92 public static final String CLIENT_ID = "clientId";
93 public static final String USERNAME = "username"; 93 public static final String USERNAME = "username";
94 public static final String PASSWORD = "password"; 94 public static final String PASSWORD = "password";
95 -  
96 -//<<<<<<< HEAD  
97 -//=======  
98 -// //firmware  
99 -// //telemetry  
100 -// public static final String CURRENT_FIRMWARE_TITLE = "current_fw_title";  
101 -// public static final String CURRENT_FIRMWARE_VERSION = "current_fw_version";  
102 -// public static final String TARGET_FIRMWARE_TITLE = "target_fw_title";  
103 -// public static final String TARGET_FIRMWARE_VERSION = "target_fw_version";  
104 -// public static final String TARGET_FIRMWARE_TS = "target_fw_ts";  
105 -// public static final String FIRMWARE_STATE = "fw_state";  
106 -//  
107 -// //attributes  
108 -// //telemetry  
109 -// public static final String FIRMWARE_TITLE = "fw_title";  
110 -// public static final String FIRMWARE_VERSION = "fw_version";  
111 -// public static final String FIRMWARE_SIZE = "fw_size";  
112 -// public static final String FIRMWARE_CHECKSUM = "fw_checksum";  
113 -// public static final String FIRMWARE_CHECKSUM_ALGORITHM = "fw_checksum_algorithm";  
114 -//>>>>>>> origin/master  
115 public static final String EDGE_MSG_SOURCE = "edge"; 95 public static final String EDGE_MSG_SOURCE = "edge";
116 public static final String MSG_SOURCE_KEY = "source"; 96 public static final String MSG_SOURCE_KEY = "source";
117 97
@@ -21,6 +21,7 @@ import lombok.Data; @@ -21,6 +21,7 @@ import lombok.Data;
21 import lombok.EqualsAndHashCode; 21 import lombok.EqualsAndHashCode;
22 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
23 import org.thingsboard.server.common.data.device.profile.DeviceProfileData; 23 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
  24 +import org.thingsboard.server.common.data.id.DashboardId;
24 import org.thingsboard.server.common.data.id.DeviceProfileId; 25 import org.thingsboard.server.common.data.id.DeviceProfileId;
25 import org.thingsboard.server.common.data.id.FirmwareId; 26 import org.thingsboard.server.common.data.id.FirmwareId;
26 import org.thingsboard.server.common.data.id.RuleChainId; 27 import org.thingsboard.server.common.data.id.RuleChainId;
@@ -43,11 +44,13 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H @@ -43,11 +44,13 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
43 private String name; 44 private String name;
44 @NoXss 45 @NoXss
45 private String description; 46 private String description;
  47 + private String image;
46 private boolean isDefault; 48 private boolean isDefault;
47 private DeviceProfileType type; 49 private DeviceProfileType type;
48 private DeviceTransportType transportType; 50 private DeviceTransportType transportType;
49 private DeviceProfileProvisionType provisionType; 51 private DeviceProfileProvisionType provisionType;
50 private RuleChainId defaultRuleChainId; 52 private RuleChainId defaultRuleChainId;
  53 + private DashboardId defaultDashboardId;
51 @NoXss 54 @NoXss
52 private String defaultQueueName; 55 private String defaultQueueName;
53 @Valid 56 @Valid
@@ -74,8 +77,10 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H @@ -74,8 +77,10 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
74 this.tenantId = deviceProfile.getTenantId(); 77 this.tenantId = deviceProfile.getTenantId();
75 this.name = deviceProfile.getName(); 78 this.name = deviceProfile.getName();
76 this.description = deviceProfile.getDescription(); 79 this.description = deviceProfile.getDescription();
  80 + this.image = deviceProfile.getImage();
77 this.isDefault = deviceProfile.isDefault(); 81 this.isDefault = deviceProfile.isDefault();
78 this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId(); 82 this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId();
  83 + this.defaultDashboardId = deviceProfile.getDefaultDashboardId();
79 this.defaultQueueName = deviceProfile.getDefaultQueueName(); 84 this.defaultQueueName = deviceProfile.getDefaultQueueName();
80 this.setProfileData(deviceProfile.getProfileData()); 85 this.setProfileData(deviceProfile.getProfileData());
81 this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey(); 86 this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey();
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
20 import lombok.EqualsAndHashCode; 20 import lombok.EqualsAndHashCode;
21 import lombok.ToString; 21 import lombok.ToString;
22 import lombok.Value; 22 import lombok.Value;
  23 +import org.thingsboard.server.common.data.id.DashboardId;
23 import org.thingsboard.server.common.data.id.EntityId; 24 import org.thingsboard.server.common.data.id.EntityId;
24 import org.thingsboard.server.common.data.id.EntityIdFactory; 25 import org.thingsboard.server.common.data.id.EntityIdFactory;
25 26
@@ -30,21 +31,29 @@ import java.util.UUID; @@ -30,21 +31,29 @@ import java.util.UUID;
30 @ToString(callSuper = true) 31 @ToString(callSuper = true)
31 public class DeviceProfileInfo extends EntityInfo { 32 public class DeviceProfileInfo extends EntityInfo {
32 33
  34 + private final String image;
  35 + private final DashboardId defaultDashboardId;
33 private final DeviceProfileType type; 36 private final DeviceProfileType type;
34 private final DeviceTransportType transportType; 37 private final DeviceTransportType transportType;
35 38
36 @JsonCreator 39 @JsonCreator
37 public DeviceProfileInfo(@JsonProperty("id") EntityId id, 40 public DeviceProfileInfo(@JsonProperty("id") EntityId id,
38 @JsonProperty("name") String name, 41 @JsonProperty("name") String name,
  42 + @JsonProperty("image") String image,
  43 + @JsonProperty("defaultDashboardId") DashboardId defaultDashboardId,
39 @JsonProperty("type") DeviceProfileType type, 44 @JsonProperty("type") DeviceProfileType type,
40 @JsonProperty("transportType") DeviceTransportType transportType) { 45 @JsonProperty("transportType") DeviceTransportType transportType) {
41 super(id, name); 46 super(id, name);
  47 + this.image = image;
  48 + this.defaultDashboardId = defaultDashboardId;
42 this.type = type; 49 this.type = type;
43 this.transportType = transportType; 50 this.transportType = transportType;
44 } 51 }
45 52
46 - public DeviceProfileInfo(UUID uuid, String name, DeviceProfileType type, DeviceTransportType transportType) { 53 + public DeviceProfileInfo(UUID uuid, String name, String image, UUID defaultDashboardId, DeviceProfileType type, DeviceTransportType transportType) {
47 super(EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE_PROFILE, uuid), name); 54 super(EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE_PROFILE, uuid), name);
  55 + this.image = image;
  56 + this.defaultDashboardId = defaultDashboardId != null ? new DashboardId(defaultDashboardId) : null;
48 this.type = type; 57 this.type = type;
49 this.transportType = transportType; 58 this.transportType = transportType;
50 } 59 }
@@ -21,9 +21,11 @@ import lombok.AllArgsConstructor; @@ -21,9 +21,11 @@ import lombok.AllArgsConstructor;
21 import lombok.Builder; 21 import lombok.Builder;
22 import lombok.Data; 22 import lombok.Data;
23 import org.thingsboard.server.common.data.BaseData; 23 import org.thingsboard.server.common.data.BaseData;
  24 +import org.thingsboard.server.common.data.HasCustomerId;
24 import org.thingsboard.server.common.data.HasName; 25 import org.thingsboard.server.common.data.HasName;
25 import org.thingsboard.server.common.data.HasTenantId; 26 import org.thingsboard.server.common.data.HasTenantId;
26 import org.thingsboard.server.common.data.id.AlarmId; 27 import org.thingsboard.server.common.data.id.AlarmId;
  28 +import org.thingsboard.server.common.data.id.CustomerId;
27 import org.thingsboard.server.common.data.id.EntityId; 29 import org.thingsboard.server.common.data.id.EntityId;
28 import org.thingsboard.server.common.data.id.TenantId; 30 import org.thingsboard.server.common.data.id.TenantId;
29 31
@@ -35,9 +37,10 @@ import java.util.List; @@ -35,9 +37,10 @@ import java.util.List;
35 @Data 37 @Data
36 @Builder 38 @Builder
37 @AllArgsConstructor 39 @AllArgsConstructor
38 -public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId { 40 +public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId, HasCustomerId {
39 41
40 private TenantId tenantId; 42 private TenantId tenantId;
  43 + private CustomerId customerId;
41 private String type; 44 private String type;
42 private EntityId originator; 45 private EntityId originator;
43 private AlarmSeverity severity; 46 private AlarmSeverity severity;
@@ -62,6 +65,7 @@ public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId { @@ -62,6 +65,7 @@ public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId {
62 super(alarm.getId()); 65 super(alarm.getId());
63 this.createdTime = alarm.getCreatedTime(); 66 this.createdTime = alarm.getCreatedTime();
64 this.tenantId = alarm.getTenantId(); 67 this.tenantId = alarm.getTenantId();
  68 + this.customerId = alarm.getCustomerId();
65 this.type = alarm.getType(); 69 this.type = alarm.getType();
66 this.originator = alarm.getOriginator(); 70 this.originator = alarm.getOriginator();
67 this.severity = alarm.getSeverity(); 71 this.severity = alarm.getSeverity();
@@ -82,7 +82,7 @@ public class MqttTopics { @@ -82,7 +82,7 @@ public class MqttTopics {
82 public static final String DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + REQUEST + "/" + REQUEST_ID_PATTERN + CHUNK + CHUNK_PATTERN; 82 public static final String DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + REQUEST + "/" + REQUEST_ID_PATTERN + CHUNK + CHUNK_PATTERN;
83 public static final String DEVICE_FIRMWARE_RESPONSES_TOPIC = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + RESPONSE + "/" + SUB_TOPIC + CHUNK + SUB_TOPIC; 83 public static final String DEVICE_FIRMWARE_RESPONSES_TOPIC = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + RESPONSE + "/" + SUB_TOPIC + CHUNK + SUB_TOPIC;
84 public static final String DEVICE_FIRMWARE_ERROR_TOPIC = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + ERROR; 84 public static final String DEVICE_FIRMWARE_ERROR_TOPIC = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + ERROR;
85 - public static final String DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT = BASE_DEVICE_API_TOPIC_V2 + "%s" + RESPONSE + "/"+ "%s" + CHUNK + "%d"; 85 + public static final String DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT = BASE_DEVICE_API_TOPIC_V2 + "/%s" + RESPONSE + "/"+ "%s" + CHUNK + "%d";
86 86
87 public static final String DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN = BASE_DEVICE_API_TOPIC_V2 + SOFTWARE + REQUEST + "/" + REQUEST_ID_PATTERN + CHUNK + CHUNK_PATTERN; 87 public static final String DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN = BASE_DEVICE_API_TOPIC_V2 + SOFTWARE + REQUEST + "/" + REQUEST_ID_PATTERN + CHUNK + CHUNK_PATTERN;
88 public static final String DEVICE_SOFTWARE_RESPONSES_TOPIC = BASE_DEVICE_API_TOPIC_V2 + SOFTWARE + RESPONSE + "/" + SUB_TOPIC + CHUNK + SUB_TOPIC; 88 public static final String DEVICE_SOFTWARE_RESPONSES_TOPIC = BASE_DEVICE_API_TOPIC_V2 + SOFTWARE + RESPONSE + "/" + SUB_TOPIC + CHUNK + SUB_TOPIC;
common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareUpdateStatus.java renamed from application/src/main/java/org/thingsboard/server/service/firmware/FirmwareUpdateStatus.java
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.thingsboard.server.service.firmware; 16 +package org.thingsboard.server.common.data.firmware;
17 17
18 public enum FirmwareUpdateStatus { 18 public enum FirmwareUpdateStatus {
19 QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED 19 QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
@@ -50,6 +50,7 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura @@ -50,6 +50,7 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura
50 private int maxRuleNodeExecutionsPerMessage; 50 private int maxRuleNodeExecutionsPerMessage;
51 private long maxEmails; 51 private long maxEmails;
52 private long maxSms; 52 private long maxSms;
  53 + private long maxCreatedAlarms;
53 54
54 private int defaultStorageTtlDays; 55 private int defaultStorageTtlDays;
55 56
@@ -72,6 +73,8 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura @@ -72,6 +73,8 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura
72 return maxEmails; 73 return maxEmails;
73 case SMS_EXEC_COUNT: 74 case SMS_EXEC_COUNT:
74 return maxSms; 75 return maxSms;
  76 + case CREATED_ALARMS_COUNT:
  77 + return maxCreatedAlarms;
75 } 78 }
76 return 0L; 79 return 0L;
77 } 80 }
@@ -53,6 +53,10 @@ @@ -53,6 +53,10 @@
53 <artifactId>spring-context</artifactId> 53 <artifactId>spring-context</artifactId>
54 </dependency> 54 </dependency>
55 <dependency> 55 <dependency>
  56 + <groupId>org.springframework.integration</groupId>
  57 + <artifactId>spring-integration-redis</artifactId>
  58 + </dependency>
  59 + <dependency>
56 <groupId>org.slf4j</groupId> 60 <groupId>org.slf4j</groupId>
57 <artifactId>slf4j-api</artifactId> 61 <artifactId>slf4j-api</artifactId>
58 </dependency> 62 </dependency>
@@ -46,6 +46,7 @@ import java.util.UUID; @@ -46,6 +46,7 @@ import java.util.UUID;
46 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.BOOTSTRAP_SERVER; 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; 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; 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;
49 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_SERVER; 50 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_SERVER;
50 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SERVERS; 51 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SERVERS;
51 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getBootstrapParametersFromThingsboard; 52 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getBootstrapParametersFromThingsboard;
@@ -165,13 +166,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @@ -165,13 +166,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
165 lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); 166 lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);
166 lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); 167 lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);
167 String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndpoint()); 168 String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndpoint());
168 - helper.sendParametersOnThingsboardTelemetry(helper.getKvLogyToThingsboard(logMsg), sessionInfo); 169 + helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo);
169 return lwM2MBootstrapConfig; 170 return lwM2MBootstrapConfig;
170 } else { 171 } else {
171 log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint()); 172 log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint());
172 log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndpoint()); 173 log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndpoint());
173 String logMsg = String.format("%s: getParametersBootstrap: %s 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());
174 - helper.sendParametersOnThingsboardTelemetry(helper.getKvLogyToThingsboard(logMsg), sessionInfo); 175 + helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo);
175 return null; 176 return null;
176 } 177 }
177 } 178 }
@@ -65,6 +65,14 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { @@ -65,6 +65,14 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
65 private int registeredPoolSize; 65 private int registeredPoolSize;
66 66
67 @Getter 67 @Getter
  68 + @Value("${transport.lwm2m.registration_store_pool_size:}")
  69 + private int registrationStorePoolSize;
  70 +
  71 + @Getter
  72 + @Value("${transport.lwm2m.clean_period_in_sec:}")
  73 + private int cleanPeriodInSec;
  74 +
  75 + @Getter
68 @Value("${transport.lwm2m.update_registered_pool_size:}") 76 @Value("${transport.lwm2m.update_registered_pool_size:}")
69 private int updateRegisteredPoolSize; 77 private int updateRegisteredPoolSize;
70 78
@@ -23,13 +23,12 @@ import com.google.gson.JsonElement; @@ -23,13 +23,12 @@ import com.google.gson.JsonElement;
23 import com.google.gson.JsonObject; 23 import com.google.gson.JsonObject;
24 import com.google.gson.reflect.TypeToken; 24 import com.google.gson.reflect.TypeToken;
25 import lombok.extern.slf4j.Slf4j; 25 import lombok.extern.slf4j.Slf4j;
  26 +import org.eclipse.leshan.core.model.ObjectModel;
26 import org.eclipse.leshan.core.model.ResourceModel; 27 import org.eclipse.leshan.core.model.ResourceModel;
27 -import org.eclipse.leshan.core.node.LwM2mMultipleResource;  
28 import org.eclipse.leshan.core.node.LwM2mObject; 28 import org.eclipse.leshan.core.node.LwM2mObject;
29 import org.eclipse.leshan.core.node.LwM2mObjectInstance; 29 import org.eclipse.leshan.core.node.LwM2mObjectInstance;
30 import org.eclipse.leshan.core.node.LwM2mPath; 30 import org.eclipse.leshan.core.node.LwM2mPath;
31 import org.eclipse.leshan.core.node.LwM2mResource; 31 import org.eclipse.leshan.core.node.LwM2mResource;
32 -import org.eclipse.leshan.core.node.LwM2mSingleResource;  
33 import org.eclipse.leshan.core.observation.Observation; 32 import org.eclipse.leshan.core.observation.Observation;
34 import org.eclipse.leshan.core.request.ContentFormat; 33 import org.eclipse.leshan.core.request.ContentFormat;
35 import org.eclipse.leshan.core.request.WriteRequest; 34 import org.eclipse.leshan.core.request.WriteRequest;
@@ -56,6 +55,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; @@ -56,6 +55,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent;
56 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; 55 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
57 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 56 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
58 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; 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; 59 import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
60 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 60 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
61 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; 61 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
@@ -85,19 +85,21 @@ import java.util.stream.Collectors; @@ -85,19 +85,21 @@ import java.util.stream.Collectors;
85 85
86 import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST; 86 import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST;
87 import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION; 87 import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
88 -import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY; 88 +import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.DOWNLOADED;
  89 +import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.UPDATING;
89 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; 90 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
90 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto; 91 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto;
91 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.CLIENT_NOT_AUTHORIZED; 92 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.CLIENT_NOT_AUTHORIZED;
92 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEVICE_ATTRIBUTES_REQUEST; 93 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEVICE_ATTRIBUTES_REQUEST;
93 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FR_OBJECT_ID;  
94 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FR_PATH_RESOURCE_VER_ID; 94 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_ID;
  95 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID;
95 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR; 96 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR;
96 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO; 97 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;
  98 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_TELEMETRY;
97 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE; 99 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE;
98 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_STRATEGY_2; 100 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_STRATEGY_2;
99 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;  
100 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER; 101 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER;
  102 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER_All;
101 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE; 103 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
102 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE; 104 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE;
103 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL; 105 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;
@@ -105,6 +107,9 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L @@ -105,6 +107,9 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
105 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.READ; 107 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.READ;
106 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES; 108 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;
107 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE; 109 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
  110 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_UPDATE;
  111 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_ID;
  112 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_RESULT_ID;
108 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertJsonArrayToSet; 113 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertJsonArrayToSet;
109 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId; 114 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
110 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; 115 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
@@ -119,19 +124,20 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -119,19 +124,20 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
119 124
120 private ExecutorService registrationExecutor; 125 private ExecutorService registrationExecutor;
121 private ExecutorService updateRegistrationExecutor; 126 private ExecutorService updateRegistrationExecutor;
122 - private ExecutorService unregistrationExecutor; 127 + private ExecutorService unRegistrationExecutor;
123 private LwM2mValueConverterImpl converter; 128 private LwM2mValueConverterImpl converter;
124 129
125 private final TransportService transportService; 130 private final TransportService transportService;
126 private final LwM2mTransportContext context; 131 private final LwM2mTransportContext context;
127 - private final LwM2MTransportServerConfig config;  
128 - private final FirmwareDataCache firmwareDataCache;  
129 - private final LwM2mTransportServerHelper helper; 132 + public final LwM2MTransportServerConfig config;
  133 + public final FirmwareDataCache firmwareDataCache;
  134 + public final LwM2mTransportServerHelper helper;
130 private final LwM2MJsonAdaptor adaptor; 135 private final LwM2MJsonAdaptor adaptor;
131 private final LwM2mClientContext clientContext; 136 private final LwM2mClientContext clientContext;
132 private final LwM2mTransportRequest lwM2mTransportRequest; 137 private final LwM2mTransportRequest lwM2mTransportRequest;
133 private final TbLwM2MDtlsSessionStore sessionStore; 138 private final TbLwM2MDtlsSessionStore sessionStore;
134 139
  140 +
135 public DefaultLwM2MTransportMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, LwM2mTransportServerHelper helper, 141 public DefaultLwM2MTransportMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, LwM2mTransportServerHelper helper,
136 LwM2mClientContext clientContext, 142 LwM2mClientContext clientContext,
137 @Lazy LwM2mTransportRequest lwM2mTransportRequest, 143 @Lazy LwM2mTransportRequest lwM2mTransportRequest,
@@ -153,7 +159,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -153,7 +159,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
153 this.context.getScheduler().scheduleAtFixedRate(this::reportActivity, new Random().nextInt((int) config.getSessionReportTimeout()), config.getSessionReportTimeout(), TimeUnit.MILLISECONDS); 159 this.context.getScheduler().scheduleAtFixedRate(this::reportActivity, new Random().nextInt((int) config.getSessionReportTimeout()), config.getSessionReportTimeout(), TimeUnit.MILLISECONDS);
154 this.registrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getRegisteredPoolSize(), "LwM2M registration"); 160 this.registrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getRegisteredPoolSize(), "LwM2M registration");
155 this.updateRegistrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getUpdateRegisteredPoolSize(), "LwM2M update registration"); 161 this.updateRegistrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getUpdateRegisteredPoolSize(), "LwM2M update registration");
156 - this.unregistrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getUnRegisteredPoolSize(), "LwM2M unregistration"); 162 + this.unRegistrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getUnRegisteredPoolSize(), "LwM2M unRegistration");
157 this.converter = LwM2mValueConverterImpl.getInstance(); 163 this.converter = LwM2mValueConverterImpl.getInstance();
158 } 164 }
159 165
@@ -184,6 +190,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -184,6 +190,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
184 transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); 190 transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null);
185 transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null); 191 transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null);
186 this.getInfoFirmwareUpdate(lwM2MClient); 192 this.getInfoFirmwareUpdate(lwM2MClient);
  193 + this.getInfoSoftwareUpdate(lwM2MClient);
187 this.initLwM2mFromClientValue(registration, lwM2MClient); 194 this.initLwM2mFromClientValue(registration, lwM2MClient);
188 this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration.getId()); 195 this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration.getId());
189 } else { 196 } else {
@@ -216,11 +223,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -216,11 +223,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
216 request.send(); 223 request.send();
217 } 224 }
218 } 225 }
  226 + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client update Registration", registration.getId());
219 } else { 227 } else {
220 log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); 228 log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
  229 + this.sendLogsToThingsboard(LOG_LW2M_ERROR + ": Client update Registration", registration.getId());
221 } 230 }
222 } catch (Throwable t) { 231 } catch (Throwable t) {
223 log.error("[{}] endpoint [{}] error Unable update registration.", registration.getEndpoint(), t); 232 log.error("[{}] endpoint [{}] error Unable update registration.", registration.getEndpoint(), t);
  233 + this.sendLogsToThingsboard(LOG_LW2M_ERROR + String.format(": Client update Registration, %s", t.getMessage()), registration.getId());
224 } 234 }
225 }); 235 });
226 } 236 }
@@ -231,13 +241,15 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -231,13 +241,15 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
231 * !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect 241 * !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect
232 */ 242 */
233 public void unReg(Registration registration, Collection<Observation> observations) { 243 public void unReg(Registration registration, Collection<Observation> observations) {
234 - unregistrationExecutor.submit(() -> { 244 + unRegistrationExecutor.submit(() -> {
235 try { 245 try {
236 - this.setCancelObservations(registration); 246 + this.setCancelObservationsAll(registration);
237 this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); 247 this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId());
238 this.closeClientSession(registration); 248 this.closeClientSession(registration);
  249 + ;
239 } catch (Throwable t) { 250 } catch (Throwable t) {
240 log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); 251 log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t);
  252 + this.sendLogsToThingsboard(LOG_LW2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage()), registration.getId());
241 } 253 }
242 }); 254 });
243 } 255 }
@@ -263,13 +275,18 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -263,13 +275,18 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
263 //TODO: associate endpointId with device information. 275 //TODO: associate endpointId with device information.
264 } 276 }
265 277
  278 + /**
  279 + * Cancel observation for All objects for this registration
  280 + */
266 @Override 281 @Override
267 - public void setCancelObservations(Registration registration) { 282 + public void setCancelObservationsAll(Registration registration) {
268 if (registration != null) { 283 if (registration != null) {
269 - Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);  
270 - observations.forEach(observation -> lwM2mTransportRequest.sendAllRequest(registration,  
271 - convertPathFromObjectIdToIdVer(observation.getPath().toString(), registration), OBSERVE_CANCEL,  
272 - null, null, this.config.getTimeout(), null)); 284 + lwM2mTransportRequest.sendAllRequest(registration, null, OBSERVE_CANCEL,
  285 + null, null, this.config.getTimeout(), null);
  286 +// Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
  287 +// observations.forEach(observation -> lwM2mTransportRequest.sendAllRequest(registration,
  288 +// convertPathFromObjectIdToIdVer(observation.getPath().toString(), registration), OBSERVE_CANCEL,
  289 +// null, null, this.config.getTimeout(), null));
273 } 290 }
274 } 291 }
275 292
@@ -283,34 +300,43 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -283,34 +300,43 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
283 @Override 300 @Override
284 public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) { 301 public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) {
285 if (response.getContent() != null) { 302 if (response.getContent() != null) {
286 - Object value = null;  
287 - if (response.getContent() instanceof LwM2mObject) {  
288 - LwM2mObject lwM2mObject = (LwM2mObject) response.getContent();  
289 - if (rpcRequest != null) {  
290 - value = lwM2mObject.toString(); 303 + LwM2mClient lwM2MClient = clientContext.getOrRegister(registration);
  304 + ObjectModel objectModelVersion = lwM2MClient.getObjectModel(path, this.config.getModelProvider());
  305 + if (objectModelVersion != null) {
  306 + if (response.getContent() instanceof LwM2mObject) {
  307 + LwM2mObject lwM2mObject = (LwM2mObject) response.getContent();
  308 + this.updateObjectResourceValue(registration, lwM2mObject, path);
  309 + } else if (response.getContent() instanceof LwM2mObjectInstance) {
  310 + LwM2mObjectInstance lwM2mObjectInstance = (LwM2mObjectInstance) response.getContent();
  311 + this.updateObjectInstanceResourceValue(registration, lwM2mObjectInstance, path);
  312 + } else if (response.getContent() instanceof LwM2mResource) {
  313 + LwM2mResource lwM2mResource = (LwM2mResource) response.getContent();
  314 + this.updateResourcesValue(registration, lwM2mResource, path);
291 } 315 }
292 - this.updateObjectResourceValue(registration, lwM2mObject, path);  
293 - } else if (response.getContent() instanceof LwM2mObjectInstance) {  
294 - LwM2mObjectInstance lwM2mObjectInstance = (LwM2mObjectInstance) response.getContent();  
295 - if (rpcRequest != null) {  
296 - value = lwM2mObjectInstance.toString();  
297 - }  
298 - this.updateObjectInstanceResourceValue(registration, lwM2mObjectInstance, path);  
299 - } else if (response.getContent() instanceof LwM2mResource) {  
300 - LwM2mResource lwM2mResource = (LwM2mResource) response.getContent();  
301 - if (rpcRequest != null) {  
302 - value = lwM2mResource.isMultiInstances() ? ((LwM2mMultipleResource) lwM2mResource).toString() :  
303 - ((LwM2mSingleResource) lwM2mResource).toString();  
304 - }  
305 - this.updateResourcesValue(registration, lwM2mResource, path);  
306 } 316 }
307 if (rpcRequest != null) { 317 if (rpcRequest != null) {
308 - rpcRequest.setValueMsg(String.format("%s", value));  
309 - this.sentRpcRequest(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE); 318 + this.sendRpcRequestAfterReadResponse(registration, lwM2MClient, path, response, rpcRequest);
310 } 319 }
311 } 320 }
312 } 321 }
313 322
  323 + private void sendRpcRequestAfterReadResponse(Registration registration, LwM2mClient lwM2MClient, String pathIdVer, ReadResponse response,
  324 + Lwm2mClientRpcRequest rpcRequest) {
  325 + Object value = null;
  326 + if (response.getContent() instanceof LwM2mObject) {
  327 + value = lwM2MClient.objectToString((LwM2mObject) response.getContent(), this.converter, pathIdVer);
  328 + } else if (response.getContent() instanceof LwM2mObjectInstance) {
  329 + value = lwM2MClient.instanceToString((LwM2mObjectInstance) response.getContent(), this.converter, pathIdVer);
  330 + } else if (response.getContent() instanceof LwM2mResource) {
  331 + value = lwM2MClient.resourceToString((LwM2mResource) response.getContent(), this.converter, pathIdVer);
  332 + }
  333 + String msg = String.format("%s: type operation %s path - %s value - %s", LOG_LW2M_INFO,
  334 + READ, pathIdVer, value);
  335 + this.sendLogsToThingsboard(msg, registration.getId());
  336 + rpcRequest.setValueMsg(String.format("%s", value));
  337 + this.sentRpcRequest(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE);
  338 + }
  339 +
314 /** 340 /**
315 * Update - send request in change value resources in Client 341 * Update - send request in change value resources in Client
316 * 1. FirmwareUpdate: 342 * 1. FirmwareUpdate:
@@ -330,9 +356,16 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -330,9 +356,16 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
330 String pathName = tsKvProto.getKv().getKey(); 356 String pathName = tsKvProto.getKv().getKey();
331 String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName); 357 String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName);
332 Object valueNew = getValueFromKvProto(tsKvProto.getKv()); 358 Object valueNew = getValueFromKvProto(tsKvProto.getKv());
333 - //TODO: react on change of the firmware name.  
334 - if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) { 359 + if ((FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName)
  360 + && (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())))
  361 + || (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.TITLE).equals(pathName)
  362 + && (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentTitle())))) {
335 this.getInfoFirmwareUpdate(lwM2MClient); 363 this.getInfoFirmwareUpdate(lwM2MClient);
  364 + } else if ((FirmwareUtil.getAttributeKey(FirmwareType.SOFTWARE, FirmwareKey.VERSION).equals(pathName)
  365 + && (!valueNew.equals(lwM2MClient.getSwUpdate().getCurrentVersion())))
  366 + || (FirmwareUtil.getAttributeKey(FirmwareType.SOFTWARE, FirmwareKey.TITLE).equals(pathName)
  367 + && (!valueNew.equals(lwM2MClient.getSwUpdate().getCurrentTitle())))) {
  368 + this.getInfoSoftwareUpdate(lwM2MClient);
336 } 369 }
337 if (pathIdVer != null) { 370 if (pathIdVer != null) {
338 ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.config 371 ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.config
@@ -357,8 +390,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -357,8 +390,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
357 msg.getSharedUpdatedList().forEach(tsKvProto -> { 390 msg.getSharedUpdatedList().forEach(tsKvProto -> {
358 String pathName = tsKvProto.getKv().getKey(); 391 String pathName = tsKvProto.getKv().getKey();
359 Object valueNew = getValueFromKvProto(tsKvProto.getKv()); 392 Object valueNew = getValueFromKvProto(tsKvProto.getKv());
360 - if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) {  
361 - lwM2MClient.getFrUpdate().setCurrentFwVersion((String) valueNew); 393 + if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())) {
  394 + lwM2MClient.getFwUpdate().setCurrentVersion((String) valueNew);
362 } 395 }
363 }); 396 });
364 log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo); 397 log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo);
@@ -402,12 +435,12 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -402,12 +435,12 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
402 } 435 }
403 436
404 @Override 437 @Override
405 - public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest, SessionInfoProto sessionInfo) { 438 + public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRpcRequestMsg, SessionInfoProto sessionInfo) {
  439 + log.warn("4) RPC-OK finish to [{}]", toDeviceRpcRequestMsg);
406 Lwm2mClientRpcRequest lwm2mClientRpcRequest = null; 440 Lwm2mClientRpcRequest lwm2mClientRpcRequest = null;
407 try { 441 try {
408 - log.info("[{}] toDeviceRpcRequest", toDeviceRequest);  
409 Registration registration = clientContext.getClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).getRegistration(); 442 Registration registration = clientContext.getClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).getRegistration();
410 - lwm2mClientRpcRequest = this.getDeviceRpcRequest(toDeviceRequest, sessionInfo, registration); 443 + lwm2mClientRpcRequest = this.getDeviceRpcRequest(toDeviceRpcRequestMsg, sessionInfo, registration);
411 if (lwm2mClientRpcRequest.getErrorMsg() != null) { 444 if (lwm2mClientRpcRequest.getErrorMsg() != null) {
412 lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name()); 445 lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());
413 this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo); 446 this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);
@@ -459,12 +492,27 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -459,12 +492,27 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
459 lwm2mClientRpcRequest.setValue(rpcRequest.get(lwm2mClientRpcRequest.valueKey).getAsString()); 492 lwm2mClientRpcRequest.setValue(rpcRequest.get(lwm2mClientRpcRequest.valueKey).getAsString());
460 } 493 }
461 if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonObject()) { 494 if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonObject()) {
462 - lwm2mClientRpcRequest.setParams(new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey) 495 + ConcurrentHashMap<String, Object> params = new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey)
  496 + .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() {
  497 + }.getType());
  498 + if (WRITE_UPDATE == lwm2mClientRpcRequest.getTypeOper()) {
  499 + ConcurrentHashMap<String, Object> paramsResourceId = convertParamsToResourceId(params, sessionInfo);
  500 + if (paramsResourceId.size() > 0) {
  501 + lwm2mClientRpcRequest.setParams(paramsResourceId);
  502 + }
  503 + } else {
  504 + lwm2mClientRpcRequest.setParams(params);
  505 + }
  506 + } else if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonArray()) {
  507 + new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey)
463 .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() { 508 .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() {
464 - }.getType())); 509 + }.getType());
465 } 510 }
466 lwm2mClientRpcRequest.setSessionInfo(sessionInfo); 511 lwm2mClientRpcRequest.setSessionInfo(sessionInfo);
467 - if (OBSERVE_READ_ALL != lwm2mClientRpcRequest.getTypeOper() && lwm2mClientRpcRequest.getTargetIdVer() == null) { 512 + if (!(OBSERVE_READ_ALL == lwm2mClientRpcRequest.getTypeOper()
  513 + || DISCOVER_All == lwm2mClientRpcRequest.getTypeOper()
  514 + || OBSERVE_CANCEL == lwm2mClientRpcRequest.getTypeOper())
  515 + && lwm2mClientRpcRequest.getTargetIdVer() == null) {
468 lwm2mClientRpcRequest.setErrorMsg(lwm2mClientRpcRequest.targetIdVerKey + " and " + 516 lwm2mClientRpcRequest.setErrorMsg(lwm2mClientRpcRequest.targetIdVerKey + " and " +
469 lwm2mClientRpcRequest.keyNameKey + " is null or bad format"); 517 lwm2mClientRpcRequest.keyNameKey + " is null or bad format");
470 } 518 }
@@ -488,6 +536,21 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -488,6 +536,21 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
488 return lwm2mClientRpcRequest; 536 return lwm2mClientRpcRequest;
489 } 537 }
490 538
  539 + private ConcurrentHashMap<String, Object> convertParamsToResourceId(ConcurrentHashMap<String, Object> params,
  540 + SessionInfoProto sessionInfo) {
  541 + ConcurrentHashMap<String, Object> paramsIdVer = new ConcurrentHashMap<>();
  542 + params.forEach((k, v) -> {
  543 + String targetIdVer = this.getPresentPathIntoProfile(sessionInfo, k);
  544 + if (targetIdVer != null) {
  545 + LwM2mPath targetId = new LwM2mPath(convertPathFromIdVerToObjectId(targetIdVer));
  546 + if (targetId.isResource()) {
  547 + paramsIdVer.put(String.valueOf(targetId.getResourceId()), v);
  548 + }
  549 + }
  550 + });
  551 + return paramsIdVer;
  552 + }
  553 +
491 public void sentRpcRequest(Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) { 554 public void sentRpcRequest(Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) {
492 rpcRequest.setResponseCode(requestCode); 555 rpcRequest.setResponseCode(requestCode);
493 if (LOG_LW2M_ERROR.equals(typeMsg)) { 556 if (LOG_LW2M_ERROR.equals(typeMsg)) {
@@ -561,7 +624,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -561,7 +624,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
561 */ 624 */
562 @Override 625 @Override
563 public void onAwakeDev(Registration registration) { 626 public void onAwakeDev(Registration registration) {
564 - log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint()); 627 + log.trace("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint());
565 this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is awake!", registration.getId()); 628 this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is awake!", registration.getId());
566 //TODO: associate endpointId with device information. 629 //TODO: associate endpointId with device information.
567 } 630 }
@@ -577,7 +640,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -577,7 +640,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
577 if (logMsg.length() > 1024) { 640 if (logMsg.length() > 1024) {
578 logMsg = logMsg.substring(0, 1024); 641 logMsg = logMsg.substring(0, 1024);
579 } 642 }
580 - this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvLogyToThingsboard(logMsg), sessionInfo); 643 + this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo);
581 } 644 }
582 } 645 }
583 646
@@ -614,7 +677,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -614,7 +677,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
614 /** 677 /**
615 * @param registration - 678 * @param registration -
616 * @param lwM2mObject - 679 * @param lwM2mObject -
617 - * @param pathIdVer - 680 + * @param pathIdVer -
618 */ 681 */
619 private void updateObjectResourceValue(Registration registration, LwM2mObject lwM2mObject, String pathIdVer) { 682 private void updateObjectResourceValue(Registration registration, LwM2mObject lwM2mObject, String pathIdVer) {
620 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)); 683 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));
@@ -651,18 +714,63 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -651,18 +714,63 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
651 private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) { 714 private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) {
652 LwM2mClient lwM2MClient = clientContext.getOrRegister(registration); 715 LwM2mClient lwM2MClient = clientContext.getOrRegister(registration);
653 if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider())) { 716 if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider())) {
654 - if (FR_PATH_RESOURCE_VER_ID.equals(convertPathFromIdVerToObjectId(path)) &&  
655 - lwM2MClient.getFrUpdate().getCurrentFwVersion() != null  
656 - && !lwM2MClient.getFrUpdate().getCurrentFwVersion().equals(lwM2MClient.getFrUpdate().getClientFwVersion())  
657 - && lwM2MClient.isUpdateFw()) {  
658 -  
659 - /** version != null  
660 - * set setClient_fw_version = value  
661 - **/  
662 - lwM2MClient.setUpdateFw(false);  
663 - lwM2MClient.getFrUpdate().setClientFwVersion(lwM2mResource.getValue().toString());  
664 - log.warn("updateFirmwareClient3");  
665 - this.updateFirmwareClient(lwM2MClient); 717 + /** version != null
  718 + * set setClient_fw_info... = value
  719 + **/
  720 + if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {
  721 + lwM2MClient.getFwUpdate().initReadValue(this, lwM2mTransportRequest, path);
  722 + }
  723 + if (lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {
  724 + lwM2MClient.getSwUpdate().initReadValue(this, lwM2mTransportRequest, path);
  725 + }
  726 +
  727 + /**
  728 + * Before operation Execute (FwUpdate) inspection Update Result :
  729 + * - after finished operation Write result: success (FwUpdate): fw_state = DOWNLOADED
  730 + * - before start operation Execute (FwUpdate) Update Result = 0 - Initial value
  731 + * - start Execute (FwUpdate)
  732 + * After finished operation Execute (FwUpdate) inspection Update Result :
  733 + * - after start operation Execute (FwUpdate): fw_state = UPDATING
  734 + * - after success finished operation Execute (FwUpdate) Update Result == 1 ("Firmware updated successfully")
  735 + * - finished operation Execute (FwUpdate)
  736 + */
  737 + if (lwM2MClient.getFwUpdate() != null
  738 + && (convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path))) {
  739 + if (DOWNLOADED.name().equals(lwM2MClient.getFwUpdate().getStateUpdate())
  740 + && lwM2MClient.getFwUpdate().conditionalFwExecuteStart()) {
  741 + lwM2MClient.getFwUpdate().executeFwSwWare(this, lwM2mTransportRequest);
  742 + } else if (UPDATING.name().equals(lwM2MClient.getFwUpdate().getStateUpdate())
  743 + && lwM2MClient.getFwUpdate().conditionalFwExecuteAfterSuccess()) {
  744 + lwM2MClient.getFwUpdate().finishFwSwUpdate(this, true);
  745 + } else if (UPDATING.name().equals(lwM2MClient.getFwUpdate().getStateUpdate())
  746 + && lwM2MClient.getFwUpdate().conditionalFwExecuteAfterError()) {
  747 + lwM2MClient.getFwUpdate().finishFwSwUpdate(this, false);
  748 + }
  749 + }
  750 +
  751 + /**
  752 + * Before operation Execute (SwUpdate) inspection Update Result :
  753 + * - after finished operation Write result: success (SwUpdate): fw_state = DOWNLOADED
  754 + * - before operation Execute (SwUpdate) Update Result = 3 - Successfully Downloaded and package integrity verified
  755 + * - start Execute (SwUpdate)
  756 + * After finished operation Execute (SwUpdate) inspection Update Result :
  757 + * - after start operation Execute (SwUpdate): fw_state = UPDATING
  758 + * - after success finished operation Execute (SwUpdate) Update Result == 2 "Software successfully installed.""
  759 + * - after success finished operation Execute (SwUpdate) Update Result == 2 "Software successfully installed.""
  760 + * - finished operation Execute (SwUpdate)
  761 + */
  762 + if (lwM2MClient.getSwUpdate() != null
  763 + && (convertPathFromObjectIdToIdVer(SW_RESULT_ID, registration).equals(path))) {
  764 + if (DOWNLOADED.name().equals(lwM2MClient.getSwUpdate().getStateUpdate())
  765 + && lwM2MClient.getSwUpdate().conditionalSwUpdateExecute()) {
  766 + lwM2MClient.getSwUpdate().executeFwSwWare(this, lwM2mTransportRequest);
  767 + } else if (UPDATING.name().equals(lwM2MClient.getSwUpdate().getStateUpdate())
  768 + && lwM2MClient.getSwUpdate().conditionalSwExecuteAfterSuccess()) {
  769 + lwM2MClient.getSwUpdate().finishFwSwUpdate(this, true);
  770 + } else if (UPDATING.name().equals(lwM2MClient.getSwUpdate().getStateUpdate())
  771 + && lwM2MClient.getSwUpdate().conditionalSwExecuteAfterError()) {
  772 + lwM2MClient.getSwUpdate().finishFwSwUpdate(this, false);
  773 + }
666 } 774 }
667 Set<String> paths = new HashSet<>(); 775 Set<String> paths = new HashSet<>();
668 paths.add(path); 776 paths.add(path);
@@ -684,7 +792,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -684,7 +792,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
684 */ 792 */
685 private void updateAttrTelemetry(Registration registration, Set<String> paths) { 793 private void updateAttrTelemetry(Registration registration, Set<String> paths) {
686 try { 794 try {
687 - ResultsAddKeyValueProto results = getParametersFromProfile(registration, paths); 795 + ResultsAddKeyValueProto results = this.getParametersFromProfile(registration, paths);
688 SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registration); 796 SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registration);
689 if (results != null && sessionInfo != null) { 797 if (results != null && sessionInfo != null) {
690 if (results.getResultAttributes().size() > 0) { 798 if (results.getResultAttributes().size() > 0) {
@@ -818,7 +926,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -818,7 +926,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
818 Object finalvalueKvProto = valueKvProto; 926 Object finalvalueKvProto = valueKvProto;
819 Gson gson = new GsonBuilder().create(); 927 Gson gson = new GsonBuilder().create();
820 resourceValue.getValues().forEach((k, v) -> { 928 resourceValue.getValues().forEach((k, v) -> {
821 - Object val = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType, 929 + Object val = this.converter.convertValue(v, currentType, expectedType,
822 new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))); 930 new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
823 JsonElement element = gson.toJsonTree(val, val.getClass()); 931 JsonElement element = gson.toJsonTree(val, val.getClass());
824 ((JsonObject) finalvalueKvProto).add(String.valueOf(k), element); 932 ((JsonObject) finalvalueKvProto).add(String.valueOf(k), element);
@@ -910,7 +1018,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -910,7 +1018,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
910 */ 1018 */
911 private void onDeviceProfileUpdate(Set<String> registrationIds, DeviceProfile deviceProfile) { 1019 private void onDeviceProfileUpdate(Set<String> registrationIds, DeviceProfile deviceProfile) {
912 LwM2mClientProfile lwM2MClientProfileOld = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone(); 1020 LwM2mClientProfile lwM2MClientProfileOld = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone();
913 - if (clientContext.toClientProfile(deviceProfile) != null) { 1021 + if (clientContext.profileUpdate(deviceProfile) != null) {
914 // #1 1022 // #1
915 JsonArray attributeOld = lwM2MClientProfileOld.getPostAttributeProfile(); 1023 JsonArray attributeOld = lwM2MClientProfileOld.getPostAttributeProfile();
916 Set<String> attributeSetOld = convertJsonArrayToSet(attributeOld); 1024 Set<String> attributeSetOld = convertJsonArrayToSet(attributeOld);
@@ -920,7 +1028,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -920,7 +1028,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
920 JsonObject keyNameOld = lwM2MClientProfileOld.getPostKeyNameProfile(); 1028 JsonObject keyNameOld = lwM2MClientProfileOld.getPostKeyNameProfile();
921 JsonObject attributeLwm2mOld = lwM2MClientProfileOld.getPostAttributeLwm2mProfile(); 1029 JsonObject attributeLwm2mOld = lwM2MClientProfileOld.getPostAttributeLwm2mProfile();
922 1030
923 - LwM2mClientProfile lwM2MClientProfileNew = clientContext.getProfiles().get(deviceProfile.getUuidId()); 1031 + LwM2mClientProfile lwM2MClientProfileNew = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone();
924 JsonArray attributeNew = lwM2MClientProfileNew.getPostAttributeProfile(); 1032 JsonArray attributeNew = lwM2MClientProfileNew.getPostAttributeProfile();
925 Set<String> attributeSetNew = convertJsonArrayToSet(attributeNew); 1033 Set<String> attributeSetNew = convertJsonArrayToSet(attributeNew);
926 JsonArray telemetryNew = lwM2MClientProfileNew.getPostTelemetryProfile(); 1034 JsonArray telemetryNew = lwM2MClientProfileNew.getPostTelemetryProfile();
@@ -968,8 +1076,6 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -968,8 +1076,6 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
968 registrationIds.forEach(registrationId -> { 1076 registrationIds.forEach(registrationId -> {
969 Registration registration = clientContext.getRegistration(registrationId); 1077 Registration registration = clientContext.getRegistration(registrationId);
970 this.readObserveFromProfile(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ); 1078 this.readObserveFromProfile(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ);
971 - // send attr/telemetry to tingsboard for new path  
972 - this.updateAttrTelemetry(registration, sendAttrToThingsboard.getPathPostParametersAdd());  
973 }); 1079 });
974 } 1080 }
975 // #4.2 del 1081 // #4.2 del
@@ -1248,7 +1354,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -1248,7 +1354,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1248 * @param registration - Registration LwM2M Client 1354 * @param registration - Registration LwM2M Client
1249 * @return - sessionInfo after access connect client 1355 * @return - sessionInfo after access connect client
1250 */ 1356 */
1251 - private SessionInfoProto getSessionInfoOrCloseSession(Registration registration) { 1357 + public SessionInfoProto getSessionInfoOrCloseSession(Registration registration) {
1252 return getSessionInfoOrCloseSession(clientContext.getOrRegister(registration)); 1358 return getSessionInfoOrCloseSession(clientContext.getOrRegister(registration));
1253 } 1359 }
1254 1360
@@ -1296,7 +1402,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -1296,7 +1402,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1296 TransportProtos.GetAttributeRequestMsg getAttributeMsg = adaptor.convertToGetAttributes(null, keyNamesMap.values()); 1402 TransportProtos.GetAttributeRequestMsg getAttributeMsg = adaptor.convertToGetAttributes(null, keyNamesMap.values());
1297 transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST)); 1403 transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST));
1298 } catch (AdaptorException e) { 1404 } catch (AdaptorException e) {
1299 - log.warn("Failed to decode get attributes request", e); 1405 + log.trace("Failed to decode get attributes request", e);
1300 } 1406 }
1301 } 1407 }
1302 1408
@@ -1304,62 +1410,72 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -1304,62 +1410,72 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1304 } 1410 }
1305 1411
1306 public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient) { 1412 public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient) {
1307 - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);  
1308 - if (sessionInfo != null) {  
1309 - TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()  
1310 - .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())  
1311 - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())  
1312 - .setTenantIdMSB(sessionInfo.getTenantIdMSB())  
1313 - .setTenantIdLSB(sessionInfo.getTenantIdLSB())  
1314 - .setType(FirmwareType.FIRMWARE.name())  
1315 - .build();  
1316 - transportService.process(sessionInfo, getFirmwareRequestMsg,  
1317 - new TransportServiceCallback<>() {  
1318 - @Override  
1319 - public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) {  
1320 - if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) {  
1321 - lwM2MClient.getFrUpdate().setCurrentFwVersion(response.getVersion());  
1322 - lwM2MClient.getFrUpdate().setCurrentFwId(new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())).getId());  
1323 - lwM2MClient.setUpdateFw(true);  
1324 - readRequestToClientFirmwareVer(lwM2MClient.getRegistration());  
1325 - } else {  
1326 - log.trace("Firmware [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString()); 1413 + if (lwM2MClient.getRegistration().getSupportedVersion(FW_ID) != null) {
  1414 + SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
  1415 + if (sessionInfo != null) {
  1416 + DefaultLwM2MTransportMsgHandler serviceImpl = this;
  1417 + transportService.process(sessionInfo, createFirmwareRequestMsg(sessionInfo, FirmwareType.FIRMWARE.name()),
  1418 + new TransportServiceCallback<>() {
  1419 + @Override
  1420 + public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) {
  1421 + if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())
  1422 + && response.getType().equals(FirmwareType.FIRMWARE.name())) {
  1423 + lwM2MClient.getFwUpdate().setCurrentVersion(response.getVersion());
  1424 + lwM2MClient.getFwUpdate().setCurrentTitle(response.getTitle());
  1425 + lwM2MClient.getFwUpdate().setCurrentId(new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())).getId());
  1426 + lwM2MClient.getFwUpdate().sendReadObserveInfo(lwM2mTransportRequest);
  1427 + } else {
  1428 + log.trace("Firmware [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
  1429 + }
1327 } 1430 }
1328 - }  
1329 1431
1330 - @Override  
1331 - public void onError(Throwable e) {  
1332 - log.trace("Failed to process credentials ", e);  
1333 - }  
1334 - }); 1432 + @Override
  1433 + public void onError(Throwable e) {
  1434 + log.trace("Failed to process firmwareUpdate ", e);
  1435 + }
  1436 + });
  1437 + }
1335 } 1438 }
1336 } 1439 }
1337 1440
1338 - /**  
1339 - * @param registration  
1340 - */  
1341 - public void readRequestToClientFirmwareVer(Registration registration) {  
1342 - String pathIdVer = convertPathFromObjectIdToIdVer(FR_PATH_RESOURCE_VER_ID, registration);  
1343 - lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, READ, ContentFormat.TLV.getName(),  
1344 - null, config.getTimeout(), null);  
1345 - } 1441 + public void getInfoSoftwareUpdate(LwM2mClient lwM2MClient) {
  1442 + if (lwM2MClient.getRegistration().getSupportedVersion(SW_ID) != null) {
  1443 + SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
  1444 + if (sessionInfo != null) {
  1445 + DefaultLwM2MTransportMsgHandler serviceImpl = this;
  1446 + transportService.process(sessionInfo, createFirmwareRequestMsg(sessionInfo, FirmwareType.SOFTWARE.name()),
  1447 + new TransportServiceCallback<>() {
  1448 + @Override
  1449 + public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) {
  1450 + if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())
  1451 + && response.getType().equals(FirmwareType.SOFTWARE.name())) {
  1452 + lwM2MClient.getSwUpdate().setCurrentVersion(response.getVersion());
  1453 + lwM2MClient.getSwUpdate().setCurrentTitle(response.getTitle());
  1454 + lwM2MClient.getSwUpdate().setCurrentId(new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())).getId());
  1455 + lwM2MClient.getSwUpdate().sendReadObserveInfo(lwM2mTransportRequest);
  1456 + } else {
  1457 + log.trace("Software [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
  1458 + }
  1459 + }
1346 1460
1347 - /**  
1348 - * @param lwM2MClient -  
1349 - */  
1350 - public void updateFirmwareClient(LwM2mClient lwM2MClient) {  
1351 - if (!lwM2MClient.getFrUpdate().getCurrentFwVersion().equals(lwM2MClient.getFrUpdate().getClientFwVersion())) {  
1352 - int chunkSize = 0;  
1353 - int chunk = 0;  
1354 - byte[] firmwareChunk = firmwareDataCache.get(lwM2MClient.getFrUpdate().getCurrentFwId().toString(), chunkSize, chunk);  
1355 - String verSupportedObject = lwM2MClient.getRegistration().getSupportedObject().get(FR_OBJECT_ID);  
1356 - String targetIdVer = LWM2M_SEPARATOR_PATH + FR_OBJECT_ID + LWM2M_SEPARATOR_KEY + verSupportedObject + LWM2M_SEPARATOR_PATH + 0 + LWM2M_SEPARATOR_PATH + 0;  
1357 - lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(),  
1358 - firmwareChunk, config.getTimeout(), null);  
1359 - log.warn("updateFirmwareClient [{}] [{}]", lwM2MClient.getFrUpdate().getCurrentFwVersion(), lwM2MClient.getFrUpdate().getClientFwVersion()); 1461 + @Override
  1462 + public void onError(Throwable e) {
  1463 + log.trace("Failed to process softwareUpdate ", e);
  1464 + }
  1465 + });
  1466 + }
1360 } 1467 }
1361 } 1468 }
1362 1469
  1470 + private TransportProtos.GetFirmwareRequestMsg createFirmwareRequestMsg(SessionInfoProto sessionInfo, String nameFwSW) {
  1471 + return TransportProtos.GetFirmwareRequestMsg.newBuilder()
  1472 + .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
  1473 + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
  1474 + .setTenantIdMSB(sessionInfo.getTenantIdMSB())
  1475 + .setTenantIdLSB(sessionInfo.getTenantIdLSB())
  1476 + .setType(nameFwSW)
  1477 + .build();
  1478 + }
1363 1479
1364 /** 1480 /**
1365 * !!! sharedAttr === profileAttr !!! 1481 * !!! sharedAttr === profileAttr !!!
@@ -1386,4 +1502,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -1386,4 +1502,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1386 objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId))); 1502 objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)));
1387 } 1503 }
1388 1504
  1505 + public LwM2MTransportServerConfig getConfig() {
  1506 + return this.config;
  1507 + }
  1508 +
1389 } 1509 }
@@ -28,6 +28,7 @@ import org.eclipse.leshan.server.californium.registration.CaliforniumRegistratio @@ -28,6 +28,7 @@ import org.eclipse.leshan.server.californium.registration.CaliforniumRegistratio
28 import org.eclipse.leshan.server.model.LwM2mModelProvider; 28 import org.eclipse.leshan.server.model.LwM2mModelProvider;
29 import org.eclipse.leshan.server.security.EditableSecurityStore; 29 import org.eclipse.leshan.server.security.EditableSecurityStore;
30 import org.springframework.stereotype.Component; 30 import org.springframework.stereotype.Component;
  31 +import org.thingsboard.common.util.ThingsBoardThreadFactory;
31 import org.thingsboard.server.common.data.StringUtils; 32 import org.thingsboard.server.common.data.StringUtils;
32 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 33 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
33 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; 34 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
@@ -57,6 +58,8 @@ import java.security.spec.InvalidParameterSpecException; @@ -57,6 +58,8 @@ import java.security.spec.InvalidParameterSpecException;
57 import java.security.spec.KeySpec; 58 import java.security.spec.KeySpec;
58 import java.security.spec.PKCS8EncodedKeySpec; 59 import java.security.spec.PKCS8EncodedKeySpec;
59 import java.util.Arrays; 60 import java.util.Arrays;
  61 +import java.util.concurrent.Executors;
  62 +import java.util.concurrent.ScheduledExecutorService;
60 63
61 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; 64 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
62 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; 65 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
@@ -122,7 +125,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { @@ -122,7 +125,6 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
122 /* Use a magic converter to support bad type send by the UI. */ 125 /* Use a magic converter to support bad type send by the UI. */
123 builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance())); 126 builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance()));
124 127
125 -  
126 /* Create CoAP Config */ 128 /* Create CoAP Config */
127 builder.setCoapConfig(getCoapConfig(config.getPort(), config.getSecurePort())); 129 builder.setCoapConfig(getCoapConfig(config.getPort(), config.getSecurePort()));
128 130
@@ -86,21 +86,22 @@ public class LwM2mServerListener { @@ -86,21 +86,22 @@ public class LwM2mServerListener {
86 86
87 @Override 87 @Override
88 public void cancelled(Observation observation) { 88 public void cancelled(Observation observation) {
89 - String msg = String.format("%s: Cancel Observation %s.", LOG_LW2M_INFO, observation.getPath()); 89 + String msg = String.format("%s: Canceled Observation %s.", LOG_LW2M_INFO, observation.getPath());
90 service.sendLogsToThingsboard(msg, observation.getRegistrationId()); 90 service.sendLogsToThingsboard(msg, observation.getRegistrationId());
91 - log.trace(msg); 91 + log.warn(msg);
92 } 92 }
93 93
94 @Override 94 @Override
95 public void onResponse(Observation observation, Registration registration, ObserveResponse response) { 95 public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
96 if (registration != null) { 96 if (registration != null) {
97 - try {  
98 - service.onUpdateValueAfterReadResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(),  
99 - registration), response, null);  
100 - } catch (Exception e) {  
101 - log.error("Observation/Read onResponse", e);  
102 -  
103 - } 97 +// if (observation.getPath().isResource() || observation.getPath().isResourceInstance()) {
  98 +// String msg = String.format("%s: Successful Observation %s.", LOG_LW2M_INFO,
  99 +// observation.getPath());
  100 +// log.warn(msg);
  101 +// service.sendLogsToThingsboard(msg, registration.getId());
  102 +// }
  103 + service.onUpdateValueAfterReadResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(),
  104 + registration), response, null);
104 } 105 }
105 } 106 }
106 107
@@ -113,9 +114,8 @@ public class LwM2mServerListener { @@ -113,9 +114,8 @@ public class LwM2mServerListener {
113 public void newObservation(Observation observation, Registration registration) { 114 public void newObservation(Observation observation, Registration registration) {
114 String msg = String.format("%s: Successful start newObservation %s.", LOG_LW2M_INFO, 115 String msg = String.format("%s: Successful start newObservation %s.", LOG_LW2M_INFO,
115 observation.getPath()); 116 observation.getPath());
  117 + log.warn(msg);
116 service.sendLogsToThingsboard(msg, registration.getId()); 118 service.sendLogsToThingsboard(msg, registration.getId());
117 - log.trace(msg);  
118 } 119 }
119 }; 120 };
120 -  
121 } 121 }
@@ -21,6 +21,7 @@ import org.eclipse.leshan.server.registration.Registration; @@ -21,6 +21,7 @@ import org.eclipse.leshan.server.registration.Registration;
21 import org.thingsboard.server.common.data.Device; 21 import org.thingsboard.server.common.data.Device;
22 import org.thingsboard.server.common.data.DeviceProfile; 22 import org.thingsboard.server.common.data.DeviceProfile;
23 import org.thingsboard.server.gen.transport.TransportProtos; 23 import org.thingsboard.server.gen.transport.TransportProtos;
  24 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
24 import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest; 25 import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest;
25 26
26 import java.util.Collection; 27 import java.util.Collection;
@@ -36,7 +37,7 @@ public interface LwM2mTransportMsgHandler { @@ -36,7 +37,7 @@ public interface LwM2mTransportMsgHandler {
36 37
37 void onSleepingDev(Registration registration); 38 void onSleepingDev(Registration registration);
38 39
39 - void setCancelObservations(Registration registration); 40 + void setCancelObservationsAll(Registration registration);
40 41
41 void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest); 42 void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest);
42 43
@@ -63,4 +64,6 @@ public interface LwM2mTransportMsgHandler { @@ -63,4 +64,6 @@ public interface LwM2mTransportMsgHandler {
63 void onAwakeDev(Registration registration); 64 void onAwakeDev(Registration registration);
64 65
65 void sendLogsToThingsboard(String msg, String registrationId); 66 void sendLogsToThingsboard(String msg, String registrationId);
  67 +
  68 + LwM2MTransportServerConfig getConfig();
66 } 69 }
@@ -19,6 +19,7 @@ import lombok.RequiredArgsConstructor; @@ -19,6 +19,7 @@ import lombok.RequiredArgsConstructor;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
20 import org.eclipse.californium.core.coap.CoAP; 20 import org.eclipse.californium.core.coap.CoAP;
21 import org.eclipse.californium.core.coap.Response; 21 import org.eclipse.californium.core.coap.Response;
  22 +import org.eclipse.leshan.core.Link;
22 import org.eclipse.leshan.core.model.ResourceModel; 23 import org.eclipse.leshan.core.model.ResourceModel;
23 import org.eclipse.leshan.core.node.LwM2mNode; 24 import org.eclipse.leshan.core.node.LwM2mNode;
24 import org.eclipse.leshan.core.node.LwM2mPath; 25 import org.eclipse.leshan.core.node.LwM2mPath;
@@ -35,7 +36,6 @@ import org.eclipse.leshan.core.request.ObserveRequest; @@ -35,7 +36,6 @@ import org.eclipse.leshan.core.request.ObserveRequest;
35 import org.eclipse.leshan.core.request.ReadRequest; 36 import org.eclipse.leshan.core.request.ReadRequest;
36 import org.eclipse.leshan.core.request.WriteRequest; 37 import org.eclipse.leshan.core.request.WriteRequest;
37 import org.eclipse.leshan.core.request.exception.ClientSleepingException; 38 import org.eclipse.leshan.core.request.exception.ClientSleepingException;
38 -import org.eclipse.leshan.core.response.CancelObservationResponse;  
39 import org.eclipse.leshan.core.response.DeleteResponse; 39 import org.eclipse.leshan.core.response.DeleteResponse;
40 import org.eclipse.leshan.core.response.DiscoverResponse; 40 import org.eclipse.leshan.core.response.DiscoverResponse;
41 import org.eclipse.leshan.core.response.ExecuteResponse; 41 import org.eclipse.leshan.core.response.ExecuteResponse;
@@ -68,15 +68,26 @@ import java.util.stream.Collectors; @@ -68,15 +68,26 @@ import java.util.stream.Collectors;
68 import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT; 68 import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT;
69 import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST; 69 import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST;
70 import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND; 70 import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND;
  71 +import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.DOWNLOADED;
  72 +import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.FAILED;
  73 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getContentFormatByResourceModelType;
71 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEFAULT_TIMEOUT; 74 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEFAULT_TIMEOUT;
72 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FR_PATH_RESOURCE_VER_ID; 75 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_ID;
  76 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_UPDATE_ID;
73 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR; 77 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR;
74 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO; 78 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;
75 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE; 79 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE;
76 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper; 80 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;
  81 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER;
  82 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER_All;
  83 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
77 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL; 84 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;
78 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_READ_ALL; 85 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_READ_ALL;
79 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.RESPONSE_CHANNEL; 86 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
  87 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_UPDATE;
  88 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.RESPONSE_REQUEST_CHANNEL;
  89 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_INSTALL_ID;
  90 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_PACKAGE_ID;
80 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId; 91 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
81 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; 92 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
82 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.createWriteAttributeRequest; 93 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.createWriteAttributeRequest;
@@ -86,20 +97,20 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c @@ -86,20 +97,20 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c
86 @TbLwM2mTransportComponent 97 @TbLwM2mTransportComponent
87 @RequiredArgsConstructor 98 @RequiredArgsConstructor
88 public class LwM2mTransportRequest { 99 public class LwM2mTransportRequest {
89 - private ExecutorService executorResponse; 100 + private ExecutorService responseRequestExecutor;
90 101
91 public LwM2mValueConverterImpl converter; 102 public LwM2mValueConverterImpl converter;
92 103
93 private final LwM2mTransportContext context; 104 private final LwM2mTransportContext context;
94 private final LwM2MTransportServerConfig config; 105 private final LwM2MTransportServerConfig config;
95 private final LwM2mClientContext lwM2mClientContext; 106 private final LwM2mClientContext lwM2mClientContext;
96 - private final DefaultLwM2MTransportMsgHandler serviceImpl; 107 + private final DefaultLwM2MTransportMsgHandler handler;
97 108
98 @PostConstruct 109 @PostConstruct
99 public void init() { 110 public void init() {
100 this.converter = LwM2mValueConverterImpl.getInstance(); 111 this.converter = LwM2mValueConverterImpl.getInstance();
101 - executorResponse = Executors.newFixedThreadPool(this.config.getResponsePoolSize(),  
102 - new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL))); 112 + responseRequestExecutor = Executors.newFixedThreadPool(this.config.getResponsePoolSize(),
  113 + new NamedThreadFactory(String.format("LwM2M %s channel response after request", RESPONSE_REQUEST_CHANNEL)));
103 } 114 }
104 115
105 /** 116 /**
@@ -115,154 +126,186 @@ public class LwM2mTransportRequest { @@ -115,154 +126,186 @@ public class LwM2mTransportRequest {
115 String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) { 126 String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) {
116 try { 127 try {
117 String target = convertPathFromIdVerToObjectId(targetIdVer); 128 String target = convertPathFromIdVerToObjectId(targetIdVer);
118 - DownlinkRequest request = null;  
119 ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT; 129 ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT;
120 LwM2mClient lwM2MClient = this.lwM2mClientContext.getOrRegister(registration); 130 LwM2mClient lwM2MClient = this.lwM2mClientContext.getOrRegister(registration);
121 LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null; 131 LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null;
122 if (!OBSERVE_READ_ALL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) { 132 if (!OBSERVE_READ_ALL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) {
123 if (lwM2MClient.isValidObjectVersion(targetIdVer)) { 133 if (lwM2MClient.isValidObjectVersion(targetIdVer)) {
124 timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; 134 timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT;
125 - ResourceModel resourceModel = null;  
126 - switch (typeOper) {  
127 - case READ:  
128 - request = new ReadRequest(contentFormat, target);  
129 - break;  
130 - case DISCOVER:  
131 - request = new DiscoverRequest(target);  
132 - break;  
133 - case OBSERVE:  
134 - if (resultIds.isResource()) {  
135 - request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());  
136 - } else if (resultIds.isObjectInstance()) {  
137 - request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId());  
138 - } else if (resultIds.getObjectId() >= 0) {  
139 - request = new ObserveRequest(contentFormat, resultIds.getObjectId());  
140 - }  
141 - break;  
142 - case OBSERVE_CANCEL:  
143 - /*  
144 - lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_OBSERVE_CANCEL, null, null, null, null, context.getTimeout());  
145 - At server side this will not remove the observation from the observation store, to do it you need to use  
146 - {@code ObservationService#cancelObservation()}  
147 - */  
148 - context.getServer().getObservationService().cancelObservations(registration, target);  
149 - break;  
150 - case EXECUTE:  
151 - resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.config  
152 - .getModelProvider());  
153 - if (params != null && !resourceModel.multiple) {  
154 - request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resourceModel.type, ResourceModel.Type.STRING, resultIds));  
155 - } else {  
156 - request = new ExecuteRequest(target);  
157 - }  
158 - break;  
159 - case WRITE_REPLACE:  
160 - // Request to write a <b>String Single-Instance Resource</b> using the TLV content format.  
161 - resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider());  
162 - if (contentFormat.equals(ContentFormat.TLV)) {  
163 - request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(),  
164 - resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModel.type,  
165 - registration, rpcRequest);  
166 - }  
167 - // Mode.REPLACE && Request to write a <b>String Single-Instance Resource</b> using the given content format (TEXT, TLV, JSON)  
168 - else if (!contentFormat.equals(ContentFormat.TLV)) {  
169 - request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(),  
170 - resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModel.type,  
171 - registration, rpcRequest);  
172 - }  
173 - break;  
174 - case WRITE_UPDATE:  
175 - if (resultIds.isResource()) {  
176 - /**  
177 - * send request: path = '/3/0' node == wM2mObjectInstance  
178 - * with params == "\"resources\": {15: resource:{id:15. value:'+01'...}}  
179 - **/  
180 - Collection<LwM2mResource> resources = lwM2MClient.getNewOneResourceForInstance(  
181 - targetIdVer, params,  
182 - this.config.getModelProvider(),  
183 - this.converter);  
184 - request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(),  
185 - resultIds.getObjectInstanceId(), resources);  
186 - }  
187 -  
188 - /**  
189 - * params = "{\"id\":0,\"resources\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}"  
190 - *  
191 - * int rscId = resultIds.getObjectInstanceId();  
192 - */  
193 -  
194 - else if (resultIds.isObjectInstance()) {  
195 - if (((ConcurrentHashMap) params).size() > 0) {  
196 - Collection<LwM2mResource> resources = lwM2MClient.getNewManyResourcesForInstance(  
197 - targetIdVer, params,  
198 - this.config.getModelProvider(),  
199 - this.converter);  
200 - request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(),  
201 - resultIds.getObjectInstanceId(), resources);  
202 - }  
203 - } else if (resultIds.getObjectId() >= 0) {  
204 - request = new ObserveRequest(resultIds.getObjectId());  
205 - }  
206 - break;  
207 - case WRITE_ATTRIBUTES:  
208 - request = createWriteAttributeRequest(target, params);  
209 - break;  
210 - case DELETE:  
211 - request = new DeleteRequest(target);  
212 - break;  
213 - }  
214 - 135 + DownlinkRequest request = createRequest (registration, lwM2MClient, typeOper, contentFormat, target,
  136 + targetIdVer, resultIds, params, rpcRequest);
215 if (request != null) { 137 if (request != null) {
216 try { 138 try {
217 this.sendRequest(registration, lwM2MClient, request, timeoutInMs, rpcRequest); 139 this.sendRequest(registration, lwM2MClient, request, timeoutInMs, rpcRequest);
218 } catch (ClientSleepingException e) { 140 } catch (ClientSleepingException e) {
219 DownlinkRequest finalRequest = request; 141 DownlinkRequest finalRequest = request;
220 long finalTimeoutInMs = timeoutInMs; 142 long finalTimeoutInMs = timeoutInMs;
221 - lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, rpcRequest)); 143 + Lwm2mClientRpcRequest finalRpcRequest = rpcRequest;
  144 + lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, finalRpcRequest));
222 } catch (Exception e) { 145 } catch (Exception e) {
223 log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper.name(), e); 146 log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper.name(), e);
224 } 147 }
225 - } else if (OBSERVE_CANCEL == typeOper) {  
226 - log.trace("[{}], [{}] - [{}] SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer);  
227 - if (rpcRequest != null) {  
228 - rpcRequest.setInfoMsg(null);  
229 - serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), null, null); 148 + }
  149 + else if (WRITE_UPDATE.name().equals(typeOper.name())) {
  150 + Lwm2mClientRpcRequest rpcRequestClone = (Lwm2mClientRpcRequest) rpcRequest.clone();
  151 + if (rpcRequestClone != null) {
  152 + String errorMsg = String.format("Path %s params is not valid", targetIdVer);
  153 + handler.sentRpcRequest(rpcRequestClone, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);
  154 + rpcRequest = null;
230 } 155 }
231 - } else { 156 + }
  157 + else if (!OBSERVE_CANCEL.name().equals(typeOper.name())) {
232 log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer); 158 log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer);
233 if (rpcRequest != null) { 159 if (rpcRequest != null) {
  160 + ResourceModel resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider());
234 String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null"; 161 String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null";
235 - serviceImpl.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); 162 + handler.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
236 } 163 }
237 } 164 }
238 } else if (rpcRequest != null) { 165 } else if (rpcRequest != null) {
239 String errorMsg = String.format("Path %s not found in object version", targetIdVer); 166 String errorMsg = String.format("Path %s not found in object version", targetIdVer);
240 - serviceImpl.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); 167 + handler.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
  168 + }
  169 + } else if (OBSERVE_READ_ALL.name().equals(typeOper.name()) || DISCOVER_All.name().equals(typeOper.name())) {
  170 + Set<String> paths;
  171 + if (OBSERVE_READ_ALL.name().equals(typeOper.name())) {
  172 + Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
  173 + paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet());
  174 + } else {
  175 + assert registration != null;
  176 + Link[] objectLinks = registration.getSortedObjectLinks();
  177 + paths = Arrays.stream(objectLinks).map(Link::toString).collect(Collectors.toUnmodifiableSet());
  178 + String msg = String.format("%s: type operation %s paths - %s", LOG_LW2M_INFO,
  179 + typeOper.name(), paths);
  180 + handler.sendLogsToThingsboard(msg, registration.getId());
241 } 181 }
242 - } else if (OBSERVE_READ_ALL.name().equals(typeOper.name())) {  
243 - Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);  
244 - Set<String> observationPaths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet());  
245 - String msg = String.format("%s: type operation %s observation paths - %s", LOG_LW2M_INFO,  
246 - OBSERVE_READ_ALL.type, observationPaths);  
247 - serviceImpl.sendLogsToThingsboard(msg, registration.getId());  
248 - log.trace("[{}] [{}], [{}]", typeOper.name(), registration.getEndpoint(), msg);  
249 if (rpcRequest != null) { 182 if (rpcRequest != null) {
250 - String valueMsg = String.format("Observation paths - %s", observationPaths);  
251 - serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE); 183 + String valueMsg = String.format("Paths - %s", paths);
  184 + handler.sentRpcRequest(rpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE);
252 } 185 }
  186 + } else if (OBSERVE_CANCEL.name().equals(typeOper.name())) {
  187 + int observeCancelCnt = context.getServer().getObservationService().cancelObservations(registration);
  188 + String observeCancelMsgAll = String.format("%s: type operation %s paths: All count: %d", LOG_LW2M_INFO,
  189 + OBSERVE_CANCEL.name(), observeCancelCnt);
  190 + this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsgAll, rpcRequest);
253 } 191 }
254 } catch (Exception e) { 192 } catch (Exception e) {
255 String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR, 193 String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR,
256 typeOper.name(), e.getMessage()); 194 typeOper.name(), e.getMessage());
257 - serviceImpl.sendLogsToThingsboard(msg, registration.getId());  
258 - try {  
259 - throw new Exception(e);  
260 - } catch (Exception exception) {  
261 - exception.printStackTrace(); 195 + handler.sendLogsToThingsboard(msg, registration.getId());
  196 + if (rpcRequest != null) {
  197 + String errorMsg = String.format("Path %s type operation %s %s", targetIdVer, typeOper.name(), e.getMessage());
  198 + handler.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
262 } 199 }
263 } 200 }
264 } 201 }
265 202
  203 + private DownlinkRequest createRequest (Registration registration, LwM2mClient lwM2MClient, LwM2mTypeOper typeOper,
  204 + ContentFormat contentFormat, String target, String targetIdVer,
  205 + LwM2mPath resultIds, Object params, Lwm2mClientRpcRequest rpcRequest) {
  206 + DownlinkRequest request = null;
  207 + switch (typeOper) {
  208 + case READ:
  209 + request = new ReadRequest(contentFormat, target);
  210 + break;
  211 + case DISCOVER:
  212 + request = new DiscoverRequest(target);
  213 + break;
  214 + case OBSERVE:
  215 + String msg = String.format("%s: Send Observation %s.", LOG_LW2M_INFO, targetIdVer);
  216 + log.warn(msg);
  217 + if (resultIds.isResource()) {
  218 + Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
  219 + Set<Observation> paths = observations.stream().filter(observation -> observation.getPath().equals(resultIds)).collect(Collectors.toSet());
  220 + if (paths.size() == 0) {
  221 + request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
  222 + } else {
  223 + request = new ReadRequest(contentFormat, target);
  224 + }
  225 + } else if (resultIds.isObjectInstance()) {
  226 + request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId());
  227 + } else if (resultIds.getObjectId() >= 0) {
  228 + request = new ObserveRequest(contentFormat, resultIds.getObjectId());
  229 + }
  230 + break;
  231 + case OBSERVE_CANCEL:
  232 + /*
  233 + lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_OBSERVE_CANCEL, null, null, null, null, context.getTimeout());
  234 + At server side this will not remove the observation from the observation store, to do it you need to use
  235 + {@code ObservationService#cancelObservation()}
  236 + */
  237 + int observeCancelCnt = context.getServer().getObservationService().cancelObservations(registration, target);
  238 + String observeCancelMsg = String.format("%s: type operation %s paths: %s count: %d", LOG_LW2M_INFO,
  239 + OBSERVE_CANCEL.name(), target, observeCancelCnt);
  240 + this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsg, rpcRequest);
  241 + break;
  242 + case EXECUTE:
  243 + ResourceModel resourceModelExe = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider());
  244 + if (params != null && !resourceModelExe.multiple) {
  245 + request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resourceModelExe.type, ResourceModel.Type.STRING, resultIds));
  246 + } else {
  247 + request = new ExecuteRequest(target);
  248 + }
  249 + break;
  250 + case WRITE_REPLACE:
  251 + /**
  252 + * Request to write a <b>String Single-Instance Resource</b> using the TLV content format.
  253 + * Type from resourceModel -> STRING, INTEGER, FLOAT, BOOLEAN, OPAQUE, TIME, OBJLNK
  254 + * contentFormat -> TLV, TLV, TLV, TLV, OPAQUE, TLV, LINK
  255 + * JSON, TEXT;
  256 + **/
  257 + ResourceModel resourceModelWrite = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider());
  258 + contentFormat = getContentFormatByResourceModelType(resourceModelWrite, contentFormat);
  259 + request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(),
  260 + resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModelWrite.type,
  261 + registration, rpcRequest);
  262 + break;
  263 + case WRITE_UPDATE:
  264 + if (resultIds.isResource()) {
  265 + /**
  266 + * send request: path = '/3/0' node == wM2mObjectInstance
  267 + * with params == "\"resources\": {15: resource:{id:15. value:'+01'...}}
  268 + **/
  269 + Collection<LwM2mResource> resources = lwM2MClient.getNewResourceForInstance(
  270 + targetIdVer, params,
  271 + this.config.getModelProvider(),
  272 + this.converter);
  273 + contentFormat = getContentFormatByResourceModelType(lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider()),
  274 + contentFormat);
  275 + request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(),
  276 + resultIds.getObjectInstanceId(), resources);
  277 + }
  278 + /**
  279 + * params = "{\"id\":0,\"resources\":[{\"id\":14,\"value\":\"+5\"},{\"id\":15,\"value\":\"+9\"}]}"
  280 + * int rscId = resultIds.getObjectInstanceId();
  281 + * contentFormat – Format of the payload (TLV or JSON).
  282 + */
  283 + else if (resultIds.isObjectInstance()) {
  284 + if (((ConcurrentHashMap) params).size() > 0) {
  285 + Collection<LwM2mResource> resources = lwM2MClient.getNewResourcesForInstance(
  286 + targetIdVer, params,
  287 + this.config.getModelProvider(),
  288 + this.converter);
  289 + if (resources.size() > 0) {
  290 + contentFormat = contentFormat.equals(ContentFormat.JSON) ? contentFormat : ContentFormat.TLV;
  291 + request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(),
  292 + resultIds.getObjectInstanceId(), resources);
  293 + }
  294 + }
  295 + } else if (resultIds.getObjectId() >= 0) {
  296 + request = new ObserveRequest(resultIds.getObjectId());
  297 + }
  298 + break;
  299 + case WRITE_ATTRIBUTES:
  300 + request = createWriteAttributeRequest(target, params);
  301 + break;
  302 + case DELETE:
  303 + request = new DeleteRequest(target);
  304 + break;
  305 + }
  306 + return request;
  307 + }
  308 +
266 /** 309 /**
267 * @param registration - 310 * @param registration -
268 * @param request - 311 * @param request -
@@ -273,52 +316,66 @@ public class LwM2mTransportRequest { @@ -273,52 +316,66 @@ public class LwM2mTransportRequest {
273 private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, 316 private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request,
274 long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) { 317 long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) {
275 context.getServer().send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> { 318 context.getServer().send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
  319 +
276 if (!lwM2MClient.isInit()) { 320 if (!lwM2MClient.isInit()) {
277 - lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); 321 + lwM2MClient.initReadValue(this.handler, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
278 } 322 }
279 if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) { 323 if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) {
280 this.handleResponse(registration, request.getPath().toString(), response, request, rpcRequest); 324 this.handleResponse(registration, request.getPath().toString(), response, request, rpcRequest);
281 } else { 325 } else {
282 String msg = String.format("%s: SendRequest %s: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s", LOG_LW2M_ERROR, request.getClass().getName().toString(), 326 String msg = String.format("%s: SendRequest %s: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s", LOG_LW2M_ERROR, request.getClass().getName().toString(),
283 ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); 327 ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString());
284 - serviceImpl.sendLogsToThingsboard(msg, registration.getId()); 328 + handler.sendLogsToThingsboard(msg, registration.getId());
285 log.error("[{}] [{}], [{}] - [{}] [{}] error SendRequest", request.getClass().getName().toString(), registration.getEndpoint(), 329 log.error("[{}] [{}], [{}] - [{}] [{}] error SendRequest", request.getClass().getName().toString(), registration.getEndpoint(),
286 ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); 330 ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString());
287 if (!lwM2MClient.isInit()) { 331 if (!lwM2MClient.isInit()) {
288 - lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); 332 + lwM2MClient.initReadValue(this.handler, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
289 } 333 }
  334 + /** Not Found */
290 if (rpcRequest != null) { 335 if (rpcRequest != null) {
291 - serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), response.getErrorMessage(), LOG_LW2M_ERROR); 336 + handler.sentRpcRequest(rpcRequest, response.getCode().getName(), response.getErrorMessage(), LOG_LW2M_ERROR);
292 } 337 }
293 - /* Not Found  
294 - set setClient_fw_version = empty  
295 - */  
296 - if (FR_PATH_RESOURCE_VER_ID.equals(request.getPath().toString()) && lwM2MClient.isUpdateFw()) {  
297 - lwM2MClient.setUpdateFw(false);  
298 - lwM2MClient.getFrUpdate().setClientFwVersion("");  
299 - log.warn("updateFirmwareClient1");  
300 - serviceImpl.updateFirmwareClient(lwM2MClient); 338 + /** Not Found
  339 + set setClient_fw_info... = empty
  340 + **/
  341 + if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {
  342 + lwM2MClient.getFwUpdate().initReadValue(handler, this, request.getPath().toString());
  343 + }
  344 + if (lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {
  345 + lwM2MClient.getSwUpdate().initReadValue(handler, this, request.getPath().toString());
  346 + }
  347 + if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) {
  348 + this.afterWriteFwSWUpdateError(registration, request, response.getErrorMessage());
  349 + }
  350 + if (request.getPath().toString().equals(FW_UPDATE_ID) || request.getPath().toString().equals(SW_INSTALL_ID)) {
  351 + this.afterExecuteFwSwUpdateError(registration, request, response.getErrorMessage());
301 } 352 }
302 } 353 }
303 }, e -> { 354 }, e -> {
304 - /* version == null  
305 - set setClient_fw_version = empty  
306 - */  
307 - if (FR_PATH_RESOURCE_VER_ID.equals(request.getPath().toString()) && lwM2MClient.isUpdateFw()) {  
308 - lwM2MClient.setUpdateFw(false);  
309 - lwM2MClient.getFrUpdate().setClientFwVersion("");  
310 - log.warn("updateFirmwareClient2");  
311 - serviceImpl.updateFirmwareClient(lwM2MClient); 355 + /** version == null
  356 + set setClient_fw_info... = empty
  357 + **/
  358 + if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {
  359 + lwM2MClient.getFwUpdate().initReadValue(handler, this, request.getPath().toString());
  360 + }
  361 + if (lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {
  362 + lwM2MClient.getSwUpdate().initReadValue(handler, this, request.getPath().toString());
  363 + }
  364 + if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) {
  365 + this.afterWriteFwSWUpdateError(registration, request, e.getMessage());
  366 + }
  367 + if (request.getPath().toString().equals(FW_UPDATE_ID) || request.getPath().toString().equals(SW_INSTALL_ID)) {
  368 + this.afterExecuteFwSwUpdateError(registration, request, e.getMessage());
312 } 369 }
313 if (!lwM2MClient.isInit()) { 370 if (!lwM2MClient.isInit()) {
314 - lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); 371 + lwM2MClient.initReadValue(this.handler, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
315 } 372 }
316 String msg = String.format("%s: SendRequest %s: Resource path - %s msg error - %s", 373 String msg = String.format("%s: SendRequest %s: Resource path - %s msg error - %s",
317 LOG_LW2M_ERROR, request.getClass().getName().toString(), request.getPath().toString(), e.getMessage()); 374 LOG_LW2M_ERROR, request.getClass().getName().toString(), request.getPath().toString(), e.getMessage());
318 - serviceImpl.sendLogsToThingsboard(msg, registration.getId()); 375 + handler.sendLogsToThingsboard(msg, registration.getId());
319 log.error("[{}] [{}] - [{}] error SendRequest", request.getClass().getName().toString(), request.getPath().toString(), e.toString()); 376 log.error("[{}] [{}] - [{}] error SendRequest", request.getClass().getName().toString(), request.getPath().toString(), e.toString());
320 if (rpcRequest != null) { 377 if (rpcRequest != null) {
321 - serviceImpl.sentRpcRequest(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR); 378 + handler.sentRpcRequest(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR);
322 } 379 }
323 }); 380 });
324 } 381 }
@@ -360,11 +417,11 @@ public class LwM2mTransportRequest { @@ -360,11 +417,11 @@ public class LwM2mTransportRequest {
360 String patn = "/" + objectId + "/" + instanceId + "/" + resourceId; 417 String patn = "/" + objectId + "/" + instanceId + "/" + resourceId;
361 String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client", 418 String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client",
362 patn, type, value, e.toString()); 419 patn, type, value, e.toString());
363 - serviceImpl.sendLogsToThingsboard(msg, registration.getId()); 420 + handler.sendLogsToThingsboard(msg, registration.getId());
364 log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString()); 421 log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString());
365 if (rpcRequest != null) { 422 if (rpcRequest != null) {
366 String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value); 423 String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value);
367 - serviceImpl.sentRpcRequest(rpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR); 424 + handler.sentRpcRequest(rpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);
368 } 425 }
369 return null; 426 return null;
370 } 427 }
@@ -372,7 +429,7 @@ public class LwM2mTransportRequest { @@ -372,7 +429,7 @@ public class LwM2mTransportRequest {
372 429
373 private void handleResponse(Registration registration, final String path, LwM2mResponse response, 430 private void handleResponse(Registration registration, final String path, LwM2mResponse response,
374 DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { 431 DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
375 - executorResponse.submit(() -> { 432 + responseRequestExecutor.submit(() -> {
376 try { 433 try {
377 this.sendResponse(registration, path, response, request, rpcRequest); 434 this.sendResponse(registration, path, response, request, rpcRequest);
378 } catch (Exception e) { 435 } catch (Exception e) {
@@ -391,39 +448,37 @@ public class LwM2mTransportRequest { @@ -391,39 +448,37 @@ public class LwM2mTransportRequest {
391 private void sendResponse(Registration registration, String path, LwM2mResponse response, 448 private void sendResponse(Registration registration, String path, LwM2mResponse response,
392 DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { 449 DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
393 String pathIdVer = convertPathFromObjectIdToIdVer(path, registration); 450 String pathIdVer = convertPathFromObjectIdToIdVer(path, registration);
  451 + String msgLog = "";
394 if (response instanceof ReadResponse) { 452 if (response instanceof ReadResponse) {
395 - serviceImpl.onUpdateValueAfterReadResponse(registration, pathIdVer, (ReadResponse) response, rpcRequest);  
396 - } else if (response instanceof CancelObservationResponse) {  
397 - log.info("[{}] Path [{}] CancelObservationResponse 3_Send", pathIdVer, response);  
398 - 453 + handler.onUpdateValueAfterReadResponse(registration, pathIdVer, (ReadResponse) response, rpcRequest);
399 } else if (response instanceof DeleteResponse) { 454 } else if (response instanceof DeleteResponse) {
400 - log.info("[{}] Path [{}] DeleteResponse 5_Send", pathIdVer, response); 455 + log.warn("[{}] Path [{}] DeleteResponse 5_Send", pathIdVer, response);
401 } else if (response instanceof DiscoverResponse) { 456 } else if (response instanceof DiscoverResponse) {
402 - log.info("[{}] [{}] - [{}] [{}] Discovery value: [{}]", registration.getEndpoint(),  
403 - ((Response) response.getCoapResponse()).getCode(), response.getCode(),  
404 - request.getPath().toString(), ((DiscoverResponse) response).getObjectLinks()); 457 + String discoverValue = Link.serialize(((DiscoverResponse)response).getObjectLinks());
  458 + msgLog = String.format("%s: type operation: %s path: %s value: %s",
  459 + LOG_LW2M_INFO, DISCOVER.name(), request.getPath().toString(), discoverValue);
  460 + handler.sendLogsToThingsboard(msgLog, registration.getId());
  461 + log.warn("DiscoverResponse: [{}]", (DiscoverResponse) response);
405 if (rpcRequest != null) { 462 if (rpcRequest != null) {
406 - String discoveryMsg = String.format("%s",  
407 - Arrays.stream(((DiscoverResponse) response).getObjectLinks()).collect(Collectors.toSet()));  
408 - serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), discoveryMsg, LOG_LW2M_VALUE); 463 + handler.sentRpcRequest(rpcRequest, response.getCode().getName(), discoverValue, LOG_LW2M_VALUE);
409 } 464 }
410 } else if (response instanceof ExecuteResponse) { 465 } else if (response instanceof ExecuteResponse) {
411 - log.info("[{}] Path [{}] ExecuteResponse 7_Send", pathIdVer, response); 466 + log.warn("[{}] Path [{}] ExecuteResponse 7_Send", pathIdVer, response);
412 } else if (response instanceof WriteAttributesResponse) { 467 } else if (response instanceof WriteAttributesResponse) {
413 - log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", pathIdVer, response); 468 + log.warn("[{}] Path [{}] WriteAttributesResponse 8_Send", pathIdVer, response);
414 } else if (response instanceof WriteResponse) { 469 } else if (response instanceof WriteResponse) {
415 - log.info("[{}] Path [{}] WriteResponse 9_Send", pathIdVer, response); 470 + log.warn("[{}] Path [{}] WriteResponse 9_Send", pathIdVer, response);
416 this.infoWriteResponse(registration, response, request); 471 this.infoWriteResponse(registration, response, request);
417 - serviceImpl.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request); 472 + handler.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request);
418 } 473 }
419 if (rpcRequest != null) { 474 if (rpcRequest != null) {
420 if (response instanceof ExecuteResponse 475 if (response instanceof ExecuteResponse
421 || response instanceof WriteAttributesResponse 476 || response instanceof WriteAttributesResponse
422 || response instanceof DeleteResponse) { 477 || response instanceof DeleteResponse) {
423 rpcRequest.setInfoMsg(null); 478 rpcRequest.setInfoMsg(null);
424 - serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, null); 479 + handler.sentRpcRequest(rpcRequest, response.getCode().getName(), null, null);
425 } else if (response instanceof WriteResponse) { 480 } else if (response instanceof WriteResponse) {
426 - serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, LOG_LW2M_INFO); 481 + handler.sentRpcRequest(rpcRequest, response.getCode().getName(), null, LOG_LW2M_INFO);
427 } 482 }
428 } 483 }
429 } 484 }
@@ -447,21 +502,73 @@ public class LwM2mTransportRequest { @@ -447,21 +502,73 @@ public class LwM2mTransportRequest {
447 Math.min(valueLength, config.getLogMaxLength()))); 502 Math.min(valueLength, config.getLogMaxLength())));
448 } 503 }
449 value = valueLength > config.getLogMaxLength() ? value + "..." : value; 504 value = valueLength > config.getLogMaxLength() ? value + "..." : value;
450 - msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path - %s length - %s value - %s", 505 + msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path: %s length: %s value: %s",
451 LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), valueLength, value); 506 LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), valueLength, value);
452 } else { 507 } else {
453 value = this.converter.convertValue(singleResource.getValue(), 508 value = this.converter.convertValue(singleResource.getValue(),
454 singleResource.getType(), ResourceModel.Type.STRING, request.getPath()); 509 singleResource.getType(), ResourceModel.Type.STRING, request.getPath());
455 - msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path - %s value - %s", 510 + msg = String.format("%s: Update finished successfully. Lwm2m code: %d Resource path: %s value: %s",
456 LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), value); 511 LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), value);
457 } 512 }
458 if (msg != null) { 513 if (msg != null) {
459 - serviceImpl.sendLogsToThingsboard(msg, registration.getId());  
460 - log.warn("[{}] [{}] [{}] - [{}] [{}] Update finished successfully: [{}]", request.getClass().getName(), registration.getEndpoint(),  
461 - ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString(), value); 514 + handler.sendLogsToThingsboard(msg, registration.getId());
  515 + if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) {
  516 + this.afterWriteSuccessFwSwUpdate(registration, request);
  517 + }
462 } 518 }
463 } catch (Exception e) { 519 } catch (Exception e) {
464 log.trace("Fail convert value from request to string. ", e); 520 log.trace("Fail convert value from request to string. ", e);
465 } 521 }
466 } 522 }
  523 +
  524 + /**
  525 + * After finish operation FwSwUpdate Write (success):
  526 + * fw_state/sw_state = DOWNLOADED
  527 + * send operation Execute
  528 + */
  529 + private void afterWriteSuccessFwSwUpdate(Registration registration, DownlinkRequest request) {
  530 + LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());
  531 + if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) {
  532 + lwM2MClient.getFwUpdate().setStateUpdate(DOWNLOADED.name());
  533 + lwM2MClient.getFwUpdate().sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null);
  534 + }
  535 + if (request.getPath().toString().equals(SW_PACKAGE_ID) && lwM2MClient.getSwUpdate() != null) {
  536 + lwM2MClient.getSwUpdate().setStateUpdate(DOWNLOADED.name());
  537 + lwM2MClient.getSwUpdate().sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null);
  538 + }
  539 + }
  540 +
  541 + /**
  542 + * After finish operation FwSwUpdate Write (error): fw_state = FAILED
  543 + */
  544 + private void afterWriteFwSWUpdateError(Registration registration, DownlinkRequest request, String msgError) {
  545 + LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());
  546 + if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) {
  547 + lwM2MClient.getFwUpdate().setStateUpdate(FAILED.name());
  548 + lwM2MClient.getFwUpdate().sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError);
  549 + }
  550 + if (request.getPath().toString().equals(SW_PACKAGE_ID) && lwM2MClient.getSwUpdate() != null) {
  551 + lwM2MClient.getSwUpdate().setStateUpdate(FAILED.name());
  552 + lwM2MClient.getSwUpdate().sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError);
  553 + }
  554 + }
  555 +
  556 + private void afterExecuteFwSwUpdateError(Registration registration, DownlinkRequest request, String msgError) {
  557 + LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());
  558 + if (request.getPath().toString().equals(FW_UPDATE_ID) && lwM2MClient.getFwUpdate() != null) {
  559 + lwM2MClient.getFwUpdate().sendLogs(handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError);
  560 + }
  561 + if (request.getPath().toString().equals(SW_INSTALL_ID) && lwM2MClient.getSwUpdate() != null) {
  562 + lwM2MClient.getSwUpdate().sendLogs(handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError);
  563 + }
  564 + }
  565 +
  566 + private void afterObserveCancel(Registration registration, int observeCancelCnt, String observeCancelMsg, Lwm2mClientRpcRequest rpcRequest) {
  567 + handler.sendLogsToThingsboard(observeCancelMsg, registration.getId());
  568 + log.warn("[{}]", observeCancelMsg);
  569 + if (rpcRequest != null) {
  570 + rpcRequest.setInfoMsg(String.format("Count: %d", observeCancelCnt));
  571 + handler.sentRpcRequest(rpcRequest, CONTENT.name(), null, LOG_LW2M_INFO);
  572 + }
  573 + }
467 } 574 }
@@ -38,6 +38,7 @@ import org.eclipse.leshan.core.model.InvalidDDFFileException; @@ -38,6 +38,7 @@ import org.eclipse.leshan.core.model.InvalidDDFFileException;
38 import org.eclipse.leshan.core.model.ObjectModel; 38 import org.eclipse.leshan.core.model.ObjectModel;
39 import org.eclipse.leshan.core.model.ResourceModel; 39 import org.eclipse.leshan.core.model.ResourceModel;
40 import org.eclipse.leshan.core.node.codec.CodecException; 40 import org.eclipse.leshan.core.node.codec.CodecException;
  41 +import org.eclipse.leshan.core.request.ContentFormat;
41 import org.springframework.stereotype.Component; 42 import org.springframework.stereotype.Component;
42 import org.thingsboard.server.common.transport.TransportServiceCallback; 43 import org.thingsboard.server.common.transport.TransportServiceCallback;
43 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 44 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
@@ -54,7 +55,6 @@ import java.util.ArrayList; @@ -54,7 +55,6 @@ import java.util.ArrayList;
54 import java.util.List; 55 import java.util.List;
55 56
56 import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType.BOOLEAN_V; 57 import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType.BOOLEAN_V;
57 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_TELEMETRY;  
58 58
59 @Slf4j 59 @Slf4j
60 @Component 60 @Component
@@ -69,7 +69,7 @@ public class LwM2mTransportServerHelper { @@ -69,7 +69,7 @@ public class LwM2mTransportServerHelper {
69 * send to Thingsboard Attribute || Telemetry 69 * send to Thingsboard Attribute || Telemetry
70 * 70 *
71 * @param msg - JsonObject: [{name: value}] 71 * @param msg - JsonObject: [{name: value}]
72 - * @return - dummy 72 + * @return - dummyWriteReplace {\"targetIdVer\":\"/19_1.0/0/0\",\"value\":0082}
73 */ 73 */
74 private <T> TransportServiceCallback<Void> getPubAckCallbackSendAttrTelemetry(final T msg) { 74 private <T> TransportServiceCallback<Void> getPubAckCallbackSendAttrTelemetry(final T msg) {
75 return new TransportServiceCallback<>() { 75 return new TransportServiceCallback<>() {
@@ -136,16 +136,16 @@ public class LwM2mTransportServerHelper { @@ -136,16 +136,16 @@ public class LwM2mTransportServerHelper {
136 } 136 }
137 137
138 /** 138 /**
139 - *  
140 - * @param logMsg - info about Logs 139 + * @param value - info about Logs
141 * @return- KeyValueProto for telemetry (Logs) 140 * @return- KeyValueProto for telemetry (Logs)
142 */ 141 */
143 - public List<TransportProtos.KeyValueProto> getKvLogyToThingsboard(String logMsg) { 142 + public List<TransportProtos.KeyValueProto> getKvStringtoThingsboard(String key, String value) {
144 List<TransportProtos.KeyValueProto> result = new ArrayList<>(); 143 List<TransportProtos.KeyValueProto> result = new ArrayList<>();
  144 + value = value.replaceAll("<", "").replaceAll(">", "");
145 result.add(TransportProtos.KeyValueProto.newBuilder() 145 result.add(TransportProtos.KeyValueProto.newBuilder()
146 - .setKey(LOG_LW2M_TELEMETRY) 146 + .setKey(key)
147 .setType(TransportProtos.KeyValueType.STRING_V) 147 .setType(TransportProtos.KeyValueType.STRING_V)
148 - .setStringV(logMsg).build()); 148 + .setStringV(value).build());
149 return result; 149 return result;
150 } 150 }
151 151
@@ -181,8 +181,7 @@ public class LwM2mTransportServerHelper { @@ -181,8 +181,7 @@ public class LwM2mTransportServerHelper {
181 } 181 }
182 182
183 /** 183 /**
184 - *  
185 - * @param currentType - 184 + * @param currentType -
186 * @param resourcePath - 185 * @param resourcePath -
187 * @return 186 * @return
188 */ 187 */
@@ -204,6 +203,28 @@ public class LwM2mTransportServerHelper { @@ -204,6 +203,28 @@ public class LwM2mTransportServerHelper {
204 throw new CodecException("Invalid ResourceModel_Type for resource %s, got %s", resourcePath, currentType); 203 throw new CodecException("Invalid ResourceModel_Type for resource %s, got %s", resourcePath, currentType);
205 } 204 }
206 205
  206 + public static ContentFormat convertResourceModelTypeToContentFormat(ResourceModel.Type type) {
  207 + switch (type) {
  208 + case BOOLEAN:
  209 + case STRING:
  210 + case TIME:
  211 + case INTEGER:
  212 + case FLOAT:
  213 + return ContentFormat.TLV;
  214 + case OPAQUE:
  215 + return ContentFormat.OPAQUE;
  216 + case OBJLNK:
  217 + return ContentFormat.LINK;
  218 + default:
  219 + }
  220 + throw new CodecException("Invalid ResourceModel_Type for %s ContentFormat.", type);
  221 + }
  222 +
  223 + public static ContentFormat getContentFormatByResourceModelType(ResourceModel resourceModel, ContentFormat contentFormat) {
  224 + return contentFormat.equals(ContentFormat.TLV) ? convertResourceModelTypeToContentFormat(resourceModel.type) :
  225 + contentFormat;
  226 + }
  227 +
207 public static Object getValueFromKvProto(TransportProtos.KeyValueProto kv) { 228 public static Object getValueFromKvProto(TransportProtos.KeyValueProto kv) {
208 switch (kv.getType()) { 229 switch (kv.getType()) {
209 case BOOLEAN_V: 230 case BOOLEAN_V:
@@ -43,6 +43,7 @@ import org.eclipse.leshan.server.registration.Registration; @@ -43,6 +43,7 @@ import org.eclipse.leshan.server.registration.Registration;
43 import org.nustaq.serialization.FSTConfiguration; 43 import org.nustaq.serialization.FSTConfiguration;
44 import org.thingsboard.server.common.data.DeviceProfile; 44 import org.thingsboard.server.common.data.DeviceProfile;
45 import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; 45 import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
  46 +import org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus;
46 import org.thingsboard.server.common.data.id.TenantId; 47 import org.thingsboard.server.common.data.id.TenantId;
47 import org.thingsboard.server.common.transport.TransportServiceCallback; 48 import org.thingsboard.server.common.transport.TransportServiceCallback;
48 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 49 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
@@ -70,6 +71,12 @@ import static org.eclipse.leshan.core.model.ResourceModel.Type.OBJLNK; @@ -70,6 +71,12 @@ import static org.eclipse.leshan.core.model.ResourceModel.Type.OBJLNK;
70 import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; 71 import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
71 import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING; 72 import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING;
72 import static org.eclipse.leshan.core.model.ResourceModel.Type.TIME; 73 import static org.eclipse.leshan.core.model.ResourceModel.Type.TIME;
  74 +import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.DOWNLOADED;
  75 +import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.DOWNLOADING;
  76 +import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.FAILED;
  77 +import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.UPDATED;
  78 +import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.UPDATING;
  79 +import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.VERIFIED;
73 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY; 80 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
74 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; 81 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
75 82
@@ -97,7 +104,8 @@ public class LwM2mTransportUtil { @@ -97,7 +104,8 @@ public class LwM2mTransportUtil {
97 104
98 public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms 105 public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms
99 106
100 - public static final String LOG_LW2M_TELEMETRY = "logLwm2m"; 107 + public static final String
  108 + LOG_LW2M_TELEMETRY = "LwM2MLog";
101 public static final String LOG_LW2M_INFO = "info"; 109 public static final String LOG_LW2M_INFO = "info";
102 public static final String LOG_LW2M_ERROR = "error"; 110 public static final String LOG_LW2M_ERROR = "error";
103 public static final String LOG_LW2M_WARN = "warn"; 111 public static final String LOG_LW2M_WARN = "warn";
@@ -107,11 +115,41 @@ public class LwM2mTransportUtil { @@ -107,11 +115,41 @@ public class LwM2mTransportUtil {
107 public static final int LWM2M_STRATEGY_2 = 2; 115 public static final int LWM2M_STRATEGY_2 = 2;
108 116
109 public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized"; 117 public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized";
110 -  
111 - public static final Integer FR_OBJECT_ID = 5;  
112 - public static final Integer FR_RESOURCE_VER_ID = 7;  
113 - public static final String FR_PATH_RESOURCE_VER_ID = LWM2M_SEPARATOR_PATH + FR_OBJECT_ID + LWM2M_SEPARATOR_PATH  
114 - + "0" + LWM2M_SEPARATOR_PATH + FR_RESOURCE_VER_ID; 118 + public static final String LWM2M_VERSION_DEFAULT = "1.0";
  119 +
  120 + // FirmWare
  121 + public static final String FW_UPDATE = "Firmware update";
  122 + public static final Integer FW_ID = 5;
  123 + // Package W
  124 + public static final String FW_PACKAGE_ID = "/5/0/0";
  125 + // State R
  126 + public static final String FW_STATE_ID = "/5/0/3";
  127 + // Update Result R
  128 + public static final String FW_RESULT_ID = "/5/0/5";
  129 + // PkgName R
  130 + public static final String FW_NAME_ID = "/5/0/6";
  131 + // PkgVersion R
  132 + public static final String FW_VER_ID = "/5/0/7";
  133 + // Update E
  134 + public static final String FW_UPDATE_ID = "/5/0/2";
  135 +
  136 + // SoftWare
  137 + public static final String SW_UPDATE = "Software update";
  138 + public static final Integer SW_ID = 9;
  139 + // Package W
  140 + public static final String SW_PACKAGE_ID = "/9/0/2";
  141 + // Update State R
  142 + public static final String SW_UPDATE_STATE_ID = "/9/0/7";
  143 + // Update Result R
  144 + public static final String SW_RESULT_ID = "/9/0/9";
  145 + // PkgName R
  146 + public static final String SW_NAME_ID = "/9/0/0";
  147 + // PkgVersion R
  148 + public static final String SW_VER_ID = "/9/0/1";
  149 + // Install E
  150 + public static final String SW_INSTALL_ID = "/9/0/4";
  151 + // Uninstall E
  152 + public static final String SW_UN_INSTALL_ID = "/9/0/6";
115 153
116 public enum LwM2mTypeServer { 154 public enum LwM2mTypeServer {
117 BOOTSTRAP(0, "bootstrap"), 155 BOOTSTRAP(0, "bootstrap"),
@@ -144,19 +182,20 @@ public class LwM2mTransportUtil { @@ -144,19 +182,20 @@ public class LwM2mTransportUtil {
144 */ 182 */
145 READ(0, "Read"), 183 READ(0, "Read"),
146 DISCOVER(1, "Discover"), 184 DISCOVER(1, "Discover"),
147 - OBSERVE_READ_ALL(2, "ObserveReadAll"), 185 + DISCOVER_All(2, "DiscoverAll"),
  186 + OBSERVE_READ_ALL(3, "ObserveReadAll"),
148 /** 187 /**
149 * POST 188 * POST
150 */ 189 */
151 - OBSERVE(3, "Observe"),  
152 - OBSERVE_CANCEL(4, "ObserveCancel"),  
153 - EXECUTE(5, "Execute"), 190 + OBSERVE(4, "Observe"),
  191 + OBSERVE_CANCEL(5, "ObserveCancel"),
  192 + EXECUTE(6, "Execute"),
154 /** 193 /**
155 * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see 194 * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see
156 * section 5.3.3 of the LW M2M spec). 195 * section 5.3.3 of the LW M2M spec).
157 * if all resources are to be replaced 196 * if all resources are to be replaced
158 */ 197 */
159 - WRITE_REPLACE(6, "WriteReplace"), 198 + WRITE_REPLACE(7, "WriteReplace"),
160 /* 199 /*
161 PUT 200 PUT
162 */ 201 */
@@ -165,11 +204,18 @@ public class LwM2mTransportUtil { @@ -165,11 +204,18 @@ public class LwM2mTransportUtil {
165 * 5.3.3 of the LW M2M spec). 204 * 5.3.3 of the LW M2M spec).
166 * if this is a partial update request 205 * if this is a partial update request
167 */ 206 */
168 - WRITE_UPDATE(7, "WriteUpdate"),  
169 - WRITE_ATTRIBUTES(8, "WriteAttributes"),  
170 - DELETE(9, "Delete");  
171 -  
172 -// READ_INFO_FW(10, "ReadInfoFirmware"); 207 + WRITE_UPDATE(8, "WriteUpdate"),
  208 + WRITE_ATTRIBUTES(9, "WriteAttributes"),
  209 + DELETE(10, "Delete"),
  210 +
  211 + // only for RPC
  212 + FW_READ_INFO(11, "FirmwareReadInfo"),
  213 + FW_UPDATE(12, "FirmwareUpdate"),
  214 + FW_UPDATE_URL(14, "FirmwareUpdateUrl"),
  215 + SW_READ_INFO(15, "SoftwareReadInfo"),
  216 + SW_UPDATE(16, "SoftwareUpdate"),
  217 + SW_UPDATE_URL(17, "SoftwareUpdateUrl"),
  218 + SW_UNINSTALL(18, "SoftwareUninstall");
173 219
174 public int code; 220 public int code;
175 public String type; 221 public String type;
@@ -189,10 +235,290 @@ public class LwM2mTransportUtil { @@ -189,10 +235,290 @@ public class LwM2mTransportUtil {
189 } 235 }
190 } 236 }
191 237
  238 + /**
  239 + * /** State R
  240 + * 0: Idle (before downloading or after successful updating)
  241 + * 1: Downloading (The data sequence is on the way)
  242 + * 2: Downloaded
  243 + * 3: Updating
  244 + */
  245 + public enum StateFw {
  246 + IDLE(0, "Idle"),
  247 + DOWNLOADING(1, "Downloading"),
  248 + DOWNLOADED(2, "Downloaded"),
  249 + UPDATING(3, "Updating");
  250 +
  251 + public int code;
  252 + public String type;
  253 +
  254 + StateFw(int code, String type) {
  255 + this.code = code;
  256 + this.type = type;
  257 + }
  258 +
  259 + public static StateFw fromStateFwByType(String type) {
  260 + for (StateFw to : StateFw.values()) {
  261 + if (to.type.equals(type)) {
  262 + return to;
  263 + }
  264 + }
  265 + throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type));
  266 + }
  267 +
  268 + public static StateFw fromStateFwByCode(int code) {
  269 + for (StateFw to : StateFw.values()) {
  270 + if (to.code == code) {
  271 + return to;
  272 + }
  273 + }
  274 + throw new IllegalArgumentException(String.format("Unsupported FW State code : %s", code));
  275 + }
  276 + }
  277 +
  278 + /**
  279 + * FW Update Result
  280 + * 0: Initial value. Once the updating process is initiated (Download /Update), this Resource MUST be reset to Initial value.
  281 + * 1: Firmware updated successfully.
  282 + * 2: Not enough flash memory for the new firmware package.
  283 + * 3: Out of RAM during downloading process.
  284 + * 4: Connection lost during downloading process.
  285 + * 5: Integrity check failure for new downloaded package.
  286 + * 6: Unsupported package type.
  287 + * 7: Invalid URI.
  288 + * 8: Firmware update failed.
  289 + * 9: Unsupported protocol.
  290 + */
  291 + public enum UpdateResultFw {
  292 + INITIAL(0, "Initial value", false),
  293 + UPDATE_SUCCESSFULLY(1, "Firmware updated successfully", false),
  294 + NOT_ENOUGH(2, "Not enough flash memory for the new firmware package", false),
  295 + OUT_OFF_MEMORY(3, "Out of RAM during downloading process", false),
  296 + CONNECTION_LOST(4, "Connection lost during downloading process", true),
  297 + INTEGRITY_CHECK_FAILURE(5, "Integrity check failure for new downloaded package", true),
  298 + UNSUPPORTED_TYPE(6, "Unsupported package type", false),
  299 + INVALID_URI(7, "Invalid URI", false),
  300 + UPDATE_FAILED(8, "Firmware update failed", false),
  301 + UNSUPPORTED_PROTOCOL(9, "Unsupported protocol", false);
  302 +
  303 + public int code;
  304 + public String type;
  305 + public boolean isAgain;
  306 +
  307 + UpdateResultFw(int code, String type, boolean isAgain) {
  308 + this.code = code;
  309 + this.type = type;
  310 + this.isAgain = isAgain;
  311 + }
  312 +
  313 + public static UpdateResultFw fromUpdateResultFwByType(String type) {
  314 + for (UpdateResultFw to : UpdateResultFw.values()) {
  315 + if (to.type.equals(type)) {
  316 + return to;
  317 + }
  318 + }
  319 + throw new IllegalArgumentException(String.format("Unsupported FW Update Result type : %s", type));
  320 + }
  321 +
  322 + public static UpdateResultFw fromUpdateResultFwByCode(int code) {
  323 + for (UpdateResultFw to : UpdateResultFw.values()) {
  324 + if (to.code == code) {
  325 + return to;
  326 + }
  327 + }
  328 + throw new IllegalArgumentException(String.format("Unsupported FW Update Result code : %s", code));
  329 + }
  330 + }
  331 +
  332 + /**
  333 + * FirmwareUpdateStatus {
  334 + * DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
  335 + */
  336 + public static FirmwareUpdateStatus EqualsFwSateToFirmwareUpdateStatus(StateFw stateFw, UpdateResultFw updateResultFw) {
  337 + switch (updateResultFw) {
  338 + case INITIAL:
  339 + switch (stateFw) {
  340 + case IDLE:
  341 + return VERIFIED;
  342 + case DOWNLOADING:
  343 + return DOWNLOADING;
  344 + case DOWNLOADED:
  345 + return DOWNLOADED;
  346 + case UPDATING:
  347 + return UPDATING;
  348 + }
  349 + case UPDATE_SUCCESSFULLY:
  350 + return UPDATED;
  351 + case NOT_ENOUGH:
  352 + case OUT_OFF_MEMORY:
  353 + case CONNECTION_LOST:
  354 + case INTEGRITY_CHECK_FAILURE:
  355 + case UNSUPPORTED_TYPE:
  356 + case INVALID_URI:
  357 + case UPDATE_FAILED:
  358 + case UNSUPPORTED_PROTOCOL:
  359 + return FAILED;
  360 + default:
  361 + throw new CodecException("Invalid value stateFw %s %s for FirmwareUpdateStatus.", stateFw.name(), updateResultFw.name());
  362 + }
  363 + }
  364 +
  365 + /**
  366 + * SW Update State R
  367 + * 0: INITIAL Before downloading. (see 5.1.2.1)
  368 + * 1: DOWNLOAD STARTED The downloading process has started and is on-going. (see 5.1.2.2)
  369 + * 2: DOWNLOADED The package has been completely downloaded (see 5.1.2.3)
  370 + * 3: DELIVERED In that state, the package has been correctly downloaded and is ready to be installed. (see 5.1.2.4)
  371 + * If executing the Install Resource failed, the state remains at DELIVERED.
  372 + * If executing the Install Resource was successful, the state changes from DELIVERED to INSTALLED.
  373 + * After executing the UnInstall Resource, the state changes to INITIAL.
  374 + * 4: INSTALLED
  375 + */
  376 + public enum UpdateStateSw {
  377 + INITIAL(0, "Initial"),
  378 + DOWNLOAD_STARTED(1, "DownloadStarted"),
  379 + DOWNLOADED(2, "Downloaded"),
  380 + DELIVERED(3, "Delivered"),
  381 + INSTALLED(4, "Installed");
  382 +
  383 + public int code;
  384 + public String type;
  385 +
  386 + UpdateStateSw(int code, String type) {
  387 + this.code = code;
  388 + this.type = type;
  389 + }
  390 +
  391 + public static UpdateStateSw fromUpdateStateSwByType(String type) {
  392 + for (UpdateStateSw to : UpdateStateSw.values()) {
  393 + if (to.type.equals(type)) {
  394 + return to;
  395 + }
  396 + }
  397 + throw new IllegalArgumentException(String.format("Unsupported SW State type : %s", type));
  398 + }
  399 +
  400 + public static UpdateStateSw fromUpdateStateSwByCode(int code) {
  401 + for (UpdateStateSw to : UpdateStateSw.values()) {
  402 + if (to.code == code) {
  403 + return to;
  404 + }
  405 + }
  406 + throw new IllegalArgumentException(String.format("Unsupported SW State type : %s", code));
  407 + }
  408 + }
  409 +
  410 + /**
  411 + * SW Update Result
  412 + * Contains the result of downloading or installing/uninstalling the software
  413 + * 0: Initial value.
  414 + * - Prior to download any new package in the Device, Update Result MUST be reset to this initial value.
  415 + * - One side effect of executing the Uninstall resource is to reset Update Result to this initial value "0".
  416 + * 1: Downloading.
  417 + * - The package downloading process is on-going.
  418 + * 2: Software successfully installed.
  419 + * 3: Successfully Downloaded and package integrity verified
  420 + * (( 4-49, for expansion, of other scenarios))
  421 + * ** Failed
  422 + * 50: Not enough storage for the new software package.
  423 + * 51: Out of memory during downloading process.
  424 + * 52: Connection lost during downloading process.
  425 + * 53: Package integrity check failure.
  426 + * 54: Unsupported package type.
  427 + * 56: Invalid URI
  428 + * 57: Device defined update error
  429 + * 58: Software installation failure
  430 + * 59: Uninstallation Failure during forUpdate(arg=0)
  431 + * 60-200 : (for expansion, selection to be in blocks depending on new introduction of features)
  432 + * This Resource MAY be reported by sending Observe operation.
  433 + */
  434 + public enum UpdateResultSw {
  435 + INITIAL(0, "Initial value", false),
  436 + DOWNLOADING(1, "Downloading", false),
  437 + SUCCESSFULLY_INSTALLED(2, "Software successfully installed", false),
  438 + SUCCESSFULLY_DOWNLOADED_VERIFIED(3, "Successfully Downloaded and package integrity verified", false),
  439 + NOT_ENOUGH_STORAGE(50, "Not enough storage for the new software package", true),
  440 + OUT_OFF_MEMORY(51, "Out of memory during downloading process", true),
  441 + CONNECTION_LOST(52, "Connection lost during downloading process", false),
  442 + PACKAGE_CHECK_FAILURE(53, "Package integrity check failure.", false),
  443 + UNSUPPORTED_PACKAGE_TYPE(54, "Unsupported package type", false),
  444 + INVALID_URI(56, "Invalid URI", true),
  445 + UPDATE_ERROR(57, "Device defined update error", true),
  446 + INSTALL_FAILURE(58, "Software installation failure", true),
  447 + UN_INSTALL_FAILURE(59, "Uninstallation Failure during forUpdate(arg=0)", true);
  448 +
  449 + public int code;
  450 + public String type;
  451 + public boolean isAgain;
  452 +
  453 + UpdateResultSw(int code, String type, boolean isAgain) {
  454 + this.code = code;
  455 + this.type = type;
  456 + this.isAgain = isAgain;
  457 + }
  458 +
  459 + public static UpdateResultSw fromUpdateResultSwByType(String type) {
  460 + for (UpdateResultSw to : UpdateResultSw.values()) {
  461 + if (to.type.equals(type)) {
  462 + return to;
  463 + }
  464 + }
  465 + throw new IllegalArgumentException(String.format("Unsupported SW Update Result type : %s", type));
  466 + }
  467 +
  468 + public static UpdateResultSw fromUpdateResultSwByCode(int code) {
  469 + for (UpdateResultSw to : UpdateResultSw.values()) {
  470 + if (to.code == code) {
  471 + return to;
  472 + }
  473 + }
  474 + throw new IllegalArgumentException(String.format("Unsupported SW Update Result code : %s", code));
  475 + }
  476 + }
  477 +
  478 + /**
  479 + * FirmwareUpdateStatus {
  480 + * DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
  481 + */
  482 + public static FirmwareUpdateStatus EqualsSwSateToFirmwareUpdateStatus(UpdateStateSw updateStateSw, UpdateResultSw updateResultSw) {
  483 + switch (updateResultSw) {
  484 + case INITIAL:
  485 + switch (updateStateSw) {
  486 + case INITIAL:
  487 + case DOWNLOAD_STARTED:
  488 + return DOWNLOADING;
  489 + case DOWNLOADED:
  490 + return DOWNLOADED;
  491 + case DELIVERED:
  492 + return VERIFIED;
  493 + }
  494 + case DOWNLOADING:
  495 + return DOWNLOADING;
  496 + case SUCCESSFULLY_INSTALLED:
  497 + return UPDATED;
  498 + case SUCCESSFULLY_DOWNLOADED_VERIFIED:
  499 + return VERIFIED;
  500 + case NOT_ENOUGH_STORAGE:
  501 + case OUT_OFF_MEMORY:
  502 + case CONNECTION_LOST:
  503 + case PACKAGE_CHECK_FAILURE:
  504 + case UNSUPPORTED_PACKAGE_TYPE:
  505 + case INVALID_URI:
  506 + case UPDATE_ERROR:
  507 + case INSTALL_FAILURE:
  508 + case UN_INSTALL_FAILURE:
  509 + return FAILED;
  510 + default:
  511 + throw new CodecException("Invalid value stateFw %s %s for FirmwareUpdateStatus.", updateStateSw.name(), updateResultSw.name());
  512 + }
  513 + }
  514 +
192 public static final String EVENT_AWAKE = "AWAKE"; 515 public static final String EVENT_AWAKE = "AWAKE";
  516 + public static final String RESPONSE_REQUEST_CHANNEL = "RESP_REQ";
193 public static final String RESPONSE_CHANNEL = "RESP"; 517 public static final String RESPONSE_CHANNEL = "RESP";
  518 + public static final String OBSERVE_CHANNEL = "OBSERVE";
194 519
195 - public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath resourcePath) throws CodecException { 520 + public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath
  521 + resourcePath) throws CodecException {
196 switch (type) { 522 switch (type) {
197 case BOOLEAN: 523 case BOOLEAN:
198 case INTEGER: 524 case INTEGER:
@@ -256,7 +582,7 @@ public class LwM2mTransportUtil { @@ -256,7 +582,7 @@ public class LwM2mTransportUtil {
256 * "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}} 582 * "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}}
257 */ 583 */
258 public static LwM2mClientProfile toLwM2MClientProfile(DeviceProfile deviceProfile) { 584 public static LwM2mClientProfile toLwM2MClientProfile(DeviceProfile deviceProfile) {
259 - if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) { 585 + if (((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {
260 Object profile = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties(); 586 Object profile = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties();
261 try { 587 try {
262 ObjectMapper mapper = new ObjectMapper(); 588 ObjectMapper mapper = new ObjectMapper();
@@ -375,7 +701,8 @@ public class LwM2mTransportUtil { @@ -375,7 +701,8 @@ public class LwM2mTransportUtil {
375 return StringUtils.join(linkedListOut, ""); 701 return StringUtils.join(linkedListOut, "");
376 } 702 }
377 703
378 - public static <T> TransportServiceCallback<Void> getAckCallback(LwM2mClient lwM2MClient, int requestId, String typeTopic) { 704 + public static <T> TransportServiceCallback<Void> getAckCallback(LwM2mClient lwM2MClient,
  705 + int requestId, String typeTopic) {
379 return new TransportServiceCallback<Void>() { 706 return new TransportServiceCallback<Void>() {
380 @Override 707 @Override
381 public void onSuccess(Void dummy) { 708 public void onSuccess(Void dummy) {
@@ -420,7 +747,8 @@ public class LwM2mTransportUtil { @@ -420,7 +747,8 @@ public class LwM2mTransportUtil {
420 return null; 747 return null;
421 } 748 }
422 749
423 - public static String validPathIdVer(String pathIdVer, Registration registration) throws IllegalArgumentException { 750 + public static String validPathIdVer(String pathIdVer, Registration registration) throws
  751 + IllegalArgumentException {
424 if (!pathIdVer.contains(LWM2M_SEPARATOR_PATH)) { 752 if (!pathIdVer.contains(LWM2M_SEPARATOR_PATH)) {
425 throw new IllegalArgumentException(String.format("Error:")); 753 throw new IllegalArgumentException(String.format("Error:"));
426 } else { 754 } else {
@@ -436,6 +764,7 @@ public class LwM2mTransportUtil { @@ -436,6 +764,7 @@ public class LwM2mTransportUtil {
436 764
437 public static String convertPathFromObjectIdToIdVer(String path, Registration registration) { 765 public static String convertPathFromObjectIdToIdVer(String path, Registration registration) {
438 String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId()); 766 String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
  767 + ver = ver != null ? ver : LWM2M_VERSION_DEFAULT;
439 try { 768 try {
440 String[] keyArray = path.split(LWM2M_SEPARATOR_PATH); 769 String[] keyArray = path.split(LWM2M_SEPARATOR_PATH);
441 if (keyArray.length > 1) { 770 if (keyArray.length > 1) {
@@ -531,7 +860,7 @@ public class LwM2mTransportUtil { @@ -531,7 +860,7 @@ public class LwM2mTransportUtil {
531 case "ObjectLink": 860 case "ObjectLink":
532 return OBJLNK; 861 return OBJLNK;
533 default: 862 default:
534 - return null; 863 + return null;
535 } 864 }
536 } 865 }
537 } 866 }
@@ -82,7 +82,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider { @@ -82,7 +82,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
82 if (objectModel != null) 82 if (objectModel != null)
83 return objectModel.resources.get(resourceId); 83 return objectModel.resources.get(resourceId);
84 else 84 else
85 - log.warn("TbResources (Object model) with id [{}/0/{}] not found on the server", objectId, resourceId); 85 + log.trace("TbResources (Object model) with id [{}/0/{}] not found on the server", objectId, resourceId);
86 return null; 86 return null;
87 } catch (Exception e) { 87 } catch (Exception e) {
88 log.error("", e); 88 log.error("", e);
@@ -64,7 +64,6 @@ public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor { @@ -64,7 +64,6 @@ public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor {
64 } 64 }
65 return result.build(); 65 return result.build();
66 } catch (RuntimeException e) { 66 } catch (RuntimeException e) {
67 - log.warn("Failed to decode get attributes request", e);  
68 throw new AdaptorException(e); 67 throw new AdaptorException(e);
69 } 68 }
70 } 69 }
@@ -18,7 +18,11 @@ package org.thingsboard.server.transport.lwm2m.server.client; @@ -18,7 +18,11 @@ package org.thingsboard.server.transport.lwm2m.server.client;
18 import lombok.Getter; 18 import lombok.Getter;
19 import lombok.Setter; 19 import lombok.Setter;
20 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
  21 +import org.eclipse.leshan.core.model.ObjectModel;
21 import org.eclipse.leshan.core.model.ResourceModel; 22 import org.eclipse.leshan.core.model.ResourceModel;
  23 +import org.eclipse.leshan.core.node.LwM2mMultipleResource;
  24 +import org.eclipse.leshan.core.node.LwM2mObject;
  25 +import org.eclipse.leshan.core.node.LwM2mObjectInstance;
22 import org.eclipse.leshan.core.node.LwM2mPath; 26 import org.eclipse.leshan.core.node.LwM2mPath;
23 import org.eclipse.leshan.core.node.LwM2mResource; 27 import org.eclipse.leshan.core.node.LwM2mResource;
24 import org.eclipse.leshan.core.node.LwM2mSingleResource; 28 import org.eclipse.leshan.core.node.LwM2mSingleResource;
@@ -28,9 +32,9 @@ import org.eclipse.leshan.server.security.SecurityInfo; @@ -28,9 +32,9 @@ import org.eclipse.leshan.server.security.SecurityInfo;
28 import org.thingsboard.server.common.data.Device; 32 import org.thingsboard.server.common.data.Device;
29 import org.thingsboard.server.common.data.DeviceProfile; 33 import org.thingsboard.server.common.data.DeviceProfile;
30 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 34 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
  35 +import org.thingsboard.server.common.data.firmware.FirmwareType;
31 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; 36 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
32 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; 37 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
33 -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;  
34 import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler; 38 import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;
35 import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest; 39 import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest;
36 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; 40 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
@@ -47,11 +51,14 @@ import java.util.concurrent.ConcurrentLinkedQueue; @@ -47,11 +51,14 @@ import java.util.concurrent.ConcurrentLinkedQueue;
47 import java.util.concurrent.CopyOnWriteArrayList; 51 import java.util.concurrent.CopyOnWriteArrayList;
48 import java.util.stream.Collectors; 52 import java.util.stream.Collectors;
49 53
  54 +import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
  55 +import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING;
50 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; 56 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
51 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TRANSPORT_DEFAULT_LWM2M_VERSION; 57 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TRANSPORT_DEFAULT_LWM2M_VERSION;
52 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId; 58 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
53 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId; 59 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
54 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; 60 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName;
  61 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId;
55 62
56 @Slf4j 63 @Slf4j
57 public class LwM2mClient implements Cloneable { 64 public class LwM2mClient implements Cloneable {
@@ -75,25 +82,27 @@ public class LwM2mClient implements Cloneable { @@ -75,25 +82,27 @@ public class LwM2mClient implements Cloneable {
75 private UUID profileId; 82 private UUID profileId;
76 @Getter 83 @Getter
77 @Setter 84 @Setter
78 - private volatile LwM2mFirmwareUpdate frUpdate; 85 + private volatile LwM2mFwSwUpdate fwUpdate;
  86 + @Getter
  87 + @Setter
  88 + private volatile LwM2mFwSwUpdate swUpdate;
79 @Getter 89 @Getter
80 @Setter 90 @Setter
81 private Registration registration; 91 private Registration registration;
82 92
83 private ValidateDeviceCredentialsResponse credentials; 93 private ValidateDeviceCredentialsResponse credentials;
  94 +
84 @Getter 95 @Getter
85 private final Map<String, ResourceValue> resources; 96 private final Map<String, ResourceValue> resources;
86 @Getter 97 @Getter
87 private final Map<String, TsKvProto> delayedRequests; 98 private final Map<String, TsKvProto> delayedRequests;
88 @Getter 99 @Getter
  100 + @Setter
89 private final List<String> pendingReadRequests; 101 private final List<String> pendingReadRequests;
90 @Getter 102 @Getter
91 private final Queue<LwM2mQueuedRequest> queuedRequests; 103 private final Queue<LwM2mQueuedRequest> queuedRequests;
92 @Getter 104 @Getter
93 private boolean init; 105 private boolean init;
94 - @Getter  
95 - @Setter  
96 - private volatile boolean updateFw;  
97 106
98 public Object clone() throws CloneNotSupportedException { 107 public Object clone() throws CloneNotSupportedException {
99 return super.clone(); 108 return super.clone();
@@ -110,9 +119,10 @@ public class LwM2mClient implements Cloneable { @@ -110,9 +119,10 @@ public class LwM2mClient implements Cloneable {
110 this.profileId = profileId; 119 this.profileId = profileId;
111 this.sessionId = sessionId; 120 this.sessionId = sessionId;
112 this.init = false; 121 this.init = false;
113 - this.updateFw = false;  
114 this.queuedRequests = new ConcurrentLinkedQueue<>(); 122 this.queuedRequests = new ConcurrentLinkedQueue<>();
115 - this.frUpdate = new LwM2mFirmwareUpdate(); 123 +
  124 + this.fwUpdate = new LwM2mFwSwUpdate(this, FirmwareType.FIRMWARE);
  125 + this.swUpdate = new LwM2mFwSwUpdate(this, FirmwareType.SOFTWARE);
116 if (this.credentials != null && this.credentials.hasDeviceInfo()) { 126 if (this.credentials != null && this.credentials.hasDeviceInfo()) {
117 this.session = createSession(nodeId, sessionId, credentials); 127 this.session = createSession(nodeId, sessionId, credentials);
118 this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB()); 128 this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB());
@@ -165,15 +175,15 @@ public class LwM2mClient implements Cloneable { @@ -165,15 +175,15 @@ public class LwM2mClient implements Cloneable {
165 .build(); 175 .build();
166 } 176 }
167 177
168 - public boolean saveResourceValue(String pathRez, LwM2mResource rez, LwM2mModelProvider modelProvider) {  
169 - if (this.resources.get(pathRez) != null && this.resources.get(pathRez).getResourceModel() != null) {  
170 - this.resources.get(pathRez).setLwM2mResource(rez); 178 + public boolean saveResourceValue(String pathRezIdVer, LwM2mResource rez, LwM2mModelProvider modelProvider) {
  179 + if (this.resources.get(pathRezIdVer) != null && this.resources.get(pathRezIdVer).getResourceModel() != null) {
  180 + this.resources.get(pathRezIdVer).setLwM2mResource(rez);
171 return true; 181 return true;
172 } else { 182 } else {
173 - LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez)); 183 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer));
174 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); 184 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
175 if (resourceModel != null) { 185 if (resourceModel != null) {
176 - this.resources.put(pathRez, new ResourceValue(rez, resourceModel)); 186 + this.resources.put(pathRezIdVer, new ResourceValue(rez, resourceModel));
177 return true; 187 return true;
178 } else { 188 } else {
179 return false; 189 return false;
@@ -181,6 +191,24 @@ public class LwM2mClient implements Cloneable { @@ -181,6 +191,24 @@ public class LwM2mClient implements Cloneable {
181 } 191 }
182 } 192 }
183 193
  194 + public Object getResourceValue(String pathRezIdVer, String pathRezId) {
  195 + String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer;
  196 + if (this.resources.get(pathRez) != null) {
  197 + return this.resources.get(pathRez).getLwM2mResource().isMultiInstances() ?
  198 + this.resources.get(pathRez).getLwM2mResource().getValues() :
  199 + this.resources.get(pathRez).getLwM2mResource().getValue();
  200 + }
  201 + return null;
  202 + }
  203 +
  204 + public Object getResourceName (String pathRezIdVer, String pathRezId) {
  205 + String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer;
  206 + if (this.resources.get(pathRez) != null) {
  207 + return this.resources.get(pathRez).getResourceModel().name;
  208 + }
  209 + return null;
  210 + }
  211 +
184 public ResourceModel getResourceModel(String pathIdVer, LwM2mModelProvider modelProvider) { 212 public ResourceModel getResourceModel(String pathIdVer, LwM2mModelProvider modelProvider) {
185 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)); 213 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));
186 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); 214 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
@@ -189,8 +217,55 @@ public class LwM2mClient implements Cloneable { @@ -189,8 +217,55 @@ public class LwM2mClient implements Cloneable {
189 .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null; 217 .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null;
190 } 218 }
191 219
192 - public Collection<LwM2mResource> getNewOneResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,  
193 - LwM2mValueConverterImpl converter) { 220 + public ObjectModel getObjectModel(String pathIdVer, LwM2mModelProvider modelProvider) {
  221 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer));
  222 + String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
  223 + String verRez = getVerFromPathIdVerOrId(pathIdVer);
  224 + return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
  225 + .getObjectModel(pathIds.getObjectId()) : null;
  226 + }
  227 +
  228 + public String objectToString (LwM2mObject lwM2mObject, LwM2mValueConverterImpl converter, String pathIdVer) {
  229 + StringBuilder builder = new StringBuilder();
  230 + builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={");
  231 + lwM2mObject.getInstances().forEach((instId, inst) -> {
  232 + builder.append(instId).append("=").append(this.instanceToString(inst, converter, pathIdVer)).append(", ");
  233 + });
  234 + int startInd = builder.lastIndexOf(", ");
  235 + if (startInd > 0) {
  236 + builder.delete(startInd, startInd + 2);
  237 + }
  238 + builder.append("}]");
  239 + return builder.toString();
  240 + }
  241 + public String instanceToString (LwM2mObjectInstance objectInstance, LwM2mValueConverterImpl converter, String pathIdVer) {
  242 + StringBuilder builder = new StringBuilder();
  243 + builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={");
  244 + objectInstance.getResources().forEach((resId, res) -> {
  245 + builder.append(resId).append("=").append(this.resourceToString (res, converter, pathIdVer)).append(", ");
  246 + });
  247 + int startInd = builder.lastIndexOf(", ");
  248 + if (startInd > 0) {
  249 + builder.delete(startInd, startInd + 2);
  250 + }
  251 + builder.append("}]");
  252 + return builder.toString();
  253 + }
  254 +
  255 + public String resourceToString (LwM2mResource lwM2mResource, LwM2mValueConverterImpl converter, String pathIdVer) {
  256 + if (!OPAQUE.equals(lwM2mResource.getType())) {
  257 + return lwM2mResource.isMultiInstances() ? ((LwM2mMultipleResource) lwM2mResource).toString() :
  258 + ((LwM2mSingleResource) lwM2mResource).toString();
  259 + }
  260 + else {
  261 + return String.format("LwM2mSingleResource [id=%s, value=%s, type=%s]", lwM2mResource.getId(),
  262 + converter.convertValue(lwM2mResource.getValue(),
  263 + OPAQUE, STRING, new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))), lwM2mResource.getType().name());
  264 + }
  265 + }
  266 +
  267 + public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
  268 + LwM2mValueConverterImpl converter) {
194 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); 269 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer));
195 Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet(); 270 Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
196 Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration) 271 Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
@@ -204,8 +279,8 @@ public class LwM2mClient implements Cloneable { @@ -204,8 +279,8 @@ public class LwM2mClient implements Cloneable {
204 return resources; 279 return resources;
205 } 280 }
206 281
207 - public Collection<LwM2mResource> getNewManyResourcesForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,  
208 - LwM2mValueConverterImpl converter) { 282 + public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
  283 + LwM2mValueConverterImpl converter) {
209 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); 284 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer));
210 Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet(); 285 Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
211 Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration) 286 Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
@@ -55,7 +55,7 @@ public interface LwM2mClientContext { @@ -55,7 +55,7 @@ public interface LwM2mClientContext {
55 55
56 Map<UUID, LwM2mClientProfile> setProfiles(Map<UUID, LwM2mClientProfile> profiles); 56 Map<UUID, LwM2mClientProfile> setProfiles(Map<UUID, LwM2mClientProfile> profiles);
57 57
58 - LwM2mClientProfile toClientProfile(DeviceProfile deviceProfile); 58 + LwM2mClientProfile profileUpdate(DeviceProfile deviceProfile);
59 59
60 Set<String> getSupportedIdVerInClient(Registration registration); 60 Set<String> getSupportedIdVerInClient(Registration registration);
61 61
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 package org.thingsboard.server.transport.lwm2m.server.client; 16 package org.thingsboard.server.transport.lwm2m.server.client;
17 17
18 import lombok.RequiredArgsConstructor; 18 import lombok.RequiredArgsConstructor;
  19 +import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.leshan.core.node.LwM2mPath; 20 import org.eclipse.leshan.core.node.LwM2mPath;
20 import org.eclipse.leshan.server.registration.Registration; 21 import org.eclipse.leshan.server.registration.Registration;
21 import org.eclipse.leshan.server.security.EditableSecurityStore; 22 import org.eclipse.leshan.server.security.EditableSecurityStore;
@@ -40,6 +41,7 @@ import java.util.concurrent.ConcurrentHashMap; @@ -40,6 +41,7 @@ import java.util.concurrent.ConcurrentHashMap;
40 import static org.eclipse.leshan.core.SecurityMode.NO_SEC; 41 import static org.eclipse.leshan.core.SecurityMode.NO_SEC;
41 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; 42 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
42 43
  44 +@Slf4j
43 @Service 45 @Service
44 @TbLwM2mTransportComponent 46 @TbLwM2mTransportComponent
45 @RequiredArgsConstructor 47 @RequiredArgsConstructor
@@ -112,8 +114,12 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -112,8 +114,12 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
112 EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endpoint, LwM2mTransportUtil.LwM2mTypeServer.CLIENT); 114 EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endpoint, LwM2mTransportUtil.LwM2mTypeServer.CLIENT);
113 if (securityInfo.getSecurityMode() != null) { 115 if (securityInfo.getSecurityMode() != null) {
114 if (securityInfo.getDeviceProfile() != null) { 116 if (securityInfo.getDeviceProfile() != null) {
115 - toClientProfile(securityInfo.getDeviceProfile());  
116 - UUID profileUuid = securityInfo.getDeviceProfile().getUuidId(); 117 + UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile())!= null ?
  118 + securityInfo.getDeviceProfile().getUuidId() : null;
  119 + // TODO: for tests bug.
  120 + if (profileUuid== null) {
  121 + log.warn("input parameters toClientProfile if the result is null: [{}]", securityInfo.getDeviceProfile());
  122 + }
117 LwM2mClient client; 123 LwM2mClient client;
118 if (securityInfo.getSecurityInfo() != null) { 124 if (securityInfo.getSecurityInfo() != null) {
119 client = new LwM2mClient(context.getNodeId(), securityInfo.getSecurityInfo().getEndpoint(), 125 client = new LwM2mClient(context.getNodeId(), securityInfo.getSecurityInfo().getEndpoint(),
@@ -141,7 +147,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -141,7 +147,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
141 LwM2mClient client = new LwM2mClient(context.getNodeId(), registration.getEndpoint(), null, null, credentials, credentials.getDeviceProfile().getUuidId(), UUID.randomUUID()); 147 LwM2mClient client = new LwM2mClient(context.getNodeId(), registration.getEndpoint(), null, null, credentials, credentials.getDeviceProfile().getUuidId(), UUID.randomUUID());
142 lwM2mClientsByEndpoint.put(registration.getEndpoint(), client); 148 lwM2mClientsByEndpoint.put(registration.getEndpoint(), client);
143 lwM2mClientsByRegistrationId.put(registration.getId(), client); 149 lwM2mClientsByRegistrationId.put(registration.getId(), client);
144 - toClientProfile(credentials.getDeviceProfile()); 150 + profileUpdate(credentials.getDeviceProfile());
145 } 151 }
146 152
147 @Override 153 @Override
@@ -170,13 +176,16 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -170,13 +176,16 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
170 } 176 }
171 177
172 @Override 178 @Override
173 - public LwM2mClientProfile toClientProfile(DeviceProfile deviceProfile) {  
174 - LwM2mClientProfile lwM2MClientProfile = profiles.get(deviceProfile.getUuidId());  
175 - if (lwM2MClientProfile == null) {  
176 - lwM2MClientProfile = LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile); 179 + public LwM2mClientProfile profileUpdate(DeviceProfile deviceProfile) {
  180 + LwM2mClientProfile lwM2MClientProfile = deviceProfile != null ?
  181 + LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile) : null;
  182 + if (lwM2MClientProfile != null) {
177 profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile); 183 profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile);
  184 + return lwM2MClientProfile;
  185 + }
  186 + else {
  187 + return null;
178 } 188 }
179 - return lwM2MClientProfile;  
180 } 189 }
181 190
182 /** 191 /**
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.Data;  
19 -  
20 -import java.util.UUID;  
21 -  
22 -@Data  
23 -public class LwM2mFirmwareUpdate {  
24 - private volatile String clientFwVersion;  
25 - private volatile String currentFwVersion;  
26 - private volatile UUID currentFwId;  
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.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.thingsboard.server.common.data.firmware.FirmwareType;
  24 +import org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus;
  25 +import org.thingsboard.server.gen.transport.TransportProtos;
  26 +import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;
  27 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportRequest;
  28 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
  29 +
  30 +import java.util.ArrayList;
  31 +import java.util.List;
  32 +import java.util.UUID;
  33 +import java.util.concurrent.CopyOnWriteArrayList;
  34 +
  35 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.STATE;
  36 +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
  37 +import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;
  38 +import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.UPDATING;
  39 +import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getAttributeKey;
  40 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_NAME_ID;
  41 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_ID;
  42 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID;
  43 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_STATE_ID;
  44 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_UPDATE;
  45 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_UPDATE_ID;
  46 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_VER_ID;
  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.LwM2mTypeOper.EXECUTE;
  50 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE;
  51 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
  52 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_INSTALL_ID;
  53 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_NAME_ID;
  54 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_PACKAGE_ID;
  55 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_RESULT_ID;
  56 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UN_INSTALL_ID;
  57 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UPDATE;
  58 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UPDATE_STATE_ID;
  59 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_VER_ID;
  60 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
  61 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.splitCamelCaseString;
  62 +
  63 +@Slf4j
  64 +public class LwM2mFwSwUpdate {
  65 + // 5/0/6 PkgName
  66 + // 9/0/0 PkgName
  67 + @Getter
  68 + @Setter
  69 + private volatile String currentTitle;
  70 + // 5/0/7 PkgVersion
  71 + // 9/0/1 PkgVersion
  72 + @Getter
  73 + @Setter
  74 + private volatile String currentVersion;
  75 + @Getter
  76 + @Setter
  77 + private volatile UUID currentId;
  78 + @Getter
  79 + @Setter
  80 + private volatile String stateUpdate;
  81 + @Getter
  82 + private String pathPackageId;
  83 + @Getter
  84 + private String pathStateId;
  85 + @Getter
  86 + private String pathResultId;
  87 + @Getter
  88 + private String pathNameId;
  89 + @Getter
  90 + private String pathVerId;
  91 + @Getter
  92 + private String pathInstallId;
  93 + @Getter
  94 + private String pathUnInstallId;
  95 + @Getter
  96 + private String wUpdate;
  97 + @Getter
  98 + @Setter
  99 + private volatile boolean infoFwSwUpdate = false;
  100 + private final FirmwareType type;
  101 + @Getter
  102 + LwM2mClient lwM2MClient;
  103 + @Getter
  104 + @Setter
  105 + private final List<String> pendingInfoRequestsStart;
  106 +
  107 + public LwM2mFwSwUpdate(LwM2mClient lwM2MClient, FirmwareType type) {
  108 + this.lwM2MClient = lwM2MClient;
  109 + this.pendingInfoRequestsStart = new CopyOnWriteArrayList<>();
  110 + this.type = type;
  111 + this.stateUpdate = null;
  112 + this.initPathId();
  113 + }
  114 +
  115 + private void initPathId() {
  116 + if (FIRMWARE.equals(this.type)) {
  117 + this.pathPackageId = FW_PACKAGE_ID;
  118 + this.pathStateId = FW_STATE_ID;
  119 + this.pathResultId = FW_RESULT_ID;
  120 + this.pathNameId = FW_NAME_ID;
  121 + this.pathVerId = FW_VER_ID;
  122 + this.pathInstallId = FW_UPDATE_ID;
  123 + this.wUpdate = FW_UPDATE;
  124 + } else if (SOFTWARE.equals(this.type)) {
  125 + this.pathPackageId = SW_PACKAGE_ID;
  126 + this.pathStateId = SW_UPDATE_STATE_ID;
  127 + this.pathResultId = SW_RESULT_ID;
  128 + this.pathNameId = SW_NAME_ID;
  129 + this.pathVerId = SW_VER_ID;
  130 + this.pathInstallId = SW_INSTALL_ID;
  131 + this.pathUnInstallId = SW_UN_INSTALL_ID;
  132 + this.wUpdate = SW_UPDATE;
  133 + }
  134 + }
  135 +
  136 + public void initReadValue(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request, String pathIdVer) {
  137 + if (pathIdVer != null) {
  138 + this.pendingInfoRequestsStart.remove(pathIdVer);
  139 + }
  140 + if (this.pendingInfoRequestsStart.size() == 0) {
  141 + this.infoFwSwUpdate = false;
  142 + if (!FirmwareUpdateStatus.DOWNLOADING.name().equals(this.stateUpdate)) {
  143 + boolean conditionalStart = this.type.equals(FIRMWARE) ? this.conditionalFwUpdateStart() :
  144 + this.conditionalSwUpdateStart();
  145 + if (conditionalStart) {
  146 + this.writeFwSwWare(handler, request);
  147 + }
  148 + }
  149 + }
  150 + }
  151 +
  152 + /**
  153 + * Send FsSw to Lwm2mClient:
  154 + * before operation Write: fw_state = DOWNLOADING
  155 + */
  156 + private void writeFwSwWare(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) {
  157 + this.stateUpdate = FirmwareUpdateStatus.DOWNLOADING.name();
  158 +// this.observeStateUpdate();
  159 + this.sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null);
  160 + int chunkSize = 0;
  161 + int chunk = 0;
  162 + byte[] firmwareChunk = handler.firmwareDataCache.get(this.currentId.toString(), chunkSize, chunk);
  163 + String targetIdVer = convertPathFromObjectIdToIdVer(this.pathPackageId, this.lwM2MClient.getRegistration());
  164 + request.sendAllRequest(lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(),
  165 + firmwareChunk, handler.config.getTimeout(), null);
  166 + }
  167 +
  168 + public void sendLogs(DefaultLwM2MTransportMsgHandler handler, String typeOper, String typeInfo, String msgError) {
  169 + this.sendSateOnThingsBoard(handler);
  170 + String msg = String.format("%s: %s, %s, pkgVer: %s: pkgName - %s state - %s.",
  171 + typeInfo, this.wUpdate, typeOper, this.currentVersion, this.currentTitle, this.stateUpdate);
  172 + if (LOG_LW2M_ERROR.equals(typeInfo)) {
  173 + msg = String.format("%s Error: %s", msg, msgError);
  174 + }
  175 + handler.sendLogsToThingsboard(msg, lwM2MClient.getRegistration().getId());
  176 + }
  177 +
  178 +
  179 + /**
  180 + * After inspection Update Result
  181 + * fw_state/sw_state = UPDATING
  182 + * send execute
  183 + */
  184 + public void executeFwSwWare(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) {
  185 + this.setStateUpdate(UPDATING.name());
  186 + this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_INFO, null);
  187 + request.sendAllRequest(this.lwM2MClient.getRegistration(), this.pathInstallId, EXECUTE, ContentFormat.TLV.getName(),
  188 + null, 0, null);
  189 + }
  190 +
  191 +
  192 + /**
  193 + * Firmware start:
  194 + * -- Если Update Result -errors (более 1) - Это означает что пред. апдейт не прошел.
  195 + * - Запускаем апдейт в независимости от состяния прошивки и ее версии.
  196 + * -- Если Update Result - не errors (менее или равно 1) и ver не пустой - Это означает что пред. апдейт прошел.
  197 + * -- Если Update Result - не errors и ver пустой - Это означает что апдейта еще не было.
  198 + * - Проверяем поменялась ли версия и запускаем новый апдейт.
  199 + */
  200 + private boolean conditionalFwUpdateStart() {
  201 + Long updateResultFw = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
  202 + // #1/#2
  203 + return updateResultFw > LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code ||
  204 + (
  205 + (updateResultFw <= LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code
  206 + ) &&
  207 + (
  208 + (this.currentVersion != null && !this.currentVersion.equals(this.lwM2MClient.getResourceValue(null, this.pathVerId))) ||
  209 + (this.currentTitle != null && !this.currentTitle.equals(this.lwM2MClient.getResourceValue(null, this.pathNameId)))
  210 + )
  211 + );
  212 + }
  213 +
  214 +
  215 + /**
  216 + * Before operation Execute inspection Update Result :
  217 + * 0 - Initial value
  218 + */
  219 + public boolean conditionalFwExecuteStart() {
  220 + Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
  221 + return LwM2mTransportUtil.UpdateResultFw.INITIAL.code == updateResult;
  222 + }
  223 +
  224 + /**
  225 + * After operation Execute success inspection Update Result :
  226 + * 1 - "Firmware updated successfully"
  227 + */
  228 + public boolean conditionalFwExecuteAfterSuccess() {
  229 + Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
  230 + return LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code == updateResult;
  231 + }
  232 +
  233 + /**
  234 + * After operation Execute success inspection Update Result :
  235 + * > 1 error: "Firmware updated successfully"
  236 + */
  237 + public boolean conditionalFwExecuteAfterError() {
  238 + Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
  239 + return LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code < updateResult;
  240 + }
  241 +
  242 + /**
  243 + * Software start
  244 + * -- Если Update Result -errors (равно и более 50) - Это означает что пред. апдейт не прошел.
  245 + * * - Запускаем апдейт в независимости от состяния прошивки и ее версии.
  246 + * -- Если Update Result - не errors (менее 50) и ver не пустой - Это означает что пред. апдейт прошел.
  247 + * -- Если Update Result - не errors и ver пустой - Это означает что апдейта еще не было или пред. апдейт UnInstall
  248 + * -- Если Update Result - не errors и ver не пустой - Это означает что пред. апдейт UnInstall
  249 + * - Проверяем поменялась ли версия и запускаем новый апдейт.
  250 + */
  251 + private boolean conditionalSwUpdateStart() {
  252 + Long updateResultSw = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
  253 + // #1/#2
  254 + return updateResultSw >= LwM2mTransportUtil.UpdateResultSw.NOT_ENOUGH_STORAGE.code ||
  255 + (
  256 + (updateResultSw <= LwM2mTransportUtil.UpdateResultSw.NOT_ENOUGH_STORAGE.code
  257 + ) &&
  258 + (
  259 + (this.currentVersion != null && !this.currentVersion.equals(this.lwM2MClient.getResourceValue(null, this.pathVerId))) ||
  260 + (this.currentTitle != null && !this.currentTitle.equals(this.lwM2MClient.getResourceValue(null, this.pathNameId)))
  261 + )
  262 + );
  263 + }
  264 +
  265 + /**
  266 + * Before operation Execute inspection Update Result :
  267 + * 3 - Successfully Downloaded and package integrity verified
  268 + */
  269 + public boolean conditionalSwUpdateExecute() {
  270 + Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
  271 + return LwM2mTransportUtil.UpdateResultSw.SUCCESSFULLY_DOWNLOADED_VERIFIED.code == updateResult;
  272 + }
  273 +
  274 + /**
  275 + * After finish operation Execute (success):
  276 + * -- inspection Update Result:
  277 + * ---- FW если Update Result == 1 ("Firmware updated successfully") или SW если Update Result == 2 ("Software successfully installed.")
  278 + * -- fw_state/sw_state = UPDATED
  279 + *
  280 + * After finish operation Execute (error):
  281 + * -- inspection updateResult and send to thingsboard info about error
  282 + * --- send to telemetry ( key - this is name Update Result in model) (
  283 + * -- fw_state/sw_state = FAILED
  284 + */
  285 + public void finishFwSwUpdate(DefaultLwM2MTransportMsgHandler handler, boolean success) {
  286 + Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
  287 + String value = FIRMWARE.equals(this.type) ? LwM2mTransportUtil.UpdateResultFw.fromUpdateResultFwByCode(updateResult.intValue()).type :
  288 + LwM2mTransportUtil.UpdateResultSw.fromUpdateResultSwByCode(updateResult.intValue()).type;
  289 + String key = splitCamelCaseString((String) this.lwM2MClient.getResourceName(null, this.pathResultId));
  290 + if (success) {
  291 + this.stateUpdate = FirmwareUpdateStatus.UPDATED.name();
  292 + this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_INFO, null);
  293 + } else {
  294 + this.stateUpdate = FirmwareUpdateStatus.FAILED.name();
  295 + this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_ERROR, value);
  296 + }
  297 + handler.helper.sendParametersOnThingsboardTelemetry(
  298 + handler.helper.getKvStringtoThingsboard(key, value), this.lwM2MClient.getSession());
  299 + }
  300 +
  301 + /**
  302 + * After operation Execute success inspection Update Result :
  303 + * 2 - "Software successfully installed."
  304 + */
  305 + public boolean conditionalSwExecuteAfterSuccess() {
  306 + Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
  307 + return LwM2mTransportUtil.UpdateResultSw.SUCCESSFULLY_INSTALLED.code == updateResult;
  308 + }
  309 +
  310 + /**
  311 + * After operation Execute success inspection Update Result :
  312 + * >= 50 - error "NOT_ENOUGH_STORAGE"
  313 + */
  314 + public boolean conditionalSwExecuteAfterError() {
  315 + Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
  316 + return LwM2mTransportUtil.UpdateResultSw.NOT_ENOUGH_STORAGE.code <= updateResult;
  317 + }
  318 +
  319 + private void observeStateUpdate(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) {
  320 + request.sendAllRequest(lwM2MClient.getRegistration(),
  321 + convertPathFromObjectIdToIdVer(this.pathStateId, this.lwM2MClient.getRegistration()), OBSERVE,
  322 + null, null, 0, null);
  323 + request.sendAllRequest(lwM2MClient.getRegistration(),
  324 + convertPathFromObjectIdToIdVer(this.pathResultId, this.lwM2MClient.getRegistration()), OBSERVE,
  325 + null, null, 0, null);
  326 + }
  327 +
  328 + public void sendSateOnThingsBoard(DefaultLwM2MTransportMsgHandler handler) {
  329 + if (StringUtils.trimToNull(this.stateUpdate) != null) {
  330 + List<TransportProtos.KeyValueProto> result = new ArrayList<>();
  331 + TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(getAttributeKey(this.type, STATE));
  332 + kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV(stateUpdate);
  333 + result.add(kvProto.build());
  334 + handler.helper.sendParametersOnThingsboardTelemetry(result,
  335 + handler.getSessionInfoOrCloseSession(this.lwM2MClient.getRegistration()));
  336 + }
  337 + }
  338 +
  339 + public void sendReadObserveInfo(LwM2mTransportRequest request) {
  340 + this.infoFwSwUpdate = true;
  341 + this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
  342 + this.pathVerId, this.lwM2MClient.getRegistration()));
  343 + this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
  344 + this.pathNameId, this.lwM2MClient.getRegistration()));
  345 + this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
  346 + this.pathStateId, this.lwM2MClient.getRegistration()));
  347 + this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
  348 + this.pathResultId, this.lwM2MClient.getRegistration()));
  349 + this.pendingInfoRequestsStart.forEach(pathIdVer -> {
  350 + request.sendAllRequest(this.lwM2MClient.getRegistration(), pathIdVer, OBSERVE, ContentFormat.TLV.getName(),
  351 + null, 0, null);
  352 + });
  353 +
  354 + }
  355 +}
@@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.client; @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.client;
17 17
18 import com.google.gson.JsonObject; 18 import com.google.gson.JsonObject;
19 import lombok.Data; 19 import lombok.Data;
  20 +import lombok.extern.slf4j.Slf4j;
20 import org.eclipse.leshan.core.request.ContentFormat; 21 import org.eclipse.leshan.core.request.ContentFormat;
21 import org.eclipse.leshan.server.registration.Registration; 22 import org.eclipse.leshan.server.registration.Registration;
22 import org.thingsboard.server.gen.transport.TransportProtos; 23 import org.thingsboard.server.gen.transport.TransportProtos;
@@ -27,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap; @@ -27,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap;
27 28
28 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validPathIdVer; 29 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validPathIdVer;
29 30
  31 +@Slf4j
30 @Data 32 @Data
31 public class Lwm2mClientRpcRequest { 33 public class Lwm2mClientRpcRequest {
32 public final String targetIdVerKey = "targetIdVer"; 34 public final String targetIdVerKey = "targetIdVer";
@@ -107,4 +109,14 @@ public class Lwm2mClientRpcRequest { @@ -107,4 +109,14 @@ public class Lwm2mClientRpcRequest {
107 .setRequestId(this.requestId) 109 .setRequestId(this.requestId)
108 .build(); 110 .build();
109 } 111 }
  112 +
  113 + @Override
  114 + public Object clone() {
  115 + try {
  116 + return super.clone();
  117 + } catch (CloneNotSupportedException e) {
  118 + log.error("", e);
  119 + }
  120 + return null;
  121 + }
110 } 122 }
@@ -26,9 +26,7 @@ import org.eclipse.leshan.core.util.NamedThreadFactory; @@ -26,9 +26,7 @@ import org.eclipse.leshan.core.util.NamedThreadFactory;
26 import org.eclipse.leshan.core.util.Validate; 26 import org.eclipse.leshan.core.util.Validate;
27 import org.eclipse.leshan.server.californium.observation.ObserveUtil; 27 import org.eclipse.leshan.server.californium.observation.ObserveUtil;
28 import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; 28 import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
29 -import org.eclipse.leshan.server.redis.JedisLock;  
30 import org.eclipse.leshan.server.redis.RedisRegistrationStore; 29 import org.eclipse.leshan.server.redis.RedisRegistrationStore;
31 -import org.eclipse.leshan.server.redis.SingleInstanceJedisLock;  
32 import org.eclipse.leshan.server.redis.serialization.ObservationSerDes; 30 import org.eclipse.leshan.server.redis.serialization.ObservationSerDes;
33 import org.eclipse.leshan.server.redis.serialization.RegistrationSerDes; 31 import org.eclipse.leshan.server.redis.serialization.RegistrationSerDes;
34 import org.eclipse.leshan.server.registration.Deregistration; 32 import org.eclipse.leshan.server.registration.Deregistration;
@@ -38,11 +36,12 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate; @@ -38,11 +36,12 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate;
38 import org.eclipse.leshan.server.registration.UpdatedRegistration; 36 import org.eclipse.leshan.server.registration.UpdatedRegistration;
39 import org.slf4j.Logger; 37 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory; 38 import org.slf4j.LoggerFactory;
  39 +import org.springframework.data.redis.connection.RedisClusterConnection;
  40 +import org.springframework.data.redis.connection.RedisConnection;
41 import org.springframework.data.redis.connection.RedisConnectionFactory; 41 import org.springframework.data.redis.connection.RedisConnectionFactory;
42 -import redis.clients.jedis.Jedis;  
43 -import redis.clients.jedis.ScanParams;  
44 -import redis.clients.jedis.ScanResult;  
45 -import redis.clients.jedis.Transaction; 42 +import org.springframework.data.redis.core.Cursor;
  43 +import org.springframework.data.redis.core.ScanOptions;
  44 +import org.springframework.integration.redis.util.RedisLockRegistry;
46 45
47 import java.net.InetSocketAddress; 46 import java.net.InetSocketAddress;
48 import java.util.ArrayList; 47 import java.util.ArrayList;
@@ -50,13 +49,14 @@ import java.util.Arrays; @@ -50,13 +49,14 @@ import java.util.Arrays;
50 import java.util.Collection; 49 import java.util.Collection;
51 import java.util.Collections; 50 import java.util.Collections;
52 import java.util.Iterator; 51 import java.util.Iterator;
  52 +import java.util.LinkedList;
53 import java.util.List; 53 import java.util.List;
54 -import java.util.NoSuchElementException;  
55 import java.util.Set; 54 import java.util.Set;
56 import java.util.concurrent.Executors; 55 import java.util.concurrent.Executors;
57 import java.util.concurrent.ScheduledExecutorService; 56 import java.util.concurrent.ScheduledExecutorService;
58 import java.util.concurrent.ScheduledFuture; 57 import java.util.concurrent.ScheduledFuture;
59 import java.util.concurrent.TimeUnit; 58 import java.util.concurrent.TimeUnit;
  59 +import java.util.concurrent.locks.Lock;
60 60
61 import static java.nio.charset.StandardCharsets.UTF_8; 61 import static java.nio.charset.StandardCharsets.UTF_8;
62 62
@@ -92,7 +92,7 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -92,7 +92,7 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
92 private final int cleanLimit; // maximum number to clean in a clean period 92 private final int cleanLimit; // maximum number to clean in a clean period
93 private final long gracePeriod; // in seconds 93 private final long gracePeriod; // in seconds
94 94
95 - private final JedisLock lock; 95 + private final RedisLockRegistry redisLock;
96 96
97 public TbLwM2mRedisRegistrationStore(RedisConnectionFactory connectionFactory) { 97 public TbLwM2mRedisRegistrationStore(RedisConnectionFactory connectionFactory) {
98 this(connectionFactory, DEFAULT_CLEAN_PERIOD, DEFAULT_GRACE_PERIOD, DEFAULT_CLEAN_LIMIT); // default clean period 60s 98 this(connectionFactory, DEFAULT_CLEAN_PERIOD, DEFAULT_GRACE_PERIOD, DEFAULT_CLEAN_LIMIT); // default clean period 60s
@@ -106,20 +106,12 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -106,20 +106,12 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
106 106
107 public TbLwM2mRedisRegistrationStore(RedisConnectionFactory connectionFactory, ScheduledExecutorService schedExecutor, long cleanPeriodInSec, 107 public TbLwM2mRedisRegistrationStore(RedisConnectionFactory connectionFactory, ScheduledExecutorService schedExecutor, long cleanPeriodInSec,
108 long lifetimeGracePeriodInSec, int cleanLimit) { 108 long lifetimeGracePeriodInSec, int cleanLimit) {
109 - this(connectionFactory, schedExecutor, cleanPeriodInSec, lifetimeGracePeriodInSec, cleanLimit, new SingleInstanceJedisLock());  
110 - }  
111 -  
112 - /**  
113 - * @since 1.1  
114 - */  
115 - public TbLwM2mRedisRegistrationStore(RedisConnectionFactory connectionFactory, ScheduledExecutorService schedExecutor, long cleanPeriodInSec,  
116 - long lifetimeGracePeriodInSec, int cleanLimit, JedisLock redisLock) {  
117 this.connectionFactory = connectionFactory; 109 this.connectionFactory = connectionFactory;
118 this.schedExecutor = schedExecutor; 110 this.schedExecutor = schedExecutor;
119 this.cleanPeriod = cleanPeriodInSec; 111 this.cleanPeriod = cleanPeriodInSec;
120 this.cleanLimit = cleanLimit; 112 this.cleanLimit = cleanLimit;
121 this.gracePeriod = lifetimeGracePeriodInSec; 113 this.gracePeriod = lifetimeGracePeriodInSec;
122 - this.lock = redisLock; 114 + this.redisLock = new RedisLockRegistry(connectionFactory, "Registration");
123 } 115 }
124 116
125 /* *************** Redis Key utility function **************** */ 117 /* *************** Redis Key utility function **************** */
@@ -135,76 +127,79 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -135,76 +127,79 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
135 return (prefix + registrationID).getBytes(); 127 return (prefix + registrationID).getBytes();
136 } 128 }
137 129
138 - private byte[] toLockKey(String endpoint) {  
139 - return toKey(LOCK_EP, endpoint); 130 + private String toLockKey(String endpoint) {
  131 + return new String(toKey(LOCK_EP, endpoint));
140 } 132 }
141 133
142 - private byte[] toLockKey(byte[] endpoint) {  
143 - return toKey(LOCK_EP.getBytes(UTF_8), endpoint); 134 + private String toLockKey(byte[] endpoint) {
  135 + return new String(toKey(LOCK_EP.getBytes(UTF_8), endpoint));
144 } 136 }
145 137
146 /* *************** Leshan Registration API **************** */ 138 /* *************** Leshan Registration API **************** */
147 139
148 @Override 140 @Override
149 public Deregistration addRegistration(Registration registration) { 141 public Deregistration addRegistration(Registration registration) {
150 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
151 - byte[] lockValue = null;  
152 - byte[] lockKey = toLockKey(registration.getEndpoint()); 142 + Lock lock = null;
  143 + try (var connection = connectionFactory.getConnection()) {
  144 + String lockKey = toLockKey(registration.getEndpoint());
153 145
154 try { 146 try {
155 - lockValue = lock.acquire(j, lockKey);  
156 - 147 + lock = redisLock.obtain(lockKey);
  148 + lock.lock();
157 // add registration 149 // add registration
158 byte[] k = toEndpointKey(registration.getEndpoint()); 150 byte[] k = toEndpointKey(registration.getEndpoint());
159 - byte[] old = j.getSet(k, serializeReg(registration)); 151 + byte[] old = connection.getSet(k, serializeReg(registration));
160 152
161 // add registration: secondary indexes 153 // add registration: secondary indexes
162 byte[] regid_idx = toRegIdKey(registration.getId()); 154 byte[] regid_idx = toRegIdKey(registration.getId());
163 - j.set(regid_idx, registration.getEndpoint().getBytes(UTF_8)); 155 + connection.set(regid_idx, registration.getEndpoint().getBytes(UTF_8));
164 byte[] addr_idx = toRegAddrKey(registration.getSocketAddress()); 156 byte[] addr_idx = toRegAddrKey(registration.getSocketAddress());
165 - j.set(addr_idx, registration.getEndpoint().getBytes(UTF_8)); 157 + connection.set(addr_idx, registration.getEndpoint().getBytes(UTF_8));
166 158
167 // Add or update expiration 159 // Add or update expiration
168 - addOrUpdateExpiration(j, registration); 160 + addOrUpdateExpiration(connection, registration);
169 161
170 if (old != null) { 162 if (old != null) {
171 Registration oldRegistration = deserializeReg(old); 163 Registration oldRegistration = deserializeReg(old);
172 // remove old secondary index 164 // remove old secondary index
173 if (!registration.getId().equals(oldRegistration.getId())) 165 if (!registration.getId().equals(oldRegistration.getId()))
174 - j.del(toRegIdKey(oldRegistration.getId())); 166 + connection.del(toRegIdKey(oldRegistration.getId()));
175 if (!oldRegistration.getSocketAddress().equals(registration.getSocketAddress())) { 167 if (!oldRegistration.getSocketAddress().equals(registration.getSocketAddress())) {
176 - removeAddrIndex(j, oldRegistration); 168 + removeAddrIndex(connection, oldRegistration);
177 } 169 }
178 // remove old observation 170 // remove old observation
179 - Collection<Observation> obsRemoved = unsafeRemoveAllObservations(j, oldRegistration.getId()); 171 + Collection<Observation> obsRemoved = unsafeRemoveAllObservations(connection, oldRegistration.getId());
180 172
181 return new Deregistration(oldRegistration, obsRemoved); 173 return new Deregistration(oldRegistration, obsRemoved);
182 } 174 }
183 175
184 return null; 176 return null;
185 } finally { 177 } finally {
186 - lock.release(j, lockKey, lockValue); 178 + if (lock != null) {
  179 + lock.unlock();
  180 + }
187 } 181 }
188 } 182 }
189 } 183 }
190 184
191 @Override 185 @Override
192 public UpdatedRegistration updateRegistration(RegistrationUpdate update) { 186 public UpdatedRegistration updateRegistration(RegistrationUpdate update) {
193 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { 187 + Lock lock = null;
  188 + try (var connection = connectionFactory.getConnection()) {
194 189
195 // Fetch the registration ep by registration ID index 190 // Fetch the registration ep by registration ID index
196 - byte[] ep = j.get(toRegIdKey(update.getRegistrationId())); 191 + byte[] ep = connection.get(toRegIdKey(update.getRegistrationId()));
197 if (ep == null) { 192 if (ep == null) {
198 return null; 193 return null;
199 } 194 }
200 195
201 - byte[] lockValue = null;  
202 - byte[] lockKey = toLockKey(ep); 196 + String lockKey = toLockKey(ep);
203 try { 197 try {
204 - lockValue = lock.acquire(j, lockKey); 198 + lock = redisLock.obtain(lockKey);
  199 + lock.lock();
205 200
206 // Fetch the registration 201 // Fetch the registration
207 - byte[] data = j.get(toEndpointKey(ep)); 202 + byte[] data = connection.get(toEndpointKey(ep));
208 if (data == null) { 203 if (data == null) {
209 return null; 204 return null;
210 } 205 }
@@ -214,40 +209,42 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -214,40 +209,42 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
214 Registration updatedRegistration = update.update(r); 209 Registration updatedRegistration = update.update(r);
215 210
216 // Store the new registration 211 // Store the new registration
217 - j.set(toEndpointKey(updatedRegistration.getEndpoint()), serializeReg(updatedRegistration)); 212 + connection.set(toEndpointKey(updatedRegistration.getEndpoint()), serializeReg(updatedRegistration));
218 213
219 // Add or update expiration 214 // Add or update expiration
220 - addOrUpdateExpiration(j, updatedRegistration); 215 + addOrUpdateExpiration(connection, updatedRegistration);
221 216
222 // Update secondary index : 217 // Update secondary index :
223 // If registration is already associated to this address we don't care as we only want to keep the most 218 // If registration is already associated to this address we don't care as we only want to keep the most
224 // recent binding. 219 // recent binding.
225 byte[] addr_idx = toRegAddrKey(updatedRegistration.getSocketAddress()); 220 byte[] addr_idx = toRegAddrKey(updatedRegistration.getSocketAddress());
226 - j.set(addr_idx, updatedRegistration.getEndpoint().getBytes(UTF_8)); 221 + connection.set(addr_idx, updatedRegistration.getEndpoint().getBytes(UTF_8));
227 if (!r.getSocketAddress().equals(updatedRegistration.getSocketAddress())) { 222 if (!r.getSocketAddress().equals(updatedRegistration.getSocketAddress())) {
228 - removeAddrIndex(j, r); 223 + removeAddrIndex(connection, r);
229 } 224 }
230 225
231 return new UpdatedRegistration(r, updatedRegistration); 226 return new UpdatedRegistration(r, updatedRegistration);
232 227
233 } finally { 228 } finally {
234 - lock.release(j, lockKey, lockValue); 229 + if (lock != null) {
  230 + lock.unlock();
  231 + }
235 } 232 }
236 } 233 }
237 } 234 }
238 235
239 @Override 236 @Override
240 public Registration getRegistration(String registrationId) { 237 public Registration getRegistration(String registrationId) {
241 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
242 - return getRegistration(j, registrationId); 238 + try (var connection = connectionFactory.getConnection()) {
  239 + return getRegistration(connection, registrationId);
243 } 240 }
244 } 241 }
245 242
246 @Override 243 @Override
247 public Registration getRegistrationByEndpoint(String endpoint) { 244 public Registration getRegistrationByEndpoint(String endpoint) {
248 Validate.notNull(endpoint); 245 Validate.notNull(endpoint);
249 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
250 - byte[] data = j.get(toEndpointKey(endpoint)); 246 + try (var connection = connectionFactory.getConnection()) {
  247 + byte[] data = connection.get(toEndpointKey(endpoint));
251 if (data == null) { 248 if (data == null) {
252 return null; 249 return null;
253 } 250 }
@@ -258,12 +255,12 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -258,12 +255,12 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
258 @Override 255 @Override
259 public Registration getRegistrationByAdress(InetSocketAddress address) { 256 public Registration getRegistrationByAdress(InetSocketAddress address) {
260 Validate.notNull(address); 257 Validate.notNull(address);
261 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
262 - byte[] ep = j.get(toRegAddrKey(address)); 258 + try (var connection = connectionFactory.getConnection()) {
  259 + byte[] ep = connection.get(toRegAddrKey(address));
263 if (ep == null) { 260 if (ep == null) {
264 return null; 261 return null;
265 } 262 }
266 - byte[] data = j.get(toEndpointKey(ep)); 263 + byte[] data = connection.get(toEndpointKey(ep));
267 if (data == null) { 264 if (data == null) {
268 return null; 265 return null;
269 } 266 }
@@ -273,140 +270,99 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -273,140 +270,99 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
273 270
274 @Override 271 @Override
275 public Iterator<Registration> getAllRegistrations() { 272 public Iterator<Registration> getAllRegistrations() {
276 - return new TbLwM2mRedisRegistrationStore.RedisIterator(connectionFactory, new ScanParams().match(REG_EP + "*").count(100));  
277 - }  
278 -  
279 - protected class RedisIterator implements Iterator<Registration> {  
280 -  
281 - private final RedisConnectionFactory connectionFactory;  
282 - private final ScanParams scanParams;  
283 -  
284 - private String cursor;  
285 - private List<Registration> scanResult;  
286 -  
287 - public RedisIterator(RedisConnectionFactory connectionFactory, ScanParams scanParams) {  
288 - this.connectionFactory = connectionFactory;  
289 - this.scanParams = scanParams;  
290 - // init scan result  
291 - scanNext("0");  
292 - }  
293 -  
294 - private void scanNext(String cursor) {  
295 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
296 - do {  
297 - ScanResult<byte[]> sr = j.scan(cursor.getBytes(), scanParams);  
298 -  
299 - this.scanResult = new ArrayList<>();  
300 - if (sr.getResult() != null && !sr.getResult().isEmpty()) {  
301 - for (byte[] value : j.mget(sr.getResult().toArray(new byte[][]{}))) {  
302 - this.scanResult.add(deserializeReg(value));  
303 - }  
304 - }  
305 -  
306 - cursor = sr.getCursor();  
307 - } while (!"0".equals(cursor) && scanResult.isEmpty());  
308 -  
309 - this.cursor = cursor;  
310 - }  
311 - }  
312 -  
313 - @Override  
314 - public boolean hasNext() {  
315 - if (!scanResult.isEmpty()) {  
316 - return true;  
317 - }  
318 - if ("0".equals(cursor)) {  
319 - // no more elements to scan  
320 - return false;  
321 - }  
322 -  
323 - // read more elements  
324 - scanNext(cursor);  
325 - return !scanResult.isEmpty();  
326 - }  
327 -  
328 - @Override  
329 - public Registration next() {  
330 - if (!hasNext()) {  
331 - throw new NoSuchElementException(); 273 + try (var connection = connectionFactory.getConnection()) {
  274 + Collection<Registration> list = new LinkedList<>();
  275 + ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(REG_EP + "*").build();
  276 + List<Cursor<byte[]>> scans = new ArrayList<>();
  277 + if (connection instanceof RedisClusterConnection) {
  278 + ((RedisClusterConnection) connection).clusterGetNodes().forEach(node -> {
  279 + scans.add(((RedisClusterConnection) connection).scan(node, scanOptions));
  280 + });
  281 + } else {
  282 + scans.add(connection.scan(scanOptions));
332 } 283 }
333 - return scanResult.remove(0);  
334 - }  
335 284
336 - @Override  
337 - public void remove() {  
338 - throw new UnsupportedOperationException(); 285 + scans.forEach(scan -> {
  286 + scan.forEachRemaining(key -> {
  287 + byte[] element = connection.get(key);
  288 + list.add(deserializeReg(element));
  289 + });
  290 + });
  291 + return list.iterator();
339 } 292 }
340 } 293 }
341 294
342 @Override 295 @Override
343 public Deregistration removeRegistration(String registrationId) { 296 public Deregistration removeRegistration(String registrationId) {
344 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
345 - return removeRegistration(j, registrationId, false); 297 + try (var connection = connectionFactory.getConnection()) {
  298 + return removeRegistration(connection, registrationId, false);
346 } 299 }
347 } 300 }
348 301
349 - private Deregistration removeRegistration(Jedis j, String registrationId, boolean removeOnlyIfNotAlive) { 302 + private Deregistration removeRegistration(RedisConnection connection, String registrationId, boolean removeOnlyIfNotAlive) {
350 // fetch the client ep by registration ID index 303 // fetch the client ep by registration ID index
351 - byte[] ep = j.get(toRegIdKey(registrationId)); 304 + byte[] ep = connection.get(toRegIdKey(registrationId));
352 if (ep == null) { 305 if (ep == null) {
353 return null; 306 return null;
354 } 307 }
355 308
356 - byte[] lockValue = null;  
357 - byte[] lockKey = toLockKey(ep); 309 + Lock lock = null;
  310 + String lockKey = toLockKey(ep);
358 try { 311 try {
359 - lockValue = lock.acquire(j, lockKey); 312 + lock = redisLock.obtain(lockKey);
  313 + lock.lock();
360 314
361 // fetch the client 315 // fetch the client
362 - byte[] data = j.get(toEndpointKey(ep)); 316 + byte[] data = connection.get(toEndpointKey(ep));
363 if (data == null) { 317 if (data == null) {
364 return null; 318 return null;
365 } 319 }
366 Registration r = deserializeReg(data); 320 Registration r = deserializeReg(data);
367 321
368 if (!removeOnlyIfNotAlive || !r.isAlive(gracePeriod)) { 322 if (!removeOnlyIfNotAlive || !r.isAlive(gracePeriod)) {
369 - long nbRemoved = j.del(toRegIdKey(r.getId())); 323 + long nbRemoved = connection.del(toRegIdKey(r.getId()));
370 if (nbRemoved > 0) { 324 if (nbRemoved > 0) {
371 - j.del(toEndpointKey(r.getEndpoint()));  
372 - Collection<Observation> obsRemoved = unsafeRemoveAllObservations(j, r.getId());  
373 - removeAddrIndex(j, r);  
374 - removeExpiration(j, r); 325 + connection.del(toEndpointKey(r.getEndpoint()));
  326 + Collection<Observation> obsRemoved = unsafeRemoveAllObservations(connection, r.getId());
  327 + removeAddrIndex(connection, r);
  328 + removeExpiration(connection, r);
375 return new Deregistration(r, obsRemoved); 329 return new Deregistration(r, obsRemoved);
376 } 330 }
377 } 331 }
378 return null; 332 return null;
379 } finally { 333 } finally {
380 - lock.release(j, lockKey, lockValue); 334 + if (lock != null) {
  335 + lock.unlock();
  336 + }
381 } 337 }
382 } 338 }
383 339
384 - private void removeAddrIndex(Jedis j, Registration registration) { 340 + private void removeAddrIndex(RedisConnection connection, Registration registration) {
385 // Watch the key to remove. 341 // Watch the key to remove.
386 byte[] regAddrKey = toRegAddrKey(registration.getSocketAddress()); 342 byte[] regAddrKey = toRegAddrKey(registration.getSocketAddress());
387 - j.watch(regAddrKey); 343 + connection.watch(regAddrKey);
388 344
389 - byte[] epFromAddr = j.get(regAddrKey); 345 + byte[] epFromAddr = connection.get(regAddrKey);
390 // Delete the key if needed. 346 // Delete the key if needed.
391 if (Arrays.equals(epFromAddr, registration.getEndpoint().getBytes(UTF_8))) { 347 if (Arrays.equals(epFromAddr, registration.getEndpoint().getBytes(UTF_8))) {
392 // Try to delete the key 348 // Try to delete the key
393 - Transaction transaction = j.multi();  
394 - transaction.del(regAddrKey);  
395 - transaction.exec(); 349 + connection.multi();
  350 + connection.del(regAddrKey);
  351 + connection.exec();
396 // if transaction failed this is not an issue as the socket address is probably reused and we don't neeed to 352 // if transaction failed this is not an issue as the socket address is probably reused and we don't neeed to
397 // delete it anymore. 353 // delete it anymore.
398 } else { 354 } else {
399 // the key must not be deleted. 355 // the key must not be deleted.
400 - j.unwatch(); 356 + connection.unwatch();
401 } 357 }
402 } 358 }
403 359
404 - private void addOrUpdateExpiration(Jedis j, Registration registration) {  
405 - j.zadd(EXP_EP, registration.getExpirationTimeStamp(gracePeriod), registration.getEndpoint().getBytes(UTF_8)); 360 + private void addOrUpdateExpiration(RedisConnection connection, Registration registration) {
  361 + connection.zAdd(EXP_EP, registration.getExpirationTimeStamp(gracePeriod), registration.getEndpoint().getBytes(UTF_8));
406 } 362 }
407 363
408 - private void removeExpiration(Jedis j, Registration registration) {  
409 - j.zrem(EXP_EP, registration.getEndpoint().getBytes(UTF_8)); 364 + private void removeExpiration(RedisConnection connection, Registration registration) {
  365 + connection.zRem(EXP_EP, registration.getEndpoint().getBytes(UTF_8));
410 } 366 }
411 367
412 private byte[] toRegIdKey(String registrationId) { 368 private byte[] toRegIdKey(String registrationId) {
@@ -441,33 +397,35 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -441,33 +397,35 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
441 */ 397 */
442 @Override 398 @Override
443 public Collection<Observation> addObservation(String registrationId, Observation observation) { 399 public Collection<Observation> addObservation(String registrationId, Observation observation) {
444 -  
445 List<Observation> removed = new ArrayList<>(); 400 List<Observation> removed = new ArrayList<>();
446 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { 401 + try (var connection = connectionFactory.getConnection()) {
447 402
448 // fetch the client ep by registration ID index 403 // fetch the client ep by registration ID index
449 - byte[] ep = j.get(toRegIdKey(registrationId)); 404 + byte[] ep = connection.get(toRegIdKey(registrationId));
450 if (ep == null) { 405 if (ep == null) {
451 return null; 406 return null;
452 } 407 }
453 408
454 - byte[] lockValue = null;  
455 - byte[] lockKey = toLockKey(ep); 409 + Lock lock = null;
  410 + String lockKey = toLockKey(ep);
456 411
457 try { 412 try {
458 - lockValue = lock.acquire(j, lockKey); 413 + lock = redisLock.obtain(lockKey);
  414 + lock.lock();
459 415
460 // cancel existing observations for the same path and registration id. 416 // cancel existing observations for the same path and registration id.
461 - for (Observation obs : getObservations(j, registrationId)) { 417 + for (Observation obs : getObservations(connection, registrationId)) {
462 if (observation.getPath().equals(obs.getPath()) 418 if (observation.getPath().equals(obs.getPath())
463 && !Arrays.equals(observation.getId(), obs.getId())) { 419 && !Arrays.equals(observation.getId(), obs.getId())) {
464 removed.add(obs); 420 removed.add(obs);
465 - unsafeRemoveObservation(j, registrationId, obs.getId()); 421 + unsafeRemoveObservation(connection, registrationId, obs.getId());
466 } 422 }
467 } 423 }
468 424
469 } finally { 425 } finally {
470 - lock.release(j, lockKey, lockValue); 426 + if (lock != null) {
  427 + lock.unlock();
  428 + }
471 } 429 }
472 } 430 }
473 return removed; 431 return removed;
@@ -475,29 +433,32 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -475,29 +433,32 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
475 433
476 @Override 434 @Override
477 public Observation removeObservation(String registrationId, byte[] observationId) { 435 public Observation removeObservation(String registrationId, byte[] observationId) {
478 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { 436 + try (var connection = connectionFactory.getConnection()) {
479 437
480 // fetch the client ep by registration ID index 438 // fetch the client ep by registration ID index
481 - byte[] ep = j.get(toRegIdKey(registrationId)); 439 + byte[] ep = connection.get(toRegIdKey(registrationId));
482 if (ep == null) { 440 if (ep == null) {
483 return null; 441 return null;
484 } 442 }
485 443
486 // remove observation 444 // remove observation
487 - byte[] lockValue = null;  
488 - byte[] lockKey = toLockKey(ep); 445 + Lock lock = null;
  446 + String lockKey = toLockKey(ep);
489 try { 447 try {
490 - lockValue = lock.acquire(j, lockKey); 448 + lock = redisLock.obtain(lockKey);
  449 + lock.lock();
491 450
492 Observation observation = build(get(new Token(observationId))); 451 Observation observation = build(get(new Token(observationId)));
493 if (observation != null && registrationId.equals(observation.getRegistrationId())) { 452 if (observation != null && registrationId.equals(observation.getRegistrationId())) {
494 - unsafeRemoveObservation(j, registrationId, observationId); 453 + unsafeRemoveObservation(connection, registrationId, observationId);
495 return observation; 454 return observation;
496 } 455 }
497 return null; 456 return null;
498 457
499 } finally { 458 } finally {
500 - lock.release(j, lockKey, lockValue); 459 + if (lock != null) {
  460 + lock.unlock();
  461 + }
501 } 462 }
502 } 463 }
503 } 464 }
@@ -509,15 +470,15 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -509,15 +470,15 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
509 470
510 @Override 471 @Override
511 public Collection<Observation> getObservations(String registrationId) { 472 public Collection<Observation> getObservations(String registrationId) {
512 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
513 - return getObservations(j, registrationId); 473 + try (var connection = connectionFactory.getConnection()) {
  474 + return getObservations(connection, registrationId);
514 } 475 }
515 } 476 }
516 477
517 - private Collection<Observation> getObservations(Jedis j, String registrationId) { 478 + private Collection<Observation> getObservations(RedisConnection connection, String registrationId) {
518 Collection<Observation> result = new ArrayList<>(); 479 Collection<Observation> result = new ArrayList<>();
519 - for (byte[] token : j.lrange(toKey(OBS_TKNS_REGID_IDX, registrationId), 0, -1)) {  
520 - byte[] obs = j.get(toKey(OBS_TKN, token)); 480 + for (byte[] token : connection.lRange(toKey(OBS_TKNS_REGID_IDX, registrationId), 0, -1)) {
  481 + byte[] obs = connection.get(toKey(OBS_TKN, token));
521 if (obs != null) { 482 if (obs != null) {
522 result.add(build(deserializeObs(obs))); 483 result.add(build(deserializeObs(obs)));
523 } 484 }
@@ -527,22 +488,24 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -527,22 +488,24 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
527 488
528 @Override 489 @Override
529 public Collection<Observation> removeObservations(String registrationId) { 490 public Collection<Observation> removeObservations(String registrationId) {
530 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { 491 + try (var connection = connectionFactory.getConnection()) {
531 // check registration exists 492 // check registration exists
532 - Registration registration = getRegistration(j, registrationId); 493 + Registration registration = getRegistration(connection, registrationId);
533 if (registration == null) 494 if (registration == null)
534 return Collections.emptyList(); 495 return Collections.emptyList();
535 496
536 // get endpoint and create lock 497 // get endpoint and create lock
537 String endpoint = registration.getEndpoint(); 498 String endpoint = registration.getEndpoint();
538 - byte[] lockValue = null;  
539 - byte[] lockKey = toKey(LOCK_EP, endpoint); 499 + Lock lock = null;
  500 + String lockKey = toLockKey(endpoint);
540 try { 501 try {
541 - lockValue = lock.acquire(j, lockKey);  
542 -  
543 - return unsafeRemoveAllObservations(j, registrationId); 502 + lock = redisLock.obtain(lockKey);
  503 + lock.lock();
  504 + return unsafeRemoveAllObservations(connection, registrationId);
544 } finally { 505 } finally {
545 - lock.release(j, lockKey, lockValue); 506 + if (lock != null) {
  507 + lock.unlock();
  508 + }
546 } 509 }
547 } 510 }
548 } 511 }
@@ -565,31 +528,32 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -565,31 +528,32 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
565 String endpoint = ObserveUtil.validateCoapObservation(obs); 528 String endpoint = ObserveUtil.validateCoapObservation(obs);
566 org.eclipse.californium.core.observe.Observation previousObservation = null; 529 org.eclipse.californium.core.observe.Observation previousObservation = null;
567 530
568 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
569 - byte[] lockValue = null;  
570 - byte[] lockKey = toKey(LOCK_EP, endpoint); 531 + try (var connection = connectionFactory.getConnection()) {
  532 + Lock lock = null;
  533 + String lockKey = toLockKey(endpoint);
571 try { 534 try {
572 - lockValue = lock.acquire(j, lockKey); 535 + lock = redisLock.obtain(lockKey);
  536 + lock.lock();
573 537
574 String registrationId = ObserveUtil.extractRegistrationId(obs); 538 String registrationId = ObserveUtil.extractRegistrationId(obs);
575 - if (!j.exists(toRegIdKey(registrationId))) 539 + if (!connection.exists(toRegIdKey(registrationId)))
576 throw new ObservationStoreException("no registration for this Id"); 540 throw new ObservationStoreException("no registration for this Id");
577 byte[] key = toKey(OBS_TKN, obs.getRequest().getToken().getBytes()); 541 byte[] key = toKey(OBS_TKN, obs.getRequest().getToken().getBytes());
578 byte[] serializeObs = serializeObs(obs); 542 byte[] serializeObs = serializeObs(obs);
579 byte[] previousValue; 543 byte[] previousValue;
580 if (ifAbsent) { 544 if (ifAbsent) {
581 - previousValue = j.get(key); 545 + previousValue = connection.get(key);
582 if (previousValue == null || previousValue.length == 0) { 546 if (previousValue == null || previousValue.length == 0) {
583 - j.set(key, serializeObs); 547 + connection.set(key, serializeObs);
584 } else { 548 } else {
585 return deserializeObs(previousValue); 549 return deserializeObs(previousValue);
586 } 550 }
587 } else { 551 } else {
588 - previousValue = j.getSet(key, serializeObs); 552 + previousValue = connection.getSet(key, serializeObs);
589 } 553 }
590 554
591 // secondary index to get the list by registrationId 555 // secondary index to get the list by registrationId
592 - j.lpush(toKey(OBS_TKNS_REGID_IDX, registrationId), obs.getRequest().getToken().getBytes()); 556 + connection.lPush(toKey(OBS_TKNS_REGID_IDX, registrationId), obs.getRequest().getToken().getBytes());
593 557
594 // log any collisions 558 // log any collisions
595 if (previousValue != null && previousValue.length != 0) { 559 if (previousValue != null && previousValue.length != 0) {
@@ -599,7 +563,9 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -599,7 +563,9 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
599 previousObservation.getRequest(), obs.getRequest()); 563 previousObservation.getRequest(), obs.getRequest());
600 } 564 }
601 } finally { 565 } finally {
602 - lock.release(j, lockKey, lockValue); 566 + if (lock != null) {
  567 + lock.unlock();
  568 + }
603 } 569 }
604 } 570 }
605 return previousObservation; 571 return previousObservation;
@@ -607,17 +573,17 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -607,17 +573,17 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
607 573
608 @Override 574 @Override
609 public void remove(Token token) { 575 public void remove(Token token) {
610 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { 576 + try (var connection = connectionFactory.getConnection()) {
611 byte[] tokenKey = toKey(OBS_TKN, token.getBytes()); 577 byte[] tokenKey = toKey(OBS_TKN, token.getBytes());
612 578
613 // fetch the observation by token 579 // fetch the observation by token
614 - byte[] serializedObs = j.get(tokenKey); 580 + byte[] serializedObs = connection.get(tokenKey);
615 if (serializedObs == null) 581 if (serializedObs == null)
616 return; 582 return;
617 583
618 org.eclipse.californium.core.observe.Observation obs = deserializeObs(serializedObs); 584 org.eclipse.californium.core.observe.Observation obs = deserializeObs(serializedObs);
619 String registrationId = ObserveUtil.extractRegistrationId(obs); 585 String registrationId = ObserveUtil.extractRegistrationId(obs);
620 - Registration registration = getRegistration(j, registrationId); 586 + Registration registration = getRegistration(connection, registrationId);
621 if (registration == null) { 587 if (registration == null) {
622 LOG.warn("Unable to remove observation {}, registration {} does not exist anymore", obs.getRequest(), 588 LOG.warn("Unable to remove observation {}, registration {} does not exist anymore", obs.getRequest(),
623 registrationId); 589 registrationId);
@@ -625,14 +591,17 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -625,14 +591,17 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
625 } 591 }
626 592
627 String endpoint = registration.getEndpoint(); 593 String endpoint = registration.getEndpoint();
628 - byte[] lockValue = null;  
629 - byte[] lockKey = toKey(LOCK_EP, endpoint); 594 + Lock lock = null;
  595 + String lockKey = toLockKey(endpoint);
630 try { 596 try {
631 - lockValue = lock.acquire(j, lockKey); 597 + lock = redisLock.obtain(lockKey);
  598 + lock.lock();
632 599
633 - unsafeRemoveObservation(j, registrationId, token.getBytes()); 600 + unsafeRemoveObservation(connection, registrationId, token.getBytes());
634 } finally { 601 } finally {
635 - lock.release(j, lockKey, lockValue); 602 + if (lock != null) {
  603 + lock.unlock();
  604 + }
636 } 605 }
637 } 606 }
638 607
@@ -640,8 +609,8 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -640,8 +609,8 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
640 609
641 @Override 610 @Override
642 public org.eclipse.californium.core.observe.Observation get(Token token) { 611 public org.eclipse.californium.core.observe.Observation get(Token token) {
643 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
644 - byte[] obs = j.get(toKey(OBS_TKN, token.getBytes())); 612 + try (var connection = connectionFactory.getConnection()) {
  613 + byte[] obs = connection.get(toKey(OBS_TKN, token.getBytes()));
645 if (obs == null) { 614 if (obs == null) {
646 return null; 615 return null;
647 } else { 616 } else {
@@ -652,12 +621,12 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -652,12 +621,12 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
652 621
653 /* *************** Observation utility functions **************** */ 622 /* *************** Observation utility functions **************** */
654 623
655 - private Registration getRegistration(Jedis j, String registrationId) {  
656 - byte[] ep = j.get(toRegIdKey(registrationId)); 624 + private Registration getRegistration(RedisConnection connection, String registrationId) {
  625 + byte[] ep = connection.get(toRegIdKey(registrationId));
657 if (ep == null) { 626 if (ep == null) {
658 return null; 627 return null;
659 } 628 }
660 - byte[] data = j.get(toEndpointKey(ep)); 629 + byte[] data = connection.get(toEndpointKey(ep));
661 if (data == null) { 630 if (data == null) {
662 return null; 631 return null;
663 } 632 }
@@ -665,25 +634,25 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -665,25 +634,25 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
665 return deserializeReg(data); 634 return deserializeReg(data);
666 } 635 }
667 636
668 - private void unsafeRemoveObservation(Jedis j, String registrationId, byte[] observationId) {  
669 - if (j.del(toKey(OBS_TKN, observationId)) > 0L) {  
670 - j.lrem(toKey(OBS_TKNS_REGID_IDX, registrationId), 0, observationId); 637 + private void unsafeRemoveObservation(RedisConnection connection, String registrationId, byte[] observationId) {
  638 + if (connection.del(toKey(OBS_TKN, observationId)) > 0L) {
  639 + connection.lRem(toKey(OBS_TKNS_REGID_IDX, registrationId), 0, observationId);
671 } 640 }
672 } 641 }
673 642
674 - private Collection<Observation> unsafeRemoveAllObservations(Jedis j, String registrationId) { 643 + private Collection<Observation> unsafeRemoveAllObservations(RedisConnection connection, String registrationId) {
675 Collection<Observation> removed = new ArrayList<>(); 644 Collection<Observation> removed = new ArrayList<>();
676 byte[] regIdKey = toKey(OBS_TKNS_REGID_IDX, registrationId); 645 byte[] regIdKey = toKey(OBS_TKNS_REGID_IDX, registrationId);
677 646
678 // fetch all observations by token 647 // fetch all observations by token
679 - for (byte[] token : j.lrange(regIdKey, 0, -1)) {  
680 - byte[] obs = j.get(toKey(OBS_TKN, token)); 648 + for (byte[] token : connection.lRange(regIdKey, 0, -1)) {
  649 + byte[] obs = connection.get(toKey(OBS_TKN, token));
681 if (obs != null) { 650 if (obs != null) {
682 removed.add(build(deserializeObs(obs))); 651 removed.add(build(deserializeObs(obs)));
683 } 652 }
684 - j.del(toKey(OBS_TKN, token)); 653 + connection.del(toKey(OBS_TKN, token));
685 } 654 }
686 - j.del(regIdKey); 655 + connection.del(regIdKey);
687 656
688 return removed; 657 return removed;
689 } 658 }
@@ -754,14 +723,14 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @@ -754,14 +723,14 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
754 @Override 723 @Override
755 public void run() { 724 public void run() {
756 725
757 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
758 - Set<byte[]> endpointsExpired = j.zrangeByScore(EXP_EP, Double.NEGATIVE_INFINITY, 726 + try (var connection = connectionFactory.getConnection()) {
  727 + Set<byte[]> endpointsExpired = connection.zRangeByScore(EXP_EP, Double.NEGATIVE_INFINITY,
759 System.currentTimeMillis(), 0, cleanLimit); 728 System.currentTimeMillis(), 0, cleanLimit);
760 729
761 for (byte[] endpoint : endpointsExpired) { 730 for (byte[] endpoint : endpointsExpired) {
762 - Registration r = deserializeReg(j.get(toEndpointKey(endpoint))); 731 + Registration r = deserializeReg(connection.get(toEndpointKey(endpoint)));
763 if (!r.isAlive(gracePeriod)) { 732 if (!r.isAlive(gracePeriod)) {
764 - Deregistration dereg = removeRegistration(j, r.getId(), true); 733 + Deregistration dereg = removeRegistration(connection, r.getId(), true);
765 if (dereg != null) 734 if (dereg != null)
766 expirationListener.registrationExpired(dereg.getRegistration(), dereg.getObservations()); 735 expirationListener.registrationExpired(dereg.getRegistration(), dereg.getObservations());
767 } 736 }
@@ -20,13 +20,15 @@ import org.eclipse.leshan.server.security.EditableSecurityStore; @@ -20,13 +20,15 @@ import org.eclipse.leshan.server.security.EditableSecurityStore;
20 import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; 20 import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
21 import org.eclipse.leshan.server.security.SecurityInfo; 21 import org.eclipse.leshan.server.security.SecurityInfo;
22 import org.eclipse.leshan.server.security.SecurityStoreListener; 22 import org.eclipse.leshan.server.security.SecurityStoreListener;
  23 +import org.springframework.data.redis.connection.RedisClusterConnection;
23 import org.springframework.data.redis.connection.RedisConnectionFactory; 24 import org.springframework.data.redis.connection.RedisConnectionFactory;
24 -import redis.clients.jedis.Jedis;  
25 -import redis.clients.jedis.ScanParams;  
26 -import redis.clients.jedis.ScanResult; 25 +import org.springframework.data.redis.core.Cursor;
  26 +import org.springframework.data.redis.core.ScanOptions;
27 27
  28 +import java.util.ArrayList;
28 import java.util.Collection; 29 import java.util.Collection;
29 import java.util.LinkedList; 30 import java.util.LinkedList;
  31 +import java.util.List;
30 32
31 public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { 33 public class TbLwM2mRedisSecurityStore implements EditableSecurityStore {
32 private static final String SEC_EP = "SEC#EP#"; 34 private static final String SEC_EP = "SEC#EP#";
@@ -42,8 +44,8 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { @@ -42,8 +44,8 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore {
42 44
43 @Override 45 @Override
44 public SecurityInfo getByEndpoint(String endpoint) { 46 public SecurityInfo getByEndpoint(String endpoint) {
45 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
46 - byte[] data = j.get((SEC_EP + endpoint).getBytes()); 47 + try (var connection = connectionFactory.getConnection()) {
  48 + byte[] data = connection.get((SEC_EP + endpoint).getBytes());
47 if (data == null) { 49 if (data == null) {
48 return null; 50 return null;
49 } else { 51 } else {
@@ -54,12 +56,12 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { @@ -54,12 +56,12 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore {
54 56
55 @Override 57 @Override
56 public SecurityInfo getByIdentity(String identity) { 58 public SecurityInfo getByIdentity(String identity) {
57 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
58 - String ep = j.hget(PSKID_SEC, identity); 59 + try (var connection = connectionFactory.getConnection()) {
  60 + byte[] ep = connection.hGet(PSKID_SEC.getBytes(), identity.getBytes());
59 if (ep == null) { 61 if (ep == null) {
60 return null; 62 return null;
61 } else { 63 } else {
62 - byte[] data = j.get((SEC_EP + ep).getBytes()); 64 + byte[] data = connection.get((SEC_EP + new String(ep)).getBytes());
63 if (data == null) { 65 if (data == null) {
64 return null; 66 return null;
65 } else { 67 } else {
@@ -71,18 +73,24 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { @@ -71,18 +73,24 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore {
71 73
72 @Override 74 @Override
73 public Collection<SecurityInfo> getAll() { 75 public Collection<SecurityInfo> getAll() {
74 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
75 - ScanParams params = new ScanParams().match(SEC_EP + "*").count(100); 76 + try (var connection = connectionFactory.getConnection()) {
76 Collection<SecurityInfo> list = new LinkedList<>(); 77 Collection<SecurityInfo> list = new LinkedList<>();
77 - String cursor = "0";  
78 - do {  
79 - ScanResult<byte[]> res = j.scan(cursor.getBytes(), params);  
80 - for (byte[] key : res.getResult()) {  
81 - byte[] element = j.get(key); 78 + ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(SEC_EP + "*").build();
  79 + List<Cursor<byte[]>> scans = new ArrayList<>();
  80 + if (connection instanceof RedisClusterConnection) {
  81 + ((RedisClusterConnection) connection).clusterGetNodes().forEach(node -> {
  82 + scans.add(((RedisClusterConnection) connection).scan(node, scanOptions));
  83 + });
  84 + } else {
  85 + scans.add(connection.scan(scanOptions));
  86 + }
  87 +
  88 + scans.forEach(scan -> {
  89 + scan.forEachRemaining(key -> {
  90 + byte[] element = connection.get(key);
82 list.add(deserialize(element)); 91 list.add(deserialize(element));
83 - }  
84 - cursor = res.getCursor();  
85 - } while (!"0".equals(cursor)); 92 + });
  93 + });
86 return list; 94 return list;
87 } 95 }
88 } 96 }
@@ -90,21 +98,21 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { @@ -90,21 +98,21 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore {
90 @Override 98 @Override
91 public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException { 99 public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException {
92 byte[] data = serialize(info); 100 byte[] data = serialize(info);
93 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { 101 + try (var connection = connectionFactory.getConnection()) {
94 if (info.getIdentity() != null) { 102 if (info.getIdentity() != null) {
95 // populate the secondary index (security info by PSK id) 103 // populate the secondary index (security info by PSK id)
96 - String oldEndpoint = j.hget(PSKID_SEC, info.getIdentity());  
97 - if (oldEndpoint != null && !oldEndpoint.equals(info.getEndpoint())) { 104 + String oldEndpoint = new String(connection.hGet(PSKID_SEC.getBytes(), info.getIdentity().getBytes()));
  105 + if (!oldEndpoint.equals(info.getEndpoint())) {
98 throw new NonUniqueSecurityInfoException("PSK Identity " + info.getIdentity() + " is already used"); 106 throw new NonUniqueSecurityInfoException("PSK Identity " + info.getIdentity() + " is already used");
99 } 107 }
100 - j.hset(PSKID_SEC.getBytes(), info.getIdentity().getBytes(), info.getEndpoint().getBytes()); 108 + connection.hSet(PSKID_SEC.getBytes(), info.getIdentity().getBytes(), info.getEndpoint().getBytes());
101 } 109 }
102 110
103 - byte[] previousData = j.getSet((SEC_EP + info.getEndpoint()).getBytes(), data); 111 + byte[] previousData = connection.getSet((SEC_EP + info.getEndpoint()).getBytes(), data);
104 SecurityInfo previous = previousData == null ? null : deserialize(previousData); 112 SecurityInfo previous = previousData == null ? null : deserialize(previousData);
105 String previousIdentity = previous == null ? null : previous.getIdentity(); 113 String previousIdentity = previous == null ? null : previous.getIdentity();
106 if (previousIdentity != null && !previousIdentity.equals(info.getIdentity())) { 114 if (previousIdentity != null && !previousIdentity.equals(info.getIdentity())) {
107 - j.hdel(PSKID_SEC, previousIdentity); 115 + connection.hDel(PSKID_SEC.getBytes(), previousIdentity.getBytes());
108 } 116 }
109 117
110 return previous; 118 return previous;
@@ -113,15 +121,15 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { @@ -113,15 +121,15 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore {
113 121
114 @Override 122 @Override
115 public SecurityInfo remove(String endpoint, boolean infosAreCompromised) { 123 public SecurityInfo remove(String endpoint, boolean infosAreCompromised) {
116 - try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) {  
117 - byte[] data = j.get((SEC_EP + endpoint).getBytes()); 124 + try (var connection = connectionFactory.getConnection()) {
  125 + byte[] data = connection.get((SEC_EP + endpoint).getBytes());
118 126
119 if (data != null) { 127 if (data != null) {
120 SecurityInfo info = deserialize(data); 128 SecurityInfo info = deserialize(data);
121 if (info.getIdentity() != null) { 129 if (info.getIdentity() != null) {
122 - j.hdel(PSKID_SEC.getBytes(), info.getIdentity().getBytes()); 130 + connection.hDel(PSKID_SEC.getBytes(), info.getIdentity().getBytes());
123 } 131 }
124 - j.del((SEC_EP + endpoint).getBytes()); 132 + connection.del((SEC_EP + endpoint).getBytes());
125 if (listener != null) { 133 if (listener != null) {
126 listener.securityInfoRemoved(infosAreCompromised, info); 134 listener.securityInfoRemoved(infosAreCompromised, info);
127 } 135 }
@@ -74,7 +74,7 @@ public class TbLwM2mSecurityStore implements EditableSecurityStore { @@ -74,7 +74,7 @@ public class TbLwM2mSecurityStore implements EditableSecurityStore {
74 add(securityInfo); 74 add(securityInfo);
75 } 75 }
76 } catch (NonUniqueSecurityInfoException e) { 76 } catch (NonUniqueSecurityInfoException e) {
77 - log.warn("Failed to add security info: {}", securityInfo, e); 77 + log.trace("Failed to add security info: {}", securityInfo, e);
78 } 78 }
79 } 79 }
80 return securityInfo; 80 return securityInfo;
@@ -90,7 +90,7 @@ public class TbLwM2mSecurityStore implements EditableSecurityStore { @@ -90,7 +90,7 @@ public class TbLwM2mSecurityStore implements EditableSecurityStore {
90 add(securityInfo); 90 add(securityInfo);
91 } 91 }
92 } catch (NonUniqueSecurityInfoException e) { 92 } catch (NonUniqueSecurityInfoException e) {
93 - log.warn("Failed to add security info: {}", securityInfo, e); 93 + log.trace("Failed to add security info: {}", securityInfo, e);
94 } 94 }
95 } 95 }
96 return securityInfo; 96 return securityInfo;
@@ -26,6 +26,7 @@ import org.springframework.context.annotation.Lazy; @@ -26,6 +26,7 @@ import org.springframework.context.annotation.Lazy;
26 import org.springframework.stereotype.Component; 26 import org.springframework.stereotype.Component;
27 import org.thingsboard.server.cache.TBRedisCacheConfiguration; 27 import org.thingsboard.server.cache.TBRedisCacheConfiguration;
28 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 28 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
  29 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
29 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; 30 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
30 31
31 import java.util.Optional; 32 import java.util.Optional;
@@ -38,6 +39,9 @@ public class TbLwM2mStoreFactory { @@ -38,6 +39,9 @@ public class TbLwM2mStoreFactory {
38 private Optional<TBRedisCacheConfiguration> redisConfiguration; 39 private Optional<TBRedisCacheConfiguration> redisConfiguration;
39 40
40 @Autowired 41 @Autowired
  42 + private LwM2MTransportServerConfig config;
  43 +
  44 + @Autowired
41 @Lazy 45 @Lazy
42 private LwM2mClientContext clientContext; 46 private LwM2mClientContext clientContext;
43 47
@@ -47,7 +51,7 @@ public class TbLwM2mStoreFactory { @@ -47,7 +51,7 @@ public class TbLwM2mStoreFactory {
47 @Bean 51 @Bean
48 private CaliforniumRegistrationStore registrationStore() { 52 private CaliforniumRegistrationStore registrationStore() {
49 return redisConfiguration.isPresent() && useRedis ? 53 return redisConfiguration.isPresent() && useRedis ?
50 - new TbLwM2mRedisRegistrationStore(redisConfiguration.get().redisConnectionFactory()) : new InMemoryRegistrationStore(); 54 + new TbLwM2mRedisRegistrationStore(redisConfiguration.get().redisConnectionFactory()) : new InMemoryRegistrationStore(config.getCleanPeriodInSec());
51 } 55 }
52 56
53 @Bean 57 @Bean
@@ -121,9 +121,11 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter { @@ -121,9 +121,11 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
121 /** let's assume we received an ISO 8601 format date */ 121 /** let's assume we received an ISO 8601 format date */
122 try { 122 try {
123 return new Date(Long.decode(value.toString())); 123 return new Date(Long.decode(value.toString()));
124 -// DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();  
125 -// XMLGregorianCalendar cal = datatypeFactory.newXMLGregorianCalendar((String) value);  
126 -// return cal.toGregorianCalendar().getTime(); 124 + /**
  125 + DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
  126 + XMLGregorianCalendar cal = datatypeFactory.newXMLGregorianCalendar((String) value);
  127 + return cal.toGregorianCalendar().getTime();
  128 + **/
127 } catch (IllegalArgumentException e) { 129 } catch (IllegalArgumentException e) {
128 log.debug("Unable to convert string to date", e); 130 log.debug("Unable to convert string to date", e);
129 throw new CodecException("Unable to convert string (%s) to date for resource %s", value, 131 throw new CodecException("Unable to convert string (%s) to date for resource %s", value,
@@ -48,6 +48,8 @@ public interface AlarmDao extends Dao<Alarm> { @@ -48,6 +48,8 @@ public interface AlarmDao extends Dao<Alarm> {
48 48
49 PageData<AlarmInfo> findAlarms(TenantId tenantId, AlarmQuery query); 49 PageData<AlarmInfo> findAlarms(TenantId tenantId, AlarmQuery query);
50 50
  51 + PageData<AlarmInfo> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query);
  52 +
51 PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, 53 PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId,
52 AlarmDataQuery query, Collection<EntityId> orderedEntityIds); 54 AlarmDataQuery query, Collection<EntityId> orderedEntityIds);
53 55
@@ -41,7 +41,6 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -41,7 +41,6 @@ import org.thingsboard.server.common.data.id.TenantId;
41 import org.thingsboard.server.common.data.page.PageData; 41 import org.thingsboard.server.common.data.page.PageData;
42 import org.thingsboard.server.common.data.query.AlarmData; 42 import org.thingsboard.server.common.data.query.AlarmData;
43 import org.thingsboard.server.common.data.query.AlarmDataQuery; 43 import org.thingsboard.server.common.data.query.AlarmDataQuery;
44 -import org.thingsboard.server.common.data.query.DeviceTypeFilter;  
45 import org.thingsboard.server.common.data.relation.EntityRelation; 44 import org.thingsboard.server.common.data.relation.EntityRelation;
46 import org.thingsboard.server.common.data.relation.EntityRelationsQuery; 45 import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
47 import org.thingsboard.server.common.data.relation.EntitySearchDirection; 46 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
@@ -102,6 +101,11 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @@ -102,6 +101,11 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
102 101
103 @Override 102 @Override
104 public AlarmOperationResult createOrUpdateAlarm(Alarm alarm) { 103 public AlarmOperationResult createOrUpdateAlarm(Alarm alarm) {
  104 + return createOrUpdateAlarm(alarm, true);
  105 + }
  106 +
  107 + @Override
  108 + public AlarmOperationResult createOrUpdateAlarm(Alarm alarm, boolean alarmCreationEnabled) {
105 alarmDataValidator.validate(alarm, Alarm::getTenantId); 109 alarmDataValidator.validate(alarm, Alarm::getTenantId);
106 try { 110 try {
107 if (alarm.getStartTs() == 0L) { 111 if (alarm.getStartTs() == 0L) {
@@ -110,9 +114,13 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @@ -110,9 +114,13 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
110 if (alarm.getEndTs() == 0L) { 114 if (alarm.getEndTs() == 0L) {
111 alarm.setEndTs(alarm.getStartTs()); 115 alarm.setEndTs(alarm.getStartTs());
112 } 116 }
  117 + alarm.setCustomerId(entityService.fetchEntityCustomerId(alarm.getTenantId(), alarm.getOriginator()));
113 if (alarm.getId() == null) { 118 if (alarm.getId() == null) {
114 Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get(); 119 Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get();
115 if (existing == null || existing.getStatus().isCleared()) { 120 if (existing == null || existing.getStatus().isCleared()) {
  121 + if (!alarmCreationEnabled) {
  122 + throw new IllegalStateException("Alarm creation is disabled");
  123 + }
116 return createAlarm(alarm); 124 return createAlarm(alarm);
117 } else { 125 } else {
118 return updateAlarm(existing, alarm); 126 return updateAlarm(existing, alarm);
@@ -158,7 +166,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @@ -158,7 +166,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
158 log.debug("New Alarm : {}", alarm); 166 log.debug("New Alarm : {}", alarm);
159 Alarm saved = alarmDao.save(alarm.getTenantId(), alarm); 167 Alarm saved = alarmDao.save(alarm.getTenantId(), alarm);
160 List<EntityId> propagatedEntitiesList = createAlarmRelations(saved); 168 List<EntityId> propagatedEntitiesList = createAlarmRelations(saved);
161 - return new AlarmOperationResult(saved, true, propagatedEntitiesList); 169 + return new AlarmOperationResult(saved, true, true, propagatedEntitiesList);
162 } 170 }
163 171
164 private List<EntityId> createAlarmRelations(Alarm alarm) throws InterruptedException, ExecutionException { 172 private List<EntityId> createAlarmRelations(Alarm alarm) throws InterruptedException, ExecutionException {
@@ -292,26 +300,39 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @@ -292,26 +300,39 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
292 public ListenableFuture<PageData<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query) { 300 public ListenableFuture<PageData<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query) {
293 PageData<AlarmInfo> alarms = alarmDao.findAlarms(tenantId, query); 301 PageData<AlarmInfo> alarms = alarmDao.findAlarms(tenantId, query);
294 if (query.getFetchOriginator() != null && query.getFetchOriginator().booleanValue()) { 302 if (query.getFetchOriginator() != null && query.getFetchOriginator().booleanValue()) {
295 - List<ListenableFuture<AlarmInfo>> alarmFutures = new ArrayList<>(alarms.getData().size());  
296 - for (AlarmInfo alarmInfo : alarms.getData()) {  
297 - alarmFutures.add(Futures.transform(  
298 - entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> {  
299 - if (originatorName == null) {  
300 - originatorName = "Deleted";  
301 - }  
302 - alarmInfo.setOriginatorName(originatorName);  
303 - return alarmInfo;  
304 - }, MoreExecutors.directExecutor()  
305 - ));  
306 - }  
307 - return Futures.transform(Futures.successfulAsList(alarmFutures),  
308 - alarmInfos -> new PageData<>(alarmInfos, alarms.getTotalPages(), alarms.getTotalElements(),  
309 - alarms.hasNext()), MoreExecutors.directExecutor()); 303 + return fetchAlarmsOriginators(tenantId, alarms);
310 } 304 }
311 return Futures.immediateFuture(alarms); 305 return Futures.immediateFuture(alarms);
312 } 306 }
313 307
314 @Override 308 @Override
  309 + public ListenableFuture<PageData<AlarmInfo>> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query) {
  310 + PageData<AlarmInfo> alarms = alarmDao.findCustomerAlarms(tenantId, customerId, query);
  311 + if (query.getFetchOriginator() != null && query.getFetchOriginator().booleanValue()) {
  312 + return fetchAlarmsOriginators(tenantId, alarms);
  313 + }
  314 + return Futures.immediateFuture(alarms);
  315 + }
  316 +
  317 + private ListenableFuture<PageData<AlarmInfo>> fetchAlarmsOriginators(TenantId tenantId, PageData<AlarmInfo> alarms) {
  318 + List<ListenableFuture<AlarmInfo>> alarmFutures = new ArrayList<>(alarms.getData().size());
  319 + for (AlarmInfo alarmInfo : alarms.getData()) {
  320 + alarmFutures.add(Futures.transform(
  321 + entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> {
  322 + if (originatorName == null) {
  323 + originatorName = "Deleted";
  324 + }
  325 + alarmInfo.setOriginatorName(originatorName);
  326 + return alarmInfo;
  327 + }, MoreExecutors.directExecutor()
  328 + ));
  329 + }
  330 + return Futures.transform(Futures.successfulAsList(alarmFutures),
  331 + alarmInfos -> new PageData<>(alarmInfos, alarms.getTotalPages(), alarms.getTotalElements(),
  332 + alarms.hasNext()), MoreExecutors.directExecutor());
  333 + }
  334 +
  335 + @Override
315 public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, 336 public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus,
316 AlarmStatus alarmStatus) { 337 AlarmStatus alarmStatus) {
317 Set<AlarmStatus> statusList = null; 338 Set<AlarmStatus> statusList = null;
@@ -342,6 +363,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @@ -342,6 +363,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
342 existing.setStatus(alarm.getStatus()); 363 existing.setStatus(alarm.getStatus());
343 existing.setSeverity(alarm.getSeverity()); 364 existing.setSeverity(alarm.getSeverity());
344 existing.setDetails(alarm.getDetails()); 365 existing.setDetails(alarm.getDetails());
  366 + existing.setCustomerId(alarm.getCustomerId());
345 existing.setPropagate(existing.isPropagate() || alarm.isPropagate()); 367 existing.setPropagate(existing.isPropagate() || alarm.isPropagate());
346 List<String> existingPropagateRelationTypes = existing.getPropagateRelationTypes(); 368 List<String> existingPropagateRelationTypes = existing.getPropagateRelationTypes();
347 List<String> newRelationTypes = alarm.getPropagateRelationTypes(); 369 List<String> newRelationTypes = alarm.getPropagateRelationTypes();
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.dao.asset; 16 package org.thingsboard.server.dao.asset;
17 17
18 18
19 -import com.google.common.base.Function;  
20 import com.google.common.util.concurrent.Futures; 19 import com.google.common.util.concurrent.Futures;
21 import com.google.common.util.concurrent.ListenableFuture; 20 import com.google.common.util.concurrent.ListenableFuture;
22 import com.google.common.util.concurrent.MoreExecutors; 21 import com.google.common.util.concurrent.MoreExecutors;
@@ -46,11 +45,10 @@ import org.thingsboard.server.common.data.id.EntityId; @@ -46,11 +45,10 @@ import org.thingsboard.server.common.data.id.EntityId;
46 import org.thingsboard.server.common.data.id.TenantId; 45 import org.thingsboard.server.common.data.id.TenantId;
47 import org.thingsboard.server.common.data.page.PageData; 46 import org.thingsboard.server.common.data.page.PageData;
48 import org.thingsboard.server.common.data.page.PageLink; 47 import org.thingsboard.server.common.data.page.PageLink;
49 -import org.thingsboard.server.common.data.page.TimePageLink;  
50 import org.thingsboard.server.common.data.relation.EntityRelation; 48 import org.thingsboard.server.common.data.relation.EntityRelation;
51 import org.thingsboard.server.common.data.relation.EntitySearchDirection; 49 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
52 -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;  
53 import org.thingsboard.server.common.data.relation.RelationTypeGroup; 50 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
  51 +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
54 import org.thingsboard.server.dao.customer.CustomerDao; 52 import org.thingsboard.server.dao.customer.CustomerDao;
55 import org.thingsboard.server.dao.entity.AbstractEntityService; 53 import org.thingsboard.server.dao.entity.AbstractEntityService;
56 import org.thingsboard.server.dao.exception.DataValidationException; 54 import org.thingsboard.server.dao.exception.DataValidationException;
@@ -59,8 +57,8 @@ import org.thingsboard.server.dao.service.PaginatedRemover; @@ -59,8 +57,8 @@ import org.thingsboard.server.dao.service.PaginatedRemover;
59 import org.thingsboard.server.dao.tenant.TbTenantProfileCache; 57 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
60 import org.thingsboard.server.dao.tenant.TenantDao; 58 import org.thingsboard.server.dao.tenant.TenantDao;
61 59
62 -import javax.annotation.Nullable;  
63 import java.util.ArrayList; 60 import java.util.ArrayList;
  61 +import java.util.Arrays;
64 import java.util.Collections; 62 import java.util.Collections;
65 import java.util.Comparator; 63 import java.util.Comparator;
66 import java.util.List; 64 import java.util.List;
@@ -180,15 +178,16 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ @@ -180,15 +178,16 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
180 throw new RuntimeException("Exception while finding entity views for assetId [" + assetId + "]", e); 178 throw new RuntimeException("Exception while finding entity views for assetId [" + assetId + "]", e);
181 } 179 }
182 180
183 - List<Object> list = new ArrayList<>();  
184 - list.add(asset.getTenantId());  
185 - list.add(asset.getName());  
186 - Cache cache = cacheManager.getCache(ASSET_CACHE);  
187 - cache.evict(list); 181 + removeAssetFromCacheByName(asset.getTenantId(), asset.getName());
188 182
189 assetDao.removeById(tenantId, assetId.getId()); 183 assetDao.removeById(tenantId, assetId.getId());
190 } 184 }
191 185
  186 + private void removeAssetFromCacheByName(TenantId tenantId, String name) {
  187 + Cache cache = cacheManager.getCache(ASSET_CACHE);
  188 + cache.evict(Arrays.asList(tenantId, name));
  189 + }
  190 +
192 @Override 191 @Override
193 public PageData<Asset> findAssetsByTenantId(TenantId tenantId, PageLink pageLink) { 192 public PageData<Asset> findAssetsByTenantId(TenantId tenantId, PageLink pageLink) {
194 log.trace("Executing findAssetsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); 193 log.trace("Executing findAssetsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
@@ -397,6 +396,13 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ @@ -397,6 +396,13 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
397 396
398 @Override 397 @Override
399 protected void validateUpdate(TenantId tenantId, Asset asset) { 398 protected void validateUpdate(TenantId tenantId, Asset asset) {
  399 + Asset old = assetDao.findById(asset.getTenantId(), asset.getId().getId());
  400 + if (old == null) {
  401 + throw new DataValidationException("Can't update non existing asset!");
  402 + }
  403 + if (!old.getName().equals(asset.getName())) {
  404 + removeAssetFromCacheByName(tenantId, old.getName());
  405 + }
400 } 406 }
401 407
402 @Override 408 @Override
@@ -18,6 +18,7 @@ package org.thingsboard.server.dao.dashboard; @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.dashboard;
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
20 import org.apache.commons.lang3.StringUtils; 20 import org.apache.commons.lang3.StringUtils;
  21 +import org.hibernate.exception.ConstraintViolationException;
21 import org.springframework.beans.factory.annotation.Autowired; 22 import org.springframework.beans.factory.annotation.Autowired;
22 import org.springframework.context.annotation.Lazy; 23 import org.springframework.context.annotation.Lazy;
23 import org.springframework.stereotype.Service; 24 import org.springframework.stereotype.Service;
@@ -166,7 +167,16 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb @@ -166,7 +167,16 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
166 log.trace("Executing deleteDashboard [{}]", dashboardId); 167 log.trace("Executing deleteDashboard [{}]", dashboardId);
167 Validator.validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId); 168 Validator.validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId);
168 deleteEntityRelations(tenantId, dashboardId); 169 deleteEntityRelations(tenantId, dashboardId);
169 - dashboardDao.removeById(tenantId, dashboardId.getId()); 170 + try {
  171 + dashboardDao.removeById(tenantId, dashboardId.getId());
  172 + } catch (Exception t) {
  173 + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
  174 + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_default_dashboard_device_profile")) {
  175 + throw new DataValidationException("The dashboard referenced by the device profiles cannot be deleted!");
  176 + } else {
  177 + throw t;
  178 + }
  179 + }
170 } 180 }
171 181
172 @Override 182 @Override
@@ -36,6 +36,7 @@ import org.springframework.cache.CacheManager; @@ -36,6 +36,7 @@ import org.springframework.cache.CacheManager;
36 import org.springframework.cache.annotation.Cacheable; 36 import org.springframework.cache.annotation.Cacheable;
37 import org.springframework.stereotype.Service; 37 import org.springframework.stereotype.Service;
38 import org.springframework.util.CollectionUtils; 38 import org.springframework.util.CollectionUtils;
  39 +import org.thingsboard.server.common.data.DashboardInfo;
39 import org.thingsboard.server.common.data.Device; 40 import org.thingsboard.server.common.data.Device;
40 import org.thingsboard.server.common.data.DeviceProfile; 41 import org.thingsboard.server.common.data.DeviceProfile;
41 import org.thingsboard.server.common.data.DeviceProfileInfo; 42 import org.thingsboard.server.common.data.DeviceProfileInfo;
@@ -61,9 +62,12 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -61,9 +62,12 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
61 import org.thingsboard.server.common.data.id.TenantId; 62 import org.thingsboard.server.common.data.id.TenantId;
62 import org.thingsboard.server.common.data.page.PageData; 63 import org.thingsboard.server.common.data.page.PageData;
63 import org.thingsboard.server.common.data.page.PageLink; 64 import org.thingsboard.server.common.data.page.PageLink;
  65 +import org.thingsboard.server.common.data.rule.RuleChain;
  66 +import org.thingsboard.server.dao.dashboard.DashboardService;
64 import org.thingsboard.server.dao.entity.AbstractEntityService; 67 import org.thingsboard.server.dao.entity.AbstractEntityService;
65 import org.thingsboard.server.dao.exception.DataValidationException; 68 import org.thingsboard.server.dao.exception.DataValidationException;
66 import org.thingsboard.server.dao.firmware.FirmwareService; 69 import org.thingsboard.server.dao.firmware.FirmwareService;
  70 +import org.thingsboard.server.dao.rule.RuleChainService;
67 import org.thingsboard.server.dao.service.DataValidator; 71 import org.thingsboard.server.dao.service.DataValidator;
68 import org.thingsboard.server.dao.service.PaginatedRemover; 72 import org.thingsboard.server.dao.service.PaginatedRemover;
69 import org.thingsboard.server.dao.service.Validator; 73 import org.thingsboard.server.dao.service.Validator;
@@ -117,6 +121,12 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -117,6 +121,12 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
117 @Autowired 121 @Autowired
118 private FirmwareService firmwareService; 122 private FirmwareService firmwareService;
119 123
  124 + @Autowired
  125 + private RuleChainService ruleChainService;
  126 +
  127 + @Autowired
  128 + private DashboardService dashboardService;
  129 +
120 private final Lock findOrCreateLock = new ReentrantLock(); 130 private final Lock findOrCreateLock = new ReentrantLock();
121 131
122 @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}") 132 @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}")
@@ -336,7 +346,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -336,7 +346,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
336 } 346 }
337 347
338 private DataValidator<DeviceProfile> deviceProfileValidator = 348 private DataValidator<DeviceProfile> deviceProfileValidator =
339 - new DataValidator<DeviceProfile>() { 349 + new DataValidator<>() {
340 @Override 350 @Override
341 protected void validateDataImpl(TenantId tenantId, DeviceProfile deviceProfile) { 351 protected void validateDataImpl(TenantId tenantId, DeviceProfile deviceProfile) {
342 if (StringUtils.isEmpty(deviceProfile.getName())) { 352 if (StringUtils.isEmpty(deviceProfile.getName())) {
@@ -402,6 +412,20 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -402,6 +412,20 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
402 } 412 }
403 } 413 }
404 414
  415 + if (deviceProfile.getDefaultRuleChainId() != null) {
  416 + RuleChain ruleChain = ruleChainService.findRuleChainById(tenantId, deviceProfile.getDefaultRuleChainId());
  417 + if (ruleChain == null) {
  418 + throw new DataValidationException("Can't assign non-existent rule chain!");
  419 + }
  420 + }
  421 +
  422 + if (deviceProfile.getDefaultDashboardId() != null) {
  423 + DashboardInfo dashboard = dashboardService.findDashboardInfoById(tenantId, deviceProfile.getDefaultDashboardId());
  424 + if (dashboard == null) {
  425 + throw new DataValidationException("Can't assign non-existent dashboard!");
  426 + }
  427 + }
  428 +
405 if (deviceProfile.getFirmwareId() != null) { 429 if (deviceProfile.getFirmwareId() != null) {
406 Firmware firmware = firmwareService.findFirmwareById(tenantId, deviceProfile.getFirmwareId()); 430 Firmware firmware = firmwareService.findFirmwareById(tenantId, deviceProfile.getFirmwareId());
407 if (firmware == null) { 431 if (firmware == null) {
@@ -84,6 +84,7 @@ import org.thingsboard.common.util.JacksonUtil; @@ -84,6 +84,7 @@ import org.thingsboard.common.util.JacksonUtil;
84 84
85 import javax.annotation.Nullable; 85 import javax.annotation.Nullable;
86 import java.util.ArrayList; 86 import java.util.ArrayList;
  87 +import java.util.Arrays;
87 import java.util.Collections; 88 import java.util.Collections;
88 import java.util.Comparator; 89 import java.util.Comparator;
89 import java.util.List; 90 import java.util.List;
@@ -245,7 +246,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -245,7 +246,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
245 ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); 246 ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
246 if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_name_unq_key")) { 247 if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_name_unq_key")) {
247 // remove device from cache in case null value cached in the distributed redis. 248 // remove device from cache in case null value cached in the distributed redis.
248 - removeDeviceFromCache(device.getTenantId(), device.getName()); 249 + removeDeviceFromCacheByName(device.getTenantId(), device.getName());
249 throw new DataValidationException("Device with such name already exists!"); 250 throw new DataValidationException("Device with such name already exists!");
250 } else { 251 } else {
251 throw t; 252 throw t;
@@ -322,17 +323,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -322,17 +323,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
322 } 323 }
323 deleteEntityRelations(tenantId, deviceId); 324 deleteEntityRelations(tenantId, deviceId);
324 325
325 - removeDeviceFromCache(tenantId, device.getName()); 326 + removeDeviceFromCacheByName(tenantId, device.getName());
326 327
327 deviceDao.removeById(tenantId, deviceId.getId()); 328 deviceDao.removeById(tenantId, deviceId.getId());
328 } 329 }
329 330
330 - private void removeDeviceFromCache(TenantId tenantId, String name) {  
331 - List<Object> list = new ArrayList<>();  
332 - list.add(tenantId);  
333 - list.add(name); 331 + private void removeDeviceFromCacheByName(TenantId tenantId, String name) {
334 Cache cache = cacheManager.getCache(DEVICE_CACHE); 332 Cache cache = cacheManager.getCache(DEVICE_CACHE);
335 - cache.evict(list); 333 + cache.evict(Arrays.asList(tenantId, name));
336 } 334 }
337 335
338 @Override 336 @Override
@@ -671,6 +669,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -671,6 +669,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
671 if (old == null) { 669 if (old == null) {
672 throw new DataValidationException("Can't update non existing device!"); 670 throw new DataValidationException("Can't update non existing device!");
673 } 671 }
  672 + if (!old.getName().equals(device.getName())) {
  673 + removeDeviceFromCacheByName(tenantId, old.getName());
  674 + }
674 } 675 }
675 676
676 @Override 677 @Override
@@ -58,7 +58,6 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -58,7 +58,6 @@ import org.thingsboard.server.common.data.id.TenantId;
58 import org.thingsboard.server.common.data.id.UserId; 58 import org.thingsboard.server.common.data.id.UserId;
59 import org.thingsboard.server.common.data.page.PageData; 59 import org.thingsboard.server.common.data.page.PageData;
60 import org.thingsboard.server.common.data.page.PageLink; 60 import org.thingsboard.server.common.data.page.PageLink;
61 -import org.thingsboard.server.common.data.page.TimePageLink;  
62 import org.thingsboard.server.common.data.relation.EntityRelation; 61 import org.thingsboard.server.common.data.relation.EntityRelation;
63 import org.thingsboard.server.common.data.relation.EntitySearchDirection; 62 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
64 import org.thingsboard.server.common.data.relation.RelationTypeGroup; 63 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
@@ -80,6 +79,7 @@ import javax.annotation.PostConstruct; @@ -80,6 +79,7 @@ import javax.annotation.PostConstruct;
80 import java.net.InetSocketAddress; 79 import java.net.InetSocketAddress;
81 import java.net.Proxy; 80 import java.net.Proxy;
82 import java.util.ArrayList; 81 import java.util.ArrayList;
  82 +import java.util.Arrays;
83 import java.util.Collections; 83 import java.util.Collections;
84 import java.util.Comparator; 84 import java.util.Comparator;
85 import java.util.HashMap; 85 import java.util.HashMap;
@@ -222,17 +222,18 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic @@ -222,17 +222,18 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
222 222
223 Edge edge = edgeDao.findById(tenantId, edgeId.getId()); 223 Edge edge = edgeDao.findById(tenantId, edgeId.getId());
224 224
225 - List<Object> list = new ArrayList<>();  
226 - list.add(edge.getTenantId());  
227 - list.add(edge.getName());  
228 - Cache cache = cacheManager.getCache(EDGE_CACHE);  
229 - cache.evict(list);  
230 -  
231 deleteEntityRelations(tenantId, edgeId); 225 deleteEntityRelations(tenantId, edgeId);
232 226
  227 + removeEdgeFromCacheByName(edge.getTenantId(), edge.getName());
  228 +
233 edgeDao.removeById(tenantId, edgeId.getId()); 229 edgeDao.removeById(tenantId, edgeId.getId());
234 } 230 }
235 231
  232 + private void removeEdgeFromCacheByName(TenantId tenantId, String name) {
  233 + Cache cache = cacheManager.getCache(EDGE_CACHE);
  234 + cache.evict(Arrays.asList(tenantId, name));
  235 + }
  236 +
236 @Override 237 @Override
237 public PageData<Edge> findEdgesByTenantId(TenantId tenantId, PageLink pageLink) { 238 public PageData<Edge> findEdgesByTenantId(TenantId tenantId, PageLink pageLink) {
238 log.trace("Executing findEdgesByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); 239 log.trace("Executing findEdgesByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
@@ -423,6 +424,10 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic @@ -423,6 +424,10 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
423 424
424 @Override 425 @Override
425 protected void validateUpdate(TenantId tenantId, Edge edge) { 426 protected void validateUpdate(TenantId tenantId, Edge edge) {
  427 + Edge old = edgeDao.findById(edge.getTenantId(), edge.getId().getId());
  428 + if (!old.getName().equals(edge.getName())) {
  429 + removeEdgeFromCacheByName(tenantId, old.getName());
  430 + }
426 } 431 }
427 432
428 @Override 433 @Override