Commit cf405be4f3a350e9fada398d5c775fea41354398

Authored by Igor Kulikov
2 parents 59606f83 8a4c0a71

Merge branch 'master' of github.com:thingsboard/thingsboard

Showing 66 changed files with 1599 additions and 938 deletions

Too many changes to show.

To preserve performance only 66 of 140 files are displayed.

... ... @@ -63,6 +63,8 @@ CREATE TABLE IF NOT EXISTS firmware (
63 63 id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY,
64 64 created_time bigint NOT NULL,
65 65 tenant_id uuid NOT NULL,
  66 + device_profile_id uuid,
  67 + type varchar(32) NOT NULL,
66 68 title varchar(255) NOT NULL,
67 69 version varchar(255) NOT NULL,
68 70 file_name varchar(255),
... ... @@ -77,10 +79,12 @@ CREATE TABLE IF NOT EXISTS firmware (
77 79 );
78 80
79 81 ALTER TABLE device_profile
80   - ADD COLUMN IF NOT EXISTS firmware_id uuid;
  82 + ADD COLUMN IF NOT EXISTS firmware_id uuid,
  83 + ADD COLUMN IF NOT EXISTS software_id uuid;
81 84
82 85 ALTER TABLE device
83   - ADD COLUMN IF NOT EXISTS firmware_id uuid;
  86 + ADD COLUMN IF NOT EXISTS firmware_id uuid,
  87 + ADD COLUMN IF NOT EXISTS software_id uuid;
84 88
85 89 DO $$
86 90 BEGIN
... ... @@ -90,11 +94,23 @@ DO $$
90 94 FOREIGN KEY (firmware_id) REFERENCES firmware(id);
91 95 END IF;
92 96
  97 + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_software_device_profile') THEN
  98 + ALTER TABLE device_profile
  99 + ADD CONSTRAINT fk_software_device_profile
  100 + FOREIGN KEY (firmware_id) REFERENCES firmware(id);
  101 + END IF;
  102 +
93 103 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device') THEN
94 104 ALTER TABLE device
95 105 ADD CONSTRAINT fk_firmware_device
96 106 FOREIGN KEY (firmware_id) REFERENCES firmware(id);
97 107 END IF;
  108 +
  109 + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_software_device') THEN
  110 + ALTER TABLE device
  111 + ADD CONSTRAINT fk_software_device
  112 + FOREIGN KEY (firmware_id) REFERENCES firmware(id);
  113 + END IF;
98 114 END;
99 115 $$;
100 116
... ...
... ... @@ -132,7 +132,7 @@ import org.thingsboard.server.service.firmware.FirmwareStateService;
132 132 import org.thingsboard.server.service.edge.EdgeNotificationService;
133 133 import org.thingsboard.server.service.edge.rpc.EdgeGrpcService;
134 134 import org.thingsboard.server.service.edge.rpc.init.SyncEdgeService;
135   -import org.thingsboard.server.service.lwm2m.LwM2MModelsRepository;
  135 +import org.thingsboard.server.service.lwm2m.LwM2MServerSecurityInfoRepository;
136 136 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
137 137 import org.thingsboard.server.service.queue.TbClusterService;
138 138 import org.thingsboard.server.service.resource.TbResourceService;
... ... @@ -267,7 +267,7 @@ public abstract class BaseController {
267 267 protected TbDeviceProfileCache deviceProfileCache;
268 268
269 269 @Autowired
270   - protected LwM2MModelsRepository lwM2MModelsRepository;
  270 + protected LwM2MServerSecurityInfoRepository lwM2MServerSecurityInfoRepository;
271 271
272 272 @Autowired(required = false)
273 273 protected EdgeService edgeService;
... ...
... ... @@ -146,12 +146,16 @@ public class DeviceProfileController extends BaseController {
146 146 checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE);
147 147
148 148 boolean isFirmwareChanged = false;
  149 + boolean isSoftwareChanged = false;
149 150
150 151 if (!created) {
151 152 DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(getTenantId(), deviceProfile.getId());
152 153 if (!Objects.equals(deviceProfile.getFirmwareId(), oldDeviceProfile.getFirmwareId())) {
153 154 isFirmwareChanged = true;
154 155 }
  156 + if (!Objects.equals(deviceProfile.getSoftwareId(), oldDeviceProfile.getSoftwareId())) {
  157 + isSoftwareChanged = true;
  158 + }
155 159 }
156 160
157 161 DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile));
... ... @@ -164,9 +168,8 @@ public class DeviceProfileController extends BaseController {
164 168 null,
165 169 created ? ActionType.ADDED : ActionType.UPDATED, null);
166 170
167   - if (isFirmwareChanged) {
168   - firmwareStateService.update(savedDeviceProfile);
169   - }
  171 + firmwareStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged);
  172 +
170 173 sendEntityNotificationMsg(getTenantId(), savedDeviceProfile.getId(),
171 174 deviceProfile.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
172 175 return savedDeviceProfile;
... ...
... ... @@ -35,6 +35,8 @@ import org.thingsboard.server.common.data.Firmware;
35 35 import org.thingsboard.server.common.data.FirmwareInfo;
36 36 import org.thingsboard.server.common.data.audit.ActionType;
37 37 import org.thingsboard.server.common.data.exception.ThingsboardException;
  38 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  39 +import org.thingsboard.server.common.data.id.DeviceProfileId;
38 40 import org.thingsboard.server.common.data.id.FirmwareId;
39 41 import org.thingsboard.server.common.data.page.PageData;
40 42 import org.thingsboard.server.common.data.page.PageLink;
... ... @@ -133,6 +135,8 @@ public class FirmwareController extends BaseController {
133 135 Firmware firmware = new Firmware(firmwareId);
134 136 firmware.setCreatedTime(info.getCreatedTime());
135 137 firmware.setTenantId(getTenantId());
  138 + firmware.setDeviceProfileId(info.getDeviceProfileId());
  139 + firmware.setType(info.getType());
136 140 firmware.setTitle(info.getTitle());
137 141 firmware.setVersion(info.getVersion());
138 142 firmware.setAdditionalInfo(info.getAdditionalInfo());
... ... @@ -175,17 +179,22 @@ public class FirmwareController extends BaseController {
175 179 }
176 180
177 181 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
178   - @RequestMapping(value = "/firmwares/{hasData}", method = RequestMethod.GET)
  182 + @RequestMapping(value = "/firmwares/{deviceProfileId}/{type}/{hasData}", method = RequestMethod.GET)
179 183 @ResponseBody
180   - public PageData<FirmwareInfo> getFirmwares(@PathVariable("hasData") boolean hasData,
  184 + public PageData<FirmwareInfo> getFirmwares(@PathVariable("deviceProfileId") String strDeviceProfileId,
  185 + @PathVariable("type") String strType,
  186 + @PathVariable("hasData") boolean hasData,
181 187 @RequestParam int pageSize,
182 188 @RequestParam int page,
183 189 @RequestParam(required = false) String textSearch,
184 190 @RequestParam(required = false) String sortProperty,
185 191 @RequestParam(required = false) String sortOrder) throws ThingsboardException {
  192 + checkParameter("deviceProfileId", strDeviceProfileId);
  193 + checkParameter("type", strType);
186 194 try {
187 195 PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
188   - return checkNotNull(firmwareService.findTenantFirmwaresByTenantIdAndHasData(getTenantId(), hasData, pageLink));
  196 + return checkNotNull(firmwareService.findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(getTenantId(),
  197 + new DeviceProfileId(toUUID(strDeviceProfileId)), FirmwareType.valueOf(strType), hasData, pageLink));
189 198 } catch (Exception e) {
190 199 throw handleException(e);
191 200 }
... ...
... ... @@ -47,9 +47,9 @@ public class Lwm2mController extends BaseController {
47 47 @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{securityMode}/{bootstrapServerIs}", method = RequestMethod.GET)
48 48 @ResponseBody
49 49 public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("securityMode") String securityMode,
50   - @PathVariable("bootstrapServerIs") boolean bootstrapServerIs) throws ThingsboardException {
  50 + @PathVariable("bootstrapServerIs") boolean bootstrapServer) throws ThingsboardException {
51 51 try {
52   - return lwM2MModelsRepository.getBootstrapSecurityInfo(securityMode, bootstrapServerIs);
  52 + return lwM2MServerSecurityInfoRepository.getServerSecurityInfo(securityMode, bootstrapServer);
53 53 } catch (Exception e) {
54 54 throw handleException(e);
55 55 }
... ...
... ... @@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.RequestParam;
32 32 import org.springframework.web.bind.annotation.ResponseBody;
33 33 import org.springframework.web.bind.annotation.ResponseStatus;
34 34 import org.springframework.web.bind.annotation.RestController;
  35 +import org.thingsboard.common.util.JacksonUtil;
35 36 import org.thingsboard.rule.engine.api.MailService;
36 37 import org.thingsboard.server.common.data.EntityType;
37 38 import org.thingsboard.server.common.data.User;
... ... @@ -89,13 +90,14 @@ public class UserController extends BaseController {
89 90 try {
90 91 UserId userId = new UserId(toUUID(strUserId));
91 92 User user = checkUserId(userId, Operation.READ);
92   - if(!user.getAdditionalInfo().isNull()) {
93   - processDashboardIdFromAdditionalInfo((ObjectNode) user.getAdditionalInfo(), DEFAULT_DASHBOARD);
94   - processDashboardIdFromAdditionalInfo((ObjectNode) user.getAdditionalInfo(), HOME_DASHBOARD);
95   - }
96   - UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
97   - if(userCredentials.isEnabled()) {
98   - addUserCredentialsEnabled((ObjectNode) user.getAdditionalInfo());
  93 + if(user.getAdditionalInfo().isObject()) {
  94 + ObjectNode additionalInfo = (ObjectNode) user.getAdditionalInfo();
  95 + processDashboardIdFromAdditionalInfo(additionalInfo, DEFAULT_DASHBOARD);
  96 + processDashboardIdFromAdditionalInfo(additionalInfo, HOME_DASHBOARD);
  97 + UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
  98 + if(userCredentials.isEnabled() && !additionalInfo.has("userCredentialsEnabled")) {
  99 + additionalInfo.put("userCredentialsEnabled", true);
  100 + }
99 101 }
100 102 return user;
101 103 } catch (Exception e) {
... ... @@ -103,14 +105,6 @@ public class UserController extends BaseController {
103 105 }
104 106 }
105 107
106   - private void addUserCredentialsEnabled(ObjectNode additionalInfo) {
107   - if(!additionalInfo.isNull()) {
108   - if(!additionalInfo.has("userCredentialsEnabled")) {
109   - additionalInfo.put("userCredentialsEnabled", true);
110   - }
111   - }
112   - }
113   -
114 108 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
115 109 @RequestMapping(value = "/user/tokenAccessEnabled", method = RequestMethod.GET)
116 110 @ResponseBody
... ...
... ... @@ -19,13 +19,17 @@ import com.google.common.util.concurrent.FutureCallback;
19 19 import lombok.extern.slf4j.Slf4j;
20 20 import org.springframework.stereotype.Service;
21 21 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
  22 +import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
22 23 import org.thingsboard.server.common.data.DataConstants;
23 24 import org.thingsboard.server.common.data.Device;
24 25 import org.thingsboard.server.common.data.DeviceProfile;
25 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;
26 29 import org.thingsboard.server.common.data.id.DeviceId;
27 30 import org.thingsboard.server.common.data.id.FirmwareId;
28 31 import org.thingsboard.server.common.data.id.TenantId;
  32 +import org.thingsboard.server.common.data.kv.AttributeKey;
29 33 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
30 34 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
31 35 import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
... ... @@ -43,37 +47,49 @@ import org.thingsboard.server.queue.TbQueueProducer;
43 47 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
44 48 import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
45 49 import org.thingsboard.server.queue.util.TbCoreComponent;
  50 +import org.thingsboard.server.service.queue.TbClusterService;
46 51
47 52 import javax.annotation.Nullable;
48 53 import java.util.ArrayList;
49   -import java.util.Arrays;
50 54 import java.util.Collections;
  55 +import java.util.HashSet;
51 56 import java.util.List;
  57 +import java.util.Set;
52 58 import java.util.UUID;
53 59 import java.util.function.Consumer;
54   -
55   -import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_CHECKSUM;
56   -import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_CHECKSUM_ALGORITHM;
57   -import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_SIZE;
58   -import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_TITLE;
59   -import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_VERSION;
  60 +import java.util.function.Function;
  61 +
  62 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.CHECKSUM;
  63 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.CHECKSUM_ALGORITHM;
  64 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.SIZE;
  65 +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.TS;
  68 +import static org.thingsboard.server.common.data.firmware.FirmwareKey.VERSION;
  69 +import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getAttributeKey;
  70 +import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getTargetTelemetryKey;
  71 +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;
60 74
61 75 @Slf4j
62 76 @Service
63 77 @TbCoreComponent
64 78 public class DefaultFirmwareStateService implements FirmwareStateService {
65 79
  80 + private final TbClusterService tbClusterService;
66 81 private final FirmwareService firmwareService;
67 82 private final DeviceService deviceService;
68 83 private final DeviceProfileService deviceProfileService;
69 84 private final RuleEngineTelemetryService telemetryService;
70 85 private final TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> fwStateMsgProducer;
71 86
72   - public DefaultFirmwareStateService(FirmwareService firmwareService,
  87 + public DefaultFirmwareStateService(TbClusterService tbClusterService, FirmwareService firmwareService,
73 88 DeviceService deviceService,
74 89 DeviceProfileService deviceProfileService,
75 90 RuleEngineTelemetryService telemetryService,
76 91 TbCoreQueueFactory coreQueueFactory) {
  92 + this.tbClusterService = tbClusterService;
77 93 this.firmwareService = firmwareService;
78 94 this.deviceService = deviceService;
79 95 this.deviceProfileService = deviceProfileService;
... ... @@ -83,6 +99,11 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
83 99
84 100 @Override
85 101 public void update(Device device, Device oldDevice) {
  102 + updateFirmware(device, oldDevice);
  103 + updateSoftware(device, oldDevice);
  104 + }
  105 +
  106 + private void updateFirmware(Device device, Device oldDevice) {
86 107 FirmwareId newFirmwareId = device.getFirmwareId();
87 108 if (newFirmwareId == null) {
88 109 DeviceProfile newDeviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId());
... ... @@ -97,35 +118,84 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
97 118 }
98 119 if (!newFirmwareId.equals(oldFirmwareId)) {
99 120 // Device was updated and new firmware is different from previous firmware.
100   - send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis());
  121 + send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis(), FIRMWARE);
101 122 }
102 123 } else {
103 124 // Device was updated and new firmware is not set.
104   - remove(device);
  125 + remove(device, FIRMWARE);
105 126 }
106 127 } else if (newFirmwareId != null) {
107 128 // Device was created and firmware is defined.
108   - send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis());
  129 + send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis(), FIRMWARE);
  130 + }
  131 + }
  132 +
  133 + private void updateSoftware(Device device, Device oldDevice) {
  134 + FirmwareId newSoftwareId = device.getSoftwareId();
  135 + if (newSoftwareId == null) {
  136 + DeviceProfile newDeviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId());
  137 + newSoftwareId = newDeviceProfile.getSoftwareId();
  138 + }
  139 + if (oldDevice != null) {
  140 + if (newSoftwareId != null) {
  141 + FirmwareId oldSoftwareId = oldDevice.getSoftwareId();
  142 + if (oldSoftwareId == null) {
  143 + DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(oldDevice.getTenantId(), oldDevice.getDeviceProfileId());
  144 + oldSoftwareId = oldDeviceProfile.getSoftwareId();
  145 + }
  146 + if (!newSoftwareId.equals(oldSoftwareId)) {
  147 + // Device was updated and new firmware is different from previous firmware.
  148 + send(device.getTenantId(), device.getId(), newSoftwareId, System.currentTimeMillis(), SOFTWARE);
  149 + }
  150 + } else {
  151 + // Device was updated and new firmware is not set.
  152 + remove(device, SOFTWARE);
  153 + }
  154 + } else if (newSoftwareId != null) {
  155 + // Device was created and firmware is defined.
  156 + send(device.getTenantId(), device.getId(), newSoftwareId, System.currentTimeMillis(), SOFTWARE);
109 157 }
110 158 }
111 159
112 160 @Override
113   - public void update(DeviceProfile deviceProfile) {
  161 + public void update(DeviceProfile deviceProfile, boolean isFirmwareChanged, boolean isSoftwareChanged) {
114 162 TenantId tenantId = deviceProfile.getTenantId();
115 163
  164 + if (isFirmwareChanged) {
  165 + update(tenantId, deviceProfile, FIRMWARE);
  166 + }
  167 + if (isSoftwareChanged) {
  168 + update(tenantId, deviceProfile, SOFTWARE);
  169 + }
  170 + }
  171 +
  172 + private void update(TenantId tenantId, DeviceProfile deviceProfile, FirmwareType firmwareType) {
  173 + Function<PageLink, PageData<Device>> getDevicesFunction;
116 174 Consumer<Device> updateConsumer;
  175 +
  176 + switch (firmwareType) {
  177 + case FIRMWARE:
  178 + getDevicesFunction = pl -> deviceService.findDevicesByTenantIdAndTypeAndEmptyFirmware(tenantId, deviceProfile.getName(), pl);
  179 + break;
  180 + case SOFTWARE:
  181 + getDevicesFunction = pl -> deviceService.findDevicesByTenantIdAndTypeAndEmptySoftware(tenantId, deviceProfile.getName(), pl);
  182 + break;
  183 + default:
  184 + log.warn("Unsupported firmware type: [{}]", firmwareType);
  185 + return;
  186 + }
  187 +
117 188 if (deviceProfile.getFirmwareId() != null) {
118 189 long ts = System.currentTimeMillis();
119   - updateConsumer = d -> send(d.getTenantId(), d.getId(), deviceProfile.getFirmwareId(), ts);
  190 + updateConsumer = d -> send(d.getTenantId(), d.getId(), deviceProfile.getFirmwareId(), ts, firmwareType);
120 191 } else {
121   - updateConsumer = this::remove;
  192 + updateConsumer = d -> remove(d, firmwareType);
122 193 }
123 194
124 195 PageLink pageLink = new PageLink(100);
125 196 PageData<Device> pageData;
126 197 do {
127   - pageData = deviceService.findDevicesByTenantIdAndTypeAndEmptyFirmware(tenantId, deviceProfile.getName(), pageLink);
128   -
  198 + pageData = getDevicesFunction.apply(pageLink);
129 199 pageData.getData().forEach(updateConsumer);
130 200
131 201 if (pageData.hasNext()) {
... ... @@ -140,16 +210,17 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
140 210 FirmwareId targetFirmwareId = new FirmwareId(new UUID(msg.getFirmwareIdMSB(), msg.getFirmwareIdLSB()));
141 211 DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB()));
142 212 TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB()));
  213 + FirmwareType firmwareType = FirmwareType.valueOf(msg.getType());
143 214 long ts = msg.getTs();
144 215
145 216 Device device = deviceService.findDeviceById(tenantId, deviceId);
146 217 if (device == null) {
147 218 log.warn("[{}] [{}] Device was removed during firmware update msg was queued!", tenantId, deviceId);
148 219 } else {
149   - FirmwareId currentFirmwareId = device.getFirmwareId();
150   -
  220 + FirmwareId currentFirmwareId = FirmwareUtil.getFirmwareId(device, firmwareType);
151 221 if (currentFirmwareId == null) {
152   - currentFirmwareId = deviceProfileService.findDeviceProfileById(tenantId, device.getDeviceProfileId()).getFirmwareId();
  222 + DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, device.getDeviceProfileId());
  223 + currentFirmwareId = FirmwareUtil.getFirmwareId(deviceProfile, firmwareType);
153 224 }
154 225
155 226 if (targetFirmwareId.equals(currentFirmwareId)) {
... ... @@ -162,7 +233,7 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
162 233 return isSuccess;
163 234 }
164 235
165   - private void send(TenantId tenantId, DeviceId deviceId, FirmwareId firmwareId, long ts) {
  236 + private void send(TenantId tenantId, DeviceId deviceId, FirmwareId firmwareId, long ts, FirmwareType firmwareType) {
166 237 ToFirmwareStateServiceMsg msg = ToFirmwareStateServiceMsg.newBuilder()
167 238 .setTenantIdMSB(tenantId.getId().getMostSignificantBits())
168 239 .setTenantIdLSB(tenantId.getId().getLeastSignificantBits())
... ... @@ -170,6 +241,7 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
170 241 .setDeviceIdLSB(deviceId.getId().getLeastSignificantBits())
171 242 .setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits())
172 243 .setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits())
  244 + .setType(firmwareType.name())
173 245 .setTs(ts)
174 246 .build();
175 247
... ... @@ -183,10 +255,10 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
183 255 fwStateMsgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null);
184 256
185 257 List<TsKvEntry> telemetry = new ArrayList<>();
186   - telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_TITLE, firmware.getTitle())));
187   - telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_VERSION, firmware.getVersion())));
188   - telemetry.add(new BasicTsKvEntry(ts, new LongDataEntry(DataConstants.TARGET_FIRMWARE_TS, ts)));
189   - telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_STATE, FirmwareUpdateStatus.QUEUED.name())));
  258 + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTargetTelemetryKey(firmware.getType(), TITLE), firmware.getTitle())));
  259 + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTargetTelemetryKey(firmware.getType(), VERSION), firmware.getVersion())));
  260 + telemetry.add(new BasicTsKvEntry(ts, new LongDataEntry(getTargetTelemetryKey(firmware.getType(), TS), ts)));
  261 + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTelemetryKey(firmware.getType(), STATE), FirmwareUpdateStatus.QUEUED.name())));
190 262
191 263 telemetryService.saveAndNotify(tenantId, deviceId, telemetry, new FutureCallback<>() {
192 264 @Override
... ... @@ -206,7 +278,7 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
206 278 TenantId tenantId = device.getTenantId();
207 279 DeviceId deviceId = device.getId();
208 280
209   - BasicTsKvEntry status = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(DataConstants.FIRMWARE_STATE, FirmwareUpdateStatus.INITIATED.name()));
  281 + BasicTsKvEntry status = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(getTelemetryKey(firmware.getType(), STATE), FirmwareUpdateStatus.INITIATED.name()));
210 282
211 283 telemetryService.saveAndNotify(tenantId, deviceId, Collections.singletonList(status), new FutureCallback<>() {
212 284 @Override
... ... @@ -221,13 +293,12 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
221 293 });
222 294
223 295 List<AttributeKvEntry> attributes = new ArrayList<>();
  296 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(firmware.getType(), TITLE), firmware.getTitle())));
  297 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(firmware.getType(), VERSION), firmware.getVersion())));
  298 + attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(getAttributeKey(firmware.getType(), SIZE), firmware.getDataSize())));
  299 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(firmware.getType(), CHECKSUM_ALGORITHM), firmware.getChecksumAlgorithm())));
  300 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(firmware.getType(), CHECKSUM), firmware.getChecksum())));
224 301
225   - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_TITLE, firmware.getTitle())));
226   - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_VERSION, firmware.getVersion())));
227   -
228   - attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(FIRMWARE_SIZE, firmware.getDataSize())));
229   - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM_ALGORITHM, firmware.getChecksumAlgorithm())));
230   - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM, firmware.getChecksum())));
231 302 telemetryService.saveAndNotify(tenantId, deviceId, DataConstants.SHARED_SCOPE, attributes, new FutureCallback<>() {
232 303 @Override
233 304 public void onSuccess(@Nullable Void tmp) {
... ... @@ -241,13 +312,15 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
241 312 });
242 313 }
243 314
244   - private void remove(Device device) {
245   - telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE,
246   - Arrays.asList(FIRMWARE_TITLE, FIRMWARE_VERSION, FIRMWARE_SIZE, FIRMWARE_CHECKSUM_ALGORITHM, FIRMWARE_CHECKSUM),
  315 + private void remove(Device device, FirmwareType firmwareType) {
  316 + telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE, FirmwareUtil.getAttributeKeys(firmwareType),
247 317 new FutureCallback<>() {
248 318 @Override
249 319 public void onSuccess(@Nullable Void tmp) {
250 320 log.trace("[{}] Success remove target firmware attributes!", device.getId());
  321 + Set<AttributeKey> keysToNotify = new HashSet<>();
  322 + FirmwareUtil.ALL_FW_ATTRIBUTE_KEYS.forEach(key -> keysToNotify.add(new AttributeKey(DataConstants.SHARED_SCOPE, key)));
  323 + tbClusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete(device.getTenantId(), device.getId(), keysToNotify), null);
251 324 }
252 325
253 326 @Override
... ...
... ... @@ -23,7 +23,7 @@ public interface FirmwareStateService {
23 23
24 24 void update(Device device, Device oldDevice);
25 25
26   - void update(DeviceProfile deviceProfile);
  26 + void update(DeviceProfile deviceProfile, boolean isFirmwareChanged, boolean isSoftwareChanged);
27 27
28 28 boolean process(ToFirmwareStateServiceMsg msg);
29 29
... ...
application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MServerSecurityInfoRepository.java renamed from application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java
... ... @@ -16,14 +16,15 @@
16 16 package org.thingsboard.server.service.lwm2m;
17 17
18 18
  19 +import lombok.RequiredArgsConstructor;
19 20 import lombok.extern.slf4j.Slf4j;
20 21 import org.eclipse.leshan.core.util.Hex;
21   -import org.springframework.beans.factory.annotation.Autowired;
22 22 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
23 23 import org.springframework.stereotype.Service;
24 24 import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig;
25   -import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap;
26   -import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer;
  25 +import org.thingsboard.server.transport.lwm2m.config.LwM2MSecureServerConfig;
  26 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig;
  27 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
27 28 import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
28 29
29 30 import java.math.BigInteger;
... ... @@ -42,96 +43,59 @@ import java.security.spec.KeySpec;
42 43
43 44 @Slf4j
44 45 @Service
  46 +@RequiredArgsConstructor
45 47 @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'")
46   -public class LwM2MModelsRepository {
  48 +public class LwM2MServerSecurityInfoRepository {
47 49
48   - private static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
49   -
50   - @Autowired
51   - LwM2MTransportConfigServer contextServer;
52   -
53   -
54   - @Autowired
55   - LwM2MTransportConfigBootstrap contextBootStrap;
  50 + private final LwM2MTransportServerConfig serverConfig;
  51 + private final LwM2MTransportBootstrapConfig bootstrapConfig;
56 52
57 53 /**
58 54 * @param securityMode
59   - * @param bootstrapServerIs
  55 + * @param bootstrapServer
60 56 * @return ServerSecurityConfig more value is default: Important - port, host, publicKey
61 57 */
62   - public ServerSecurityConfig getBootstrapSecurityInfo(String securityMode, boolean bootstrapServerIs) {
  58 + public ServerSecurityConfig getServerSecurityInfo(String securityMode, boolean bootstrapServer) {
63 59 LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(securityMode.toLowerCase());
64   - return getBootstrapServer(bootstrapServerIs, lwM2MSecurityMode);
  60 + ServerSecurityConfig result = getServerSecurityConfig(bootstrapServer ? bootstrapConfig : serverConfig, lwM2MSecurityMode);
  61 + result.setBootstrapServerIs(bootstrapServer);
  62 + return result;
65 63 }
66 64
67   - /**
68   - * @param bootstrapServerIs
69   - * @param mode
70   - * @return ServerSecurityConfig more value is default: Important - port, host, publicKey
71   - */
72   - private ServerSecurityConfig getBootstrapServer(boolean bootstrapServerIs, LwM2MSecurityMode mode) {
  65 + private ServerSecurityConfig getServerSecurityConfig(LwM2MSecureServerConfig serverConfig, LwM2MSecurityMode mode) {
73 66 ServerSecurityConfig bsServ = new ServerSecurityConfig();
74   - bsServ.setBootstrapServerIs(bootstrapServerIs);
75   - if (bootstrapServerIs) {
76   - bsServ.setServerId(contextBootStrap.getBootstrapServerId());
77   - switch (mode) {
78   - case NO_SEC:
79   - bsServ.setHost(contextBootStrap.getBootstrapHost());
80   - bsServ.setPort(contextBootStrap.getBootstrapPortNoSec());
81   - bsServ.setServerPublicKey("");
82   - break;
83   - case PSK:
84   - bsServ.setHost(contextBootStrap.getBootstrapHostSecurity());
85   - bsServ.setPort(contextBootStrap.getBootstrapPortSecurity());
86   - bsServ.setServerPublicKey("");
87   - break;
88   - case RPK:
89   - case X509:
90   - bsServ.setHost(contextBootStrap.getBootstrapHostSecurity());
91   - bsServ.setPort(contextBootStrap.getBootstrapPortSecurity());
92   - bsServ.setServerPublicKey(getPublicKey (contextBootStrap.getBootstrapAlias(), this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY()));
93   - break;
94   - default:
95   - break;
96   - }
97   - } else {
98   - bsServ.setServerId(contextServer.getServerId());
99   - switch (mode) {
100   - case NO_SEC:
101   - bsServ.setHost(contextServer.getServerHost());
102   - bsServ.setPort(contextServer.getServerPortNoSec());
103   - bsServ.setServerPublicKey("");
104   - break;
105   - case PSK:
106   - bsServ.setHost(contextServer.getServerHostSecurity());
107   - bsServ.setPort(contextServer.getServerPortSecurity());
108   - bsServ.setServerPublicKey("");
109   - break;
110   - case RPK:
111   - case X509:
112   - bsServ.setHost(contextServer.getServerHostSecurity());
113   - bsServ.setPort(contextServer.getServerPortSecurity());
114   - bsServ.setServerPublicKey(getPublicKey (contextServer.getServerAlias(), this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY()));
115   - break;
116   - default:
117   - break;
118   - }
  67 + bsServ.setServerId(serverConfig.getId());
  68 + switch (mode) {
  69 + case NO_SEC:
  70 + bsServ.setHost(serverConfig.getHost());
  71 + bsServ.setPort(serverConfig.getPort());
  72 + bsServ.setServerPublicKey("");
  73 + break;
  74 + case PSK:
  75 + bsServ.setHost(serverConfig.getSecureHost());
  76 + bsServ.setPort(serverConfig.getSecurePort());
  77 + bsServ.setServerPublicKey("");
  78 + break;
  79 + case RPK:
  80 + case X509:
  81 + bsServ.setHost(serverConfig.getSecureHost());
  82 + bsServ.setPort(serverConfig.getSecurePort());
  83 + bsServ.setServerPublicKey(getPublicKey(serverConfig.getCertificateAlias(), this.serverConfig.getPublicX(), this.serverConfig.getPublicY()));
  84 + break;
  85 + default:
  86 + break;
119 87 }
120 88 return bsServ;
121 89 }
122 90
123   - private String getPublicKey (String alias, String publicServerX, String publicServerY) {
  91 + private String getPublicKey(String alias, String publicServerX, String publicServerY) {
124 92 String publicKey = getServerPublicKeyX509(alias);
125 93 return publicKey != null ? publicKey : getRPKPublicKey(publicServerX, publicServerY);
126 94 }
127 95
128   - /**
129   - * @param alias
130   - * @return PublicKey format HexString or null
131   - */
132 96 private String getServerPublicKeyX509(String alias) {
133 97 try {
134   - X509Certificate serverCertificate = (X509Certificate) contextServer.getKeyStoreValue().getCertificate(alias);
  98 + X509Certificate serverCertificate = (X509Certificate) serverConfig.getKeyStoreValue().getCertificate(alias);
135 99 return Hex.encodeHexString(serverCertificate.getEncoded());
136 100 } catch (CertificateEncodingException | KeyStoreException e) {
137 101 e.printStackTrace();
... ... @@ -139,11 +103,6 @@ public class LwM2MModelsRepository {
139 103 return null;
140 104 }
141 105
142   - /**
143   - * @param publicServerX
144   - * @param publicServerY
145   - * @return PublicKey format HexString or null
146   - */
147 106 private String getRPKPublicKey(String publicServerX, String publicServerY) {
148 107 try {
149 108 /** Get Elliptic Curve Parameter spec for secp256r1 */
... ...
... ... @@ -185,7 +185,7 @@ public class DefaultTbResourceService implements TbResourceService {
185 185 instance.setId(0);
186 186 List<LwM2mResourceObserve> resources = new ArrayList<>();
187 187 obj.resources.forEach((k, v) -> {
188   - if (!v.operations.isExecutable()) {
  188 + if (v.operations.isReadable()) {
189 189 LwM2mResourceObserve lwM2MResourceObserve = new LwM2mResourceObserve(k, v.name, false, false, false);
190 190 resources.add(lwM2MResourceObserve);
191 191 }
... ...
... ... @@ -41,6 +41,8 @@ import org.thingsboard.server.common.data.TenantProfile;
41 41 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
42 42 import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData;
43 43 import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials;
  44 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  45 +import org.thingsboard.server.common.data.firmware.FirmwareUtil;
44 46 import org.thingsboard.server.common.data.id.CustomerId;
45 47 import org.thingsboard.server.common.data.id.DeviceId;
46 48 import org.thingsboard.server.common.data.id.DeviceProfileId;
... ... @@ -512,16 +514,17 @@ public class DefaultTransportApiService implements TransportApiService {
512 514 private ListenableFuture<TransportApiResponseMsg> handle(TransportProtos.GetFirmwareRequestMsg requestMsg) {
513 515 TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB()));
514 516 DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB()));
  517 + FirmwareType firmwareType = FirmwareType.valueOf(requestMsg.getType());
515 518 Device device = deviceService.findDeviceById(tenantId, deviceId);
516 519
517 520 if (device == null) {
518 521 return getEmptyTransportApiResponseFuture();
519 522 }
520 523
521   - FirmwareId firmwareId = device.getFirmwareId();
522   -
  524 + FirmwareId firmwareId = FirmwareUtil.getFirmwareId(device, firmwareType);
523 525 if (firmwareId == null) {
524   - firmwareId = deviceProfileCache.find(device.getDeviceProfileId()).getFirmwareId();
  526 + DeviceProfile deviceProfile = deviceProfileCache.find(device.getDeviceProfileId());
  527 + firmwareId = FirmwareUtil.getFirmwareId(deviceProfile, firmwareType);
525 528 }
526 529
527 530 TransportProtos.GetFirmwareResponseMsg.Builder builder = TransportProtos.GetFirmwareResponseMsg.newBuilder();
... ... @@ -537,6 +540,7 @@ public class DefaultTransportApiService implements TransportApiService {
537 540 builder.setResponseStatus(TransportProtos.ResponseStatus.SUCCESS);
538 541 builder.setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits());
539 542 builder.setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits());
  543 + builder.setType(firmwareInfo.getType().name());
540 544 builder.setTitle(firmwareInfo.getTitle());
541 545 builder.setVersion(firmwareInfo.getVersion());
542 546 builder.setFileName(firmwareInfo.getFileName());
... ...
... ... @@ -630,38 +630,14 @@ transport:
630 630 lwm2m:
631 631 # Enable/disable lvm2m transport protocol.
632 632 enabled: "${LWM2M_ENABLED:true}"
633   - # We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to
634   - # send a Confirmable message to the time when an acknowledgement is no longer expected.
635   - # DEFAULT_TIMEOUT = 2 * 60 * 1000l; 2 min in ms
636   - timeout: "${LWM2M_TIMEOUT:120000}"
637   - recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
638   - recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
639   - response_pool_size: "${LWM2M_RESPONSE_POOL_SIZE:100}"
640   - registered_pool_size: "${LWM2M_REGISTERED_POOL_SIZE:10}"
641   - update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}"
642   - un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}"
643   - secure:
644   - # Certificate_x509:
645   - # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format
646   - # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh
647   - key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}"
648   - # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks"
649   - key_store_path_file: "${KEY_STORE_PATH_FILE:}"
650   - key_store_password: "${LWM2M_KEYSTORE_PASSWORD_SERVER:server_ks_password}"
651   - root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}"
652   - enable_gen_new_key_psk_rpk: "${ENABLE_GEN_NEW_KEY_PSK_RPK:false}"
653 633 server:
654 634 id: "${LWM2M_SERVER_ID:123}"
655 635 bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}"
656   - bind_port_no_sec: "${LWM2M_BIND_PORT_NO_SEC:5685}"
657   - secure:
658   - bind_address_security: "${LWM2M_BIND_ADDRESS_SECURITY:0.0.0.0}"
659   - bind_port_security: "${LWM2M_BIND_PORT_SECURITY:5686}"
660   - # create_rpk: "${CREATE_RPK:}"
  636 + bind_port: "${LWM2M_BIND_PORT:5685}"
  637 + security:
  638 + bind_address: "${LWM2M_BIND_ADDRESS_SECURITY:0.0.0.0}"
  639 + bind_port: "${LWM2M_BIND_PORT_SECURITY:5686}"
661 640 # Only for RPK: Public & Private Key. If the keystore file is missing or not working
662   - # - Public Key (Hex): [3059301306072a8648ce3d020106082a8648ce3d0301070342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b]
663   - # - Private Key (Hex): [308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420dc774b309e547ceb48fee547e104ce201a9c48c449dc5414cd04e7f5cf05f67ba00a06082a8648ce3d030107a1440342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b],
664   - # - Elliptic Curve parameters : [secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)]
665 641 public_x: "${LWM2M_SERVER_PUBLIC_X:05064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f358}"
666 642 public_y: "${LWM2M_SERVER_PUBLIC_Y:5eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}"
667 643 private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED:308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420dc774b309e547ceb48fee547e104ce201a9c48c449dc5414cd04e7f5cf05f67ba00a06082a8648ce3d030107a1440342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}"
... ... @@ -671,19 +647,34 @@ transport:
671 647 enable: "${LWM2M_ENABLED_BS:true}"
672 648 id: "${LWM2M_SERVER_ID_BS:111}"
673 649 bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"
674   - bind_port_no_sec: "${LWM2M_BIND_PORT_NO_SEC_BS:5687}"
675   - secure:
676   - bind_address_security: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"
677   - bind_port_security: "${LWM2M_BIND_PORT_SECURITY_BS:5688}"
  650 + bind_port: "${LWM2M_BIND_PORT_BS:5687}"
  651 + security:
  652 + bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"
  653 + bind_port: "${LWM2M_BIND_PORT_SECURITY_BS:5688}"
678 654 # Only for RPK: Public & Private Key. If the keystore file is missing or not working
679   - # - Elliptic Curve parameters : [secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)]
680   - # - Public Key (Hex): [3059301306072a8648ce3d020106082a8648ce3d030107034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34]
681   - # - Private Key (Hex): [308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104205ecafd90caa7be45c42e1f3f32571632b8409e6e6249d7124f4ba56fab3c8083a00a06082a8648ce3d030107a144034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34],
682 655 public_x: "${LWM2M_SERVER_PUBLIC_X_BS:5017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f91}"
683 656 public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:3fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}"
684 657 private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED_BS:308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104205ecafd90caa7be45c42e1f3f32571632b8409e6e6249d7124f4ba56fab3c8083a00a06082a8648ce3d030107a144034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}"
685 658 # Only Certificate_x509:
686 659 alias: "${LWM2M_KEYSTORE_ALIAS_BS:bootstrap}"
  660 + security:
  661 + # Certificate_x509:
  662 + # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format
  663 + # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh
  664 + key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}"
  665 + # key_store_path_file: "${KEY_STORE_PATH_FILE:/common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks"
  666 + key_store: "${LWM2M_KEY_STORE:lwm2mserver.jks}"
  667 + key_store_password: "${LWM2M_KEY_STORE_PASSWORD:server_ks_password}"
  668 + root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}"
  669 + enable_gen_new_key_psk_rpk: "${ENABLE_GEN_NEW_KEY_PSK_RPK:false}"
  670 + timeout: "${LWM2M_TIMEOUT:120000}"
  671 + recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}"
  672 + recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}"
  673 + response_pool_size: "${LWM2M_RESPONSE_POOL_SIZE:100}"
  674 + registered_pool_size: "${LWM2M_REGISTERED_POOL_SIZE:10}"
  675 + update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}"
  676 + un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}"
  677 + log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}"
687 678 # Use redis for Security and Registration stores
688 679 redis.enabled: "${LWM2M_REDIS_ENABLED:false}"
689 680 snmp:
... ...
... ... @@ -24,10 +24,13 @@ import org.springframework.mock.web.MockMultipartFile;
24 24 import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder;
25 25 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
26 26 import org.thingsboard.common.util.JacksonUtil;
  27 +import org.thingsboard.server.common.data.DeviceProfile;
27 28 import org.thingsboard.server.common.data.Firmware;
28 29 import org.thingsboard.server.common.data.FirmwareInfo;
29 30 import org.thingsboard.server.common.data.Tenant;
30 31 import org.thingsboard.server.common.data.User;
  32 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  33 +import org.thingsboard.server.common.data.id.DeviceProfileId;
31 34 import org.thingsboard.server.common.data.page.PageData;
32 35 import org.thingsboard.server.common.data.page.PageLink;
33 36 import org.thingsboard.server.common.data.security.Authority;
... ... @@ -38,6 +41,7 @@ import java.util.Collections;
38 41 import java.util.List;
39 42
40 43 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  44 +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
41 45
42 46 public abstract class BaseFirmwareControllerTest extends AbstractControllerTest {
43 47
... ... @@ -53,6 +57,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
53 57
54 58 private Tenant savedTenant;
55 59 private User tenantAdmin;
  60 + private DeviceProfileId deviceProfileId;
56 61
57 62 @Before
58 63 public void beforeTest() throws Exception {
... ... @@ -71,6 +76,11 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
71 76 tenantAdmin.setLastName("Downs");
72 77
73 78 tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
  79 +
  80 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
  81 + DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
  82 + Assert.assertNotNull(savedDeviceProfile);
  83 + deviceProfileId = savedDeviceProfile.getId();
74 84 }
75 85
76 86 @After
... ... @@ -84,6 +94,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
84 94 @Test
85 95 public void testSaveFirmware() throws Exception {
86 96 FirmwareInfo firmwareInfo = new FirmwareInfo();
  97 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  98 + firmwareInfo.setType(FIRMWARE);
87 99 firmwareInfo.setTitle(TITLE);
88 100 firmwareInfo.setVersion(VERSION);
89 101
... ... @@ -107,6 +119,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
107 119 @Test
108 120 public void testSaveFirmwareData() throws Exception {
109 121 FirmwareInfo firmwareInfo = new FirmwareInfo();
  122 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  123 + firmwareInfo.setType(FIRMWARE);
110 124 firmwareInfo.setTitle(TITLE);
111 125 firmwareInfo.setVersion(VERSION);
112 126
... ... @@ -137,6 +151,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
137 151 @Test
138 152 public void testUpdateFirmwareFromDifferentTenant() throws Exception {
139 153 FirmwareInfo firmwareInfo = new FirmwareInfo();
  154 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  155 + firmwareInfo.setType(FIRMWARE);
140 156 firmwareInfo.setTitle(TITLE);
141 157 firmwareInfo.setVersion(VERSION);
142 158
... ... @@ -150,6 +166,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
150 166 @Test
151 167 public void testFindFirmwareInfoById() throws Exception {
152 168 FirmwareInfo firmwareInfo = new FirmwareInfo();
  169 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  170 + firmwareInfo.setType(FIRMWARE);
153 171 firmwareInfo.setTitle(TITLE);
154 172 firmwareInfo.setVersion(VERSION);
155 173
... ... @@ -163,6 +181,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
163 181 @Test
164 182 public void testFindFirmwareById() throws Exception {
165 183 FirmwareInfo firmwareInfo = new FirmwareInfo();
  184 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  185 + firmwareInfo.setType(FIRMWARE);
166 186 firmwareInfo.setTitle(TITLE);
167 187 firmwareInfo.setVersion(VERSION);
168 188
... ... @@ -180,6 +200,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
180 200 @Test
181 201 public void testDeleteFirmware() throws Exception {
182 202 FirmwareInfo firmwareInfo = new FirmwareInfo();
  203 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  204 + firmwareInfo.setType(FIRMWARE);
183 205 firmwareInfo.setTitle(TITLE);
184 206 firmwareInfo.setVersion(VERSION);
185 207
... ... @@ -197,6 +219,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
197 219 List<FirmwareInfo> firmwares = new ArrayList<>();
198 220 for (int i = 0; i < 165; i++) {
199 221 FirmwareInfo firmwareInfo = new FirmwareInfo();
  222 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  223 + firmwareInfo.setType(FIRMWARE);
200 224 firmwareInfo.setTitle(TITLE);
201 225 firmwareInfo.setVersion(VERSION + i);
202 226
... ... @@ -238,6 +262,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
238 262
239 263 for (int i = 0; i < 165; i++) {
240 264 FirmwareInfo firmwareInfo = new FirmwareInfo();
  265 + firmwareInfo.setDeviceProfileId(deviceProfileId);
  266 + firmwareInfo.setType(FIRMWARE);
241 267 firmwareInfo.setTitle(TITLE);
242 268 firmwareInfo.setVersion(VERSION + i);
243 269
... ... @@ -257,7 +283,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
257 283 PageLink pageLink = new PageLink(24);
258 284 PageData<FirmwareInfo> pageData;
259 285 do {
260   - pageData = doGetTypedWithPageLink("/api/firmwares/true?",
  286 + pageData = doGetTypedWithPageLink("/api/firmwares/" + deviceProfileId.toString() + "/FIRMWARE/true?",
261 287 new TypeReference<>() {
262 288 }, pageLink);
263 289 loadedFirmwaresWithData.addAll(pageData.getData());
... ... @@ -269,7 +295,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
269 295 List<FirmwareInfo> loadedFirmwaresWithoutData = new ArrayList<>();
270 296 pageLink = new PageLink(24);
271 297 do {
272   - pageData = doGetTypedWithPageLink("/api/firmwares/false?",
  298 + pageData = doGetTypedWithPageLink("/api/firmwares/" + deviceProfileId.toString() + "/FIRMWARE/false?",
273 299 new TypeReference<>() {
274 300 }, pageLink);
275 301 loadedFirmwaresWithoutData.addAll(pageData.getData());
... ...
... ... @@ -65,6 +65,8 @@ public interface DeviceService {
65 65
66 66 PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink);
67 67
  68 + PageData<Device> findDevicesByTenantIdAndTypeAndEmptySoftware(TenantId tenantId, String type, PageLink pageLink);
  69 +
68 70 PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink);
69 71
70 72 PageData<DeviceInfo> findDeviceInfosByTenantIdAndDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId, PageLink pageLink);
... ...
... ... @@ -18,6 +18,8 @@ package org.thingsboard.server.dao.firmware;
18 18 import com.google.common.util.concurrent.ListenableFuture;
19 19 import org.thingsboard.server.common.data.Firmware;
20 20 import org.thingsboard.server.common.data.FirmwareInfo;
  21 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  22 +import org.thingsboard.server.common.data.id.DeviceProfileId;
21 23 import org.thingsboard.server.common.data.id.FirmwareId;
22 24 import org.thingsboard.server.common.data.id.TenantId;
23 25 import org.thingsboard.server.common.data.page.PageData;
... ... @@ -37,7 +39,7 @@ public interface FirmwareService {
37 39
38 40 PageData<FirmwareInfo> findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink);
39 41
40   - PageData<FirmwareInfo> findTenantFirmwaresByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink);
  42 + PageData<FirmwareInfo> findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink);
41 43
42 44 void deleteFirmware(TenantId tenantId, FirmwareId firmwareId);
43 45
... ...
... ... @@ -93,22 +93,26 @@ public class DataConstants {
93 93 public static final String USERNAME = "username";
94 94 public static final String PASSWORD = "password";
95 95
96   - //firmware
97   - //telemetry
98   - public static final String CURRENT_FIRMWARE_TITLE = "cur_fw_title";
99   - public static final String CURRENT_FIRMWARE_VERSION = "cur_fw_version";
100   - public static final String TARGET_FIRMWARE_TITLE = "target_fw_title";
101   - public static final String TARGET_FIRMWARE_VERSION = "target_fw_version";
102   - public static final String TARGET_FIRMWARE_TS = "target_fw_ts";
103   - public static final String FIRMWARE_STATE = "fw_state";
104   -
105   - //attributes
106   - //telemetry
107   - public static final String FIRMWARE_TITLE = "fw_title";
108   - public static final String FIRMWARE_VERSION = "fw_version";
109   - public static final String FIRMWARE_SIZE = "fw_size";
110   - public static final String FIRMWARE_CHECKSUM = "fw_checksum";
111   - public static final String FIRMWARE_CHECKSUM_ALGORITHM = "fw_checksum_algorithm";
  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
112 115 public static final String EDGE_MSG_SOURCE = "edge";
113 116 public static final String MSG_SOURCE_KEY = "source";
  117 +
114 118 }
... ...
... ... @@ -32,7 +32,7 @@ import java.io.IOException;
32 32
33 33 @EqualsAndHashCode(callSuper = true)
34 34 @Slf4j
35   -public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implements HasName, HasTenantId, HasCustomerId {
  35 +public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implements HasName, HasTenantId, HasCustomerId, HasFirmware {
36 36
37 37 private static final long serialVersionUID = 2807343040519543363L;
38 38
... ... @@ -50,6 +50,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
50 50 private byte[] deviceDataBytes;
51 51
52 52 private FirmwareId firmwareId;
  53 + private FirmwareId softwareId;
53 54
54 55 public Device() {
55 56 super();
... ... @@ -69,6 +70,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
69 70 this.deviceProfileId = device.getDeviceProfileId();
70 71 this.setDeviceData(device.getDeviceData());
71 72 this.firmwareId = device.getFirmwareId();
  73 + this.softwareId = device.getSoftwareId();
72 74 }
73 75
74 76 public Device updateDevice(Device device) {
... ... @@ -79,6 +81,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
79 81 this.label = device.getLabel();
80 82 this.deviceProfileId = device.getDeviceProfileId();
81 83 this.setDeviceData(device.getDeviceData());
  84 + this.setFirmwareId(device.getFirmwareId());
  85 + this.setSoftwareId(device.getSoftwareId());
82 86 return this;
83 87 }
84 88
... ... @@ -171,6 +175,14 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
171 175 this.firmwareId = firmwareId;
172 176 }
173 177
  178 + public FirmwareId getSoftwareId() {
  179 + return softwareId;
  180 + }
  181 +
  182 + public void setSoftwareId(FirmwareId softwareId) {
  183 + this.softwareId = softwareId;
  184 + }
  185 +
174 186 @Override
175 187 public String toString() {
176 188 StringBuilder builder = new StringBuilder();
... ...
... ... @@ -36,7 +36,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn
36 36 @Data
37 37 @EqualsAndHashCode(callSuper = true)
38 38 @Slf4j
39   -public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId {
  39 +public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId, HasFirmware {
40 40
41 41 private TenantId tenantId;
42 42 @NoXss
... ... @@ -59,6 +59,8 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
59 59
60 60 private FirmwareId firmwareId;
61 61
  62 + private FirmwareId softwareId;
  63 +
62 64 public DeviceProfile() {
63 65 super();
64 66 }
... ... @@ -77,6 +79,8 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
77 79 this.defaultQueueName = deviceProfile.getDefaultQueueName();
78 80 this.setProfileData(deviceProfile.getProfileData());
79 81 this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey();
  82 + this.firmwareId = deviceProfile.getFirmwareId();
  83 + this.softwareId = deviceProfile.getSoftwareId();
80 84 }
81 85
82 86 @Override
... ...
... ... @@ -19,6 +19,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
19 19 import lombok.Data;
20 20 import lombok.EqualsAndHashCode;
21 21 import lombok.extern.slf4j.Slf4j;
  22 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  23 +import org.thingsboard.server.common.data.id.DeviceProfileId;
22 24 import org.thingsboard.server.common.data.id.FirmwareId;
23 25 import org.thingsboard.server.common.data.id.TenantId;
24 26
... ... @@ -30,6 +32,8 @@ public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo<FirmwareId>
30 32 private static final long serialVersionUID = 3168391583570815419L;
31 33
32 34 private TenantId tenantId;
  35 + private DeviceProfileId deviceProfileId;
  36 + private FirmwareType type;
33 37 private String title;
34 38 private String version;
35 39 private boolean hasData;
... ... @@ -51,6 +55,8 @@ public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo<FirmwareId>
51 55 public FirmwareInfo(FirmwareInfo firmwareInfo) {
52 56 super(firmwareInfo);
53 57 this.tenantId = firmwareInfo.getTenantId();
  58 + this.deviceProfileId = firmwareInfo.getDeviceProfileId();
  59 + this.type = firmwareInfo.getType();
54 60 this.title = firmwareInfo.getTitle();
55 61 this.version = firmwareInfo.getVersion();
56 62 this.hasData = firmwareInfo.isHasData();
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data;
  17 +
  18 +import org.thingsboard.server.common.data.id.FirmwareId;
  19 +
  20 +public interface HasFirmware {
  21 +
  22 + FirmwareId getFirmwareId();
  23 +
  24 + FirmwareId getSoftwareId();
  25 +}
... ...
... ... @@ -31,6 +31,7 @@ public class MqttTopics {
31 31 private static final String SUB_TOPIC = "+";
32 32 private static final String PROVISION = "/provision";
33 33 private static final String FIRMWARE = "/fw";
  34 + private static final String SOFTWARE = "/sw";
34 35 private static final String CHUNK = "/chunk/";
35 36 private static final String ERROR = "/error";
36 37
... ... @@ -75,9 +76,17 @@ public class MqttTopics {
75 76 // v2 topics
76 77 public static final String BASE_DEVICE_API_TOPIC_V2 = "v2";
77 78
78   - public static final String DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + RESPONSE + "/";
79   - public static final String DEVICE_FIRMWARE_RESPONSES_TOPIC = DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX + SUB_TOPIC + CHUNK + SUB_TOPIC;
  79 + public static final String REQUEST_ID_PATTERN = "(?<requestId>\\d+)";
  80 + public static final String CHUNK_PATTERN = "(?<chunk>\\d+)";
  81 +
  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;
80 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";
  86 +
  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;
  89 + public static final String DEVICE_SOFTWARE_ERROR_TOPIC = BASE_DEVICE_API_TOPIC_V2 + SOFTWARE + ERROR;
81 90
82 91 private MqttTopics() {
83 92 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.firmware;
  17 +
  18 +import lombok.Getter;
  19 +
  20 +public enum FirmwareKey {
  21 +
  22 + TITLE("title"), VERSION("version"), TS("ts"), STATE("state"), SIZE("size"), CHECKSUM("checksum"), CHECKSUM_ALGORITHM("checksum_algorithm");
  23 +
  24 + @Getter
  25 + private final String value;
  26 +
  27 + FirmwareKey(String value) {
  28 + this.value = value;
  29 + }
  30 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.firmware;
  17 +
  18 +import lombok.Getter;
  19 +
  20 +public enum FirmwareType {
  21 +
  22 + FIRMWARE("fw"), SOFTWARE("sw");
  23 +
  24 + @Getter
  25 + private final String keyPrefix;
  26 +
  27 + FirmwareType(String keyPrefix) {
  28 + this.keyPrefix = keyPrefix;
  29 + }
  30 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.firmware;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.server.common.data.HasFirmware;
  20 +import org.thingsboard.server.common.data.id.FirmwareId;
  21 +
  22 +import java.util.ArrayList;
  23 +import java.util.Collections;
  24 +import java.util.List;
  25 +
  26 +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
  27 +import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;
  28 +
  29 +@Slf4j
  30 +public class FirmwareUtil {
  31 +
  32 + public static final List<String> ALL_FW_ATTRIBUTE_KEYS;
  33 +
  34 + public static final List<String> ALL_SW_ATTRIBUTE_KEYS;
  35 +
  36 + static {
  37 + ALL_FW_ATTRIBUTE_KEYS = new ArrayList<>();
  38 + for (FirmwareKey key : FirmwareKey.values()) {
  39 + ALL_FW_ATTRIBUTE_KEYS.add(getAttributeKey(FIRMWARE, key));
  40 +
  41 + }
  42 +
  43 + ALL_SW_ATTRIBUTE_KEYS = new ArrayList<>();
  44 + for (FirmwareKey key : FirmwareKey.values()) {
  45 + ALL_SW_ATTRIBUTE_KEYS.add(getAttributeKey(SOFTWARE, key));
  46 +
  47 + }
  48 + }
  49 +
  50 + public static List<String> getAttributeKeys(FirmwareType firmwareType) {
  51 + switch (firmwareType) {
  52 + case FIRMWARE:
  53 + return ALL_FW_ATTRIBUTE_KEYS;
  54 + case SOFTWARE:
  55 + return ALL_SW_ATTRIBUTE_KEYS;
  56 + }
  57 + return Collections.emptyList();
  58 + }
  59 +
  60 + public static String getAttributeKey(FirmwareType type, FirmwareKey key) {
  61 + return type.getKeyPrefix() + "_" + key.getValue();
  62 + }
  63 +
  64 + public static String getTargetTelemetryKey(FirmwareType type, FirmwareKey key) {
  65 + return getTelemetryKey("target_", type, key);
  66 + }
  67 +
  68 + public static String getCurrentTelemetryKey(FirmwareType type, FirmwareKey key) {
  69 + return getTelemetryKey("current_", type, key);
  70 + }
  71 +
  72 + private static String getTelemetryKey(String prefix, FirmwareType type, FirmwareKey key) {
  73 + return prefix + type.getKeyPrefix() + "_" + key.getValue();
  74 + }
  75 +
  76 + public static String getTelemetryKey(FirmwareType type, FirmwareKey key) {
  77 + return type.getKeyPrefix() + "_" + key.getValue();
  78 + }
  79 +
  80 + public static FirmwareId getFirmwareId(HasFirmware entity, FirmwareType firmwareType) {
  81 + switch (firmwareType) {
  82 + case FIRMWARE:
  83 + return entity.getFirmwareId();
  84 + case SOFTWARE:
  85 + return entity.getSoftwareId();
  86 + default:
  87 + log.warn("Unsupported firmware type: [{}]", firmwareType);
  88 + return null;
  89 + }
  90 + }
  91 +}
... ...
... ... @@ -16,5 +16,5 @@
16 16 package org.thingsboard.server.common.msg.session;
17 17
18 18 public enum FeatureType {
19   - ATTRIBUTES, TELEMETRY, RPC, CLAIM, PROVISION, FIRMWARE
  19 + ATTRIBUTES, TELEMETRY, RPC, CLAIM, PROVISION, FIRMWARE, SOFTWARE
20 20 }
... ...
... ... @@ -32,7 +32,8 @@ public enum SessionMsgType {
32 32
33 33 CLAIM_REQUEST(),
34 34
35   - GET_FIRMWARE_REQUEST;
  35 + GET_FIRMWARE_REQUEST,
  36 + GET_SOFTWARE_REQUEST;
36 37
37 38 private final boolean requiresRulesProcessing;
38 39
... ...
... ... @@ -388,16 +388,18 @@ message GetFirmwareRequestMsg {
388 388 int64 deviceIdLSB = 2;
389 389 int64 tenantIdMSB = 3;
390 390 int64 tenantIdLSB = 4;
  391 + string type = 5;
391 392 }
392 393
393 394 message GetFirmwareResponseMsg {
394 395 ResponseStatus responseStatus = 1;
395 396 int64 firmwareIdMSB = 2;
396 397 int64 firmwareIdLSB = 3;
397   - string title = 4;
398   - string version = 5;
399   - string contentType = 6;
400   - string fileName = 7;
  398 + string type = 4;
  399 + string title = 5;
  400 + string version = 6;
  401 + string contentType = 7;
  402 + string fileName = 8;
401 403 }
402 404
403 405 //Used to report session state to tb-Service and persist this state in the cache on the tb-Service level.
... ... @@ -711,4 +713,5 @@ message ToFirmwareStateServiceMsg {
711 713 int64 deviceIdLSB = 5;
712 714 int64 firmwareIdMSB = 6;
713 715 int64 firmwareIdLSB = 7;
  716 + string type = 8;
714 717 }
... ...
... ... @@ -43,6 +43,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC
43 43 import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
44 44 import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
45 45 import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  46 +import org.thingsboard.server.common.data.firmware.FirmwareType;
46 47 import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
47 48 import org.thingsboard.server.common.msg.session.FeatureType;
48 49 import org.thingsboard.server.common.msg.session.SessionMsgType;
... ... @@ -122,6 +123,8 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
122 123 processRequest(exchange, SessionMsgType.GET_ATTRIBUTES_REQUEST);
123 124 } else if (featureType.get() == FeatureType.FIRMWARE) {
124 125 processRequest(exchange, SessionMsgType.GET_FIRMWARE_REQUEST);
  126 + } else if (featureType.get() == FeatureType.SOFTWARE) {
  127 + processRequest(exchange, SessionMsgType.GET_SOFTWARE_REQUEST);
125 128 } else {
126 129 log.trace("Invalid feature type parameter");
127 130 exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
... ... @@ -326,12 +329,10 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
326 329 new CoapNoOpCallback(exchange));
327 330 break;
328 331 case GET_FIRMWARE_REQUEST:
329   - TransportProtos.GetFirmwareRequestMsg requestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
330   - .setTenantIdMSB(sessionInfo.getTenantIdMSB())
331   - .setTenantIdLSB(sessionInfo.getTenantIdLSB())
332   - .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
333   - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB()).build();
334   - transportContext.getTransportService().process(sessionInfo, requestMsg, new FirmwareCallback(exchange));
  332 + getFirmwareCallback(sessionInfo, exchange, FirmwareType.FIRMWARE);
  333 + break;
  334 + case GET_SOFTWARE_REQUEST:
  335 + getFirmwareCallback(sessionInfo, exchange, FirmwareType.SOFTWARE);
335 336 break;
336 337 }
337 338 } catch (AdaptorException e) {
... ... @@ -340,6 +341,16 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
340 341 }
341 342 }
342 343
  344 + private void getFirmwareCallback(TransportProtos.SessionInfoProto sessionInfo, CoapExchange exchange, FirmwareType firmwareType) {
  345 + TransportProtos.GetFirmwareRequestMsg requestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
  346 + .setTenantIdMSB(sessionInfo.getTenantIdMSB())
  347 + .setTenantIdLSB(sessionInfo.getTenantIdLSB())
  348 + .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
  349 + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
  350 + .setType(firmwareType.name()).build();
  351 + transportContext.getTransportService().process(sessionInfo, requestMsg, new FirmwareCallback(exchange));
  352 + }
  353 +
343 354 private TransportProtos.SessionInfoProto lookupAsyncSessionInfo(String token) {
344 355 tokenToNotificationCounterMap.remove(token);
345 356 return tokenToSessionIdMap.remove(token);
... ...
... ... @@ -34,6 +34,7 @@ import org.springframework.web.bind.annotation.RequestParam;
34 34 import org.springframework.web.bind.annotation.RestController;
35 35 import org.springframework.web.context.request.async.DeferredResult;
36 36 import org.thingsboard.server.common.data.DeviceTransportType;
  37 +import org.thingsboard.server.common.data.firmware.FirmwareType;
37 38 import org.thingsboard.server.common.data.TbTransportService;
38 39 import org.thingsboard.server.common.data.id.DeviceId;
39 40 import org.thingsboard.server.common.transport.SessionMsgListener;
... ... @@ -210,8 +211,29 @@ public class DeviceApiController implements TbTransportService {
210 211 public DeferredResult<ResponseEntity> getFirmware(@PathVariable("deviceToken") String deviceToken,
211 212 @RequestParam(value = "title") String title,
212 213 @RequestParam(value = "version") String version,
213   - @RequestParam(value = "chunkSize", required = false, defaultValue = "0") int chunkSize,
  214 + @RequestParam(value = "size", required = false, defaultValue = "0") int size,
214 215 @RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) {
  216 + return getFirmwareCallback(deviceToken, title, version, size, chunk, FirmwareType.FIRMWARE);
  217 + }
  218 +
  219 + @RequestMapping(value = "/{deviceToken}/software", method = RequestMethod.GET)
  220 + public DeferredResult<ResponseEntity> getSoftware(@PathVariable("deviceToken") String deviceToken,
  221 + @RequestParam(value = "title") String title,
  222 + @RequestParam(value = "version") String version,
  223 + @RequestParam(value = "size", required = false, defaultValue = "0") int size,
  224 + @RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) {
  225 + return getFirmwareCallback(deviceToken, title, version, size, chunk, FirmwareType.SOFTWARE);
  226 + }
  227 +
  228 + @RequestMapping(value = "/provision", method = RequestMethod.POST)
  229 + public DeferredResult<ResponseEntity> provisionDevice(@RequestBody String json, HttpServletRequest httpRequest) {
  230 + DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
  231 + transportContext.getTransportService().process(JsonConverter.convertToProvisionRequestMsg(json),
  232 + new DeviceProvisionCallback(responseWriter));
  233 + return responseWriter;
  234 + }
  235 +
  236 + private DeferredResult<ResponseEntity> getFirmwareCallback(String deviceToken, String title, String version, int size, int chunk, FirmwareType firmwareType) {
215 237 DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
216 238 transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
217 239 new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> {
... ... @@ -219,20 +241,13 @@ public class DeviceApiController implements TbTransportService {
219 241 .setTenantIdMSB(sessionInfo.getTenantIdMSB())
220 242 .setTenantIdLSB(sessionInfo.getTenantIdLSB())
221 243 .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
222   - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB()).build();
223   - transportContext.getTransportService().process(sessionInfo, requestMsg, new GetFirmwareCallback(responseWriter, title, version, chunkSize, chunk));
  244 + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
  245 + .setType(firmwareType.name()).build();
  246 + transportContext.getTransportService().process(sessionInfo, requestMsg, new GetFirmwareCallback(responseWriter, title, version, size, chunk));
224 247 }));
225 248 return responseWriter;
226 249 }
227 250
228   - @RequestMapping(value = "/provision", method = RequestMethod.POST)
229   - public DeferredResult<ResponseEntity> provisionDevice(@RequestBody String json, HttpServletRequest httpRequest) {
230   - DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
231   - transportContext.getTransportService().process(JsonConverter.convertToProvisionRequestMsg(json),
232   - new DeviceProvisionCallback(responseWriter));
233   - return responseWriter;
234   - }
235   -
236 251 private static class DeviceAuthCallback implements TransportServiceCallback<ValidateDeviceCredentialsResponse> {
237 252 private final TransportContext transportContext;
238 253 private final DeferredResult<ResponseEntity> responseWriter;
... ...
... ... @@ -25,10 +25,13 @@ import org.springframework.beans.factory.annotation.Autowired;
25 25 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
26 26 import org.springframework.context.annotation.Bean;
27 27 import org.springframework.stereotype.Component;
  28 +import org.thingsboard.server.common.data.StringUtils;
28 29 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore;
29 30 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore;
30 31 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager;
31   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer;
  32 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig;
  33 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
  34 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
32 35
33 36 import java.math.BigInteger;
34 37 import java.security.AlgorithmParameters;
... ... @@ -55,7 +58,7 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE
55 58 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
56 59 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256;
57 60 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8;
58   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig;
  61 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig;
59 62
60 63 @Slf4j
61 64 @Component
... ... @@ -66,10 +69,10 @@ public class LwM2MTransportBootstrapServerConfiguration {
66 69 private boolean pskMode = false;
67 70
68 71 @Autowired
69   - private LwM2MTransportContextBootstrap contextBs;
  72 + private LwM2MTransportServerConfig serverConfig;
70 73
71 74 @Autowired
72   - private LwM2mTransportContextServer contextS;
  75 + private LwM2MTransportContextBootstrap contextBs;
73 76
74 77 @Autowired
75 78 private LwM2MBootstrapSecurityStore lwM2MBootstrapSecurityStore;
... ... @@ -81,19 +84,18 @@ public class LwM2MTransportBootstrapServerConfiguration {
81 84 @Bean
82 85 public LeshanBootstrapServer getLeshanBootstrapServer() {
83 86 log.info("Prepare and start BootstrapServer... PostConstruct");
84   - return this.getLhBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortNoSec(), this.contextBs.getCtxBootStrap().getBootstrapPortSecurity());
  87 + return this.getLhBootstrapServer(this.contextBs.getCtxBootStrap().getPort(), this.contextBs.getCtxBootStrap().getSecurePort());
85 88 }
86 89
87 90 public LeshanBootstrapServer getLhBootstrapServer(Integer bootstrapPortNoSec, Integer bootstrapSecurePort) {
88 91 LeshanBootstrapServerBuilder builder = new LeshanBootstrapServerBuilder();
89   - builder.setLocalAddress(this.contextBs.getCtxBootStrap().getBootstrapHost(), bootstrapPortNoSec);
90   - builder.setLocalSecureAddress(this.contextBs.getCtxBootStrap().getBootstrapHostSecurity(), bootstrapSecurePort);
  92 + builder.setLocalAddress(this.contextBs.getCtxBootStrap().getHost(), bootstrapPortNoSec);
  93 + builder.setLocalSecureAddress(this.contextBs.getCtxBootStrap().getSecureHost(), bootstrapSecurePort);
91 94
92 95 /** Create CoAP Config */
93 96 builder.setCoapConfig(getCoapConfig(bootstrapPortNoSec, bootstrapSecurePort));
94 97
95 98 /** Define model provider (Create Models )*/
96   -// builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValueCommon()));
97 99
98 100 /** Create credentials */
99 101 this.setServerWithCredentials(builder);
... ... @@ -107,14 +109,13 @@ public class LwM2MTransportBootstrapServerConfiguration {
107 109
108 110 /** Create and Set DTLS Config */
109 111 DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
110   - dtlsConfig.setRecommendedSupportedGroupsOnly(this.contextS.getLwM2MTransportConfigServer().isRecommendedSupportedGroups());
111   - dtlsConfig.setRecommendedCipherSuitesOnly(this.contextS.getLwM2MTransportConfigServer().isRecommendedCiphers());
  112 + dtlsConfig.setRecommendedSupportedGroupsOnly(serverConfig.isRecommendedSupportedGroups());
  113 + dtlsConfig.setRecommendedCipherSuitesOnly(serverConfig.isRecommendedCiphers());
112 114 if (this.pskMode) {
113 115 dtlsConfig.setSupportedCipherSuites(
114 116 TLS_PSK_WITH_AES_128_CCM_8,
115 117 TLS_PSK_WITH_AES_128_CBC_SHA256);
116   - }
117   - else {
  118 + } else {
118 119 dtlsConfig.setSupportedCipherSuites(
119 120 TLS_PSK_WITH_AES_128_CCM_8,
120 121 TLS_PSK_WITH_AES_128_CBC_SHA256,
... ... @@ -134,10 +135,10 @@ public class LwM2MTransportBootstrapServerConfiguration {
134 135
135 136 private void setServerWithCredentials(LeshanBootstrapServerBuilder builder) {
136 137 try {
137   - if (this.contextS.getLwM2MTransportConfigServer().getKeyStoreValue() != null) {
138   - KeyStore keyStoreServer = this.contextS.getLwM2MTransportConfigServer().getKeyStoreValue();
  138 + if (serverConfig.getKeyStoreValue() != null) {
  139 + KeyStore keyStoreServer = serverConfig.getKeyStoreValue();
139 140 if (this.setBuilderX509(builder)) {
140   - X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(this.contextS.getLwM2MTransportConfigServer().getRootAlias());
  141 + X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(serverConfig.getRootCertificateAlias());
141 142 if (rootCAX509Cert != null) {
142 143 X509Certificate[] trustedCertificates = new X509Certificate[1];
143 144 trustedCertificates[0] = rootCAX509Cert;
... ... @@ -168,12 +169,10 @@ public class LwM2MTransportBootstrapServerConfiguration {
168 169 * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks
169 170 */
170 171 try {
171   - X509Certificate serverCertificate = (X509Certificate) this.contextS.getLwM2MTransportConfigServer().getKeyStoreValue().getCertificate(this.contextBs.getCtxBootStrap().getBootstrapAlias());
172   - PrivateKey privateKey = (PrivateKey) this.contextS.getLwM2MTransportConfigServer().getKeyStoreValue().getKey(this.contextBs.getCtxBootStrap().getBootstrapAlias(), this.contextS.getLwM2MTransportConfigServer().getKeyStorePasswordServer() == null ? null : this.contextS.getLwM2MTransportConfigServer().getKeyStorePasswordServer().toCharArray());
  172 + X509Certificate serverCertificate = (X509Certificate) serverConfig.getKeyStoreValue().getCertificate(this.contextBs.getCtxBootStrap().getCertificateAlias());
  173 + PrivateKey privateKey = (PrivateKey) serverConfig.getKeyStoreValue().getKey(this.contextBs.getCtxBootStrap().getCertificateAlias(), serverConfig.getKeyStorePassword() == null ? null : serverConfig.getKeyStorePassword().toCharArray());
173 174 PublicKey publicKey = serverCertificate.getPublicKey();
174   - if (serverCertificate != null &&
175   - privateKey != null && privateKey.getEncoded().length > 0 &&
176   - publicKey != null && publicKey.getEncoded().length > 0) {
  175 + if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) {
177 176 builder.setPublicKey(serverCertificate.getPublicKey());
178 177 builder.setPrivateKey(privateKey);
179 178 builder.setCertificateChain(new X509Certificate[]{serverCertificate});
... ... @@ -200,10 +199,12 @@ public class LwM2MTransportBootstrapServerConfiguration {
200 199 }
201 200
202 201 private void infoPramsUri(String mode) {
203   - log.info("Bootstrap Server uses [{}]: serverNoSecureURI : [{}], serverSecureURI : [{}]",
  202 + log.info("Bootstrap Server uses [{}]: serverNoSecureURI : [{}:{}], serverSecureURI : [{}:{}]",
204 203 mode,
205   - this.contextBs.getCtxBootStrap().getBootstrapHost() + ":" + this.contextBs.getCtxBootStrap().getBootstrapPortNoSec(),
206   - this.contextBs.getCtxBootStrap().getBootstrapHostSecurity() + ":" + this.contextBs.getCtxBootStrap().getBootstrapPortSecurity());
  204 + this.contextBs.getCtxBootStrap().getHost(),
  205 + this.contextBs.getCtxBootStrap().getPort(),
  206 + this.contextBs.getCtxBootStrap().getSecureHost(),
  207 + this.contextBs.getCtxBootStrap().getSecurePort());
207 208 }
208 209
209 210
... ... @@ -237,23 +238,25 @@ public class LwM2MTransportBootstrapServerConfiguration {
237 238 AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
238 239 algoParameters.init(new ECGenParameterSpec("secp256r1"));
239 240 ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);
240   - if (this.contextBs.getCtxBootStrap().getBootstrapPublicX() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicX().isEmpty() && this.contextBs.getCtxBootStrap().getBootstrapPublicY() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicY().isEmpty()) {
  241 + LwM2MTransportBootstrapConfig serverConfig = this.contextBs.getCtxBootStrap();
  242 + if (StringUtils.isNotEmpty(serverConfig.getPublicX()) && StringUtils.isNotEmpty(serverConfig.getPublicY())) {
241 243 /** Get point values */
242   - byte[] publicX = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicX().toCharArray());
243   - byte[] publicY = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicY().toCharArray());
  244 + byte[] publicX = Hex.decodeHex(serverConfig.getPublicX().toCharArray());
  245 + byte[] publicY = Hex.decodeHex(serverConfig.getPublicY().toCharArray());
244 246 /** Create key specs */
245 247 KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),
246 248 parameterSpec);
247 249 /** Get public key */
248 250 this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);
249 251 }
250   - if (this.contextBs.getCtxBootStrap().getBootstrapPrivateEncoded() != null && !this.contextBs.getCtxBootStrap().getBootstrapPrivateEncoded().isEmpty()) {
  252 + String privateEncodedKey = serverConfig.getPrivateEncoded();
  253 + if (StringUtils.isNotEmpty(privateEncodedKey)) {
251 254 /** Get private key */
252   - byte[] privateS = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPrivateEncoded().toCharArray());
  255 + byte[] privateS = Hex.decodeHex(privateEncodedKey.toCharArray());
253 256 try {
254 257 this.privateKey = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(privateS));
255 258 } catch (InvalidKeySpecException ignore2) {
256   - log.error("Invalid Bootstrap Server rpk.PrivateKey.getEncoded () [{}}]. PrivateKey has no EC algorithm", this.contextBs.getCtxBootStrap().getBootstrapPrivateEncoded());
  259 + log.error("Invalid Bootstrap Server rpk.PrivateKey.getEncoded () [{}}]. PrivateKey has no EC algorithm", privateEncodedKey);
257 260 }
258 261 }
259 262 }
... ...
... ... @@ -34,7 +34,7 @@ import lombok.extern.slf4j.Slf4j;
34 34 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
35 35 import org.springframework.stereotype.Component;
36 36 import org.thingsboard.server.common.transport.TransportContext;
37   -import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap;
  37 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig;
38 38
39 39
40 40 @Slf4j
... ... @@ -42,13 +42,13 @@ import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstr
42 42 @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith'")
43 43 public class LwM2MTransportContextBootstrap extends TransportContext {
44 44
45   - private final LwM2MTransportConfigBootstrap lwM2MTransportConfigBootstrap;
  45 + private final LwM2MTransportBootstrapConfig lwM2MTransportBootstrapConfig;
46 46
47   - public LwM2MTransportContextBootstrap(LwM2MTransportConfigBootstrap ctxBootStrap) {
48   - this.lwM2MTransportConfigBootstrap = ctxBootStrap;
  47 + public LwM2MTransportContextBootstrap(LwM2MTransportBootstrapConfig ctxBootStrap) {
  48 + this.lwM2MTransportBootstrapConfig = ctxBootStrap;
49 49 }
50 50
51   - public LwM2MTransportConfigBootstrap getCtxBootStrap() {
52   - return this.lwM2MTransportConfigBootstrap;
  51 + public LwM2MTransportBootstrapConfig getCtxBootStrap() {
  52 + return this.lwM2MTransportBootstrapConfig;
53 53 }
54 54 }
... ...
... ... @@ -34,8 +34,9 @@ import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
34 34 import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
35 35 import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
36 36 import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener;
37   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer;
38   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler;
  37 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
  38 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
  39 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil;
39 40
40 41 import java.io.IOException;
41 42 import java.security.GeneralSecurityException;
... ... @@ -43,12 +44,12 @@ import java.util.Collections;
43 44 import java.util.List;
44 45 import java.util.UUID;
45 46
46   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.BOOTSTRAP_SERVER;
47   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR;
48   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO;
49   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LWM2M_SERVER;
50   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.SERVERS;
51   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getBootstrapParametersFromThingsboard;
  47 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.BOOTSTRAP_SERVER;
  48 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_ERROR;
  49 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_INFO;
  50 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LWM2M_SERVER;
  51 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.SERVERS;
  52 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.getBootstrapParametersFromThingsboard;
52 53
53 54 @Slf4j
54 55 @Service("LwM2MBootstrapSecurityStore")
... ... @@ -59,17 +60,19 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
59 60
60 61 private final LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator;
61 62
62   - private final LwM2mTransportContextServer context;
  63 + private final LwM2mTransportContext context;
  64 + private final LwM2mTransportServerHelper helper;
63 65
64   - public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore, LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator, LwM2mTransportContextServer context) {
  66 + public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore, LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator, LwM2mTransportContext context, LwM2mTransportServerHelper helper) {
65 67 this.bootstrapConfigStore = bootstrapConfigStore;
66 68 this.lwM2MCredentialsSecurityInfoValidator = lwM2MCredentialsSecurityInfoValidator;
67 69 this.context = context;
  70 + this.helper = helper;
68 71 }
69 72
70 73 @Override
71 74 public List<SecurityInfo> getAllByEndpoint(String endPoint) {
72   - ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(endPoint, LwM2mTransportHandler.LwM2mTypeServer.BOOTSTRAP);
  75 + ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(endPoint, LwM2mTransportHandlerUtil.LwM2mTypeServer.BOOTSTRAP);
73 76 if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
74 77 /** add value to store from BootstrapJson */
75 78 this.setBootstrapConfigScurityInfo(store);
... ... @@ -93,7 +96,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
93 96
94 97 @Override
95 98 public SecurityInfo getByIdentity(String identity) {
96   - ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, LwM2mTransportHandler.LwM2mTypeServer.BOOTSTRAP);
  99 + ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, LwM2mTransportHandlerUtil.LwM2mTypeServer.BOOTSTRAP);
97 100 if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
98 101 /** add value to store from BootstrapJson */
99 102 this.setBootstrapConfigScurityInfo(store);
... ... @@ -158,19 +161,19 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
158 161 LwM2MServerBootstrap profileServerBootstrap = mapper.readValue(bootstrapObject.get(BOOTSTRAP_SERVER).toString(), LwM2MServerBootstrap.class);
159 162 LwM2MServerBootstrap profileLwm2mServer = mapper.readValue(bootstrapObject.get(LWM2M_SERVER).toString(), LwM2MServerBootstrap.class);
160 163 UUID sessionUUiD = UUID.randomUUID();
161   - TransportProtos.SessionInfoProto sessionInfo = context.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits());
  164 + TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits());
162 165 context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, sessionInfo));
163 166 if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) {
164 167 lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);
165 168 lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);
166 169 String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndPoint());
167   - context.sendParametersOnThingsboardTelemetry(context.getKvLogyToThingsboard(logMsg), sessionInfo);
  170 + helper.sendParametersOnThingsboardTelemetry(helper.getKvLogyToThingsboard(logMsg), sessionInfo);
168 171 return lwM2MBootstrapConfig;
169 172 } else {
170 173 log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint());
171 174 log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint());
172 175 String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint());
173   - context.sendParametersOnThingsboardTelemetry(context.getKvLogyToThingsboard(logMsg), sessionInfo);
  176 + helper.sendParametersOnThingsboardTelemetry(helper.getKvLogyToThingsboard(logMsg), sessionInfo);
174 177 return null;
175 178 }
176 179 }
... ...
  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.client;
  17 +
  18 +import lombok.Data;
  19 +
  20 +import java.util.UUID;
  21 +
  22 +@Data
  23 +public class LwM2mSoftwareUpdate {
  24 + private volatile String clientSwVersion;
  25 + private volatile String currentSwVersion;
  26 + private volatile UUID currentSwId;
  27 +}
\ No newline at end of file
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.config;
  17 +
  18 +public interface LwM2MSecureServerConfig {
  19 +
  20 + Integer getId();
  21 +
  22 + String getHost();
  23 +
  24 + Integer getPort();
  25 +
  26 + String getSecureHost();
  27 +
  28 + Integer getSecurePort();
  29 +
  30 + String getPublicX();
  31 +
  32 + String getPublicY();
  33 +
  34 + String getPrivateEncoded();
  35 +
  36 + String getCertificateAlias();
  37 +
  38 +}
... ...
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportBootstrapConfig.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigBootstrap.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.transport.lwm2m;
  16 +package org.thingsboard.server.transport.lwm2m.config;
17 17
18 18 import lombok.Getter;
19 19 import lombok.Setter;
... ... @@ -29,53 +29,42 @@ import java.util.Map;
29 29 @Slf4j
30 30 @Component
31 31 @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'")
32   -public class LwM2MTransportConfigBootstrap {
33   -
34   - @Getter
35   - @Value("${transport.lwm2m.bootstrap.enable:}")
36   - private Boolean bootstrapEnable;
  32 +public class LwM2MTransportBootstrapConfig implements LwM2MSecureServerConfig {
37 33
38 34 @Getter
39 35 @Value("${transport.lwm2m.bootstrap.id:}")
40   - private Integer bootstrapServerId;
  36 + private Integer id;
41 37
42 38 @Getter
43 39 @Value("${transport.lwm2m.bootstrap.bind_address:}")
44   - private String bootstrapHost;
  40 + private String host;
45 41
46 42 @Getter
47   - @Value("${transport.lwm2m.bootstrap.bind_port_no_sec:}")
48   - private Integer bootstrapPortNoSec;
  43 + @Value("${transport.lwm2m.bootstrap.bind_port:}")
  44 + private Integer port;
49 45
50 46 @Getter
51   - @Value("${transport.lwm2m.bootstrap.secure.bind_address_security:}")
52   - private String bootstrapHostSecurity;
  47 + @Value("${transport.lwm2m.bootstrap.security.bind_address:}")
  48 + private String secureHost;
53 49
54 50 @Getter
55   - @Value("${transport.lwm2m.bootstrap.secure.bind_port_security:}")
56   - private Integer bootstrapPortSecurity;
  51 + @Value("${transport.lwm2m.bootstrap.security.bind_port:}")
  52 + private Integer securePort;
57 53
58 54 @Getter
59   - @Value("${transport.lwm2m.bootstrap.secure.public_x:}")
60   - private String bootstrapPublicX;
  55 + @Value("${transport.lwm2m.bootstrap.security.public_x:}")
  56 + private String publicX;
61 57
62 58 @Getter
63   - @Value("${transport.lwm2m.bootstrap.secure.public_y:}")
64   - private String bootstrapPublicY;
  59 + @Value("${transport.lwm2m.bootstrap.security.public_y:}")
  60 + private String publicY;
65 61
66 62 @Getter
67   - @Setter
68   - private PublicKey bootstrapPublicKey;
  63 + @Value("${transport.lwm2m.bootstrap.security.private_encoded:}")
  64 + private String privateEncoded;
69 65
70 66 @Getter
71   - @Value("${transport.lwm2m.bootstrap.secure.private_encoded:}")
72   - private String bootstrapPrivateEncoded;
  67 + @Value("${transport.lwm2m.bootstrap.security.alias:}")
  68 + private String certificateAlias;
73 69
74   - @Getter
75   - @Value("${transport.lwm2m.bootstrap.secure.alias:}")
76   - private String bootstrapAlias;
77   -
78   - @Getter
79   - @Setter
80   - private Map<String /** clientEndPoint */, TransportProtos.ValidateDeviceCredentialsResponseMsg> sessions;
81 70 }
... ...
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2MTransportServerConfig.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java
... ... @@ -13,8 +13,9 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.transport.lwm2m;
  16 +package org.thingsboard.server.transport.lwm2m.config;
17 17
  18 +import com.google.common.io.Resources;
18 19 import lombok.Getter;
19 20 import lombok.Setter;
20 21 import lombok.extern.slf4j.Slf4j;
... ... @@ -28,6 +29,7 @@ import java.io.File;
28 29 import java.io.FileInputStream;
29 30 import java.io.IOException;
30 31 import java.io.InputStream;
  32 +import java.net.URI;
31 33 import java.nio.file.Path;
32 34 import java.nio.file.Paths;
33 35 import java.security.KeyStore;
... ... @@ -38,38 +40,7 @@ import java.security.cert.CertificateException;
38 40 @Slf4j
39 41 @Component
40 42 @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'")
41   -public class LwM2MTransportConfigServer {
42   -
43   - @Getter
44   - private String KEY_STORE_DEFAULT_RESOURCE_PATH = "credentials";
45   -
46   - @Getter
47   - private String KEY_STORE_DEFAULT_FILE = "serverKeyStore.jks";
48   -
49   - @Getter
50   - private String APP_DIR = "common";
51   -
52   - @Getter
53   - private String TRANSPORT_DIR = "transport";
54   -
55   - @Getter
56   - private String LWM2M_DIR = "lwm2m";
57   -
58   - @Getter
59   - private String SRC_DIR = "src";
60   -
61   - @Getter
62   - private String MAIN_DIR = "main";
63   -
64   - @Getter
65   - private String RESOURCES_DIR = "resources";
66   -
67   - @Getter
68   - private String BASE_DIR_PATH = System.getProperty("user.dir");
69   -
70   - @Getter
71   - // private String PATH_DATA_MICROSERVICE = "/usr/share/tb-lwm2m-transport/data$";
72   - private String PATH_DATA = "data";
  43 +public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
73 44
74 45 @Getter
75 46 @Setter
... ... @@ -108,11 +79,11 @@ public class LwM2MTransportConfigServer {
108 79 private int unRegisteredPoolSize;
109 80
110 81 @Getter
111   - @Value("${transport.lwm2m.secure.key_store_type:}")
  82 + @Value("${transport.lwm2m.security.key_store_type:}")
112 83 private String keyStoreType;
113 84
114 85 @Getter
115   - @Value("${transport.lwm2m.secure.key_store_path_file:}")
  86 + @Value("${transport.lwm2m.security.key_store:}")
116 87 private String keyStorePathFile;
117 88
118 89 @Getter
... ... @@ -120,98 +91,72 @@ public class LwM2MTransportConfigServer {
120 91 private KeyStore keyStoreValue;
121 92
122 93 @Getter
123   - @Value("${transport.lwm2m.secure.key_store_password:}")
124   - private String keyStorePasswordServer;
  94 + @Value("${transport.lwm2m.security.key_store_password:}")
  95 + private String keyStorePassword;
125 96
126 97 @Getter
127   - @Value("${transport.lwm2m.secure.root_alias:}")
128   - private String rootAlias;
  98 + @Value("${transport.lwm2m.security.root_alias:}")
  99 + private String rootCertificateAlias;
129 100
130 101 @Getter
131   - @Value("${transport.lwm2m.secure.enable_gen_new_key_psk_rpk:}")
  102 + @Value("${transport.lwm2m.security.enable_gen_new_key_psk_rpk:}")
132 103 private Boolean enableGenNewKeyPskRpk;
133 104
134 105 @Getter
135 106 @Value("${transport.lwm2m.server.id:}")
136   - private Integer serverId;
  107 + private Integer id;
137 108
138 109 @Getter
139 110 @Value("${transport.lwm2m.server.bind_address:}")
140   - private String serverHost;
  111 + private String host;
  112 +
  113 + @Getter
  114 + @Value("${transport.lwm2m.server.bind_port:}")
  115 + private Integer port;
141 116
142 117 @Getter
143   - @Value("${transport.lwm2m.server.secure.bind_address_security:}")
144   - private String serverHostSecurity;
  118 + @Value("${transport.lwm2m.server.security.bind_address:}")
  119 + private String secureHost;
145 120
146 121 @Getter
147   - @Value("${transport.lwm2m.server.bind_port_no_sec:}")
148   - private Integer serverPortNoSec;
  122 + @Value("${transport.lwm2m.server.security.bind_port:}")
  123 + private Integer securePort;
149 124
150 125 @Getter
151   - @Value("${transport.lwm2m.server.secure.bind_port_security:}")
152   - private Integer serverPortSecurity;
  126 + @Value("${transport.lwm2m.server.security.public_x:}")
  127 + private String publicX;
153 128
154 129 @Getter
155   - @Value("${transport.lwm2m.server.secure.public_x:}")
156   - private String serverPublicX;
  130 + @Value("${transport.lwm2m.server.security.public_y:}")
  131 + private String publicY;
157 132
158 133 @Getter
159   - @Value("${transport.lwm2m.server.secure.public_y:}")
160   - private String serverPublicY;
  134 + @Value("${transport.lwm2m.server.security.private_encoded:}")
  135 + private String privateEncoded;
161 136
162 137 @Getter
163   - @Value("${transport.lwm2m.server.secure.private_encoded:}")
164   - private String serverPrivateEncoded;
  138 + @Value("${transport.lwm2m.server.security.alias:}")
  139 + private String certificateAlias;
165 140
166 141 @Getter
167   - @Value("${transport.lwm2m.server.secure.alias:}")
168   - private String serverAlias;
  142 + @Value("${transport.lwm2m.log_max_length:}")
  143 + private int logMaxLength;
  144 +
169 145
170 146 @PostConstruct
171 147 public void init() {
172   - this.getInKeyStore();
173   - }
174   -
175   - private KeyStore getInKeyStore() {
  148 + URI uri = null;
176 149 try {
177   - if (keyStoreValue != null && keyStoreValue.size() > 0)
178   - return keyStoreValue;
179   - } catch (KeyStoreException e) {
180   - log.error("Uninitialized keystore [{}]", keyStoreValue.toString());
181   - }
182   - Path keyStorePath = (keyStorePathFile != null && !keyStorePathFile.isEmpty()) ? Paths.get(keyStorePathFile) :
183   - (new File(Paths.get(getBaseDirPath(), PATH_DATA, KEY_STORE_DEFAULT_RESOURCE_PATH, KEY_STORE_DEFAULT_FILE).toUri()).isFile()) ?
184   - Paths.get(getBaseDirPath(), PATH_DATA, KEY_STORE_DEFAULT_RESOURCE_PATH, KEY_STORE_DEFAULT_FILE) :
185   - Paths.get(getBaseDirPath(), APP_DIR, TRANSPORT_DIR, LWM2M_DIR, SRC_DIR, MAIN_DIR, RESOURCES_DIR, KEY_STORE_DEFAULT_RESOURCE_PATH, KEY_STORE_DEFAULT_FILE);
186   - File keyStoreFile = new File(keyStorePath.toUri());
187   - if (keyStoreFile.isFile()) {
188   - try {
189   - InputStream inKeyStore = new FileInputStream(keyStoreFile);
190   - keyStoreValue = KeyStore.getInstance(keyStoreType);
191   - keyStoreValue.load(inKeyStore, keyStorePasswordServer == null ? null : keyStorePasswordServer.toCharArray());
192   - } catch (CertificateException | NoSuchAlgorithmException | IOException | KeyStoreException e) {
193   - log.error("[{}] Unable to load KeyStore files server, folder is not a directory", e.getMessage());
194   - keyStoreValue = null;
195   - }
196   - log.info("[{}] Load KeyStore files server, folder is a directory", keyStoreFile.getAbsoluteFile());
197   - } else {
198   - log.error("[{}] Unable to load KeyStore files server, is not a file", keyStoreFile.getAbsoluteFile());
199   - keyStoreValue = null;
200   - }
201   - return keyStoreValue;
202   - }
203   -
204   - private String getBaseDirPath() {
205   - Path FULL_FILE_PATH;
206   - if (BASE_DIR_PATH.endsWith("bin")) {
207   - FULL_FILE_PATH = Paths.get(BASE_DIR_PATH.replaceAll("bin$", ""));
208   - } else if (BASE_DIR_PATH.endsWith("conf")) {
209   - FULL_FILE_PATH = Paths.get(BASE_DIR_PATH.replaceAll("conf$", ""));
210   - } else if (BASE_DIR_PATH.endsWith("application")) {
211   - FULL_FILE_PATH = Paths.get(BASE_DIR_PATH.substring(0, BASE_DIR_PATH.length() - "application".length()));
212   - } else {
213   - FULL_FILE_PATH = Paths.get(BASE_DIR_PATH);
  150 + uri = Resources.getResource(keyStorePathFile).toURI();
  151 + log.error("URI: {}", uri);
  152 + File keyStoreFile = new File(uri);
  153 + InputStream inKeyStore = new FileInputStream(keyStoreFile);
  154 + keyStoreValue = KeyStore.getInstance(keyStoreType);
  155 + keyStoreValue.load(inKeyStore, keyStorePassword == null ? null : keyStorePassword.toCharArray());
  156 + } catch (Exception e) {
  157 + log.warn("Unable to lookup LwM2M keystore. Reason: {}, {}" , uri, e.getMessage());
  158 +// Absence of the key store should not block user from using plain LwM2M
  159 +// throw new RuntimeException("Failed to lookup LwM2M keystore: " + (uri != null ? uri.toString() : ""), e);
214 160 }
215   - return FULL_FILE_PATH.toUri().getPath();
216 161 }
217 162 }
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.transport.lwm2m.secure;
17 17
18 18 import com.google.gson.JsonObject;
  19 +import lombok.RequiredArgsConstructor;
19 20 import lombok.extern.slf4j.Slf4j;
20 21 import org.eclipse.leshan.core.util.Hex;
21 22 import org.eclipse.leshan.core.util.SecurityUtil;
... ... @@ -26,8 +27,10 @@ import org.thingsboard.server.common.transport.TransportServiceCallback;
26 27 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
27 28 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg;
28 29 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
29   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer;
30   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler;
  30 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
  31 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
  32 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
  33 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil;
31 34
32 35 import java.io.IOException;
33 36 import java.security.GeneralSecurityException;
... ... @@ -44,13 +47,11 @@ import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X5
44 47 @Slf4j
45 48 @Component
46 49 @TbLwM2mTransportComponent
  50 +@RequiredArgsConstructor
47 51 public class LwM2mCredentialsSecurityInfoValidator {
48 52
49   - private final LwM2mTransportContextServer contextS;
50   -
51   - public LwM2mCredentialsSecurityInfoValidator(LwM2mTransportContextServer contextS) {
52   - this.contextS = contextS;
53   - }
  53 + private final LwM2mTransportContext context;
  54 + private final LwM2MTransportServerConfig config;
54 55
55 56 /**
56 57 * Request to thingsboard Response from thingsboard ValidateDeviceLwM2MCredentials
... ... @@ -58,17 +59,17 @@ public class LwM2mCredentialsSecurityInfoValidator {
58 59 * @param keyValue -
59 60 * @return ValidateDeviceCredentialsResponseMsg and SecurityInfo
60 61 */
61   - public ReadResultSecurityStore createAndValidateCredentialsSecurityInfo(String endpoint, LwM2mTransportHandler.LwM2mTypeServer keyValue) {
  62 + public ReadResultSecurityStore createAndValidateCredentialsSecurityInfo(String endpoint, LwM2mTransportHandlerUtil.LwM2mTypeServer keyValue) {
62 63 CountDownLatch latch = new CountDownLatch(1);
63 64 final ReadResultSecurityStore[] resultSecurityStore = new ReadResultSecurityStore[1];
64   - contextS.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endpoint).build(),
  65 + context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endpoint).build(),
65 66 new TransportServiceCallback<>() {
66 67 @Override
67 68 public void onSuccess(ValidateDeviceCredentialsResponseMsg msg) {
68 69 String credentialsBody = msg.getCredentialsBody();
69 70 resultSecurityStore[0] = createSecurityInfo(endpoint, credentialsBody, keyValue);
70 71 resultSecurityStore[0].setMsg(msg);
71   - Optional<DeviceProfile> deviceProfileOpt = LwM2mTransportHandler.decode(msg.getProfileBody().toByteArray());
  72 + Optional<DeviceProfile> deviceProfileOpt = LwM2mTransportHandlerUtil.decode(msg.getProfileBody().toByteArray());
72 73 deviceProfileOpt.ifPresent(profile -> resultSecurityStore[0].setDeviceProfile(profile));
73 74 latch.countDown();
74 75 }
... ... @@ -81,7 +82,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
81 82 }
82 83 });
83 84 try {
84   - latch.await(contextS.getLwM2MTransportConfigServer().getTimeout(), TimeUnit.MILLISECONDS);
  85 + latch.await(config.getTimeout(), TimeUnit.MILLISECONDS);
85 86 } catch (InterruptedException e) {
86 87 log.error("Failed to await credentials!", e);
87 88 }
... ... @@ -95,9 +96,9 @@ public class LwM2mCredentialsSecurityInfoValidator {
95 96 * @param keyValue -
96 97 * @return SecurityInfo
97 98 */
98   - private ReadResultSecurityStore createSecurityInfo(String endPoint, String jsonStr, LwM2mTransportHandler.LwM2mTypeServer keyValue) {
  99 + private ReadResultSecurityStore createSecurityInfo(String endPoint, String jsonStr, LwM2mTransportHandlerUtil.LwM2mTypeServer keyValue) {
99 100 ReadResultSecurityStore result = new ReadResultSecurityStore();
100   - JsonObject objectMsg = LwM2mTransportHandler.validateJson(jsonStr);
  101 + JsonObject objectMsg = LwM2mTransportHandlerUtil.validateJson(jsonStr);
101 102 if (objectMsg != null && !objectMsg.isJsonNull()) {
102 103 JsonObject object = (objectMsg.has(keyValue.type) && !objectMsg.get(keyValue.type).isJsonNull()) ? objectMsg.get(keyValue.type).getAsJsonObject() : null;
103 104 /**
... ... @@ -108,7 +109,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
108 109 && objectMsg.get("client").getAsJsonObject().get("endpoint").isJsonPrimitive()) ? objectMsg.get("client").getAsJsonObject().get("endpoint").getAsString() : null;
109 110 endPoint = (endPointPsk == null || endPointPsk.isEmpty()) ? endPoint : endPointPsk;
110 111 if (object != null && !object.isJsonNull()) {
111   - if (keyValue.equals(LwM2mTransportHandler.LwM2mTypeServer.BOOTSTRAP)) {
  112 + if (keyValue.equals(LwM2mTransportHandlerUtil.LwM2mTypeServer.BOOTSTRAP)) {
112 113 result.setBootstrapJsonCredential(object);
113 114 result.setEndPoint(endPoint);
114 115 result.setSecurityMode(LwM2MSecurityMode.fromSecurityMode(object.get("bootstrapServer").getAsJsonObject().get("securityMode").getAsString().toLowerCase()).code);
... ...
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java renamed from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java
... ... @@ -38,10 +38,15 @@ import org.eclipse.leshan.server.registration.Registration;
38 38 import org.springframework.context.annotation.Lazy;
39 39 import org.springframework.stereotype.Service;
40 40 import org.thingsboard.common.util.JacksonUtil;
  41 +import org.thingsboard.server.cache.firmware.FirmwareDataCache;
41 42 import org.thingsboard.server.common.data.Device;
42 43 import org.thingsboard.server.common.data.DeviceProfile;
43   -import org.thingsboard.server.common.data.DeviceTransportType;
  44 +import org.thingsboard.server.common.data.firmware.FirmwareKey;
  45 +import org.thingsboard.server.common.data.firmware.FirmwareType;
  46 +import org.thingsboard.server.common.data.firmware.FirmwareUtil;
  47 +import org.thingsboard.server.common.data.id.FirmwareId;
44 48 import org.thingsboard.server.common.transport.TransportService;
  49 +import org.thingsboard.server.common.transport.TransportServiceCallback;
45 50 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
46 51 import org.thingsboard.server.common.transport.service.DefaultTransportService;
47 52 import org.thingsboard.server.gen.transport.TransportProtos;
... ... @@ -49,6 +54,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotif
49 54 import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent;
50 55 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
51 56 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
  57 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
52 58 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
53 59 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
54 60 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
... ... @@ -77,34 +83,37 @@ import java.util.stream.Collectors;
77 83
78 84 import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST;
79 85 import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
  86 +import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
80 87 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
81   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED;
82   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_REQUEST;
83   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR;
84   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO;
85   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_VALUE;
86   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LWM2M_STRATEGY_2;
87   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper;
88   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.DISCOVER;
89   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.EXECUTE;
90   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.OBSERVE;
91   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.OBSERVE_CANCEL;
92   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.OBSERVE_READ_ALL;
93   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.READ;
94   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.WRITE_ATTRIBUTES;
95   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.WRITE_REPLACE;
96   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.WRITE_UPDATE;
97   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.SERVICE_CHANNEL;
98   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertJsonArrayToSet;
99   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
100   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
101   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getAckCallback;
102   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.validateObjectVerFromKey;
  88 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.CLIENT_NOT_AUTHORIZED;
  89 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.DEVICE_ATTRIBUTES_REQUEST;
  90 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.FR_OBJECT_ID;
  91 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.FR_PATH_RESOURCE_VER_ID;
  92 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_ERROR;
  93 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_INFO;
  94 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_VALUE;
  95 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LWM2M_STRATEGY_2;
  96 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper;
  97 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper.DISCOVER;
  98 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper.EXECUTE;
  99 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper.OBSERVE;
  100 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper.OBSERVE_CANCEL;
  101 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper.OBSERVE_READ_ALL;
  102 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper.READ;
  103 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;
  104 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper.WRITE_REPLACE;
  105 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper.WRITE_UPDATE;
  106 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.SERVICE_CHANNEL;
  107 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.convertJsonArrayToSet;
  108 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.convertPathFromIdVerToObjectId;
  109 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.convertPathFromObjectIdToIdVer;
  110 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.getAckCallback;
  111 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.validateObjectVerFromKey;
103 112
104 113 @Slf4j
105 114 @Service
106 115 @TbLwM2mTransportComponent
107   -public class LwM2mTransportServiceImpl implements LwM2mTransportService {
  116 +public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler {
108 117
109 118 private ExecutorService executorRegistered;
110 119 private ExecutorService executorUpdateRegistered;
... ... @@ -112,31 +121,35 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
112 121 private LwM2mValueConverterImpl converter;
113 122
114 123 private final TransportService transportService;
115   -
116   - public final LwM2mTransportContextServer lwM2mTransportContextServer;
117   -
  124 + private final LwM2mTransportContext context;
  125 + private final LwM2MTransportServerConfig config;
  126 + private final FirmwareDataCache firmwareDataCache;
  127 + private final LwM2mTransportServerHelper helper;
118 128 private final LwM2mClientContext lwM2mClientContext;
119   -
120   - private final LeshanServer leshanServer;
121   -
122 129 private final LwM2mTransportRequest lwM2mTransportRequest;
123 130
124   - public LwM2mTransportServiceImpl(TransportService transportService, LwM2mTransportContextServer lwM2mTransportContextServer, LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, @Lazy LwM2mTransportRequest lwM2mTransportRequest) {
  131 + public DefaultLwM2MTransportMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, LwM2mTransportServerHelper helper,
  132 + LwM2mClientContext lwM2mClientContext,
  133 + @Lazy LwM2mTransportRequest lwM2mTransportRequest,
  134 + FirmwareDataCache firmwareDataCache,
  135 + LwM2mTransportContext context) {
125 136 this.transportService = transportService;
126   - this.lwM2mTransportContextServer = lwM2mTransportContextServer;
  137 + this.config = config;
  138 + this.helper = helper;
127 139 this.lwM2mClientContext = lwM2mClientContext;
128   - this.leshanServer = leshanServer;
129 140 this.lwM2mTransportRequest = lwM2mTransportRequest;
  141 + this.firmwareDataCache = firmwareDataCache;
  142 + this.context = context;
130 143 }
131 144
132 145 @PostConstruct
133 146 public void init() {
134   - this.lwM2mTransportContextServer.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) lwM2mTransportContextServer.getLwM2MTransportConfigServer().getSessionReportTimeout()), lwM2mTransportContextServer.getLwM2MTransportConfigServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS);
135   - this.executorRegistered = Executors.newFixedThreadPool(this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getRegisteredPoolSize(),
  147 + this.context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) config.getSessionReportTimeout()), config.getSessionReportTimeout(), TimeUnit.MILLISECONDS);
  148 + this.executorRegistered = Executors.newFixedThreadPool(this.config.getRegisteredPoolSize(),
136 149 new NamedThreadFactory(String.format("LwM2M %s channel registered", SERVICE_CHANNEL)));
137   - this.executorUpdateRegistered = Executors.newFixedThreadPool(this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getUpdateRegisteredPoolSize(),
  150 + this.executorUpdateRegistered = Executors.newFixedThreadPool(this.config.getUpdateRegisteredPoolSize(),
138 151 new NamedThreadFactory(String.format("LwM2M %s channel update registered", SERVICE_CHANNEL)));
139   - this.executorUnRegistered = Executors.newFixedThreadPool(this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getUnRegisteredPoolSize(),
  152 + this.executorUnRegistered = Executors.newFixedThreadPool(this.config.getUnRegisteredPoolSize(),
140 153 new NamedThreadFactory(String.format("LwM2M %s channel un registered", SERVICE_CHANNEL)));
141 154 this.converter = LwM2mValueConverterImpl.getInstance();
142 155 }
... ... @@ -168,8 +181,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
168 181 transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null);
169 182 transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null);
170 183 transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null);
  184 + this.getInfoFirmwareUpdate(lwM2MClient);
171 185 this.initLwM2mFromClientValue(registration, lwM2MClient);
172   - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration);
  186 + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration.getId());
173 187 } else {
174 188 log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
175 189 }
... ... @@ -224,7 +238,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
224 238 executorUnRegistered.submit(() -> {
225 239 try {
226 240 this.setCancelObservations(registration);
227   - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration);
  241 + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId());
228 242 this.closeClientSession(registration);
229 243 } catch (Throwable t) {
230 244 log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t);
... ... @@ -257,7 +271,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
257 271 @Override
258 272 public void onSleepingDev(Registration registration) {
259 273 log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint());
260   - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is sleeping!", registration);
  274 + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is sleeping!", registration.getId());
261 275
262 276 //TODO: associate endpointId with device information.
263 277 }
... ... @@ -265,10 +279,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
265 279 @Override
266 280 public void setCancelObservations(Registration registration) {
267 281 if (registration != null) {
268   - Set<Observation> observations = leshanServer.getObservationService().getObservations(registration);
  282 + Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
269 283 observations.forEach(observation -> lwM2mTransportRequest.sendAllRequest(registration,
270 284 convertPathFromObjectIdToIdVer(observation.getPath().toString(), registration), OBSERVE_CANCEL,
271   - null, null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null));
  285 + null, null, this.config.getTimeout(), null));
272 286 }
273 287 }
274 288
... ... @@ -280,7 +294,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
280 294 * @param response - observe
281 295 */
282 296 @Override
283   - public void onObservationResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) {
  297 + public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) {
284 298 if (response.getContent() != null) {
285 299 if (response.getContent() instanceof LwM2mObject) {
286 300 LwM2mObject lwM2mObject = (LwM2mObject) response.getContent();
... ... @@ -304,22 +318,29 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
304 318
305 319 /**
306 320 * Update - send request in change value resources in Client
307   - * Path to resources from profile equal keyName or from ModelObject equal name
308   - * Only for resources: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase)
309   - * Delete - nothing *
  321 + * 1. FirmwareUpdate:
  322 + * - If msg.getSharedUpdatedList().forEach(tsKvProto -> {tsKvProto.getKv().getKey().indexOf(FIRMWARE_UPDATE_PREFIX, 0) == 0
  323 + * 2. Shared Other AttributeUpdate
  324 + * -- Path to resources from profile equal keyName or from ModelObject equal name
  325 + * -- Only for resources: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase)
  326 + * 3. Delete - nothing
310 327 *
311 328 * @param msg -
312 329 */
313 330 @Override
314 331 public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
  332 + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
315 333 if (msg.getSharedUpdatedCount() > 0) {
316 334 msg.getSharedUpdatedList().forEach(tsKvProto -> {
317 335 String pathName = tsKvProto.getKv().getKey();
318 336 String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName);
319   - Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv());
320   - LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
  337 + Object valueNew = this.helper.getValueFromKvProto(tsKvProto.getKv());
  338 + //TODO: react on change of the firmware name.
  339 + if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) {
  340 + this.getInfoFirmwareUpdate(lwM2MClient);
  341 + }
321 342 if (pathIdVer != null) {
322   - ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer()
  343 + ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.config
323 344 .getModelProvider());
324 345 if (resourceModel != null && resourceModel.operations.isWritable()) {
325 346 this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer), valueNew, pathIdVer);
... ... @@ -327,19 +348,26 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
327 348 log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, valueNew);
328 349 String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated",
329 350 LOG_LW2M_ERROR, pathIdVer, valueNew);
330   - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
  351 + this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId());
331 352 }
332 353 } else {
333 354 log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew);
334 355 String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated",
335 356 LOG_LW2M_ERROR, pathName, valueNew);
336   - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
  357 + this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId());
337 358 }
  359 +
338 360 });
339 361 } else if (msg.getSharedDeletedCount() > 0) {
  362 + msg.getSharedUpdatedList().forEach(tsKvProto -> {
  363 + String pathName = tsKvProto.getKv().getKey();
  364 + Object valueNew = this.helper.getValueFromKvProto(tsKvProto.getKv());
  365 + if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) {
  366 + lwM2MClient.getFrUpdate().setCurrentFwVersion((String) valueNew);
  367 + }
  368 + });
340 369 log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo);
341 370 }
342   -
343 371 }
344 372
345 373 /**
... ... @@ -377,7 +405,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
377 405 @Override
378 406 public void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {
379 407 String idVer = resourceUpdateMsgOpt.get().getResourceKey();
380   - lwM2mClientContext.getLwM2mClients().values().stream().forEach(e -> e.updateResourceModel(idVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelProvider()));
  408 + lwM2mClientContext.getLwM2mClients().values().stream().forEach(e -> e.updateResourceModel(idVer, this.config.getModelProvider()));
381 409 }
382 410
383 411 /**
... ... @@ -386,7 +414,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
386 414 @Override
387 415 public void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt) {
388 416 String pathIdVer = resourceDeleteMsgOpt.get().getResourceKey();
389   - lwM2mClientContext.getLwM2mClients().values().stream().forEach(e -> e.deleteResources(pathIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelProvider()));
  417 + lwM2mClientContext.getLwM2mClients().values().stream().forEach(e -> e.deleteResources(pathIdVer, this.config.getModelProvider()));
390 418 }
391 419
392 420 @Override
... ... @@ -402,7 +430,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
402 430 } else {
403 431 lwM2mTransportRequest.sendAllRequest(registration, lwm2mClientRpcRequest.getTargetIdVer(), lwm2mClientRpcRequest.getTypeOper(), lwm2mClientRpcRequest.getContentFormatName(),
404 432 lwm2mClientRpcRequest.getValue() == null ? lwm2mClientRpcRequest.getParams() : lwm2mClientRpcRequest.getValue(),
405   - this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), lwm2mClientRpcRequest);
  433 + this.config.getTimeout(), lwm2mClientRpcRequest);
406 434 }
407 435 } catch (Exception e) {
408 436 if (lwm2mClientRpcRequest == null) {
... ... @@ -430,7 +458,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
430 458 lwm2mClientRpcRequest.setRequestId(toDeviceRequest.getRequestId());
431 459 lwm2mClientRpcRequest.setSessionInfo(sessionInfo);
432 460 lwm2mClientRpcRequest.setValidTypeOper(toDeviceRequest.getMethodName());
433   - JsonObject rpcRequest = LwM2mTransportHandler.validateJson(toDeviceRequest.getParams());
  461 + JsonObject rpcRequest = LwM2mTransportHandlerUtil.validateJson(toDeviceRequest.getParams());
434 462 if (rpcRequest != null) {
435 463 if (rpcRequest.has(lwm2mClientRpcRequest.keyNameKey)) {
436 464 String targetIdVer = this.getPresentPathIntoProfile(sessionInfo,
... ... @@ -455,23 +483,21 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
455 483 }
456 484 if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonObject()) {
457 485 lwm2mClientRpcRequest.setParams(new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey)
458   - .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() {
459   - }.getType()));
  486 + .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() {
  487 + }.getType()));
460 488 }
461 489 lwm2mClientRpcRequest.setSessionInfo(sessionInfo);
462 490 if (OBSERVE_READ_ALL != lwm2mClientRpcRequest.getTypeOper() && lwm2mClientRpcRequest.getTargetIdVer() == null) {
463 491 lwm2mClientRpcRequest.setErrorMsg(lwm2mClientRpcRequest.targetIdVerKey + " and " +
464 492 lwm2mClientRpcRequest.keyNameKey + " is null or bad format");
465   - }
466   - else if ((EXECUTE == lwm2mClientRpcRequest.getTypeOper()
  493 + } else if ((EXECUTE == lwm2mClientRpcRequest.getTypeOper()
467 494 || WRITE_REPLACE == lwm2mClientRpcRequest.getTypeOper())
468   - && lwm2mClientRpcRequest.getTargetIdVer() !=null
  495 + && lwm2mClientRpcRequest.getTargetIdVer() != null
469 496 && !(new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResource()
470 497 || new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResourceInstance())) {
471   - lwm2mClientRpcRequest.setErrorMsg("Invalid parameter " + lwm2mClientRpcRequest.targetIdVerKey
  498 + lwm2mClientRpcRequest.setErrorMsg("Invalid parameter " + lwm2mClientRpcRequest.targetIdVerKey
472 499 + ". Only Resource or ResourceInstance can be this operation");
473   - }
474   - else if (WRITE_UPDATE == lwm2mClientRpcRequest.getTypeOper()){
  500 + } else if (WRITE_UPDATE == lwm2mClientRpcRequest.getTypeOper()) {
475 501 lwm2mClientRpcRequest.setErrorMsg("Procedures In Development...");
476 502 }
477 503 } else {
... ... @@ -483,23 +509,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
483 509 return lwm2mClientRpcRequest;
484 510 }
485 511
486   - public void sentRpcRequest (Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) {
  512 + public void sentRpcRequest(Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) {
487 513 rpcRequest.setResponseCode(requestCode);
488   - if (LOG_LW2M_ERROR.equals(typeMsg)) {
489   - rpcRequest.setInfoMsg(null);
490   - rpcRequest.setValueMsg(null);
491   - if (rpcRequest.getErrorMsg() == null) {
492   - msg = msg.isEmpty() ? null : msg;
493   - rpcRequest.setErrorMsg(msg);
494   - }
495   - } else if (LOG_LW2M_INFO.equals(typeMsg)) {
496   - if (rpcRequest.getInfoMsg() == null) {
497   - rpcRequest.setInfoMsg(msg);
498   - }
499   - } else if (LOG_LW2M_VALUE.equals(typeMsg)) {
500   - if (rpcRequest.getValueMsg() == null) {
501   - rpcRequest.setValueMsg(msg);
502   - }
  514 + if (LOG_LW2M_ERROR.equals(typeMsg)) {
  515 + rpcRequest.setInfoMsg(null);
  516 + rpcRequest.setValueMsg(null);
  517 + if (rpcRequest.getErrorMsg() == null) {
  518 + msg = msg.isEmpty() ? null : msg;
  519 + rpcRequest.setErrorMsg(msg);
  520 + }
  521 + } else if (LOG_LW2M_INFO.equals(typeMsg)) {
  522 + if (rpcRequest.getInfoMsg() == null) {
  523 + rpcRequest.setInfoMsg(msg);
  524 + }
  525 + } else if (LOG_LW2M_VALUE.equals(typeMsg)) {
  526 + if (rpcRequest.getValueMsg() == null) {
  527 + rpcRequest.setValueMsg(msg);
  528 + }
503 529 }
504 530 this.onToDeviceRpcResponse(rpcRequest.getDeviceRpcResponseResultMsg(), rpcRequest.getSessionInfo());
505 531 }
... ... @@ -521,7 +547,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
521 547 @Override
522 548 public void doTrigger(Registration registration, String path) {
523 549 lwM2mTransportRequest.sendAllRequest(registration, path, EXECUTE,
524   - ContentFormat.TLV.getName(), null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
  550 + ContentFormat.TLV.getName(), null, this.config.getTimeout(), null);
525 551 }
526 552
527 553 /**
... ... @@ -554,9 +580,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
554 580 *
555 581 * @param registration -
556 582 */
557   - protected void onAwakeDev(Registration registration) {
  583 + @Override
  584 + public void onAwakeDev(Registration registration) {
558 585 log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint());
559   - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is awake!", registration);
  586 + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is awake!", registration.getId());
560 587 //TODO: associate endpointId with device information.
561 588 }
562 589
... ... @@ -583,12 +610,16 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
583 610
584 611 /**
585 612 * @param logMsg - text msg
586   - * @param registration - Id of Registration LwM2M Client
  613 + * @param registrationId - Id of Registration LwM2M Client
587 614 */
588   - public void sendLogsToThingsboard(String logMsg, Registration registration) {
589   - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
  615 + @Override
  616 + public void sendLogsToThingsboard(String logMsg, String registrationId) {
  617 + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registrationId);
590 618 if (logMsg != null && sessionInfo != null) {
591   - this.lwM2mTransportContextServer.sendParametersOnThingsboardTelemetry(this.lwM2mTransportContextServer.getKvLogyToThingsboard(logMsg), sessionInfo);
  619 + if(logMsg.length() > 1024){
  620 + logMsg = logMsg.substring(0, 1024);
  621 + }
  622 + this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvLogyToThingsboard(logMsg), sessionInfo);
592 623 }
593 624 }
594 625
... ... @@ -608,11 +639,11 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
608 639 LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration);
609 640 Set<String> clientObjects = lwM2mClientContext.getSupportedIdVerInClient(registration);
610 641 if (clientObjects != null && clientObjects.size() > 0) {
611   - if (LWM2M_STRATEGY_2 == LwM2mTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) {
  642 + if (LWM2M_STRATEGY_2 == LwM2mTransportHandlerUtil.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) {
612 643 // #2
613   - lwM2MClient.getPendingRequests().addAll(clientObjects);
  644 + lwM2MClient.getPendingReadRequests().addAll(clientObjects);
614 645 clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, READ, ContentFormat.TLV.getName(),
615   - null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null));
  646 + null, this.config.getTimeout(), null));
616 647 }
617 648 // #1
618 649 this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, READ, clientObjects);
... ... @@ -652,6 +683,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
652 683 * Sending observe value of resources to thingsboard
653 684 * #1 Return old Value Resource from LwM2MClient
654 685 * #2 Update new Resources (replace old Resource Value on new Resource Value)
  686 + * #3 If fr_update -> UpdateFirmware
  687 + * #4 updateAttrTelemetry
655 688 *
656 689 * @param registration - Registration LwM2M Client
657 690 * @param lwM2mResource - LwM2mSingleResource response.getContent()
... ... @@ -659,8 +692,21 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
659 692 */
660 693 private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) {
661 694 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
662   - if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer()
  695 + if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config
663 696 .getModelProvider())) {
  697 + if (FR_PATH_RESOURCE_VER_ID.equals(convertPathFromIdVerToObjectId(path)) &&
  698 + lwM2MClient.getFrUpdate().getCurrentFwVersion() != null
  699 + && !lwM2MClient.getFrUpdate().getCurrentFwVersion().equals(lwM2MClient.getFrUpdate().getClientFwVersion())
  700 + && lwM2MClient.isUpdateFw()) {
  701 +
  702 + /** version != null
  703 + * set setClient_fw_version = value
  704 + **/
  705 + lwM2MClient.setUpdateFw(false);
  706 + lwM2MClient.getFrUpdate().setClientFwVersion(lwM2mResource.getValue().toString());
  707 + log.warn("updateFirmwareClient3");
  708 + this.updateFirmwareClient(lwM2MClient);
  709 + }
664 710 Set<String> paths = new HashSet<>();
665 711 paths.add(path);
666 712 this.updateAttrTelemetry(registration, paths);
... ... @@ -669,6 +715,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
669 715 }
670 716 }
671 717
  718 +
672 719 /**
673 720 * send Attribute and Telemetry to Thingsboard
674 721 * #1 - get AttrName/TelemetryName with value from LwM2MClient:
... ... @@ -684,10 +731,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
684 731 SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
685 732 if (results != null && sessionInfo != null) {
686 733 if (results.getResultAttributes().size() > 0) {
687   - this.lwM2mTransportContextServer.sendParametersOnThingsboardAttribute(results.getResultAttributes(), sessionInfo);
  734 + this.helper.sendParametersOnThingsboardAttribute(results.getResultAttributes(), sessionInfo);
688 735 }
689 736 if (results.getResultTelemetries().size() > 0) {
690   - this.lwM2mTransportContextServer.sendParametersOnThingsboardTelemetry(results.getResultTelemetries(), sessionInfo);
  737 + this.helper.sendParametersOnThingsboardTelemetry(results.getResultTelemetries(), sessionInfo);
691 738 }
692 739 }
693 740 } catch (Exception e) {
... ... @@ -723,22 +770,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
723 770 params = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile());
724 771 result = params.keySet();
725 772 }
726   - if (!result.isEmpty()) {
  773 + if (result != null && !result.isEmpty()) {
727 774 // #1
728 775 Set<String> pathSend = result.stream().filter(target -> {
729 776 return target.split(LWM2M_SEPARATOR_PATH).length < 3 ?
730 777 clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]) :
731 778 clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1] + "/" + target.split(LWM2M_SEPARATOR_PATH)[2]);
732 779 }
733   - )
734   - .collect(Collectors.toUnmodifiableSet());
  780 + ).collect(Collectors.toUnmodifiableSet());
735 781 if (!pathSend.isEmpty()) {
736   - lwM2MClient.getPendingRequests().addAll(pathSend);
  782 + lwM2MClient.getPendingReadRequests().addAll(pathSend);
737 783 ConcurrentHashMap<String, Object> finalParams = params;
738   - pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(),
739   - finalParams != null ? finalParams.get(target) : null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null));
  784 + pathSend.forEach(target -> {
  785 + lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(),
  786 + finalParams != null ? finalParams.get(target) : null, this.config.getTimeout(), null);
  787 + });
740 788 if (OBSERVE.equals(typeOper)) {
741   - lwM2MClient.initValue(this, null);
  789 + lwM2MClient.initReadValue(this, null);
742 790 }
743 791 }
744 792 }
... ... @@ -820,7 +868,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
820 868 LwM2mResource resourceValue = lwM2MClient != null ? getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) : null;
821 869 if (resourceValue != null) {
822 870 ResourceModel.Type currentType = resourceValue.getType();
823   - ResourceModel.Type expectedType = this.lwM2mTransportContextServer.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
  871 + ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
824 872 Object valueKvProto = null;
825 873 if (resourceValue.isMultiInstances()) {
826 874 valueKvProto = new JsonObject();
... ... @@ -837,7 +885,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
837 885 valueKvProto = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
838 886 new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
839 887 }
840   - return valueKvProto != null ? this.lwM2mTransportContextServer.getKvAttrTelemetryToThingsboard(currentType, resourceName, valueKvProto, resourceValue.isMultiInstances()) : null;
  888 + return valueKvProto != null ? this.helper.getKvAttrTelemetryToThingsboard(currentType, resourceName, valueKvProto, resourceValue.isMultiInstances()) : null;
841 889 }
842 890 } catch (Exception e) {
843 891 log.error("Failed to add parameters.", e);
... ... @@ -856,7 +904,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
856 904 private Object getResourceValueFormatKv(LwM2mClient lwM2MClient, String pathIdVer) {
857 905 LwM2mResource resourceValue = this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);
858 906 ResourceModel.Type currentType = resourceValue.getType();
859   - ResourceModel.Type expectedType = this.lwM2mTransportContextServer.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
  907 + ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
860 908 return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
861 909 new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
862 910 }
... ... @@ -969,7 +1017,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
969 1017 // update value in Resources
970 1018 registrationIds.forEach(registrationId -> {
971 1019 Registration registration = lwM2mClientContext.getRegistration(registrationId);
972   - this.readResourceValueObserve(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ);
  1020 + this.readObserveFromProfile(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ);
973 1021 // send attr/telemetry to tingsboard for new path
974 1022 this.updateAttrTelemetry(registration, sendAttrToThingsboard.getPathPostParametersAdd());
975 1023 });
... ... @@ -998,12 +1046,12 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
998 1046 registrationIds.forEach(registrationId -> {
999 1047 Registration registration = lwM2mClientContext.getRegistration(registrationId);
1000 1048 if (postObserveAnalyzer.getPathPostParametersAdd().size() > 0) {
1001   - this.readResourceValueObserve(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE);
  1049 + this.readObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE);
1002 1050 }
1003 1051 // 5.3 del
1004 1052 // send Request cancel observe to Client
1005 1053 if (postObserveAnalyzer.getPathPostParametersDel().size() > 0) {
1006   - this.cancelObserveIsValue(registration, postObserveAnalyzer.getPathPostParametersDel());
  1054 + this.cancelObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersDel());
1007 1055 }
1008 1056 });
1009 1057 }
... ... @@ -1043,16 +1091,16 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1043 1091 * @param registration - Registration LwM2M Client
1044 1092 * @param targets - path Resources == [ "/2/0/0", "/2/0/1"]
1045 1093 */
1046   - private void readResourceValueObserve(Registration registration, Set<String> targets, LwM2mTypeOper typeOper) {
  1094 + private void readObserveFromProfile(Registration registration, Set<String> targets, LwM2mTypeOper typeOper) {
1047 1095 targets.forEach(target -> {
1048 1096 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target));
1049 1097 if (pathIds.isResource()) {
1050 1098 if (READ.equals(typeOper)) {
1051 1099 lwM2mTransportRequest.sendAllRequest(registration, target, typeOper,
1052   - ContentFormat.TLV.getName(), null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
  1100 + ContentFormat.TLV.getName(), null, this.config.getTimeout(), null);
1053 1101 } else if (OBSERVE.equals(typeOper)) {
1054 1102 lwM2mTransportRequest.sendAllRequest(registration, target, typeOper,
1055   - null, null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
  1103 + null, null, this.config.getTimeout(), null);
1056 1104 }
1057 1105 }
1058 1106 });
... ... @@ -1108,7 +1156,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1108 1156 if (!pathSend.isEmpty()) {
1109 1157 ConcurrentHashMap<String, Object> finalParams = lwm2mAttributesNew;
1110 1158 pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TLV.getName(),
1111   - finalParams.get(target), this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null));
  1159 + finalParams.get(target), this.config.getTimeout(), null));
1112 1160 }
1113 1161 });
1114 1162 }
... ... @@ -1125,7 +1173,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1125 1173 params.clear();
1126 1174 params.put(OBJECT_VERSION, "");
1127 1175 lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TLV.getName(),
1128   - params, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
  1176 + params, this.config.getTimeout(), null);
1129 1177 });
1130 1178 }
1131 1179 });
... ... @@ -1133,12 +1181,12 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1133 1181
1134 1182 }
1135 1183
1136   - private void cancelObserveIsValue(Registration registration, Set<String> paramAnallyzer) {
  1184 + private void cancelObserveFromProfile(Registration registration, Set<String> paramAnallyzer) {
1137 1185 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
1138 1186 paramAnallyzer.forEach(pathIdVer -> {
1139 1187 if (this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) != null) {
1140 1188 lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, OBSERVE_CANCEL, null,
1141   - null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
  1189 + null, this.config.getTimeout(), null);
1142 1190 }
1143 1191 }
1144 1192 );
... ... @@ -1148,12 +1196,12 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1148 1196 if (valueNew != null && (valueOld == null || !valueNew.toString().equals(valueOld.toString()))) {
1149 1197 lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), path, WRITE_REPLACE,
1150 1198 ContentFormat.TLV.getName(), valueNew,
1151   - this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
  1199 + this.config.getTimeout(), null);
1152 1200 } else {
1153 1201 log.error("Failed update resource [{}] [{}]", path, valueNew);
1154 1202 String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad",
1155 1203 LOG_LW2M_ERROR, path, valueNew);
1156   - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
  1204 + this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId());
1157 1205 log.info("Failed update resource [{}] [{}]", path, valueNew);
1158 1206 }
1159 1207 }
... ... @@ -1182,8 +1230,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1182 1230 }
1183 1231
1184 1232 /**
1185   - * Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values
1186   - * #1 Get path resource by result attributesResponse
  1233 + * 1. FirmwareUpdate:
  1234 + * - msg.getSharedUpdatedList().forEach(tsKvProto -> {tsKvProto.getKv().getKey().indexOf(FIRMWARE_UPDATE_PREFIX, 0) == 0
  1235 + * 2. Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values
  1236 + * - Get path resource by result attributesResponse
1187 1237 *
1188 1238 * @param attributesResponse -
1189 1239 * @param sessionInfo -
... ... @@ -1191,6 +1241,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1191 1241 public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) {
1192 1242 try {
1193 1243 List<TransportProtos.TsKvProto> tsKvProtos = attributesResponse.getSharedAttributeListList();
  1244 +
1194 1245 this.updateAttriuteFromThingsboard(tsKvProtos, sessionInfo);
1195 1246 } catch (Exception e) {
1196 1247 log.error(String.valueOf(e));
... ... @@ -1223,7 +1274,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1223 1274 // #2.1
1224 1275 lwM2MClient.getDelayedRequests().forEach((pathIdVer, tsKvProto) -> {
1225 1276 this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer),
1226   - this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
  1277 + this.helper.getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
1227 1278 });
1228 1279 }
1229 1280
... ... @@ -1240,7 +1291,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1240 1291 return null;
1241 1292 } else {
1242 1293 return SessionInfoProto.newBuilder()
1243   - .setNodeId(this.lwM2mTransportContextServer.getNodeId())
  1294 + .setNodeId(this.context.getNodeId())
1244 1295 .setSessionIdMSB(lwM2MClient.getSessionId().getMostSignificantBits())
1245 1296 .setSessionIdLSB(lwM2MClient.getSessionId().getLeastSignificantBits())
1246 1297 .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB())
... ... @@ -1274,7 +1325,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1274 1325 */
1275 1326 private SessionInfoProto getValidateSessionInfo(String registrationId) {
1276 1327 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(null, registrationId);
1277   - return getNewSessionInfoProto(lwM2MClient);
  1328 + return lwM2MClient != null ? this.getNewSessionInfoProto(lwM2MClient) : null;
1278 1329 }
1279 1330
1280 1331 /**
... ... @@ -1293,28 +1344,88 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1293 1344 }
1294 1345
1295 1346 /**
1296   - * !!! sharedAttr === profileAttr !!!
1297   - * If there is a difference in values between the current resource values and the shared attribute values
1298   - * when the client connects to the server
1299   - * #1 get attributes name from profile include name resources in ModelObject if resource isWritable
1300   - * #2.1 #1 size > 0 => send Request getAttributes to thingsboard
  1347 + * #1. !!! sharedAttr === profileAttr !!!
  1348 + * - If there is a difference in values between the current resource values and the shared attribute values
  1349 + * - when the client connects to the server
  1350 + * #1.1 get attributes name from profile include name resources in ModelObject if resource isWritable
  1351 + * #1.2 #1 size > 0 => send Request getAttributes to thingsboard
  1352 + * #2. FirmwareAttribute subscribe:
1301 1353 *
1302 1354 * @param lwM2MClient - LwM2M Client
1303 1355 */
1304 1356 public void putDelayedUpdateResourcesThingsboard(LwM2mClient lwM2MClient) {
1305 1357 SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration());
1306 1358 if (sessionInfo != null) {
1307   - //#1.1 + #1.2
1308   - List<String> attrSharedNames = this.getNamesAttrFromProfileIsWritable(lwM2MClient);
1309   - if (attrSharedNames.size() > 0) {
1310   - //#2.1
  1359 + //#1.1
  1360 + ConcurrentMap<String, String> keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient);
  1361 + if (keyNamesMap.values().size() > 0) {
1311 1362 try {
1312   - TransportProtos.GetAttributeRequestMsg getAttributeMsg = lwM2mTransportContextServer.getAdaptor().convertToGetAttributes(null, attrSharedNames);
  1363 + //#1.2
  1364 + TransportProtos.GetAttributeRequestMsg getAttributeMsg = helper.getAdaptor().convertToGetAttributes(null, keyNamesMap.values());
1313 1365 transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST));
1314 1366 } catch (AdaptorException e) {
1315 1367 log.warn("Failed to decode get attributes request", e);
1316 1368 }
1317 1369 }
  1370 +
  1371 + }
  1372 + }
  1373 +
  1374 + public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient) {
  1375 + SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration());
  1376 + if (sessionInfo != null) {
  1377 + TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
  1378 + .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
  1379 + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
  1380 + .setTenantIdMSB(sessionInfo.getTenantIdMSB())
  1381 + .setTenantIdLSB(sessionInfo.getTenantIdLSB())
  1382 + .setType(FirmwareType.FIRMWARE.name())
  1383 + .build();
  1384 + transportService.process(sessionInfo, getFirmwareRequestMsg,
  1385 + new TransportServiceCallback<>() {
  1386 + @Override
  1387 + public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) {
  1388 + if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) {
  1389 + lwM2MClient.getFrUpdate().setCurrentFwVersion(response.getVersion());
  1390 + lwM2MClient.getFrUpdate().setCurrentFwId(new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())).getId());
  1391 + lwM2MClient.setUpdateFw(true);
  1392 + readRequestToClientFirmwareVer(lwM2MClient.getRegistration());
  1393 + } else {
  1394 + log.trace("Firmware [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
  1395 + }
  1396 + }
  1397 +
  1398 + @Override
  1399 + public void onError(Throwable e) {
  1400 + log.trace("Failed to process credentials ", e);
  1401 + }
  1402 + });
  1403 + }
  1404 + }
  1405 +
  1406 + /**
  1407 + * @param registration
  1408 + */
  1409 + public void readRequestToClientFirmwareVer(Registration registration) {
  1410 + String pathIdVer = convertPathFromObjectIdToIdVer(FR_PATH_RESOURCE_VER_ID, registration);
  1411 + lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, READ, ContentFormat.TLV.getName(),
  1412 + null, config.getTimeout(), null);
  1413 + }
  1414 +
  1415 + /**
  1416 + *
  1417 + * @param lwM2MClient -
  1418 + */
  1419 + public void updateFirmwareClient(LwM2mClient lwM2MClient) {
  1420 + if (!lwM2MClient.getFrUpdate().getCurrentFwVersion().equals(lwM2MClient.getFrUpdate().getClientFwVersion())) {
  1421 + int chunkSize = 0;
  1422 + int chunk = 0;
  1423 + byte[] firmwareChunk = firmwareDataCache.get(lwM2MClient.getFrUpdate().getCurrentFwId().toString(), chunkSize, chunk);
  1424 + String verSupportedObject = lwM2MClient.getRegistration().getSupportedObject().get(FR_OBJECT_ID);
  1425 + String targetIdVer = LWM2M_SEPARATOR_PATH + FR_OBJECT_ID + LWM2M_SEPARATOR_KEY + verSupportedObject + LWM2M_SEPARATOR_PATH + 0 + LWM2M_SEPARATOR_PATH + 0;
  1426 + lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(),
  1427 + firmwareChunk, config.getTimeout(), null);
  1428 + log.warn("updateFirmwareClient [{}] [{}]", lwM2MClient.getFrUpdate().getCurrentFwVersion(), lwM2MClient.getFrUpdate().getClientFwVersion());
1318 1429 }
1319 1430 }
1320 1431
... ... @@ -1326,27 +1437,16 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1326 1437 * @param lwM2MClient -
1327 1438 * @return ArrayList keyNames from profile profileAttr && IsWritable
1328 1439 */
1329   - private List<String> getNamesAttrFromProfileIsWritable(LwM2mClient lwM2MClient) {
  1440 + private ConcurrentMap<String, String> getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) {
  1441 +
1330 1442 LwM2mClientProfile profile = lwM2mClientContext.getProfile(lwM2MClient.getProfileId());
1331   - Set<String> attrSet = new Gson().fromJson(profile.getPostAttributeProfile(),
1332   - new TypeToken<HashSet<String>>() {
1333   - }.getType());
1334   - ConcurrentMap<String, String> keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(),
  1443 + return new Gson().fromJson(profile.getPostKeyNameProfile().toString(),
1335 1444 new TypeToken<ConcurrentHashMap<String, String>>() {
1336 1445 }.getType());
1337   -
1338   - ConcurrentMap<String, String> keyNamesIsWritable = keyNamesMap.entrySet()
1339   - .stream()
1340   - .filter(e -> (attrSet.contains(e.getKey()) && validateResourceInModel(lwM2MClient, e.getKey(), true)))
1341   - .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue));
1342   -
1343   - Set<String> namesIsWritable = ConcurrentHashMap.newKeySet();
1344   - namesIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values()));
1345   - return new ArrayList<>(namesIsWritable);
1346 1446 }
1347 1447
1348 1448 private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) {
1349   - ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer()
  1449 + ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer, this.config
1350 1450 .getModelProvider());
1351 1451 Integer objectId = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)).getObjectId();
1352 1452 String objectVer = validateObjectVerFromKey(pathIdVer);
... ... @@ -1355,9 +1455,4 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1355 1455 objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)));
1356 1456 }
1357 1457
1358   - @Override
1359   - public String getName() {
1360   - return "LWM2M";
1361   - }
1362   -
1363 1458 }
... ...
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java renamed from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerConfiguration.java
... ... @@ -15,7 +15,10 @@
15 15 */
16 16 package org.thingsboard.server.transport.lwm2m.server;
17 17
  18 +import lombok.RequiredArgsConstructor;
18 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.californium.core.network.config.NetworkConfig;
  21 +import org.eclipse.californium.core.network.stack.BlockwiseLayer;
19 22 import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
20 23 import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder;
21 24 import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder;
... ... @@ -27,12 +30,16 @@ import org.eclipse.leshan.server.model.LwM2mModelProvider;
27 30 import org.eclipse.leshan.server.security.DefaultAuthorizer;
28 31 import org.eclipse.leshan.server.security.EditableSecurityStore;
29 32 import org.eclipse.leshan.server.security.SecurityChecker;
30   -import org.springframework.context.annotation.Bean;
31 33 import org.springframework.stereotype.Component;
  34 +import org.thingsboard.server.common.data.StringUtils;
32 35 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
  36 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
  37 +import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC;
33 38 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
34 39 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
35 40
  41 +import javax.annotation.PostConstruct;
  42 +import javax.annotation.PreDestroy;
36 43 import java.math.BigInteger;
37 44 import java.security.AlgorithmParameters;
38 45 import java.security.KeyFactory;
... ... @@ -57,61 +64,86 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE
57 64 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
58 65 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256;
59 66 import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8;
60   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig;
  67 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig;
61 68
62 69 @Slf4j
63 70 @Component
64 71 @TbLwM2mTransportComponent
65   -public class LwM2mTransportServerConfiguration {
  72 +@RequiredArgsConstructor
  73 +public class DefaultLwM2mTransportService implements LwM2MTransportService {
  74 +
66 75 private PublicKey publicKey;
67 76 private PrivateKey privateKey;
68 77 private boolean pskMode = false;
69   - private final LwM2mTransportContextServer context;
  78 +
  79 + private final LwM2mTransportContext context;
  80 + private final LwM2MTransportServerConfig config;
  81 + private final LwM2mTransportServerHelper helper;
  82 + private final LwM2mTransportMsgHandler handler;
70 83 private final CaliforniumRegistrationStore registrationStore;
71 84 private final EditableSecurityStore securityStore;
72 85 private final LwM2mClientContext lwM2mClientContext;
73 86
74   - public LwM2mTransportServerConfiguration(LwM2mTransportContextServer context, CaliforniumRegistrationStore registrationStore, EditableSecurityStore securityStore, LwM2mClientContext lwM2mClientContext) {
75   - this.context = context;
76   - this.registrationStore = registrationStore;
77   - this.securityStore = securityStore;
78   - this.lwM2mClientContext = lwM2mClientContext;
  87 + private LeshanServer server;
  88 +
  89 + @PostConstruct
  90 + public void init() {
  91 + if (config.getEnableGenNewKeyPskRpk()) {
  92 + new LWM2MGenerationPSkRPkECC();
  93 + }
  94 + this.server = getLhServer(config.getPort(), config.getSecurePort());
  95 + this.startLhServer();
  96 + this.context.setServer(server);
  97 + }
  98 +
  99 + private void startLhServer() {
  100 + log.info("Starting LwM2M transport Server...");
  101 + this.server.start();
  102 + LwM2mServerListener lhServerCertListener = new LwM2mServerListener(handler);
  103 + this.server.getRegistrationService().addListener(lhServerCertListener.registrationListener);
  104 + this.server.getPresenceService().addListener(lhServerCertListener.presenceListener);
  105 + this.server.getObservationService().addListener(lhServerCertListener.observationListener);
79 106 }
80 107
81   - @Bean
82   - public LeshanServer getLeshanServer() {
83   - log.info("Starting LwM2M transport Server... PostConstruct");
84   - return this.getLhServer(this.context.getLwM2MTransportConfigServer().getServerPortNoSec(), this.context.getLwM2MTransportConfigServer().getServerPortSecurity());
  108 + @PreDestroy
  109 + public void shutdown() {
  110 + log.info("Stopping LwM2M transport Server!");
  111 + server.destroy();
  112 + log.info("LwM2M transport Server stopped!");
85 113 }
86 114
87 115 private LeshanServer getLhServer(Integer serverPortNoSec, Integer serverSecurePort) {
88 116 LeshanServerBuilder builder = new LeshanServerBuilder();
89   - builder.setLocalAddress(this.context.getLwM2MTransportConfigServer().getServerHost(), serverPortNoSec);
90   - builder.setLocalSecureAddress(this.context.getLwM2MTransportConfigServer().getServerHostSecurity(), serverSecurePort);
  117 + builder.setLocalAddress(config.getHost(), serverPortNoSec);
  118 + builder.setLocalSecureAddress(config.getSecureHost(), serverSecurePort);
91 119 builder.setDecoder(new DefaultLwM2mNodeDecoder());
92   - /** Use a magic converter to support bad type send by the UI. */
  120 + /* Use a magic converter to support bad type send by the UI. */
93 121 builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance()));
94 122
95   - /** Create CoAP Config */
  123 +
  124 + /* Create CoAP Config */
  125 + NetworkConfig networkConfig = getCoapConfig(serverPortNoSec, serverSecurePort);
  126 + BlockwiseLayer blockwiseLayer = new BlockwiseLayer(networkConfig);
96 127 builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort));
97 128
98   - /** Define model provider (Create Models )*/
99   - LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.lwM2mClientContext, this.context);
100   - this.context.getLwM2MTransportConfigServer().setModelProvider(modelProvider);
  129 + /* Define model provider (Create Models )*/
  130 + LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.lwM2mClientContext, this.helper, this.context);
  131 + config.setModelProvider(modelProvider);
101 132 builder.setObjectModelProvider(modelProvider);
102 133
103   - /** Create credentials */
  134 + /* Create credentials */
104 135 this.setServerWithCredentials(builder);
105 136
106   - /** Set securityStore with new registrationStore */
  137 + /* Set securityStore with new registrationStore */
107 138 builder.setSecurityStore(securityStore);
108 139 builder.setRegistrationStore(registrationStore);
109 140
110 141
111   - /** Create DTLS Config */
  142 + /* Create DTLS Config */
112 143 DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
113   - dtlsConfig.setRecommendedSupportedGroupsOnly(this.context.getLwM2MTransportConfigServer().isRecommendedSupportedGroups());
114   - dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getLwM2MTransportConfigServer().isRecommendedCiphers());
  144 + dtlsConfig.setServerOnly(true);
  145 + dtlsConfig.setRecommendedSupportedGroupsOnly(config.isRecommendedSupportedGroups());
  146 + dtlsConfig.setRecommendedCipherSuitesOnly(config.isRecommendedCiphers());
115 147 if (this.pskMode) {
116 148 dtlsConfig.setSupportedCipherSuites(
117 149 TLS_PSK_WITH_AES_128_CCM_8,
... ... @@ -124,27 +156,27 @@ public class LwM2mTransportServerConfiguration {
124 156 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256);
125 157 }
126 158
127   - /** Set DTLS Config */
  159 + /* Set DTLS Config */
128 160 builder.setDtlsConfig(dtlsConfig);
129 161
130   - /** Create LWM2M server */
  162 + /* Create LWM2M server */
131 163 return builder.build();
132 164 }
133 165
134 166 private void setServerWithCredentials(LeshanServerBuilder builder) {
135 167 try {
136   - if (this.context.getLwM2MTransportConfigServer().getKeyStoreValue() != null) {
  168 + if (config.getKeyStoreValue() != null) {
137 169 if (this.setBuilderX509(builder)) {
138   - X509Certificate rootCAX509Cert = (X509Certificate) this.context.getLwM2MTransportConfigServer().getKeyStoreValue().getCertificate(this.context.getLwM2MTransportConfigServer().getRootAlias());
  170 + X509Certificate rootCAX509Cert = (X509Certificate) config.getKeyStoreValue().getCertificate(config.getRootCertificateAlias());
139 171 if (rootCAX509Cert != null) {
140 172 X509Certificate[] trustedCertificates = new X509Certificate[1];
141 173 trustedCertificates[0] = rootCAX509Cert;
142 174 builder.setTrustedCertificates(trustedCertificates);
143 175 } else {
144   - /** by default trust all */
  176 + /* by default trust all */
145 177 builder.setTrustedCertificates(new X509Certificate[0]);
146 178 }
147   - /** Set securityStore with registrationStore*/
  179 + /* Set securityStore with registrationStore*/
148 180 builder.setAuthorizer(new DefaultAuthorizer(securityStore, new SecurityChecker() {
149 181 @Override
150 182 protected boolean matchX509Identity(String endpoint, String receivedX509CommonName,
... ... @@ -157,7 +189,7 @@ public class LwM2mTransportServerConfiguration {
157 189 this.infoPramsUri("RPK");
158 190 this.infoParamsServerKey(this.publicKey, this.privateKey);
159 191 } else {
160   - /** by default trust all */
  192 + /* by default trust all */
161 193 builder.setTrustedCertificates(new X509Certificate[0]);
162 194 log.info("Unable to load X509 files for LWM2MServer");
163 195 this.pskMode = true;
... ... @@ -169,17 +201,11 @@ public class LwM2mTransportServerConfiguration {
169 201 }
170 202
171 203 private boolean setBuilderX509(LeshanServerBuilder builder) {
172   - /**
173   - * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE
174   - * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks
175   - */
176 204 try {
177   - X509Certificate serverCertificate = (X509Certificate) this.context.getLwM2MTransportConfigServer().getKeyStoreValue().getCertificate(this.context.getLwM2MTransportConfigServer().getServerAlias());
178   - PrivateKey privateKey = (PrivateKey) this.context.getLwM2MTransportConfigServer().getKeyStoreValue().getKey(this.context.getLwM2MTransportConfigServer().getServerAlias(), this.context.getLwM2MTransportConfigServer().getKeyStorePasswordServer() == null ? null : this.context.getLwM2MTransportConfigServer().getKeyStorePasswordServer().toCharArray());
  205 + X509Certificate serverCertificate = (X509Certificate) config.getKeyStoreValue().getCertificate(config.getCertificateAlias());
  206 + PrivateKey privateKey = (PrivateKey) config.getKeyStoreValue().getKey(config.getCertificateAlias(), config.getKeyStorePassword() == null ? null : config.getKeyStorePassword().toCharArray());
179 207 PublicKey publicKey = serverCertificate.getPublicKey();
180   - if (serverCertificate != null &&
181   - privateKey != null && privateKey.getEncoded().length > 0 &&
182   - publicKey != null && publicKey.getEncoded().length > 0) {
  208 + if (privateKey != null && privateKey.getEncoded().length > 0 && publicKey != null && publicKey.getEncoded().length > 0) {
183 209 builder.setPublicKey(serverCertificate.getPublicKey());
184 210 builder.setPrivateKey(privateKey);
185 211 builder.setCertificateChain(new X509Certificate[]{serverCertificate});
... ... @@ -206,10 +232,12 @@ public class LwM2mTransportServerConfiguration {
206 232 }
207 233
208 234 private void infoPramsUri(String mode) {
209   - log.info("Server uses [{}]: serverNoSecureURI : [{}], serverSecureURI : [{}]",
210   - mode,
211   - this.context.getLwM2MTransportConfigServer().getServerHost() + ":" + this.context.getLwM2MTransportConfigServer().getServerPortNoSec(),
212   - this.context.getLwM2MTransportConfigServer().getServerHostSecurity() + ":" + this.context.getLwM2MTransportConfigServer().getServerPortSecurity());
  235 + LwM2MTransportServerConfig lwM2MTransportServerConfig = config;
  236 + log.info("Server uses [{}]: serverNoSecureURI : [{}:{}], serverSecureURI : [{}:{}]", mode,
  237 + lwM2MTransportServerConfig.getHost(),
  238 + lwM2MTransportServerConfig.getPort(),
  239 + lwM2MTransportServerConfig.getSecureHost(),
  240 + lwM2MTransportServerConfig.getSecurePort());
213 241 }
214 242
215 243 private boolean setServerRPK(LeshanServerBuilder builder) {
... ... @@ -227,55 +255,42 @@ public class LwM2mTransportServerConfiguration {
227 255 return false;
228 256 }
229 257
230   -
231   - /**
232   - * From yml: server
233   - * public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}"
234   - * public_y: "${LWM2M_SERVER_PUBLIC_Y:30c9237e946a3a1692c1cafaa01a238a077f632c99371348337512363f28212b}"
235   - * private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED:274671fe40ce937b8a6352cf0a418e8a39e4bf0bb9bf74c910db953c20c73802}"
236   - */
237 258 private void generateKeyForRPK() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException {
238   - /** Get Elliptic Curve Parameter spec for secp256r1 */
  259 + /* Get Elliptic Curve Parameter spec for secp256r1 */
239 260 AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
240 261 algoParameters.init(new ECGenParameterSpec("secp256r1"));
241 262 ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);
242   - if (this.context.getLwM2MTransportConfigServer().getServerPublicX() != null &&
243   - !this.context.getLwM2MTransportConfigServer().getServerPublicX().isEmpty() &&
244   - this.context.getLwM2MTransportConfigServer().getServerPublicY() != null &&
245   - !this.context.getLwM2MTransportConfigServer().getServerPublicY().isEmpty()) {
246   - /** Get point values */
247   - byte[] publicX = Hex.decodeHex(this.context.getLwM2MTransportConfigServer().getServerPublicX().toCharArray());
248   - byte[] publicY = Hex.decodeHex(this.context.getLwM2MTransportConfigServer().getServerPublicY().toCharArray());
249   - /** Create key specs */
  263 + LwM2MTransportServerConfig serverConfig = config;
  264 + if (StringUtils.isNotEmpty(serverConfig.getPublicX()) && StringUtils.isNotEmpty(serverConfig.getPublicY())) {
  265 + byte[] publicX = Hex.decodeHex(serverConfig.getPublicX().toCharArray());
  266 + byte[] publicY = Hex.decodeHex(serverConfig.getPublicY().toCharArray());
250 267 KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),
251 268 parameterSpec);
252   - /** Get keys */
253 269 this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);
254 270 }
255   - if (this.context.getLwM2MTransportConfigServer().getServerPrivateEncoded() != null &&
256   - !this.context.getLwM2MTransportConfigServer().getServerPrivateEncoded().isEmpty()) {
257   - /** Get private key */
258   - byte[] privateS = Hex.decodeHex(this.context.getLwM2MTransportConfigServer().getServerPrivateEncoded().toCharArray());
  271 + String privateEncodedKey = serverConfig.getPrivateEncoded();
  272 + if (StringUtils.isNotEmpty(privateEncodedKey)) {
  273 + byte[] privateS = Hex.decodeHex(privateEncodedKey.toCharArray());
259 274 try {
260 275 this.privateKey = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(privateS));
261 276 } catch (InvalidKeySpecException ignore2) {
262   - log.error("Invalid Server rpk.PrivateKey.getEncoded () [{}}]. PrivateKey has no EC algorithm", this.context.getLwM2MTransportConfigServer().getServerPrivateEncoded());
  277 + log.error("Invalid Server rpk.PrivateKey.getEncoded () [{}}]. PrivateKey has no EC algorithm", privateEncodedKey);
263 278 }
264 279 }
265 280 }
266 281
267 282 private void infoParamsServerKey(PublicKey publicKey, PrivateKey privateKey) {
268   - /** Get x coordinate */
  283 + /* Get x coordinate */
269 284 byte[] x = ((ECPublicKey) publicKey).getW().getAffineX().toByteArray();
270 285 if (x[0] == 0)
271 286 x = Arrays.copyOfRange(x, 1, x.length);
272 287
273   - /** Get Y coordinate */
  288 + /* Get Y coordinate */
274 289 byte[] y = ((ECPublicKey) publicKey).getW().getAffineY().toByteArray();
275 290 if (y[0] == 0)
276 291 y = Arrays.copyOfRange(y, 1, y.length);
277 292
278   - /** Get Curves params */
  293 + /* Get Curves params */
279 294 String params = ((ECPublicKey) publicKey).getParams().toString();
280 295 String privHex = Hex.encodeHexString(privateKey.getEncoded());
281 296 log.info(" \n- Public Key (Hex): [{}] \n" +
... ... @@ -292,4 +307,9 @@ public class LwM2mTransportServerConfiguration {
292 307 params);
293 308 }
294 309
  310 + @Override
  311 + public String getName() {
  312 + return "LWM2M";
  313 + }
  314 +
295 315 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server;
  17 +
  18 +import org.thingsboard.server.common.data.TbTransportService;
  19 +
  20 +public interface LwM2MTransportService extends TbTransportService {
  21 +
  22 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server;
  17 +
  18 +import org.eclipse.californium.core.network.config.NetworkConfig;
  19 +
  20 +public class LwM2mNetworkConfig {
  21 +
  22 + public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort) {
  23 + NetworkConfig coapConfig = new NetworkConfig();
  24 + coapConfig.setInt(NetworkConfig.Keys.COAP_PORT,serverPortNoSec);
  25 + coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT,serverSecurePort);
  26 + /*
  27 + Example:Property for large packet:
  28 + #NetworkConfig config = new NetworkConfig();
  29 + #config.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE,32);
  30 + #config.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE,32);
  31 + #config.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE,2048);
  32 + #config.setInt(NetworkConfig.Keys.MAX_RETRANSMIT,3);
  33 + #config.setInt(NetworkConfig.Keys.MAX_TRANSMIT_WAIT,120000);
  34 + */
  35 +
  36 + /*
  37 + Property to indicate if the response should always include the Block2 option \
  38 + when client request early blockwise negociation but the response can be sent on one packet.
  39 + - value of false indicate that the server will respond without block2 option if no further blocks are required.
  40 + - value of true indicate that the server will response with block2 option event if no further blocks are required.
  41 + CoAP client will try to use block mode
  42 + or adapt the block size when receiving a 4.13 Entity too large response code
  43 + */
  44 + coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true);
  45 + /*
  46 + Property to indicate if the response should always include the Block2 option \
  47 + when client request early blockwise negociation but the response can be sent on one packet.
  48 + - value of false indicate that the server will respond without block2 option if no further blocks are required.
  49 + - value of true indicate that the server will response with block2 option event if no further blocks are required.
  50 + */
  51 + coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true);
  52 +
  53 + coapConfig.setInt(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, 300000);
  54 + /*
  55 + !!! REQUEST_ENTITY_TOO_LARGE CODE=4.13
  56 + The maximum size of a resource body (in bytes) that will be accepted
  57 + as the payload of a POST/PUT or the response to a GET request in a
  58 + transparent> blockwise transfer.
  59 + This option serves as a safeguard against excessive memory
  60 + consumption when many resources contain large bodies that cannot be
  61 + transferred in a single CoAP message. This option has no impact on
  62 + *manually* managed blockwise transfers in which the blocks are handled individually.
  63 + Note that this option does not prevent local clients or resource
  64 + implementations from sending large bodies as part of a request or response to a peer.
  65 + The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192
  66 + A value of {@code 0} turns off transparent handling of blockwise transfers altogether.
  67 + */
  68 + coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
  69 + /*
  70 + The default DTLS response matcher.
  71 + Supported values are STRICT, RELAXED, or PRINCIPAL.
  72 + The default value is STRICT.
  73 + Create new instance of udp endpoint context matcher.
  74 + Params:
  75 + checkAddress
  76 + – true with address check, (STRICT, UDP)
  77 + - false, without
  78 + */
  79 + coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "STRICT");
  80 + /*
  81 + https://tools.ietf.org/html/rfc7959#section-2.9.3
  82 + The block size (number of bytes) to use when doing a blockwise transfer. \
  83 + This value serves as the upper limit for block size in blockwise transfers
  84 + */
  85 + coapConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024);
  86 + /*
  87 + The maximum payload size (in bytes) that can be transferred in a
  88 + single message, i.e. without requiring a blockwise transfer.
  89 + NB: this value MUST be adapted to the maximum message size supported by the transport layer.
  90 + In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol
  91 + DEFAULT_VALUE = 1024
  92 + */
  93 + coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024);
  94 +
  95 + coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 4);
  96 +
  97 + return coapConfig;
  98 + }
  99 +}
... ...
... ... @@ -26,14 +26,15 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate;
26 26
27 27 import java.util.Collection;
28 28
29   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
  29 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_INFO;
  30 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.convertPathFromObjectIdToIdVer;
30 31
31 32 @Slf4j
32 33 public class LwM2mServerListener {
33 34
34   - private final LwM2mTransportServiceImpl service;
  35 + private final LwM2mTransportMsgHandler service;
35 36
36   - public LwM2mServerListener(LwM2mTransportServiceImpl service) {
  37 + public LwM2mServerListener(LwM2mTransportMsgHandler service) {
37 38 this.service = service;
38 39 }
39 40
... ... @@ -85,17 +86,19 @@ public class LwM2mServerListener {
85 86
86 87 @Override
87 88 public void cancelled(Observation observation) {
88   - log.info("Received notification cancelled from [{}] ", observation.getPath());
  89 + String msg = String.format("%s: Cancel Observation %s.", LOG_LW2M_INFO, observation.getPath());
  90 + service.sendLogsToThingsboard(msg, observation.getRegistrationId());
  91 + log.trace(msg);
89 92 }
90 93
91 94 @Override
92 95 public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
93 96 if (registration != null) {
94 97 try {
95   - service.onObservationResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(),
  98 + service.onUpdateValueAfterReadResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(),
96 99 registration), response, null);
97 100 } catch (Exception e) {
98   - log.error("[{}] onResponse", e.toString());
  101 + log.error("Observation/Read onResponse", e);
99 102
100 103 }
101 104 }
... ... @@ -108,7 +111,10 @@ public class LwM2mServerListener {
108 111
109 112 @Override
110 113 public void newObservation(Observation observation, Registration registration) {
111   - log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint());
  114 + String msg = String.format("%s: Successful start newObservation %s.", LOG_LW2M_INFO,
  115 + observation.getPath());
  116 + service.sendLogsToThingsboard(msg, registration.getId());
  117 + log.trace(msg);
112 118 }
113 119 };
114 120
... ...
... ... @@ -35,10 +35,10 @@ import java.util.Optional;
35 35
36 36 @Slf4j
37 37 public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? super Void>>, SessionMsgListener {
38   - private LwM2mTransportServiceImpl service;
  38 + private DefaultLwM2MTransportMsgHandler service;
39 39 private TransportProtos.SessionInfoProto sessionInfo;
40 40
41   - public LwM2mSessionMsgListener(LwM2mTransportServiceImpl service, TransportProtos.SessionInfoProto sessionInfo) {
  41 + public LwM2mSessionMsgListener(DefaultLwM2MTransportMsgHandler service, TransportProtos.SessionInfoProto sessionInfo) {
42 42 this.service = service;
43 43 this.sessionInfo = sessionInfo;
44 44 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server;
  17 +
  18 +import lombok.Getter;
  19 +import lombok.Setter;
  20 +import org.eclipse.leshan.server.californium.LeshanServer;
  21 +import org.springframework.stereotype.Component;
  22 +import org.thingsboard.server.common.transport.TransportContext;
  23 +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
  24 +
  25 +@Component
  26 +@TbLwM2mTransportComponent
  27 +public class LwM2mTransportContext extends TransportContext {
  28 +
  29 + @Getter @Setter
  30 + private LeshanServer server;
  31 +
  32 +}
... ...
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandlerUtil.java renamed from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java
... ... @@ -25,7 +25,6 @@ import com.google.gson.JsonSyntaxException;
25 25 import com.google.gson.reflect.TypeToken;
26 26 import lombok.extern.slf4j.Slf4j;
27 27 import org.apache.commons.lang3.StringUtils;
28   -import org.eclipse.californium.core.network.config.NetworkConfig;
29 28 import org.eclipse.leshan.core.attributes.Attribute;
30 29 import org.eclipse.leshan.core.attributes.AttributeSet;
31 30 import org.eclipse.leshan.core.model.ObjectModel;
... ... @@ -40,7 +39,6 @@ import org.eclipse.leshan.core.node.codec.CodecException;
40 39 import org.eclipse.leshan.core.request.DownlinkRequest;
41 40 import org.eclipse.leshan.core.request.WriteAttributesRequest;
42 41 import org.eclipse.leshan.core.util.Hex;
43   -import org.eclipse.leshan.server.californium.LeshanServerBuilder;
44 42 import org.eclipse.leshan.server.registration.Registration;
45 43 import org.nustaq.serialization.FSTConfiguration;
46 44 import org.thingsboard.server.common.data.DeviceProfile;
... ... @@ -50,7 +48,6 @@ import org.thingsboard.server.common.transport.TransportServiceCallback;
50 48 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
51 49 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
52 50
53   -import java.io.File;
54 51 import java.io.IOException;
55 52 import java.util.ArrayList;
56 53 import java.util.Arrays;
... ... @@ -70,9 +67,8 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA
70 67 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
71 68
72 69 @Slf4j
73   -public class LwM2mTransportHandler {
  70 +public class LwM2mTransportHandlerUtil {
74 71
75   - // public static final String BASE_DEVICE_API_TOPIC = "v1/devices/me";
76 72 public static final String TRANSPORT_DEFAULT_LWM2M_VERSION = "1.0";
77 73 public static final String CLIENT_LWM2M_SETTINGS = "clientLwM2mSettings";
78 74 public static final String BOOTSTRAP = "bootstrap";
... ... @@ -85,19 +81,12 @@ public class LwM2mTransportHandler {
85 81 public static final String KEY_NAME = "keyName";
86 82 public static final String OBSERVE_LWM2M = "observe";
87 83 public static final String ATTRIBUTE_LWM2M = "attributeLwm2m";
88   -// public static final String RESOURCE_VALUE = "resValue";
89   -// public static final String RESOURCE_TYPE = "resType";
90 84
91 85 private static final String REQUEST = "/request";
92   - // private static final String RESPONSE = "/response";
93 86 private static final String ATTRIBUTES = "/" + ATTRIBUTE;
94 87 public static final String TELEMETRIES = "/" + TELEMETRY;
95   - // public static final String ATTRIBUTES_RESPONSE = ATTRIBUTES + RESPONSE;
96 88 public static final String ATTRIBUTES_REQUEST = ATTRIBUTES + REQUEST;
97   - // public static final String DEVICE_ATTRIBUTES_RESPONSE = ATTRIBUTES_RESPONSE + "/";
98 89 public static final String DEVICE_ATTRIBUTES_REQUEST = ATTRIBUTES_REQUEST + "/";
99   -// public static final String DEVICE_ATTRIBUTES_TOPIC = BASE_DEVICE_API_TOPIC + ATTRIBUTES;
100   -// public static final String DEVICE_TELEMETRY_TOPIC = BASE_DEVICE_API_TOPIC + TELEMETRIES;
101 90
102 91 public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms
103 92
... ... @@ -112,6 +101,11 @@ public class LwM2mTransportHandler {
112 101
113 102 public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized";
114 103
  104 + public static final Integer FR_OBJECT_ID = 5;
  105 + public static final Integer FR_RESOURCE_VER_ID = 7;
  106 + public static final String FR_PATH_RESOURCE_VER_ID = LWM2M_SEPARATOR_PATH + FR_OBJECT_ID + LWM2M_SEPARATOR_PATH
  107 + + "0" + LWM2M_SEPARATOR_PATH + FR_RESOURCE_VER_ID;
  108 +
115 109 public enum LwM2mTypeServer {
116 110 BOOTSTRAP(0, "bootstrap"),
117 111 CLIENT(1, "client");
... ... @@ -168,6 +162,8 @@ public class LwM2mTransportHandler {
168 162 WRITE_ATTRIBUTES(8, "WriteAttributes"),
169 163 DELETE(9, "Delete");
170 164
  165 +// READ_INFO_FW(10, "ReadInfoFirmware");
  166 +
171 167 public int code;
172 168 public String type;
173 169
... ... @@ -190,21 +186,6 @@ public class LwM2mTransportHandler {
190 186 public static final String SERVICE_CHANNEL = "SERVICE";
191 187 public static final String RESPONSE_CHANNEL = "RESP";
192 188
193   - public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort) {
194   - NetworkConfig coapConfig;
195   - File configFile = new File(NetworkConfig.DEFAULT_FILE_NAME);
196   - if (configFile.isFile()) {
197   - coapConfig = new NetworkConfig();
198   - coapConfig.load(configFile);
199   - } else {
200   - coapConfig = LeshanServerBuilder.createDefaultNetworkConfig();
201   - coapConfig.store(configFile);
202   - }
203   - coapConfig.setString("COAP_PORT", Integer.toString(serverPortNoSec));
204   - coapConfig.setString("COAP_SECURE_PORT", Integer.toString(serverSecurePort));
205   - return coapConfig;
206   - }
207   -
208 189 public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath resourcePath) throws CodecException {
209 190 switch (type) {
210 191 case BOOLEAN:
... ... @@ -275,7 +256,7 @@ public class LwM2mTransportHandler {
275 256 ObjectMapper mapper = new ObjectMapper();
276 257 String profileStr = mapper.writeValueAsString(profile);
277 258 JsonObject profileJson = (profileStr != null) ? validateJson(profileStr) : null;
278   - return getValidateCredentialsBodyFromThingsboard(profileJson) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null;
  259 + return getValidateCredentialsBodyFromThingsboard(profileJson) ? LwM2mTransportHandlerUtil.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null;
279 260 } catch (IOException e) {
280 261 log.error("", e);
281 262 }
... ...
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java renamed from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportService.java
... ... @@ -27,7 +27,7 @@ import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcReques
27 27 import java.util.Collection;
28 28 import java.util.Optional;
29 29
30   -public interface LwM2mTransportService extends TbTransportService {
  30 +public interface LwM2mTransportMsgHandler {
31 31
32 32 void onRegistered(Registration registration, Collection<Observation> previousObsersations);
33 33
... ... @@ -39,7 +39,7 @@ public interface LwM2mTransportService extends TbTransportService {
39 39
40 40 void setCancelObservations(Registration registration);
41 41
42   - void onObservationResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest);
  42 + void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest);
43 43
44 44 void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo);
45 45
... ... @@ -61,5 +61,7 @@ public interface LwM2mTransportService extends TbTransportService {
61 61
62 62 void doDisconnect(TransportProtos.SessionInfoProto sessionInfo);
63 63
  64 + void onAwakeDev(Registration registration);
64 65
  66 + void sendLogsToThingsboard(String msg, String registrationId);
65 67 }
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.transport.lwm2m.server;
17 17
  18 +import lombok.RequiredArgsConstructor;
18 19 import lombok.SneakyThrows;
19 20 import lombok.extern.slf4j.Slf4j;
20 21 import org.eclipse.californium.core.coap.CoAP;
... ... @@ -50,6 +51,7 @@ import org.eclipse.leshan.server.registration.Registration;
50 51 import org.springframework.stereotype.Service;
51 52 import org.thingsboard.server.common.transport.TransportService;
52 53 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
  54 +import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
53 55 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
54 56 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
55 57 import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest;
... ... @@ -66,50 +68,38 @@ import java.util.stream.Collectors;
66 68 import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT;
67 69 import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST;
68 70 import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND;
69   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEFAULT_TIMEOUT;
70   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR;
71   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO;
72   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_VALUE;
73   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper;
74   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.OBSERVE_CANCEL;
75   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.OBSERVE_READ_ALL;
76   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.RESPONSE_CHANNEL;
77   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
78   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
79   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.createWriteAttributeRequest;
  71 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.DEFAULT_TIMEOUT;
  72 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.FR_PATH_RESOURCE_VER_ID;
  73 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_ERROR;
  74 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_INFO;
  75 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_VALUE;
  76 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper;
  77 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper.OBSERVE_CANCEL;
  78 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper.OBSERVE_READ_ALL;
  79 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.RESPONSE_CHANNEL;
  80 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.convertPathFromIdVerToObjectId;
  81 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.convertPathFromObjectIdToIdVer;
  82 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.createWriteAttributeRequest;
80 83
81 84 @Slf4j
82 85 @Service
83 86 @TbLwM2mTransportComponent
  87 +@RequiredArgsConstructor
84 88 public class LwM2mTransportRequest {
85 89 private ExecutorService executorResponse;
86 90
87 91 public LwM2mValueConverterImpl converter;
88 92
89   - private final LwM2mTransportContextServer lwM2mTransportContextServer;
90   -
  93 + private final LwM2mTransportContext context;
  94 + private final LwM2MTransportServerConfig config;
  95 + private final LwM2mTransportServerHelper lwM2MTransportServerHelper;
91 96 private final LwM2mClientContext lwM2mClientContext;
92   -
93   - private final LeshanServer leshanServer;
94   -
95   - private final LwM2mTransportServiceImpl serviceImpl;
96   -
97   - private final TransportService transportService;
98   -
99   - public LwM2mTransportRequest(LwM2mTransportContextServer lwM2mTransportContextServer,
100   - LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer,
101   - LwM2mTransportServiceImpl serviceImpl, TransportService transportService) {
102   - this.lwM2mTransportContextServer = lwM2mTransportContextServer;
103   - this.lwM2mClientContext = lwM2mClientContext;
104   - this.leshanServer = leshanServer;
105   - this.serviceImpl = serviceImpl;
106   - this.transportService = transportService;
107   - }
  97 + private final DefaultLwM2MTransportMsgHandler serviceImpl;
108 98
109 99 @PostConstruct
110 100 public void init() {
111 101 this.converter = LwM2mValueConverterImpl.getInstance();
112   - executorResponse = Executors.newFixedThreadPool(this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResponsePoolSize(),
  102 + executorResponse = Executors.newFixedThreadPool(this.config.getResponsePoolSize(),
113 103 new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL)));
114 104 }
115 105
... ... @@ -125,7 +115,6 @@ public class LwM2mTransportRequest {
125 115 public void sendAllRequest(Registration registration, String targetIdVer, LwM2mTypeOper typeOper,
126 116 String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) {
127 117 try {
128   -
129 118 String target = convertPathFromIdVerToObjectId(targetIdVer);
130 119 DownlinkRequest request = null;
131 120 ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT;
... ... @@ -145,11 +134,11 @@ public class LwM2mTransportRequest {
145 134 break;
146 135 case OBSERVE:
147 136 if (resultIds.isResource()) {
148   - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
  137 + request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
149 138 } else if (resultIds.isObjectInstance()) {
150   - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId());
  139 + request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId());
151 140 } else if (resultIds.getObjectId() >= 0) {
152   - request = new ObserveRequest(resultIds.getObjectId());
  141 + request = new ObserveRequest(contentFormat, resultIds.getObjectId());
153 142 }
154 143 break;
155 144 case OBSERVE_CANCEL:
... ... @@ -158,10 +147,10 @@ public class LwM2mTransportRequest {
158 147 * At server side this will not remove the observation from the observation store, to do it you need to use
159 148 * {@code ObservationService#cancelObservation()}
160 149 */
161   - leshanServer.getObservationService().cancelObservations(registration, target);
  150 + context.getServer().getObservationService().cancelObservations(registration, target);
162 151 break;
163 152 case EXECUTE:
164   - resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer()
  153 + resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.config
165 154 .getModelProvider());
166 155 if (params != null && !resourceModel.multiple) {
167 156 request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resourceModel.type, ResourceModel.Type.STRING, resultIds));
... ... @@ -171,9 +160,7 @@ public class LwM2mTransportRequest {
171 160 break;
172 161 case WRITE_REPLACE:
173 162 // Request to write a <b>String Single-Instance Resource</b> using the TLV content format.
174   -// resource = lwM2MClient.getResourceModel(targetIdVer);
175   -// if (contentFormat.equals(ContentFormat.TLV) && !resource.multiple) {
176   - resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer()
  163 + resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.config
177 164 .getModelProvider());
178 165 if (contentFormat.equals(ContentFormat.TLV)) {
179 166 request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(),
... ... @@ -181,7 +168,6 @@ public class LwM2mTransportRequest {
181 168 registration, rpcRequest);
182 169 }
183 170 // Mode.REPLACE && Request to write a <b>String Single-Instance Resource</b> using the given content format (TEXT, TLV, JSON)
184   -// else if (!contentFormat.equals(ContentFormat.TLV) && !resource.multiple) {
185 171 else if (!contentFormat.equals(ContentFormat.TLV)) {
186 172 request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(),
187 173 resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModel.type,
... ... @@ -215,13 +201,16 @@ public class LwM2mTransportRequest {
215 201 long finalTimeoutInMs = timeoutInMs;
216 202 lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, rpcRequest));
217 203 } catch (Exception e) {
218   - log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper, e);
  204 + log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper.name(), e);
  205 + }
  206 + } else if (OBSERVE_CANCEL == typeOper) {
  207 + log.trace("[{}], [{}] - [{}] SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer);
  208 + if (rpcRequest != null) {
  209 + rpcRequest.setInfoMsg(null);
  210 + serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), null, null);
219 211 }
220   - } else if (OBSERVE_CANCEL == typeOper && rpcRequest != null) {
221   - rpcRequest.setInfoMsg(null);
222   - serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), null, null);
223 212 } else {
224   - log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper, targetIdVer);
  213 + log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer);
225 214 if (rpcRequest != null) {
226 215 String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null";
227 216 serviceImpl.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
... ... @@ -232,12 +221,12 @@ public class LwM2mTransportRequest {
232 221 serviceImpl.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
233 222 }
234 223 } else if (OBSERVE_READ_ALL.name().equals(typeOper.name())) {
235   - Set<Observation> observations = leshanServer.getObservationService().getObservations(registration);
  224 + Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
236 225 Set<String> observationPaths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet());
237 226 String msg = String.format("%s: type operation %s observation paths - %s", LOG_LW2M_INFO,
238 227 OBSERVE_READ_ALL.type, observationPaths);
239   - serviceImpl.sendLogsToThingsboard(msg, registration);
240   - log.info("[{}], [{}]", registration.getEndpoint(), msg);
  228 + serviceImpl.sendLogsToThingsboard(msg, registration.getId());
  229 + log.trace("[{}] [{}], [{}]", typeOper.name(), registration.getEndpoint(), msg);
241 230 if (rpcRequest != null) {
242 231 String valueMsg = String.format("Observation paths - %s", observationPaths);
243 232 serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE);
... ... @@ -246,7 +235,7 @@ public class LwM2mTransportRequest {
246 235 } catch (Exception e) {
247 236 String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR,
248 237 typeOper.name(), e.getMessage());
249   - serviceImpl.sendLogsToThingsboard(msg, registration);
  238 + serviceImpl.sendLogsToThingsboard(msg, registration.getId());
250 239 throw new Exception(e);
251 240 }
252 241 }
... ... @@ -259,47 +248,55 @@ public class LwM2mTransportRequest {
259 248
260 249 @SuppressWarnings("unchecked")
261 250 private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) {
262   - leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
  251 + context.getServer().send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
263 252 if (!lwM2MClient.isInit()) {
264   - lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
  253 + lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
265 254 }
266 255 if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) {
267 256 this.handleResponse(registration, request.getPath().toString(), response, request, rpcRequest);
268   - if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest()) {
269   - LwM2mNode node = ((WriteRequest) request).getNode();
270   - Object value = this.converter.convertValue(((LwM2mSingleResource) node).getValue(),
271   - ((LwM2mSingleResource) node).getType(), ResourceModel.Type.STRING, request.getPath());
272   - String msg = String.format("%s: sendRequest Replace: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s SendRequest to Client",
273   - LOG_LW2M_INFO, ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(),
274   - response.getCode().getName(), request.getPath().toString(), value);
275   - serviceImpl.sendLogsToThingsboard(msg, registration);
276   - log.info("[{}] [{}] - [{}] [{}] Update SendRequest[{}]", registration.getEndpoint(),
277   - ((Response) response.getCoapResponse()).getCode(), response.getCode(),
278   - request.getPath().toString(), value);
279   - serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, LOG_LW2M_INFO);
280   - }
281 257 } else {
282   - String msg = String.format("%s: sendRequest: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client", LOG_LW2M_ERROR,
  258 + 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 259 ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString());
284   - serviceImpl.sendLogsToThingsboard(msg, registration);
285   - log.error("[{}], [{}] - [{}] [{}] error SendRequest", registration.getEndpoint(), ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString());
  260 + serviceImpl.sendLogsToThingsboard(msg, registration.getId());
  261 + log.error("[{}] [{}], [{}] - [{}] [{}] error SendRequest", request.getClass().getName().toString(), registration.getEndpoint(),
  262 + ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString());
  263 + if (!lwM2MClient.isInit()) {
  264 + lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
  265 + }
286 266 if (rpcRequest != null) {
287 267 serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), response.getErrorMessage(), LOG_LW2M_ERROR);
288 268 }
  269 + /** Not Found
  270 + * set setClient_fw_version = empty
  271 + **/
  272 + if (FR_PATH_RESOURCE_VER_ID.equals(request.getPath().toString()) && lwM2MClient.isUpdateFw()) {
  273 + lwM2MClient.setUpdateFw(false);
  274 + lwM2MClient.getFrUpdate().setClientFwVersion("");
  275 + log.warn("updateFirmwareClient1");
  276 + serviceImpl.updateFirmwareClient(lwM2MClient);
  277 + }
289 278 }
290 279 }, e -> {
  280 + /** version == null
  281 + * set setClient_fw_version = empty
  282 + **/
  283 + if (FR_PATH_RESOURCE_VER_ID.equals(request.getPath().toString()) && lwM2MClient.isUpdateFw()) {
  284 + lwM2MClient.setUpdateFw(false);
  285 + lwM2MClient.getFrUpdate().setClientFwVersion("");
  286 + log.warn("updateFirmwareClient2");
  287 + serviceImpl.updateFirmwareClient(lwM2MClient);
  288 + }
291 289 if (!lwM2MClient.isInit()) {
292   - lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
  290 + lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
293 291 }
294   - String msg = String.format("%s: sendRequest: Resource path - %s msg error - %s SendRequest to Client",
295   - LOG_LW2M_ERROR, request.getPath().toString(), e.getMessage());
296   - serviceImpl.sendLogsToThingsboard(msg, registration);
297   - log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString());
  292 + String msg = String.format("%s: SendRequest %s: Resource path - %s msg error - %s",
  293 + LOG_LW2M_ERROR, request.getClass().getName().toString(), request.getPath().toString(), e.getMessage());
  294 + serviceImpl.sendLogsToThingsboard(msg, registration.getId());
  295 + log.error("[{}] [{}] - [{}] error SendRequest", request.getClass().getName().toString(), request.getPath().toString(), e.toString());
298 296 if (rpcRequest != null) {
299 297 serviceImpl.sentRpcRequest(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR);
300 298 }
301 299 });
302   -
303 300 }
304 301
305 302 private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId,
... ... @@ -323,7 +320,9 @@ public class LwM2mTransportRequest {
323 320 Date date = new Date(Long.decode(value.toString()));
324 321 return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, date) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, date);
325 322 case OPAQUE: // byte[] value, base64
326   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray()));
  323 + byte[] valueRequest = value instanceof byte[] ? (byte[]) value : Hex.decodeHex(value.toString().toCharArray());
  324 + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, valueRequest) :
  325 + new WriteRequest(contentFormat, objectId, instanceId, resourceId, valueRequest);
327 326 default:
328 327 }
329 328 }
... ... @@ -337,7 +336,7 @@ public class LwM2mTransportRequest {
337 336 String patn = "/" + objectId + "/" + instanceId + "/" + resourceId;
338 337 String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client",
339 338 patn, type, value, e.toString());
340   - serviceImpl.sendLogsToThingsboard(msg, registration);
  339 + serviceImpl.sendLogsToThingsboard(msg, registration.getId());
341 340 log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString());
342 341 if (rpcRequest != null) {
343 342 String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value);
... ... @@ -369,7 +368,7 @@ public class LwM2mTransportRequest {
369 368 DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
370 369 String pathIdVer = convertPathFromObjectIdToIdVer(path, registration);
371 370 if (response instanceof ReadResponse) {
372   - serviceImpl.onObservationResponse(registration, pathIdVer, (ReadResponse) response, rpcRequest);
  371 + serviceImpl.onUpdateValueAfterReadResponse(registration, pathIdVer, (ReadResponse) response, rpcRequest);
373 372 } else if (response instanceof CancelObservationResponse) {
374 373 log.info("[{}] Path [{}] CancelObservationResponse 3_Send", pathIdVer, response);
375 374
... ... @@ -389,14 +388,56 @@ public class LwM2mTransportRequest {
389 388 } else if (response instanceof WriteAttributesResponse) {
390 389 log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", pathIdVer, response);
391 390 } else if (response instanceof WriteResponse) {
392   - log.info("[{}] Path [{}] WriteAttributesResponse 9_Send", pathIdVer, response);
  391 + log.info("[{}] Path [{}] WriteResponse 9_Send", pathIdVer, response);
  392 + this.infoWriteResponse(registration, response, request);
393 393 serviceImpl.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request);
394 394 }
395   - if (rpcRequest != null && (response instanceof ExecuteResponse
396   - || response instanceof WriteAttributesResponse
397   - || response instanceof DeleteResponse)) {
398   - rpcRequest.setInfoMsg(null);
399   - serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, null);
  395 + if (rpcRequest != null) {
  396 + if (response instanceof ExecuteResponse
  397 + || response instanceof WriteAttributesResponse
  398 + || response instanceof DeleteResponse) {
  399 + rpcRequest.setInfoMsg(null);
  400 + serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, null);
  401 + } else if (response instanceof WriteResponse) {
  402 + serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, LOG_LW2M_INFO);
  403 + }
  404 + }
  405 + }
  406 +
  407 + private void infoWriteResponse(Registration registration, LwM2mResponse response, DownlinkRequest request) {
  408 + try {
  409 + LwM2mNode node = ((WriteRequest) request).getNode();
  410 + String msg;
  411 + Object value;
  412 + LwM2mSingleResource singleResource = (LwM2mSingleResource) node;
  413 + if (singleResource.getType() == ResourceModel.Type.STRING || singleResource.getType() == ResourceModel.Type.OPAQUE) {
  414 + int valueLength;
  415 + if (singleResource.getType() == ResourceModel.Type.STRING) {
  416 + valueLength = ((String) singleResource.getValue()).length();
  417 + value = ((String) singleResource.getValue())
  418 + .substring(Math.min(valueLength, config.getLogMaxLength()));
  419 +
  420 + } else {
  421 + valueLength = ((byte[]) singleResource.getValue()).length;
  422 + value = new String(Arrays.copyOf(((byte[]) singleResource.getValue()),
  423 + Math.min(valueLength, config.getLogMaxLength())));
  424 + }
  425 + value = valueLength > config.getLogMaxLength() ? value + "..." : value;
  426 + msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path - %s length - %s value - %s",
  427 + LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), valueLength, value);
  428 + } else {
  429 + value = this.converter.convertValue(singleResource.getValue(),
  430 + singleResource.getType(), ResourceModel.Type.STRING, request.getPath());
  431 + msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path - %s value - %s",
  432 + LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), value);
  433 + }
  434 + if (msg != null) {
  435 + serviceImpl.sendLogsToThingsboard(msg, registration.getId());
  436 + log.warn("[{}] [{}] [{}] - [{}] [{}] Update finished successfully: [{}]", request.getClass().getName(), registration.getEndpoint(),
  437 + ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString(), value);
  438 + }
  439 + } catch (Exception e) {
  440 + log.trace("Fail convert value from request to string. ", e);
400 441 }
401 442 }
402 443 }
... ...
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java renamed from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContextServer.java
... ... @@ -31,6 +31,7 @@ package org.thingsboard.server.transport.lwm2m.server;
31 31 */
32 32
33 33 import lombok.Getter;
  34 +import lombok.RequiredArgsConstructor;
34 35 import lombok.extern.slf4j.Slf4j;
35 36 import org.eclipse.leshan.core.model.DDFFileParser;
36 37 import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
... ... @@ -39,11 +40,8 @@ import org.eclipse.leshan.core.model.ObjectModel;
39 40 import org.eclipse.leshan.core.model.ResourceModel;
40 41 import org.eclipse.leshan.core.node.codec.CodecException;
41 42 import org.springframework.stereotype.Component;
42   -import org.thingsboard.server.common.transport.TransportContext;
43   -import org.thingsboard.server.common.transport.TransportResourceCache;
44 43 import org.thingsboard.server.common.transport.TransportService;
45 44 import org.thingsboard.server.common.transport.TransportServiceCallback;
46   -import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer;
47 45 import org.thingsboard.server.gen.transport.TransportProtos;
48 46 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
49 47 import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
... ... @@ -57,39 +55,21 @@ import java.util.ArrayList;
57 55 import java.util.List;
58 56
59 57 import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType.BOOLEAN_V;
60   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY;
  58 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_TELEMETRY;
61 59
62 60 @Slf4j
63 61 @Component
64 62 @TbLwM2mTransportComponent
65   -public class LwM2mTransportContextServer extends TransportContext {
  63 +@RequiredArgsConstructor
  64 +public class LwM2mTransportServerHelper {
66 65
67   -
68   - private final LwM2MTransportConfigServer lwM2MTransportConfigServer;
  66 + private final LwM2mTransportContext context;
69 67
70 68 private final TransportService transportService;
71 69
72   - private final TransportResourceCache transportResourceCache;
73   -
74   -
75 70 @Getter
76 71 private final LwM2MJsonAdaptor adaptor;
77 72
78   - public LwM2mTransportContextServer(LwM2MTransportConfigServer lwM2MTransportConfigServer, TransportService transportService, TransportResourceCache transportResourceCache, LwM2MJsonAdaptor adaptor) {
79   - this.lwM2MTransportConfigServer = lwM2MTransportConfigServer;
80   - this.transportService = transportService;
81   - this.transportResourceCache = transportResourceCache;
82   - this.adaptor = adaptor;
83   - }
84   -
85   - public LwM2MTransportConfigServer getLwM2MTransportConfigServer() {
86   - return this.lwM2MTransportConfigServer;
87   - }
88   -
89   - public TransportResourceCache getTransportResourceCache() {
90   - return this.transportResourceCache;
91   - }
92   -
93 73 /**
94 74 * send to Thingsboard Attribute || Telemetry
95 75 *
... ... @@ -134,7 +114,7 @@ public class LwM2mTransportContextServer extends TransportContext {
134 114 */
135 115 public SessionInfoProto getValidateSessionInfo(TransportProtos.ValidateDeviceCredentialsResponseMsg msg, long mostSignificantBits, long leastSignificantBits) {
136 116 return SessionInfoProto.newBuilder()
137   - .setNodeId(this.getNodeId())
  117 + .setNodeId(context.getNodeId())
138 118 .setSessionIdMSB(mostSignificantBits)
139 119 .setSessionIdLSB(leastSignificantBits)
140 120 .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB())
... ... @@ -165,8 +145,8 @@ public class LwM2mTransportContextServer extends TransportContext {
165 145 * @param logMsg - info about Logs
166 146 * @return- KeyValueProto for telemetry (Logs)
167 147 */
168   - public List <TransportProtos.KeyValueProto> getKvLogyToThingsboard(String logMsg) {
169   - List <TransportProtos.KeyValueProto> result = new ArrayList<>();
  148 + public List<TransportProtos.KeyValueProto> getKvLogyToThingsboard(String logMsg) {
  149 + List<TransportProtos.KeyValueProto> result = new ArrayList<>();
170 150 result.add(TransportProtos.KeyValueProto.newBuilder()
171 151 .setKey(LOG_LW2M_TELEMETRY)
172 152 .setType(TransportProtos.KeyValueType.STRING_V)
... ... @@ -179,32 +159,31 @@ public class LwM2mTransportContextServer extends TransportContext {
179 159 * @throws CodecException -
180 160 */
181 161
182   - public TransportProtos.KeyValueProto getKvAttrTelemetryToThingsboard(ResourceModel.Type resourceType, String resourceName, Object value, boolean isMultiInstances) {
183   - TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(resourceName);
184   - if (isMultiInstances) {
185   - kvProto.setType(TransportProtos.KeyValueType.JSON_V)
186   - .setJsonV((String) value);
  162 + public TransportProtos.KeyValueProto getKvAttrTelemetryToThingsboard(ResourceModel.Type resourceType, String resourceName, Object value, boolean isMultiInstances) {
  163 + TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(resourceName);
  164 + if (isMultiInstances) {
  165 + kvProto.setType(TransportProtos.KeyValueType.JSON_V)
  166 + .setJsonV((String) value);
  167 + } else {
  168 + switch (resourceType) {
  169 + case BOOLEAN:
  170 + kvProto.setType(BOOLEAN_V).setBoolV((Boolean) value).build();
  171 + break;
  172 + case STRING:
  173 + case TIME:
  174 + case OPAQUE:
  175 + case OBJLNK:
  176 + kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV((String) value);
  177 + break;
  178 + case INTEGER:
  179 + kvProto.setType(TransportProtos.KeyValueType.LONG_V).setLongV((Long) value);
  180 + break;
  181 + case FLOAT:
  182 + kvProto.setType(TransportProtos.KeyValueType.DOUBLE_V).setDoubleV((Double) value);
187 183 }
188   - else {
189   - switch (resourceType) {
190   - case BOOLEAN:
191   - kvProto.setType(BOOLEAN_V).setBoolV((Boolean) value).build();
192   - break;
193   - case STRING:
194   - case TIME:
195   - case OPAQUE:
196   - case OBJLNK:
197   - kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV((String) value);
198   - break;
199   - case INTEGER:
200   - kvProto.setType(TransportProtos.KeyValueType.LONG_V).setLongV((Long) value);
201   - break;
202   - case FLOAT:
203   - kvProto.setType(TransportProtos.KeyValueType.DOUBLE_V).setDoubleV((Double) value);
204   - }
205   - }
206   - return kvProto.build();
207 184 }
  185 + return kvProto.build();
  186 + }
208 187
209 188 /**
210 189 *
... ... @@ -230,7 +209,7 @@ public class LwM2mTransportContextServer extends TransportContext {
230 209 throw new CodecException("Invalid ResourceModel_Type for resource %s, got %s", resourcePath, currentType);
231 210 }
232 211
233   - public Object getValueFromKvProto (TransportProtos.KeyValueProto kv) {
  212 + public Object getValueFromKvProto(TransportProtos.KeyValueProto kv) {
234 213 switch (kv.getType()) {
235 214 case BOOLEAN_V:
236 215 return kv.getBoolV();
... ...
... ... @@ -30,35 +30,4 @@ import javax.annotation.PreDestroy;
30 30 @TbLwM2mTransportComponent
31 31 public class LwM2mTransportServerInitializer {
32 32
33   - @Autowired
34   - private LwM2mTransportServiceImpl service;
35   -
36   - @Autowired
37   - private LeshanServer leshanServer;
38   -
39   - @Autowired
40   - private LwM2mTransportContextServer context;
41   -
42   - @PostConstruct
43   - public void init() {
44   - if (this.context.getLwM2MTransportConfigServer().getEnableGenNewKeyPskRpk()) {
45   - new LWM2MGenerationPSkRPkECC();
46   - }
47   - this.startLhServer();
48   - }
49   -
50   - private void startLhServer() {
51   - this.leshanServer.start();
52   - LwM2mServerListener lhServerCertListener = new LwM2mServerListener(service);
53   - this.leshanServer.getRegistrationService().addListener(lhServerCertListener.registrationListener);
54   - this.leshanServer.getPresenceService().addListener(lhServerCertListener.presenceListener);
55   - this.leshanServer.getObservationService().addListener(lhServerCertListener.observationListener);
56   - }
57   -
58   - @PreDestroy
59   - public void shutdown() {
60   - log.info("Stopping LwM2M transport Server!");
61   - leshanServer.destroy();
62   - log.info("LwM2M transport Server stopped!");
63   - }
64 33 }
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.transport.lwm2m.server;
17 17
  18 +import lombok.RequiredArgsConstructor;
18 19 import lombok.extern.slf4j.Slf4j;
19 20 import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
20 21 import org.eclipse.leshan.core.model.LwM2mModel;
... ... @@ -37,6 +38,7 @@ import static org.thingsboard.server.common.data.ResourceType.LWM2M_MODEL;
37 38 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
38 39
39 40 @Slf4j
  41 +@RequiredArgsConstructor
40 42 public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
41 43
42 44 /**
... ... @@ -46,12 +48,8 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
46 48 * Value = TenantId
47 49 */
48 50 private final LwM2mClientContext lwM2mClientContext;
49   - private final LwM2mTransportContextServer lwM2mTransportContextServer;
50   -
51   - public LwM2mVersionedModelProvider(LwM2mClientContext lwM2mClientContext, LwM2mTransportContextServer lwM2mTransportContextServer) {
52   - this.lwM2mClientContext = lwM2mClientContext;
53   - this.lwM2mTransportContextServer = lwM2mTransportContextServer;
54   - }
  51 + private final LwM2mTransportServerHelper helper;
  52 + private final LwM2mTransportContext context;
55 53
56 54 private String getKeyIdVer(Integer objectId, String version) {
57 55 return objectId != null ? objectId + LWM2M_SEPARATOR_KEY + ((version == null || version.isEmpty()) ? ObjectModel.DEFAULT_VERSION : version) : null;
... ... @@ -120,11 +118,9 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
120 118 private ObjectModel getObjectModelDynamic(Integer objectId, String version) {
121 119 String key = getKeyIdVer(objectId, version);
122 120
123   - Optional<TbResource> tbResource = lwM2mTransportContextServer
124   - .getTransportResourceCache()
125   - .get(this.tenantId, LWM2M_MODEL, key);
  121 + Optional<TbResource> tbResource = context.getTransportResourceCache().get(this.tenantId, LWM2M_MODEL, key);
126 122
127   - return tbResource.map(resource -> lwM2mTransportContextServer.parseFromXmlToObjectModel(
  123 + return tbResource.map(resource -> helper.parseFromXmlToObjectModel(
128 124 Base64.getDecoder().decode(resource.getData()),
129 125 key + ".xml",
130 126 new DefaultDDFFileValidator())).orElse(null);
... ...
... ... @@ -24,11 +24,8 @@ import org.thingsboard.server.common.transport.adaptor.AdaptorException;
24 24 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
25 25 import org.thingsboard.server.gen.transport.TransportProtos;
26 26
27   -import java.util.Arrays;
28   -import java.util.HashSet;
29   -import java.util.List;
  27 +import java.util.Collection;
30 28 import java.util.Random;
31   -import java.util.Set;
32 29
33 30 @Slf4j
34 31 @Component("LwM2MJsonAdaptor")
... ... @@ -54,11 +51,7 @@ public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor {
54 51 }
55 52
56 53 @Override
57   - public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(List<String> clientKeys, List<String> sharedKeys) throws AdaptorException {
58   - return processGetAttributeRequestMsg(clientKeys, sharedKeys);
59   - }
60   -
61   - protected TransportProtos.GetAttributeRequestMsg processGetAttributeRequestMsg(List<String> clientKeys, List<String> sharedKeys) throws AdaptorException {
  54 + public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(Collection<String> clientKeys, Collection<String> sharedKeys) throws AdaptorException {
62 55 try {
63 56 TransportProtos.GetAttributeRequestMsg.Builder result = TransportProtos.GetAttributeRequestMsg.newBuilder();
64 57 Random random = new Random();
... ... @@ -75,14 +68,4 @@ public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor {
75 68 throw new AdaptorException(e);
76 69 }
77 70 }
78   -
79   - private Set<String> toStringSet(JsonElement requestBody, String name) {
80   - JsonElement element = requestBody.getAsJsonObject().get(name);
81   - if (element != null) {
82   - return new HashSet<>(Arrays.asList(element.getAsString().split(",")));
83   - } else {
84   - return null;
85   - }
86   - }
87   -
88 71 }
... ...
... ... @@ -19,7 +19,7 @@ import com.google.gson.JsonElement;
19 19 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
20 20 import org.thingsboard.server.gen.transport.TransportProtos;
21 21
22   -import java.util.List;
  22 +import java.util.Collection;
23 23
24 24 public interface LwM2MTransportAdaptor {
25 25
... ... @@ -27,5 +27,5 @@ public interface LwM2MTransportAdaptor {
27 27
28 28 TransportProtos.PostAttributeMsg convertToPostAttributes(JsonElement jsonElement) throws AdaptorException;
29 29
30   - TransportProtos.GetAttributeRequestMsg convertToGetAttributes(List<String> clientKeys, List<String> sharedKeys) throws AdaptorException;
  30 + TransportProtos.GetAttributeRequestMsg convertToGetAttributes(Collection<String> clientKeys, Collection<String> sharedKeys) throws AdaptorException;
31 31 }
... ...
... ... @@ -27,7 +27,7 @@ import org.eclipse.leshan.server.security.SecurityInfo;
27 27 import org.thingsboard.server.gen.transport.TransportProtos;
28 28 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
29 29 import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest;
30   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServiceImpl;
  30 +import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;
31 31 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
32 32
33 33 import java.util.Collection;
... ... @@ -42,9 +42,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
42 42 import java.util.stream.Collectors;
43 43
44 44 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
45   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.TRANSPORT_DEFAULT_LWM2M_VERSION;
46   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
47   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getVerFromPathIdVerOrId;
  45 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.TRANSPORT_DEFAULT_LWM2M_VERSION;
  46 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.convertPathFromIdVerToObjectId;
  47 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.getVerFromPathIdVerOrId;
48 48
49 49 @Slf4j
50 50 @Data
... ... @@ -57,13 +57,15 @@ public class LwM2mClient implements Cloneable {
57 57 private UUID deviceId;
58 58 private UUID sessionId;
59 59 private UUID profileId;
  60 + private volatile LwM2mFirmwareUpdate frUpdate;
60 61 private Registration registration;
61 62 private ValidateDeviceCredentialsResponseMsg credentialsResponse;
62 63 private final Map<String, ResourceValue> resources;
63 64 private final Map<String, TransportProtos.TsKvProto> delayedRequests;
64   - private final List<String> pendingRequests;
  65 + private final List<String> pendingReadRequests;
65 66 private final Queue<LwM2mQueuedRequest> queuedRequests;
66 67 private boolean init;
  68 + private volatile boolean updateFw;
67 69
68 70 public Object clone() throws CloneNotSupportedException {
69 71 return super.clone();
... ... @@ -75,12 +77,14 @@ public class LwM2mClient implements Cloneable {
75 77 this.securityInfo = securityInfo;
76 78 this.credentialsResponse = credentialsResponse;
77 79 this.delayedRequests = new ConcurrentHashMap<>();
78   - this.pendingRequests = new CopyOnWriteArrayList<>();
  80 + this.pendingReadRequests = new CopyOnWriteArrayList<>();
79 81 this.resources = new ConcurrentHashMap<>();
80 82 this.profileId = profileId;
81 83 this.sessionId = sessionId;
82 84 this.init = false;
  85 + this.updateFw = false;
83 86 this.queuedRequests = new ConcurrentLinkedQueue<>();
  87 + this.frUpdate = new LwM2mFirmwareUpdate();
84 88 }
85 89
86 90 public boolean saveResourceValue(String pathRez, LwM2mResource rez, LwM2mModelProvider modelProvider) {
... ... @@ -103,15 +107,13 @@ public class LwM2mClient implements Cloneable {
103 107 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
104 108 String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
105 109 String verRez = getVerFromPathIdVerOrId(pathRez);
106   - return (verRez == null || verSupportedObject.equals(verRez)) ? modelProvider.getObjectModel(registration)
  110 + return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
107 111 .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null;
108 112 }
109 113
110 114 public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, LwM2mModelProvider modelProvider,
111 115 LwM2mValueConverterImpl converter) {
112 116 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer));
113   - String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
114   - String verRez = getVerFromPathIdVerOrId(pathRezIdVer);
115 117 Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
116 118 Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
117 119 .getObjectModel(pathIds.getObjectId()).resources;
... ... @@ -170,11 +172,11 @@ public class LwM2mClient implements Cloneable {
170 172 .collect(Collectors.toSet());
171 173 }
172 174
173   - public void initValue(LwM2mTransportServiceImpl serviceImpl, String path) {
  175 + public void initReadValue(DefaultLwM2MTransportMsgHandler serviceImpl, String path) {
174 176 if (path != null) {
175   - this.pendingRequests.remove(path);
  177 + this.pendingReadRequests.remove(path);
176 178 }
177   - if (this.pendingRequests.size() == 0) {
  179 + if (this.pendingReadRequests.size() == 0) {
178 180 this.init = true;
179 181 serviceImpl.putDelayedUpdateResourcesThingsboard(this);
180 182 }
... ...
... ... @@ -25,7 +25,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
25 25 import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
26 26 import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
27 27 import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
28   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler;
  28 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil;
29 29
30 30 import java.util.Arrays;
31 31 import java.util.Map;
... ... @@ -34,7 +34,7 @@ import java.util.UUID;
34 34 import java.util.concurrent.ConcurrentHashMap;
35 35
36 36 import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC;
37   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
  37 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.convertPathFromObjectIdToIdVer;
38 38
39 39 @Service
40 40 @TbLwM2mTransportComponent
... ... @@ -82,12 +82,12 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
82 82
83 83 @Override
84 84 public LwM2mClient getLwM2mClientWithReg(Registration registration, String registrationId) {
85   - LwM2mClient client = registrationId != null ?
  85 + LwM2mClient client = registrationId != null && this.lwM2mClients.containsKey(registrationId) ?
86 86 this.lwM2mClients.get(registrationId) :
87   - this.lwM2mClients.containsKey(registration.getId()) ?
88   - this.lwM2mClients.get(registration.getId()) :
89   - this.lwM2mClients.get(registration.getEndpoint());
90   - return client != null ? client : updateInSessionsLwM2MClient(registration);
  87 + registration !=null && this.lwM2mClients.containsKey(registration.getId()) ?
  88 + this.lwM2mClients.get(registration.getId()) : registration !=null && this.lwM2mClients.containsKey(registration) ?
  89 + this.lwM2mClients.get(registration.getEndpoint()) : null;
  90 + return client != null ? client : registration!= null ? updateInSessionsLwM2MClient(registration) : null;
91 91 }
92 92
93 93 @Override
... ... @@ -118,7 +118,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
118 118 */
119 119 @Override
120 120 public LwM2mClient addLwM2mClientToSession(String identity) {
121   - ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, LwM2mTransportHandler.LwM2mTypeServer.CLIENT);
  121 + ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, LwM2mTransportHandlerUtil.LwM2mTypeServer.CLIENT);
122 122 if (store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
123 123 UUID profileUuid = (store.getDeviceProfile() != null && addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null;
124 124 LwM2mClient client;
... ... @@ -165,7 +165,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
165 165
166 166 @Override
167 167 public boolean addUpdateProfileParameters(DeviceProfile deviceProfile) {
168   - LwM2mClientProfile lwM2MClientProfile = LwM2mTransportHandler.getLwM2MClientProfileFromThingsboard(deviceProfile);
  168 + LwM2mClientProfile lwM2MClientProfile = LwM2mTransportHandlerUtil.getLwM2MClientProfileFromThingsboard(deviceProfile);
169 169 if (lwM2MClientProfile != null) {
170 170 profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile);
171 171 return true;
... ...
  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 +}
... ...
... ... @@ -21,11 +21,11 @@ import org.eclipse.leshan.core.request.ContentFormat;
21 21 import org.eclipse.leshan.server.registration.Registration;
22 22 import org.thingsboard.server.gen.transport.TransportProtos;
23 23 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
24   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper;
  24 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LwM2mTypeOper;
25 25
26 26 import java.util.concurrent.ConcurrentHashMap;
27 27
28   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.validPathIdVer;
  28 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.validPathIdVer;
29 29
30 30 @Data
31 31 public class Lwm2mClientRpcRequest {
... ...
common/transport/lwm2m/src/main/resources/lwm2mserver.jks renamed from common/transport/lwm2m/src/main/resources/credentials/serverKeyStore.jks
No preview for this file type
... ... @@ -47,6 +47,7 @@ import org.thingsboard.server.common.data.DeviceProfile;
47 47 import org.thingsboard.server.common.data.DeviceTransportType;
48 48 import org.thingsboard.server.common.data.TransportPayloadType;
49 49 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  50 +import org.thingsboard.server.common.data.firmware.FirmwareType;
50 51 import org.thingsboard.server.common.data.id.FirmwareId;
51 52 import org.thingsboard.server.common.msg.EncryptionUtil;
52 53 import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
... ... @@ -59,6 +60,7 @@ import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
59 60 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
60 61 import org.thingsboard.server.common.transport.service.DefaultTransportService;
61 62 import org.thingsboard.server.common.transport.service.SessionMetaData;
  63 +import org.thingsboard.server.common.transport.util.SslUtil;
62 64 import org.thingsboard.server.gen.transport.TransportProtos;
63 65 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
64 66 import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent;
... ... @@ -68,7 +70,6 @@ import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor;
68 70 import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx;
69 71 import org.thingsboard.server.transport.mqtt.session.GatewaySessionHandler;
70 72 import org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher;
71   -import org.thingsboard.server.common.transport.util.SslUtil;
72 73
73 74 import javax.net.ssl.SSLPeerUnverifiedException;
74 75 import java.io.IOException;
... ... @@ -97,6 +98,8 @@ import static io.netty.handler.codec.mqtt.MqttMessageType.UNSUBACK;
97 98 import static io.netty.handler.codec.mqtt.MqttQoS.AT_LEAST_ONCE;
98 99 import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE;
99 100 import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE;
  101 +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN;
  102 +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN;
100 103
101 104 /**
102 105 * @author Andrew Shvayka
... ... @@ -104,7 +107,9 @@ import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE;
104 107 @Slf4j
105 108 public class MqttTransportHandler extends ChannelInboundHandlerAdapter implements GenericFutureListener<Future<? super Void>>, SessionMsgListener {
106 109
107   - private static final Pattern FW_PATTERN = Pattern.compile("v2/fw/request/(?<requestId>\\d+)/chunk/(?<chunk>\\d+)");
  110 + private static final Pattern FW_REQUEST_PATTERN = Pattern.compile(DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN);
  111 + private static final Pattern SW_REQUEST_PATTERN = Pattern.compile(DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN);
  112 +
108 113
109 114 private static final String PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE";
110 115
... ... @@ -314,38 +319,10 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
314 319 } else if (topicName.equals(MqttTopics.DEVICE_CLAIM_TOPIC)) {
315 320 TransportProtos.ClaimDeviceMsg claimDeviceMsg = payloadAdaptor.convertToClaimDevice(deviceSessionCtx, mqttMsg);
316 321 transportService.process(deviceSessionCtx.getSessionInfo(), claimDeviceMsg, getPubAckCallback(ctx, msgId, claimDeviceMsg));
317   - } else if ((fwMatcher = FW_PATTERN.matcher(topicName)).find()) {
318   - String payload = mqttMsg.content().toString(UTF8);
319   - int chunkSize = StringUtils.isNotEmpty(payload) ? Integer.parseInt(payload) : 0;
320   - String requestId = fwMatcher.group("requestId");
321   - int chunk = Integer.parseInt(fwMatcher.group("chunk"));
322   -
323   - if (chunkSize > 0) {
324   - this.fwChunkSizes.put(requestId, chunkSize);
325   - } else {
326   - chunkSize = fwChunkSizes.getOrDefault(requestId, 0);
327   - }
328   -
329   - if (chunkSize > context.getMaxPayloadSize()) {
330   - sendFirmwareError(ctx, PAYLOAD_TOO_LARGE);
331   - return;
332   - }
333   -
334   - String firmwareId = fwSessions.get(requestId);
335   -
336   - if (firmwareId != null) {
337   - sendFirmware(ctx, mqttMsg.variableHeader().packetId(), firmwareId, requestId, chunkSize, chunk);
338   - } else {
339   - TransportProtos.SessionInfoProto sessionInfo = deviceSessionCtx.getSessionInfo();
340   - TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
341   - .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
342   - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
343   - .setTenantIdMSB(sessionInfo.getTenantIdMSB())
344   - .setTenantIdLSB(sessionInfo.getTenantIdLSB())
345   - .build();
346   - transportService.process(deviceSessionCtx.getSessionInfo(), getFirmwareRequestMsg,
347   - new FirmwareCallback(ctx, mqttMsg.variableHeader().packetId(), getFirmwareRequestMsg, requestId, chunkSize, chunk));
348   - }
  322 + } else if ((fwMatcher = FW_REQUEST_PATTERN.matcher(topicName)).find()) {
  323 + getFirmwareCallback(ctx, mqttMsg, msgId, fwMatcher, FirmwareType.FIRMWARE);
  324 + } else if ((fwMatcher = SW_REQUEST_PATTERN.matcher(topicName)).find()) {
  325 + getFirmwareCallback(ctx, mqttMsg, msgId, fwMatcher, FirmwareType.SOFTWARE);
349 326 } else {
350 327 transportService.reportActivity(deviceSessionCtx.getSessionInfo());
351 328 ack(ctx, msgId);
... ... @@ -357,6 +334,41 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
357 334 }
358 335 }
359 336
  337 + private void getFirmwareCallback(ChannelHandlerContext ctx, MqttPublishMessage mqttMsg, int msgId, Matcher fwMatcher, FirmwareType type) {
  338 + String payload = mqttMsg.content().toString(UTF8);
  339 + int chunkSize = StringUtils.isNotEmpty(payload) ? Integer.parseInt(payload) : 0;
  340 + String requestId = fwMatcher.group("requestId");
  341 + int chunk = Integer.parseInt(fwMatcher.group("chunk"));
  342 +
  343 + if (chunkSize > 0) {
  344 + this.fwChunkSizes.put(requestId, chunkSize);
  345 + } else {
  346 + chunkSize = fwChunkSizes.getOrDefault(requestId, 0);
  347 + }
  348 +
  349 + if (chunkSize > context.getMaxPayloadSize()) {
  350 + sendFirmwareError(ctx, PAYLOAD_TOO_LARGE);
  351 + return;
  352 + }
  353 +
  354 + String firmwareId = fwSessions.get(requestId);
  355 +
  356 + if (firmwareId != null) {
  357 + sendFirmware(ctx, mqttMsg.variableHeader().packetId(), firmwareId, requestId, chunkSize, chunk, type);
  358 + } else {
  359 + TransportProtos.SessionInfoProto sessionInfo = deviceSessionCtx.getSessionInfo();
  360 + TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
  361 + .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
  362 + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
  363 + .setTenantIdMSB(sessionInfo.getTenantIdMSB())
  364 + .setTenantIdLSB(sessionInfo.getTenantIdLSB())
  365 + .setType(type.name())
  366 + .build();
  367 + transportService.process(deviceSessionCtx.getSessionInfo(), getFirmwareRequestMsg,
  368 + new FirmwareCallback(ctx, msgId, getFirmwareRequestMsg, requestId, chunkSize, chunk));
  369 + }
  370 + }
  371 +
360 372 private void ack(ChannelHandlerContext ctx, int msgId) {
361 373 if (msgId > 0) {
362 374 ctx.writeAndFlush(createMqttPubAckMsg(msgId));
... ... @@ -435,7 +447,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
435 447 if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) {
436 448 FirmwareId firmwareId = new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB()));
437 449 fwSessions.put(requestId, firmwareId.toString());
438   - sendFirmware(ctx, msgId, firmwareId.toString(), requestId, chunkSize, chunk);
  450 + sendFirmware(ctx, msgId, firmwareId.toString(), requestId, chunkSize, chunk, FirmwareType.valueOf(response.getType()));
439 451 } else {
440 452 sendFirmwareError(ctx, response.getResponseStatus().toString());
441 453 }
... ... @@ -448,13 +460,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
448 460 }
449 461 }
450 462
451   - private void sendFirmware(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk) {
  463 + private void sendFirmware(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk, FirmwareType type) {
452 464 log.trace("[{}] Send firmware [{}] to device!", sessionId, firmwareId);
453 465 ack(ctx, msgId);
454 466 try {
455 467 byte[] firmwareChunk = context.getFirmwareDataCache().get(firmwareId, chunkSize, chunk);
456 468 deviceSessionCtx.getPayloadAdaptor()
457   - .convertToPublish(deviceSessionCtx, firmwareChunk, requestId, chunk)
  469 + .convertToPublish(deviceSessionCtx, firmwareChunk, requestId, chunk, type)
458 470 .ifPresent(deviceSessionCtx.getChannel()::writeAndFlush);
459 471 if (firmwareChunk != null && chunkSize != firmwareChunk.length) {
460 472 scheduler.schedule(() -> processDisconnect(ctx), 60, TimeUnit.SECONDS);
... ... @@ -504,6 +516,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
504 516 case MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC:
505 517 case MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC:
506 518 case MqttTopics.DEVICE_FIRMWARE_ERROR_TOPIC:
  519 + case MqttTopics.DEVICE_SOFTWARE_RESPONSES_TOPIC:
  520 + case MqttTopics.DEVICE_SOFTWARE_ERROR_TOPIC:
507 521 registerSubQoS(topic, grantedQoSList, reqQoS);
508 522 break;
509 523 default:
... ...
... ... @@ -30,6 +30,7 @@ import lombok.extern.slf4j.Slf4j;
30 30 import org.springframework.stereotype.Component;
31 31 import org.springframework.util.StringUtils;
32 32 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  33 +import org.thingsboard.server.common.data.firmware.FirmwareType;
33 34 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
34 35 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
35 36 import org.thingsboard.server.gen.transport.TransportProtos;
... ... @@ -43,6 +44,9 @@ import java.util.Optional;
43 44 import java.util.Set;
44 45 import java.util.UUID;
45 46
  47 +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT;
  48 +
  49 +
46 50 /**
47 51 * @author Andrew Shvayka
48 52 */
... ... @@ -151,8 +155,8 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor {
151 155 }
152 156
153 157 @Override
154   - public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk) {
155   - return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX + requestId + "/chunk/" + chunk, firmwareChunk));
  158 + public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) {
  159 + return Optional.of(createMqttPublishMsg(ctx, String.format(DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT, firmwareType.getKeyPrefix(), requestId, chunk), firmwareChunk));
156 160 }
157 161
158 162 public static JsonElement validateJsonPayload(UUID sessionId, ByteBuf payloadData) throws AdaptorException {
... ...
... ... @@ -23,6 +23,7 @@ import io.netty.handler.codec.mqtt.MqttMessage;
23 23 import io.netty.handler.codec.mqtt.MqttMessageType;
24 24 import io.netty.handler.codec.mqtt.MqttPublishMessage;
25 25 import io.netty.handler.codec.mqtt.MqttPublishVariableHeader;
  26 +import org.thingsboard.server.common.data.firmware.FirmwareType;
26 27 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
27 28 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
28 29 import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg;
... ... @@ -77,7 +78,7 @@ public interface MqttTransportAdaptor {
77 78
78 79 Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException;
79 80
80   - Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk) throws AdaptorException;
  81 + Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) throws AdaptorException;
81 82
82 83 default MqttPublishMessage createMqttPublishMsg(MqttDeviceAwareSessionContext ctx, String topic, byte[] payloadInBytes) {
83 84 MqttFixedHeader mqttFixedHeader =
... ...
... ... @@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
28 28 import org.springframework.stereotype.Component;
29 29 import org.springframework.util.StringUtils;
30 30 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  31 +import org.thingsboard.server.common.data.firmware.FirmwareType;
31 32 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
32 33 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
33 34 import org.thingsboard.server.common.transport.adaptor.ProtoConverter;
... ... @@ -38,6 +39,8 @@ import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionConte
38 39
39 40 import java.util.Optional;
40 41
  42 +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT;
  43 +
41 44 @Component
42 45 @Slf4j
43 46 public class ProtoMqttAdaptor implements MqttTransportAdaptor {
... ... @@ -165,8 +168,8 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor {
165 168 }
166 169
167 170 @Override
168   - public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk) throws AdaptorException {
169   - return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX + requestId + "/" + chunk, firmwareChunk));
  171 + public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) throws AdaptorException {
  172 + return Optional.of(createMqttPublishMsg(ctx, String.format(DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT, firmwareType.getKeyPrefix(), requestId, chunk), firmwareChunk));
170 173 }
171 174
172 175 @Override
... ...
... ... @@ -51,11 +51,13 @@ public abstract class TransportContext {
51 51 @Getter
52 52 private ExecutorService executor;
53 53
54   -
55 54 @Getter
56 55 @Autowired
57 56 private FirmwareDataCache firmwareDataCache;
58 57
  58 + @Autowired
  59 + private TransportResourceCache transportResourceCache;
  60 +
59 61 @PostConstruct
60 62 public void init() {
61 63 executor = ThingsBoardExecutors.newWorkStealingPool(50, getClass());
... ...
... ... @@ -83,6 +83,8 @@ public interface DeviceDao extends Dao<Device>, TenantEntityDao {
83 83
84 84 PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(UUID tenantId, String type, PageLink pageLink);
85 85
  86 + PageData<Device> findDevicesByTenantIdAndTypeAndEmptySoftware(UUID tenantId, String type, PageLink pageLink);
  87 +
86 88 /**
87 89 * Find device infos by tenantId, type and page link.
88 90 *
... ...
... ... @@ -56,6 +56,7 @@ import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfilePr
56 56 import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
57 57 import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
58 58 import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  59 +import org.thingsboard.server.common.data.firmware.FirmwareType;
59 60 import org.thingsboard.server.common.data.id.DeviceProfileId;
60 61 import org.thingsboard.server.common.data.id.TenantId;
61 62 import org.thingsboard.server.common.data.page.PageData;
... ... @@ -406,9 +407,31 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
406 407 if (firmware == null) {
407 408 throw new DataValidationException("Can't assign non-existent firmware!");
408 409 }
  410 + if (!firmware.getType().equals(FirmwareType.FIRMWARE)) {
  411 + throw new DataValidationException("Can't assign firmware with type: " + firmware.getType());
  412 + }
409 413 if (firmware.getData() == null) {
410 414 throw new DataValidationException("Can't assign firmware with empty data!");
411 415 }
  416 + if (!firmware.getDeviceProfileId().equals(deviceProfile.getId())) {
  417 + throw new DataValidationException("Can't assign firmware with different deviceProfile!");
  418 + }
  419 + }
  420 +
  421 + if (deviceProfile.getSoftwareId() != null) {
  422 + Firmware software = firmwareService.findFirmwareById(tenantId, deviceProfile.getSoftwareId());
  423 + if (software == null) {
  424 + throw new DataValidationException("Can't assign non-existent software!");
  425 + }
  426 + if (!software.getType().equals(FirmwareType.SOFTWARE)) {
  427 + throw new DataValidationException("Can't assign software with type: " + software.getType());
  428 + }
  429 + if (software.getData() == null) {
  430 + throw new DataValidationException("Can't assign software with empty data!");
  431 + }
  432 + if (!software.getDeviceProfileId().equals(deviceProfile.getId())) {
  433 + throw new DataValidationException("Can't assign firmware with different deviceProfile!");
  434 + }
412 435 }
413 436 }
414 437
... ...
... ... @@ -53,6 +53,7 @@ import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfig
53 53 import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration;
54 54 import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
55 55 import org.thingsboard.server.common.data.edge.Edge;
  56 +import org.thingsboard.server.common.data.firmware.FirmwareType;
56 57 import org.thingsboard.server.common.data.id.CustomerId;
57 58 import org.thingsboard.server.common.data.id.DeviceId;
58 59 import org.thingsboard.server.common.data.id.DeviceProfileId;
... ... @@ -361,7 +362,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
361 362
362 363 @Override
363 364 public PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink) {
364   - log.trace("Executing findDevicesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
  365 + log.trace("Executing findDevicesByTenantIdAndTypeAndEmptyFirmware, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
365 366 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
366 367 validateString(type, "Incorrect type " + type);
367 368 validatePageLink(pageLink);
... ... @@ -369,6 +370,15 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
369 370 }
370 371
371 372 @Override
  373 + public PageData<Device> findDevicesByTenantIdAndTypeAndEmptySoftware(TenantId tenantId, String type, PageLink pageLink) {
  374 + log.trace("Executing findDevicesByTenantIdAndTypeAndEmptySoftware, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
  375 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  376 + validateString(type, "Incorrect type " + type);
  377 + validatePageLink(pageLink);
  378 + return deviceDao.findDevicesByTenantIdAndTypeAndEmptySoftware(tenantId.getId(), type, pageLink);
  379 + }
  380 +
  381 + @Override
372 382 public PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) {
373 383 log.trace("Executing findDeviceInfosByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
374 384 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
... ... @@ -696,9 +706,31 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
696 706 if (firmware == null) {
697 707 throw new DataValidationException("Can't assign non-existent firmware!");
698 708 }
  709 + if (!firmware.getType().equals(FirmwareType.FIRMWARE)) {
  710 + throw new DataValidationException("Can't assign firmware with type: " + firmware.getType());
  711 + }
699 712 if (firmware.getData() == null) {
700 713 throw new DataValidationException("Can't assign firmware with empty data!");
701 714 }
  715 + if (!firmware.getDeviceProfileId().equals(device.getDeviceProfileId())) {
  716 + throw new DataValidationException("Can't assign firmware with different deviceProfile!");
  717 + }
  718 + }
  719 +
  720 + if (device.getSoftwareId() != null) {
  721 + Firmware software = firmwareService.findFirmwareById(tenantId, device.getSoftwareId());
  722 + if (software == null) {
  723 + throw new DataValidationException("Can't assign non-existent software!");
  724 + }
  725 + if (!software.getType().equals(FirmwareType.SOFTWARE)) {
  726 + throw new DataValidationException("Can't assign software with type: " + software.getType());
  727 + }
  728 + if (software.getData() == null) {
  729 + throw new DataValidationException("Can't assign software with empty data!");
  730 + }
  731 + if (!software.getDeviceProfileId().equals(device.getDeviceProfileId())) {
  732 + throw new DataValidationException("Can't assign firmware with different deviceProfile!");
  733 + }
702 734 }
703 735 }
704 736 };
... ...