Commit c350fb7accc7c57f39d37a7683cf4c1c3e170e93
Committed by
GitHub
Merge pull request #4465 from thingsboard/feature/firmware
Feature/firmware
Showing
93 changed files
with
3134 additions
and
145 deletions
Too many changes to show.
To preserve performance only 93 of 138 files are displayed.
@@ -31,7 +31,7 @@ CREATE TABLE IF NOT EXISTS edge ( | @@ -31,7 +31,7 @@ CREATE TABLE IF NOT EXISTS edge ( | ||
31 | tenant_id uuid, | 31 | tenant_id uuid, |
32 | CONSTRAINT edge_name_unq_key UNIQUE (tenant_id, name), | 32 | CONSTRAINT edge_name_unq_key UNIQUE (tenant_id, name), |
33 | CONSTRAINT edge_routing_key_unq_key UNIQUE (routing_key) | 33 | CONSTRAINT edge_routing_key_unq_key UNIQUE (routing_key) |
34 | -); | 34 | + ); |
35 | 35 | ||
36 | CREATE TABLE IF NOT EXISTS edge_event ( | 36 | CREATE TABLE IF NOT EXISTS edge_event ( |
37 | id uuid NOT NULL CONSTRAINT edge_event_pkey PRIMARY KEY, | 37 | id uuid NOT NULL CONSTRAINT edge_event_pkey PRIMARY KEY, |
@@ -44,4 +44,57 @@ CREATE TABLE IF NOT EXISTS edge_event ( | @@ -44,4 +44,57 @@ CREATE TABLE IF NOT EXISTS edge_event ( | ||
44 | body varchar(10000000), | 44 | body varchar(10000000), |
45 | tenant_id uuid, | 45 | tenant_id uuid, |
46 | ts bigint NOT NULL | 46 | ts bigint NOT NULL |
47 | + ); | ||
48 | + | ||
49 | +CREATE TABLE IF NOT EXISTS resource ( | ||
50 | + id uuid NOT NULL CONSTRAINT resource_pkey PRIMARY KEY, | ||
51 | + created_time bigint NOT NULL, | ||
52 | + tenant_id uuid NOT NULL, | ||
53 | + title varchar(255) NOT NULL, | ||
54 | + resource_type varchar(32) NOT NULL, | ||
55 | + resource_key varchar(255) NOT NULL, | ||
56 | + search_text varchar(255), | ||
57 | + file_name varchar(255) NOT NULL, | ||
58 | + data varchar, | ||
59 | + CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key) | ||
60 | +); | ||
61 | + | ||
62 | +CREATE TABLE IF NOT EXISTS firmware ( | ||
63 | + id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY, | ||
64 | + created_time bigint NOT NULL, | ||
65 | + tenant_id uuid NOT NULL, | ||
66 | + title varchar(255) NOT NULL, | ||
67 | + version varchar(255) NOT NULL, | ||
68 | + file_name varchar(255), | ||
69 | + content_type varchar(255), | ||
70 | + checksum_algorithm varchar(32), | ||
71 | + checksum varchar(1020), | ||
72 | + data bytea, | ||
73 | + data_size bigint, | ||
74 | + additional_info varchar, | ||
75 | + search_text varchar(255), | ||
76 | + CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version) | ||
47 | ); | 77 | ); |
78 | + | ||
79 | +ALTER TABLE device_profile | ||
80 | + ADD COLUMN IF NOT EXISTS firmware_id uuid; | ||
81 | + | ||
82 | +ALTER TABLE device | ||
83 | + ADD COLUMN IF NOT EXISTS firmware_id uuid; | ||
84 | + | ||
85 | +DO $$ | ||
86 | + BEGIN | ||
87 | + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device_profile') THEN | ||
88 | + ALTER TABLE device_profile | ||
89 | + ADD CONSTRAINT fk_firmware_device_profile | ||
90 | + FOREIGN KEY (firmware_id) REFERENCES firmware(id); | ||
91 | + END IF; | ||
92 | + | ||
93 | + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device') THEN | ||
94 | + ALTER TABLE device | ||
95 | + ADD CONSTRAINT fk_firmware_device | ||
96 | + FOREIGN KEY (firmware_id) REFERENCES firmware(id); | ||
97 | + END IF; | ||
98 | + END; | ||
99 | +$$; | ||
100 | + |
@@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j; | @@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j; | ||
24 | import org.apache.commons.lang3.StringUtils; | 24 | import org.apache.commons.lang3.StringUtils; |
25 | import org.springframework.beans.factory.annotation.Autowired; | 25 | import org.springframework.beans.factory.annotation.Autowired; |
26 | import org.springframework.beans.factory.annotation.Value; | 26 | import org.springframework.beans.factory.annotation.Value; |
27 | +import org.springframework.http.MediaType; | ||
27 | import org.springframework.security.core.Authentication; | 28 | import org.springframework.security.core.Authentication; |
28 | import org.springframework.security.core.context.SecurityContextHolder; | 29 | import org.springframework.security.core.context.SecurityContextHolder; |
29 | import org.springframework.web.bind.annotation.ExceptionHandler; | 30 | import org.springframework.web.bind.annotation.ExceptionHandler; |
@@ -38,6 +39,8 @@ import org.thingsboard.server.common.data.EdgeUtils; | @@ -38,6 +39,8 @@ import org.thingsboard.server.common.data.EdgeUtils; | ||
38 | import org.thingsboard.server.common.data.EntityType; | 39 | import org.thingsboard.server.common.data.EntityType; |
39 | import org.thingsboard.server.common.data.EntityView; | 40 | import org.thingsboard.server.common.data.EntityView; |
40 | import org.thingsboard.server.common.data.EntityViewInfo; | 41 | import org.thingsboard.server.common.data.EntityViewInfo; |
42 | +import org.thingsboard.server.common.data.Firmware; | ||
43 | +import org.thingsboard.server.common.data.FirmwareInfo; | ||
41 | import org.thingsboard.server.common.data.HasName; | 44 | import org.thingsboard.server.common.data.HasName; |
42 | import org.thingsboard.server.common.data.HasTenantId; | 45 | import org.thingsboard.server.common.data.HasTenantId; |
43 | import org.thingsboard.server.common.data.TbResourceInfo; | 46 | import org.thingsboard.server.common.data.TbResourceInfo; |
@@ -67,6 +70,7 @@ import org.thingsboard.server.common.data.id.EdgeId; | @@ -67,6 +70,7 @@ import org.thingsboard.server.common.data.id.EdgeId; | ||
67 | import org.thingsboard.server.common.data.id.EntityId; | 70 | import org.thingsboard.server.common.data.id.EntityId; |
68 | import org.thingsboard.server.common.data.id.EntityIdFactory; | 71 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
69 | import org.thingsboard.server.common.data.id.EntityViewId; | 72 | import org.thingsboard.server.common.data.id.EntityViewId; |
73 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
70 | import org.thingsboard.server.common.data.id.TbResourceId; | 74 | import org.thingsboard.server.common.data.id.TbResourceId; |
71 | import org.thingsboard.server.common.data.id.RuleChainId; | 75 | import org.thingsboard.server.common.data.id.RuleChainId; |
72 | import org.thingsboard.server.common.data.id.RuleNodeId; | 76 | import org.thingsboard.server.common.data.id.RuleNodeId; |
@@ -106,6 +110,7 @@ import org.thingsboard.server.dao.edge.EdgeService; | @@ -106,6 +110,7 @@ import org.thingsboard.server.dao.edge.EdgeService; | ||
106 | import org.thingsboard.server.dao.entityview.EntityViewService; | 110 | import org.thingsboard.server.dao.entityview.EntityViewService; |
107 | import org.thingsboard.server.dao.exception.DataValidationException; | 111 | import org.thingsboard.server.dao.exception.DataValidationException; |
108 | import org.thingsboard.server.dao.exception.IncorrectParameterException; | 112 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
113 | +import org.thingsboard.server.dao.firmware.FirmwareService; | ||
109 | import org.thingsboard.server.dao.model.ModelConstants; | 114 | import org.thingsboard.server.dao.model.ModelConstants; |
110 | import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; | 115 | import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; |
111 | import org.thingsboard.server.dao.oauth2.OAuth2Service; | 116 | import org.thingsboard.server.dao.oauth2.OAuth2Service; |
@@ -123,6 +128,7 @@ import org.thingsboard.server.queue.discovery.PartitionService; | @@ -123,6 +128,7 @@ import org.thingsboard.server.queue.discovery.PartitionService; | ||
123 | import org.thingsboard.server.queue.provider.TbQueueProducerProvider; | 128 | import org.thingsboard.server.queue.provider.TbQueueProducerProvider; |
124 | import org.thingsboard.server.queue.util.TbCoreComponent; | 129 | import org.thingsboard.server.queue.util.TbCoreComponent; |
125 | import org.thingsboard.server.service.component.ComponentDiscoveryService; | 130 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
131 | +import org.thingsboard.server.service.firmware.FirmwareStateService; | ||
126 | import org.thingsboard.server.service.edge.EdgeNotificationService; | 132 | import org.thingsboard.server.service.edge.EdgeNotificationService; |
127 | import org.thingsboard.server.service.edge.rpc.EdgeGrpcService; | 133 | import org.thingsboard.server.service.edge.rpc.EdgeGrpcService; |
128 | import org.thingsboard.server.service.edge.rpc.init.SyncEdgeService; | 134 | import org.thingsboard.server.service.edge.rpc.init.SyncEdgeService; |
@@ -246,6 +252,12 @@ public abstract class BaseController { | @@ -246,6 +252,12 @@ public abstract class BaseController { | ||
246 | protected TbResourceService resourceService; | 252 | protected TbResourceService resourceService; |
247 | 253 | ||
248 | @Autowired | 254 | @Autowired |
255 | + protected FirmwareService firmwareService; | ||
256 | + | ||
257 | + @Autowired | ||
258 | + protected FirmwareStateService firmwareStateService; | ||
259 | + | ||
260 | + @Autowired | ||
249 | protected TbQueueProducerProvider producerProvider; | 261 | protected TbQueueProducerProvider producerProvider; |
250 | 262 | ||
251 | @Autowired | 263 | @Autowired |
@@ -501,6 +513,9 @@ public abstract class BaseController { | @@ -501,6 +513,9 @@ public abstract class BaseController { | ||
501 | case TB_RESOURCE: | 513 | case TB_RESOURCE: |
502 | checkResourceId(new TbResourceId(entityId.getId()), operation); | 514 | checkResourceId(new TbResourceId(entityId.getId()), operation); |
503 | return; | 515 | return; |
516 | + case FIRMWARE: | ||
517 | + checkFirmwareId(new FirmwareId(entityId.getId()), operation); | ||
518 | + return; | ||
504 | default: | 519 | default: |
505 | throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); | 520 | throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); |
506 | } | 521 | } |
@@ -756,6 +771,30 @@ public abstract class BaseController { | @@ -756,6 +771,30 @@ public abstract class BaseController { | ||
756 | } | 771 | } |
757 | } | 772 | } |
758 | 773 | ||
774 | + Firmware checkFirmwareId(FirmwareId firmwareId, Operation operation) throws ThingsboardException { | ||
775 | + try { | ||
776 | + validateId(firmwareId, "Incorrect firmwareId " + firmwareId); | ||
777 | + Firmware firmware = firmwareService.findFirmwareById(getCurrentUser().getTenantId(), firmwareId); | ||
778 | + checkNotNull(firmware); | ||
779 | + accessControlService.checkPermission(getCurrentUser(), Resource.FIRMWARE, operation, firmwareId, firmware); | ||
780 | + return firmware; | ||
781 | + } catch (Exception e) { | ||
782 | + throw handleException(e, false); | ||
783 | + } | ||
784 | + } | ||
785 | + | ||
786 | + FirmwareInfo checkFirmwareInfoId(FirmwareId firmwareId, Operation operation) throws ThingsboardException { | ||
787 | + try { | ||
788 | + validateId(firmwareId, "Incorrect firmwareId " + firmwareId); | ||
789 | + FirmwareInfo firmwareInfo = firmwareService.findFirmwareInfoById(getCurrentUser().getTenantId(), firmwareId); | ||
790 | + checkNotNull(firmwareInfo); | ||
791 | + accessControlService.checkPermission(getCurrentUser(), Resource.FIRMWARE, operation, firmwareId, firmwareInfo); | ||
792 | + return firmwareInfo; | ||
793 | + } catch (Exception e) { | ||
794 | + throw handleException(e, false); | ||
795 | + } | ||
796 | + } | ||
797 | + | ||
759 | @SuppressWarnings("unchecked") | 798 | @SuppressWarnings("unchecked") |
760 | protected <I extends EntityId> I emptyId(EntityType entityType) { | 799 | protected <I extends EntityId> I emptyId(EntityType entityType) { |
761 | return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); | 800 | return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); |
@@ -1082,4 +1121,11 @@ public abstract class BaseController { | @@ -1082,4 +1121,11 @@ public abstract class BaseController { | ||
1082 | } | 1121 | } |
1083 | } | 1122 | } |
1084 | 1123 | ||
1124 | + protected MediaType parseMediaType(String contentType) { | ||
1125 | + try { | ||
1126 | + return MediaType.parseMediaType(contentType); | ||
1127 | + } catch (Exception e) { | ||
1128 | + return MediaType.APPLICATION_OCTET_STREAM; | ||
1129 | + } | ||
1130 | + } | ||
1085 | } | 1131 | } |
@@ -75,6 +75,7 @@ import javax.annotation.Nullable; | @@ -75,6 +75,7 @@ import javax.annotation.Nullable; | ||
75 | import java.io.IOException; | 75 | import java.io.IOException; |
76 | import java.util.ArrayList; | 76 | import java.util.ArrayList; |
77 | import java.util.List; | 77 | import java.util.List; |
78 | +import java.util.Objects; | ||
78 | import java.util.stream.Collectors; | 79 | import java.util.stream.Collectors; |
79 | 80 | ||
80 | import static org.thingsboard.server.controller.EdgeController.EDGE_ID; | 81 | import static org.thingsboard.server.controller.EdgeController.EDGE_ID; |
@@ -124,15 +125,22 @@ public class DeviceController extends BaseController { | @@ -124,15 +125,22 @@ public class DeviceController extends BaseController { | ||
124 | 125 | ||
125 | checkEntity(device.getId(), device, Resource.DEVICE); | 126 | checkEntity(device.getId(), device, Resource.DEVICE); |
126 | 127 | ||
128 | + boolean created = device.getId() == null; | ||
129 | + Device oldDevice; | ||
130 | + if (!created) { | ||
131 | + oldDevice = deviceService.findDeviceById(getTenantId(), device.getId()); | ||
132 | + } else { | ||
133 | + oldDevice = null; | ||
134 | + } | ||
135 | + | ||
127 | Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); | 136 | Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); |
128 | 137 | ||
129 | tbClusterService.onDeviceChange(savedDevice, null); | 138 | tbClusterService.onDeviceChange(savedDevice, null); |
130 | tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(), | 139 | tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(), |
131 | savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null); | 140 | savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null); |
132 | - tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(), | ||
133 | - device.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); | 141 | + tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(), created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); |
134 | 142 | ||
135 | - if (device.getId() != null) { | 143 | + if (!created) { |
136 | sendEntityNotificationMsg(savedDevice.getTenantId(), savedDevice.getId(), EdgeEventActionType.UPDATED); | 144 | sendEntityNotificationMsg(savedDevice.getTenantId(), savedDevice.getId(), EdgeEventActionType.UPDATED); |
137 | } | 145 | } |
138 | 146 | ||
@@ -145,12 +153,17 @@ public class DeviceController extends BaseController { | @@ -145,12 +153,17 @@ public class DeviceController extends BaseController { | ||
145 | } else { | 153 | } else { |
146 | deviceStateService.onDeviceUpdated(savedDevice); | 154 | deviceStateService.onDeviceUpdated(savedDevice); |
147 | } | 155 | } |
156 | + | ||
157 | + firmwareStateService.update(savedDevice, oldDevice); | ||
158 | + | ||
148 | return savedDevice; | 159 | return savedDevice; |
149 | - } catch (Exception e) { | 160 | + } catch ( |
161 | + Exception e) { | ||
150 | logEntityAction(emptyId(EntityType.DEVICE), device, | 162 | logEntityAction(emptyId(EntityType.DEVICE), device, |
151 | null, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); | 163 | null, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); |
152 | throw handleException(e); | 164 | throw handleException(e); |
153 | } | 165 | } |
166 | + | ||
154 | } | 167 | } |
155 | 168 | ||
156 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") | 169 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
@@ -44,6 +44,7 @@ import org.thingsboard.server.service.security.permission.Operation; | @@ -44,6 +44,7 @@ import org.thingsboard.server.service.security.permission.Operation; | ||
44 | import org.thingsboard.server.service.security.permission.Resource; | 44 | import org.thingsboard.server.service.security.permission.Resource; |
45 | 45 | ||
46 | import java.util.List; | 46 | import java.util.List; |
47 | +import java.util.Objects; | ||
47 | import java.util.UUID; | 48 | import java.util.UUID; |
48 | 49 | ||
49 | @RestController | 50 | @RestController |
@@ -144,6 +145,15 @@ public class DeviceProfileController extends BaseController { | @@ -144,6 +145,15 @@ public class DeviceProfileController extends BaseController { | ||
144 | 145 | ||
145 | checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE); | 146 | checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE); |
146 | 147 | ||
148 | + boolean isFirmwareChanged = false; | ||
149 | + | ||
150 | + if (!created) { | ||
151 | + DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(getTenantId(), deviceProfile.getId()); | ||
152 | + if (!Objects.equals(deviceProfile.getFirmwareId(), oldDeviceProfile.getFirmwareId())) { | ||
153 | + isFirmwareChanged = true; | ||
154 | + } | ||
155 | + } | ||
156 | + | ||
147 | DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile)); | 157 | DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile)); |
148 | 158 | ||
149 | tbClusterService.onDeviceProfileChange(savedDeviceProfile, null); | 159 | tbClusterService.onDeviceProfileChange(savedDeviceProfile, null); |
@@ -154,9 +164,11 @@ public class DeviceProfileController extends BaseController { | @@ -154,9 +164,11 @@ public class DeviceProfileController extends BaseController { | ||
154 | null, | 164 | null, |
155 | created ? ActionType.ADDED : ActionType.UPDATED, null); | 165 | created ? ActionType.ADDED : ActionType.UPDATED, null); |
156 | 166 | ||
167 | + if (isFirmwareChanged) { | ||
168 | + firmwareStateService.update(savedDeviceProfile); | ||
169 | + } | ||
157 | sendEntityNotificationMsg(getTenantId(), savedDeviceProfile.getId(), | 170 | sendEntityNotificationMsg(getTenantId(), savedDeviceProfile.getId(), |
158 | deviceProfile.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); | 171 | deviceProfile.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); |
159 | - | ||
160 | return savedDeviceProfile; | 172 | return savedDeviceProfile; |
161 | } catch (Exception e) { | 173 | } catch (Exception e) { |
162 | logEntityAction(emptyId(EntityType.DEVICE_PROFILE), deviceProfile, | 174 | logEntityAction(emptyId(EntityType.DEVICE_PROFILE), deviceProfile, |
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.controller; | ||
17 | + | ||
18 | +import com.google.common.hash.Hashing; | ||
19 | +import lombok.extern.slf4j.Slf4j; | ||
20 | +import org.apache.commons.lang3.StringUtils; | ||
21 | +import org.springframework.core.io.ByteArrayResource; | ||
22 | +import org.springframework.http.HttpHeaders; | ||
23 | +import org.springframework.http.ResponseEntity; | ||
24 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
25 | +import org.springframework.web.bind.annotation.PathVariable; | ||
26 | +import org.springframework.web.bind.annotation.RequestBody; | ||
27 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
28 | +import org.springframework.web.bind.annotation.RequestMethod; | ||
29 | +import org.springframework.web.bind.annotation.RequestParam; | ||
30 | +import org.springframework.web.bind.annotation.ResponseBody; | ||
31 | +import org.springframework.web.bind.annotation.RestController; | ||
32 | +import org.springframework.web.multipart.MultipartFile; | ||
33 | +import org.thingsboard.server.common.data.Firmware; | ||
34 | +import org.thingsboard.server.common.data.FirmwareInfo; | ||
35 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | ||
36 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
37 | +import org.thingsboard.server.common.data.page.PageData; | ||
38 | +import org.thingsboard.server.common.data.page.PageLink; | ||
39 | +import org.thingsboard.server.queue.util.TbCoreComponent; | ||
40 | +import org.thingsboard.server.service.security.permission.Operation; | ||
41 | +import org.thingsboard.server.service.security.permission.Resource; | ||
42 | + | ||
43 | +import java.nio.ByteBuffer; | ||
44 | + | ||
45 | +@Slf4j | ||
46 | +@RestController | ||
47 | +@TbCoreComponent | ||
48 | +@RequestMapping("/api") | ||
49 | +public class FirmwareController extends BaseController { | ||
50 | + | ||
51 | + public static final String FIRMWARE_ID = "firmwareId"; | ||
52 | + | ||
53 | + @PreAuthorize("hasAnyAuthority( 'TENANT_ADMIN')") | ||
54 | + @RequestMapping(value = "/firmware/{firmwareId}/download", method = RequestMethod.GET) | ||
55 | + @ResponseBody | ||
56 | + public ResponseEntity<org.springframework.core.io.Resource> downloadFirmware(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException { | ||
57 | + checkParameter(FIRMWARE_ID, strFirmwareId); | ||
58 | + try { | ||
59 | + FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); | ||
60 | + Firmware firmware = checkFirmwareId(firmwareId, Operation.READ); | ||
61 | + | ||
62 | + ByteArrayResource resource = new ByteArrayResource(firmware.getData().array()); | ||
63 | + return ResponseEntity.ok() | ||
64 | + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + firmware.getFileName()) | ||
65 | + .header("x-filename", firmware.getFileName()) | ||
66 | + .contentLength(resource.contentLength()) | ||
67 | + .contentType(parseMediaType(firmware.getContentType())) | ||
68 | + .body(resource); | ||
69 | + } catch (Exception e) { | ||
70 | + throw handleException(e); | ||
71 | + } | ||
72 | + } | ||
73 | + | ||
74 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
75 | + @RequestMapping(value = "/firmware/info/{firmwareId}", method = RequestMethod.GET) | ||
76 | + @ResponseBody | ||
77 | + public FirmwareInfo getFirmwareInfoById(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException { | ||
78 | + checkParameter(FIRMWARE_ID, strFirmwareId); | ||
79 | + try { | ||
80 | + FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); | ||
81 | + return checkFirmwareInfoId(firmwareId, Operation.READ); | ||
82 | + } catch (Exception e) { | ||
83 | + throw handleException(e); | ||
84 | + } | ||
85 | + } | ||
86 | + | ||
87 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
88 | + @RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.GET) | ||
89 | + @ResponseBody | ||
90 | + public Firmware getFirmwareById(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException { | ||
91 | + checkParameter(FIRMWARE_ID, strFirmwareId); | ||
92 | + try { | ||
93 | + FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); | ||
94 | + return checkFirmwareId(firmwareId, Operation.READ); | ||
95 | + } catch (Exception e) { | ||
96 | + throw handleException(e); | ||
97 | + } | ||
98 | + } | ||
99 | + | ||
100 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
101 | + @RequestMapping(value = "/firmware", method = RequestMethod.POST) | ||
102 | + @ResponseBody | ||
103 | + public FirmwareInfo saveFirmwareInfo(@RequestBody FirmwareInfo firmwareInfo) throws ThingsboardException { | ||
104 | + firmwareInfo.setTenantId(getTenantId()); | ||
105 | + checkEntity(firmwareInfo.getId(), firmwareInfo, Resource.FIRMWARE); | ||
106 | + try { | ||
107 | + return firmwareService.saveFirmwareInfo(firmwareInfo); | ||
108 | + } catch (Exception e) { | ||
109 | + throw handleException(e); | ||
110 | + } | ||
111 | + } | ||
112 | + | ||
113 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
114 | + @RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.POST) | ||
115 | + @ResponseBody | ||
116 | + public Firmware saveFirmwareData(@PathVariable(FIRMWARE_ID) String strFirmwareId, | ||
117 | + @RequestParam(required = false) String checksum, | ||
118 | + @RequestParam(required = false) String checksumAlgorithm, | ||
119 | + @RequestBody MultipartFile file) throws ThingsboardException { | ||
120 | + checkParameter(FIRMWARE_ID, strFirmwareId); | ||
121 | + try { | ||
122 | + FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); | ||
123 | + FirmwareInfo info = checkFirmwareInfoId(firmwareId, Operation.READ); | ||
124 | + | ||
125 | + Firmware firmware = new Firmware(firmwareId); | ||
126 | + firmware.setCreatedTime(info.getCreatedTime()); | ||
127 | + firmware.setTenantId(getTenantId()); | ||
128 | + firmware.setTitle(info.getTitle()); | ||
129 | + firmware.setVersion(info.getVersion()); | ||
130 | + firmware.setAdditionalInfo(info.getAdditionalInfo()); | ||
131 | + | ||
132 | + byte[] data = file.getBytes(); | ||
133 | + if (StringUtils.isEmpty(checksumAlgorithm)) { | ||
134 | + checksumAlgorithm = "sha256"; | ||
135 | + checksum = Hashing.sha256().hashBytes(data).toString(); | ||
136 | + } | ||
137 | + | ||
138 | + firmware.setChecksumAlgorithm(checksumAlgorithm); | ||
139 | + firmware.setChecksum(checksum); | ||
140 | + firmware.setFileName(file.getOriginalFilename()); | ||
141 | + firmware.setContentType(file.getContentType()); | ||
142 | + firmware.setData(ByteBuffer.wrap(data)); | ||
143 | + firmware.setDataSize((long) data.length); | ||
144 | + return firmwareService.saveFirmware(firmware); | ||
145 | + } catch (Exception e) { | ||
146 | + throw handleException(e); | ||
147 | + } | ||
148 | + } | ||
149 | + | ||
150 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
151 | + @RequestMapping(value = "/firmwares", method = RequestMethod.GET) | ||
152 | + @ResponseBody | ||
153 | + public PageData<FirmwareInfo> getFirmwares(@RequestParam int pageSize, | ||
154 | + @RequestParam int page, | ||
155 | + @RequestParam(required = false) String textSearch, | ||
156 | + @RequestParam(required = false) String sortProperty, | ||
157 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | ||
158 | + try { | ||
159 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | ||
160 | + return checkNotNull(firmwareService.findTenantFirmwaresByTenantId(getTenantId(), pageLink)); | ||
161 | + } catch (Exception e) { | ||
162 | + throw handleException(e); | ||
163 | + } | ||
164 | + } | ||
165 | + | ||
166 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
167 | + @RequestMapping(value = "/firmwares/{hasData}", method = RequestMethod.GET) | ||
168 | + @ResponseBody | ||
169 | + public PageData<FirmwareInfo> getFirmwares(@PathVariable("hasData") boolean hasData, | ||
170 | + @RequestParam int pageSize, | ||
171 | + @RequestParam int page, | ||
172 | + @RequestParam(required = false) String textSearch, | ||
173 | + @RequestParam(required = false) String sortProperty, | ||
174 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | ||
175 | + try { | ||
176 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | ||
177 | + return checkNotNull(firmwareService.findTenantFirmwaresByTenantIdAndHasData(getTenantId(), hasData, pageLink)); | ||
178 | + } catch (Exception e) { | ||
179 | + throw handleException(e); | ||
180 | + } | ||
181 | + } | ||
182 | + | ||
183 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
184 | + @RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.DELETE) | ||
185 | + @ResponseBody | ||
186 | + public void deleteResource(@PathVariable("firmwareId") String strFirmwareId) throws ThingsboardException { | ||
187 | + checkParameter(FIRMWARE_ID, strFirmwareId); | ||
188 | + try { | ||
189 | + FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); | ||
190 | + checkFirmwareInfoId(firmwareId, Operation.DELETE); | ||
191 | + firmwareService.deleteFirmware(getTenantId(), firmwareId); | ||
192 | + } catch (Exception e) { | ||
193 | + throw handleException(e); | ||
194 | + } | ||
195 | + } | ||
196 | + | ||
197 | +} |
@@ -166,7 +166,7 @@ public class TbResourceController extends BaseController { | @@ -166,7 +166,7 @@ public class TbResourceController extends BaseController { | ||
166 | @RequestMapping(value = "/resource/{resourceId}", method = RequestMethod.DELETE) | 166 | @RequestMapping(value = "/resource/{resourceId}", method = RequestMethod.DELETE) |
167 | @ResponseBody | 167 | @ResponseBody |
168 | public void deleteResource(@PathVariable("resourceId") String strResourceId) throws ThingsboardException { | 168 | public void deleteResource(@PathVariable("resourceId") String strResourceId) throws ThingsboardException { |
169 | - checkParameter("resourceId", strResourceId); | 169 | + checkParameter(RESOURCE_ID, strResourceId); |
170 | try { | 170 | try { |
171 | TbResourceId resourceId = new TbResourceId(toUUID(strResourceId)); | 171 | TbResourceId resourceId = new TbResourceId(toUUID(strResourceId)); |
172 | TbResource tbResource = checkResourceId(resourceId, Operation.DELETE); | 172 | TbResource tbResource = checkResourceId(resourceId, Operation.DELETE); |
@@ -232,7 +232,6 @@ public class ThingsboardInstallService { | @@ -232,7 +232,6 @@ public class ThingsboardInstallService { | ||
232 | systemDataLoaderService.createAdminSettings(); | 232 | systemDataLoaderService.createAdminSettings(); |
233 | systemDataLoaderService.loadSystemWidgets(); | 233 | systemDataLoaderService.loadSystemWidgets(); |
234 | systemDataLoaderService.createOAuth2Templates(); | 234 | systemDataLoaderService.createOAuth2Templates(); |
235 | - systemDataLoaderService.loadSystemLwm2mResources(); | ||
236 | // systemDataLoaderService.loadSystemPlugins(); | 235 | // systemDataLoaderService.loadSystemPlugins(); |
237 | // systemDataLoaderService.loadSystemRules(); | 236 | // systemDataLoaderService.loadSystemRules(); |
238 | 237 |
application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java
0 → 100644
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.service.firmware; | ||
17 | + | ||
18 | +import com.google.common.util.concurrent.FutureCallback; | ||
19 | +import lombok.extern.slf4j.Slf4j; | ||
20 | +import org.springframework.stereotype.Service; | ||
21 | +import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; | ||
22 | +import org.thingsboard.server.common.data.DataConstants; | ||
23 | +import org.thingsboard.server.common.data.Device; | ||
24 | +import org.thingsboard.server.common.data.DeviceProfile; | ||
25 | +import org.thingsboard.server.common.data.Firmware; | ||
26 | +import org.thingsboard.server.common.data.FirmwareInfo; | ||
27 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
28 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
29 | +import org.thingsboard.server.common.data.id.TenantId; | ||
30 | +import org.thingsboard.server.common.data.kv.AttributeKvEntry; | ||
31 | +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; | ||
32 | +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; | ||
33 | +import org.thingsboard.server.common.data.kv.LongDataEntry; | ||
34 | +import org.thingsboard.server.common.data.kv.StringDataEntry; | ||
35 | +import org.thingsboard.server.common.data.kv.TsKvEntry; | ||
36 | +import org.thingsboard.server.common.data.page.PageData; | ||
37 | +import org.thingsboard.server.common.data.page.PageLink; | ||
38 | +import org.thingsboard.server.common.msg.queue.TbCallback; | ||
39 | +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | ||
40 | +import org.thingsboard.server.dao.device.DeviceProfileService; | ||
41 | +import org.thingsboard.server.dao.device.DeviceService; | ||
42 | +import org.thingsboard.server.dao.firmware.FirmwareService; | ||
43 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
44 | +import org.thingsboard.server.queue.TbQueueProducer; | ||
45 | +import org.thingsboard.server.queue.common.TbProtoQueueMsg; | ||
46 | +import org.thingsboard.server.queue.provider.TbCoreQueueFactory; | ||
47 | +import org.thingsboard.server.queue.util.TbCoreComponent; | ||
48 | + | ||
49 | +import javax.annotation.Nullable; | ||
50 | +import java.util.ArrayList; | ||
51 | +import java.util.Arrays; | ||
52 | +import java.util.Collections; | ||
53 | +import java.util.List; | ||
54 | +import java.util.UUID; | ||
55 | +import java.util.function.Consumer; | ||
56 | + | ||
57 | +import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_CHECKSUM; | ||
58 | +import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_CHECKSUM_ALGORITHM; | ||
59 | +import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_SIZE; | ||
60 | +import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_TITLE; | ||
61 | +import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_VERSION; | ||
62 | + | ||
63 | +@Slf4j | ||
64 | +@Service | ||
65 | +@TbCoreComponent | ||
66 | +public class DefaultFirmwareStateService implements FirmwareStateService { | ||
67 | + | ||
68 | + private final FirmwareService firmwareService; | ||
69 | + private final DeviceService deviceService; | ||
70 | + private final DeviceProfileService deviceProfileService; | ||
71 | + private final RuleEngineTelemetryService telemetryService; | ||
72 | + private final TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> fwStateMsgProducer; | ||
73 | + | ||
74 | + public DefaultFirmwareStateService(FirmwareService firmwareService, | ||
75 | + DeviceService deviceService, | ||
76 | + DeviceProfileService deviceProfileService, | ||
77 | + RuleEngineTelemetryService telemetryService, | ||
78 | + TbCoreQueueFactory coreQueueFactory) { | ||
79 | + this.firmwareService = firmwareService; | ||
80 | + this.deviceService = deviceService; | ||
81 | + this.deviceProfileService = deviceProfileService; | ||
82 | + this.telemetryService = telemetryService; | ||
83 | + this.fwStateMsgProducer = coreQueueFactory.createToFirmwareStateServiceMsgProducer(); | ||
84 | + } | ||
85 | + | ||
86 | + @Override | ||
87 | + public void update(Device device, Device oldDevice) { | ||
88 | + FirmwareId newFirmwareId = device.getFirmwareId(); | ||
89 | + if (newFirmwareId == null) { | ||
90 | + DeviceProfile newDeviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); | ||
91 | + newFirmwareId = newDeviceProfile.getFirmwareId(); | ||
92 | + } | ||
93 | + if (oldDevice != null) { | ||
94 | + if (newFirmwareId != null) { | ||
95 | + FirmwareId oldFirmwareId = oldDevice.getFirmwareId(); | ||
96 | + if (oldFirmwareId == null) { | ||
97 | + DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(oldDevice.getTenantId(), oldDevice.getDeviceProfileId()); | ||
98 | + oldFirmwareId = oldDeviceProfile.getFirmwareId(); | ||
99 | + } | ||
100 | + if (!newFirmwareId.equals(oldFirmwareId)) { | ||
101 | + // Device was updated and new firmware is different from previous firmware. | ||
102 | + send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis()); | ||
103 | + } | ||
104 | + } else { | ||
105 | + // Device was updated and new firmware is not set. | ||
106 | + remove(device); | ||
107 | + } | ||
108 | + } else if (newFirmwareId != null) { | ||
109 | + // Device was created and firmware is defined. | ||
110 | + send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis()); | ||
111 | + } | ||
112 | + } | ||
113 | + | ||
114 | + @Override | ||
115 | + public void update(DeviceProfile deviceProfile) { | ||
116 | + TenantId tenantId = deviceProfile.getTenantId(); | ||
117 | + | ||
118 | + Consumer<Device> updateConsumer; | ||
119 | + if (deviceProfile.getFirmwareId() != null) { | ||
120 | + long ts = System.currentTimeMillis(); | ||
121 | + updateConsumer = d -> send(d.getTenantId(), d.getId(), deviceProfile.getFirmwareId(), ts); | ||
122 | + } else { | ||
123 | + updateConsumer = this::remove; | ||
124 | + } | ||
125 | + | ||
126 | + PageLink pageLink = new PageLink(100); | ||
127 | + PageData<Device> pageData; | ||
128 | + do { | ||
129 | + pageData = deviceService.findDevicesByTenantIdAndTypeAndEmptyFirmware(tenantId, deviceProfile.getName(), pageLink); | ||
130 | + | ||
131 | + pageData.getData().forEach(updateConsumer); | ||
132 | + | ||
133 | + if (pageData.hasNext()) { | ||
134 | + pageLink = pageLink.nextPageLink(); | ||
135 | + } | ||
136 | + } while (pageData.hasNext()); | ||
137 | + } | ||
138 | + | ||
139 | + @Override | ||
140 | + public boolean process(ToFirmwareStateServiceMsg msg) { | ||
141 | + boolean isSuccess = false; | ||
142 | + FirmwareId targetFirmwareId = new FirmwareId(new UUID(msg.getFirmwareIdMSB(), msg.getFirmwareIdLSB())); | ||
143 | + DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB())); | ||
144 | + TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); | ||
145 | + long ts = msg.getTs(); | ||
146 | + | ||
147 | + Device device = deviceService.findDeviceById(tenantId, deviceId); | ||
148 | + if (device == null) { | ||
149 | + log.warn("[{}] [{}] Device was removed during firmware update msg was queued!", tenantId, deviceId); | ||
150 | + } else { | ||
151 | + FirmwareId currentFirmwareId = device.getFirmwareId(); | ||
152 | + | ||
153 | + if (currentFirmwareId == null) { | ||
154 | + currentFirmwareId = deviceProfileService.findDeviceProfileById(tenantId, device.getDeviceProfileId()).getFirmwareId(); | ||
155 | + } | ||
156 | + | ||
157 | + if (targetFirmwareId.equals(currentFirmwareId)) { | ||
158 | + update(device, firmwareService.findFirmwareById(device.getTenantId(), targetFirmwareId), ts); | ||
159 | + isSuccess = true; | ||
160 | + } else { | ||
161 | + log.warn("[{}] [{}] Can`t update firmware for the device, target firmwareId: [{}], current firmwareId: [{}]!", tenantId, deviceId, targetFirmwareId, currentFirmwareId); | ||
162 | + } | ||
163 | + } | ||
164 | + return isSuccess; | ||
165 | + } | ||
166 | + | ||
167 | + private void send(TenantId tenantId, DeviceId deviceId, FirmwareId firmwareId, long ts) { | ||
168 | + ToFirmwareStateServiceMsg msg = ToFirmwareStateServiceMsg.newBuilder() | ||
169 | + .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) | ||
170 | + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) | ||
171 | + .setDeviceIdMSB(deviceId.getId().getMostSignificantBits()) | ||
172 | + .setDeviceIdLSB(deviceId.getId().getLeastSignificantBits()) | ||
173 | + .setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits()) | ||
174 | + .setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits()) | ||
175 | + .setTs(ts) | ||
176 | + .build(); | ||
177 | + | ||
178 | + FirmwareInfo firmware = firmwareService.findFirmwareInfoById(tenantId, firmwareId); | ||
179 | + if (firmware == null) { | ||
180 | + log.warn("[{}] Failed to send firmware update because firmware was already deleted", firmwareId); | ||
181 | + return; | ||
182 | + } | ||
183 | + | ||
184 | + TopicPartitionInfo tpi = new TopicPartitionInfo(fwStateMsgProducer.getDefaultTopic(), null, null, false); | ||
185 | + fwStateMsgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null); | ||
186 | + | ||
187 | + List<TsKvEntry> telemetry = new ArrayList<>(); | ||
188 | + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_TITLE, firmware.getTitle()))); | ||
189 | + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_VERSION, firmware.getVersion()))); | ||
190 | + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_STATE, FirmwareUpdateStatus.QUEUED.name()))); | ||
191 | + | ||
192 | + telemetryService.saveAndNotify(tenantId, deviceId, telemetry, new FutureCallback<>() { | ||
193 | + @Override | ||
194 | + public void onSuccess(@Nullable Void tmp) { | ||
195 | + log.trace("[{}] Success save firmware status!", deviceId); | ||
196 | + } | ||
197 | + | ||
198 | + @Override | ||
199 | + public void onFailure(Throwable t) { | ||
200 | + log.error("[{}] Failed to save firmware status!", deviceId, t); | ||
201 | + } | ||
202 | + }); | ||
203 | + } | ||
204 | + | ||
205 | + | ||
206 | + private void update(Device device, FirmwareInfo firmware, long ts) { | ||
207 | + TenantId tenantId = device.getTenantId(); | ||
208 | + DeviceId deviceId = device.getId(); | ||
209 | + | ||
210 | + BasicTsKvEntry status = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(DataConstants.FIRMWARE_STATE, FirmwareUpdateStatus.INITIATED.name())); | ||
211 | + | ||
212 | + telemetryService.saveAndNotify(tenantId, deviceId, Collections.singletonList(status), new FutureCallback<>() { | ||
213 | + @Override | ||
214 | + public void onSuccess(@Nullable Void tmp) { | ||
215 | + log.trace("[{}] Success save telemetry with target firmware for device!", deviceId); | ||
216 | + } | ||
217 | + | ||
218 | + @Override | ||
219 | + public void onFailure(Throwable t) { | ||
220 | + log.error("[{}] Failed to save telemetry with target firmware for device!", deviceId, t); | ||
221 | + } | ||
222 | + }); | ||
223 | + | ||
224 | + List<AttributeKvEntry> attributes = new ArrayList<>(); | ||
225 | + | ||
226 | + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_TITLE, firmware.getTitle()))); | ||
227 | + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_VERSION, firmware.getVersion()))); | ||
228 | + | ||
229 | + attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(FIRMWARE_SIZE, firmware.getDataSize()))); | ||
230 | + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM_ALGORITHM, firmware.getChecksumAlgorithm()))); | ||
231 | + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM, firmware.getChecksum()))); | ||
232 | + telemetryService.saveAndNotify(tenantId, deviceId, DataConstants.SHARED_SCOPE, attributes, new FutureCallback<>() { | ||
233 | + @Override | ||
234 | + public void onSuccess(@Nullable Void tmp) { | ||
235 | + log.trace("[{}] Success save attributes with target firmware!", deviceId); | ||
236 | + } | ||
237 | + | ||
238 | + @Override | ||
239 | + public void onFailure(Throwable t) { | ||
240 | + log.error("[{}] Failed to save attributes with target firmware!", deviceId, t); | ||
241 | + } | ||
242 | + }); | ||
243 | + } | ||
244 | + | ||
245 | + private void remove(Device device) { | ||
246 | + telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE, | ||
247 | + Arrays.asList(FIRMWARE_TITLE, FIRMWARE_VERSION, FIRMWARE_SIZE, FIRMWARE_CHECKSUM_ALGORITHM, FIRMWARE_CHECKSUM), | ||
248 | + new FutureCallback<>() { | ||
249 | + @Override | ||
250 | + public void onSuccess(@Nullable Void tmp) { | ||
251 | + log.trace("[{}] Success remove target firmware attributes!", device.getId()); | ||
252 | + } | ||
253 | + | ||
254 | + @Override | ||
255 | + public void onFailure(Throwable t) { | ||
256 | + log.error("[{}] Failed to remove target firmware attributes!", device.getId(), t); | ||
257 | + } | ||
258 | + }); | ||
259 | + } | ||
260 | +} |
application/src/main/java/org/thingsboard/server/service/firmware/FirmwareStateService.java
0 → 100644
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.service.firmware; | ||
17 | + | ||
18 | +import org.thingsboard.server.common.data.Device; | ||
19 | +import org.thingsboard.server.common.data.DeviceProfile; | ||
20 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
21 | + | ||
22 | +public interface FirmwareStateService { | ||
23 | + | ||
24 | + void update(Device device, Device oldDevice); | ||
25 | + | ||
26 | + void update(DeviceProfile deviceProfile); | ||
27 | + | ||
28 | + boolean process(ToFirmwareStateServiceMsg msg); | ||
29 | + | ||
30 | +} |
application/src/main/java/org/thingsboard/server/service/firmware/FirmwareUpdateStatus.java
0 → 100644
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.service.firmware; | ||
17 | + | ||
18 | +public enum FirmwareUpdateStatus { | ||
19 | + QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED | ||
20 | +} |
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
@@ -444,11 +444,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { | @@ -444,11 +444,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { | ||
444 | installScripts.loadSystemWidgets(); | 444 | installScripts.loadSystemWidgets(); |
445 | } | 445 | } |
446 | 446 | ||
447 | - @Override | ||
448 | - public void loadSystemLwm2mResources() throws Exception { | ||
449 | - installScripts.loadSystemLwm2mResources(); | ||
450 | - } | ||
451 | - | ||
452 | private User createUser(Authority authority, | 447 | private User createUser(Authority authority, |
453 | TenantId tenantId, | 448 | TenantId tenantId, |
454 | CustomerId customerId, | 449 | CustomerId customerId, |
@@ -22,8 +22,6 @@ import org.springframework.beans.factory.annotation.Value; | @@ -22,8 +22,6 @@ import org.springframework.beans.factory.annotation.Value; | ||
22 | import org.springframework.stereotype.Component; | 22 | import org.springframework.stereotype.Component; |
23 | import org.springframework.util.StringUtils; | 23 | import org.springframework.util.StringUtils; |
24 | import org.thingsboard.server.common.data.Dashboard; | 24 | import org.thingsboard.server.common.data.Dashboard; |
25 | -import org.thingsboard.server.common.data.ResourceType; | ||
26 | -import org.thingsboard.server.common.data.TbResource; | ||
27 | import org.thingsboard.server.common.data.id.CustomerId; | 25 | import org.thingsboard.server.common.data.id.CustomerId; |
28 | import org.thingsboard.server.common.data.id.EntityId; | 26 | import org.thingsboard.server.common.data.id.EntityId; |
29 | import org.thingsboard.server.common.data.id.TenantId; | 27 | import org.thingsboard.server.common.data.id.TenantId; |
@@ -33,7 +31,6 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; | @@ -33,7 +31,6 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; | ||
33 | import org.thingsboard.server.common.data.widget.WidgetTypeDetails; | 31 | import org.thingsboard.server.common.data.widget.WidgetTypeDetails; |
34 | import org.thingsboard.server.common.data.widget.WidgetsBundle; | 32 | import org.thingsboard.server.common.data.widget.WidgetsBundle; |
35 | import org.thingsboard.server.dao.dashboard.DashboardService; | 33 | import org.thingsboard.server.dao.dashboard.DashboardService; |
36 | -import org.thingsboard.server.dao.exception.DataValidationException; | ||
37 | import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; | 34 | import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; |
38 | import org.thingsboard.server.dao.resource.ResourceService; | 35 | import org.thingsboard.server.dao.resource.ResourceService; |
39 | import org.thingsboard.server.dao.rule.RuleChainService; | 36 | import org.thingsboard.server.dao.rule.RuleChainService; |
@@ -45,7 +42,6 @@ import java.nio.file.DirectoryStream; | @@ -45,7 +42,6 @@ import java.nio.file.DirectoryStream; | ||
45 | import java.nio.file.Files; | 42 | import java.nio.file.Files; |
46 | import java.nio.file.Path; | 43 | import java.nio.file.Path; |
47 | import java.nio.file.Paths; | 44 | import java.nio.file.Paths; |
48 | -import java.util.Base64; | ||
49 | import java.util.Optional; | 45 | import java.util.Optional; |
50 | 46 | ||
51 | import static org.thingsboard.server.service.install.DatabaseHelper.objectMapper; | 47 | import static org.thingsboard.server.service.install.DatabaseHelper.objectMapper; |
@@ -210,29 +206,6 @@ public class InstallScripts { | @@ -210,29 +206,6 @@ public class InstallScripts { | ||
210 | } | 206 | } |
211 | } | 207 | } |
212 | 208 | ||
213 | - public void loadSystemLwm2mResources() throws Exception { | ||
214 | - Path modelsDir = Paths.get(getDataDir(), MODELS_DIR); | ||
215 | - if (Files.isDirectory(modelsDir)) { | ||
216 | - try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) { | ||
217 | - dirStream.forEach( | ||
218 | - path -> { | ||
219 | - try { | ||
220 | - byte[] fileBytes = Files.readAllBytes(path); | ||
221 | - TbResource resource = new TbResource(); | ||
222 | - resource.setFileName(path.getFileName().toString()); | ||
223 | - resource.setTenantId(TenantId.SYS_TENANT_ID); | ||
224 | - resource.setResourceType(ResourceType.LWM2M_MODEL); | ||
225 | - resource.setData(Base64.getEncoder().encodeToString(fileBytes)); | ||
226 | - resourceService.saveResource(resource); | ||
227 | - } catch (Exception e) { | ||
228 | - throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", path.toString())); | ||
229 | - } | ||
230 | - } | ||
231 | - ); | ||
232 | - } | ||
233 | - } | ||
234 | - } | ||
235 | - | ||
236 | public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception { | 209 | public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception { |
237 | Path dashboardsDir = Paths.get(getDataDir(), JSON_DIR, DEMO_DIR, DASHBOARDS_DIR); | 210 | Path dashboardsDir = Paths.get(getDataDir(), JSON_DIR, DEMO_DIR, DASHBOARDS_DIR); |
238 | try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dashboardsDir, path -> path.toString().endsWith(JSON_EXT))) { | 211 | try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dashboardsDir, path -> path.toString().endsWith(JSON_EXT))) { |
@@ -450,37 +450,19 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService | @@ -450,37 +450,19 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService | ||
450 | try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { | 450 | try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { |
451 | log.info("Updating schema ..."); | 451 | log.info("Updating schema ..."); |
452 | try { | 452 | try { |
453 | - conn.createStatement().execute("CREATE TABLE IF NOT EXISTS resource ( " + | ||
454 | - "id uuid NOT NULL CONSTRAINT resource_pkey PRIMARY KEY, " + | ||
455 | - "created_time bigint NOT NULL, " + | ||
456 | - "tenant_id uuid NOT NULL, " + | ||
457 | - "title varchar(255) NOT NULL, " + | ||
458 | - "resource_type varchar(32) NOT NULL, " + | ||
459 | - "resource_key varchar(255) NOT NULL, " + | ||
460 | - "search_text varchar(255), " + | ||
461 | - "file_name varchar(255) NOT NULL, " + | ||
462 | - "data varchar, " + | ||
463 | - "CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)" + | ||
464 | - ");"); | ||
465 | - | ||
466 | - conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003000;"); | ||
467 | - installScripts.loadSystemLwm2mResources(); | ||
468 | - | ||
469 | - schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.2.2", SCHEMA_UPDATE_SQL); | ||
470 | - loadSql(schemaUpdateFile, conn); | ||
471 | - try { | ||
472 | - conn.createStatement().execute("ALTER TABLE rule_chain ADD COLUMN type varchar(255) DEFAULT 'CORE'"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script | ||
473 | - } catch (Exception ignored) {} | ||
474 | - | ||
475 | - log.info("Load Edge TTL functions ..."); | ||
476 | - schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.2.2", "schema_update_ttl.sql"); | ||
477 | - loadSql(schemaUpdateFile, conn); | ||
478 | - log.info("Edge TTL functions successfully loaded!"); | ||
479 | - | ||
480 | - } catch (Exception e) { | ||
481 | - log.error("Failed updating schema!!!", e); | 453 | + conn.createStatement().execute("ALTER TABLE rule_chain ADD COLUMN type varchar(255) DEFAULT 'CORE'"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script |
454 | + } catch (Exception ignored) { | ||
482 | } | 455 | } |
456 | + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.2.2", SCHEMA_UPDATE_SQL); | ||
457 | + loadSql(schemaUpdateFile, conn); | ||
458 | + log.info("Load Edge TTL functions ..."); | ||
459 | + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.2.2", "schema_update_ttl.sql"); | ||
460 | + loadSql(schemaUpdateFile, conn); | ||
461 | + log.info("Edge TTL functions successfully loaded!"); | ||
462 | + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003000;"); | ||
483 | log.info("Schema updated."); | 463 | log.info("Schema updated."); |
464 | + } catch (Exception e) { | ||
465 | + log.error("Failed updating schema!!!", e); | ||
484 | } | 466 | } |
485 | break; | 467 | break; |
486 | default: | 468 | default: |
@@ -33,6 +33,4 @@ public interface SystemDataLoaderService { | @@ -33,6 +33,4 @@ public interface SystemDataLoaderService { | ||
33 | 33 | ||
34 | void deleteSystemWidgetBundle(String bundleAlias) throws Exception; | 34 | void deleteSystemWidgetBundle(String bundleAlias) throws Exception; |
35 | 35 | ||
36 | - void loadSystemLwm2mResources() throws Exception; | ||
37 | - | ||
38 | } | 36 | } |
@@ -24,6 +24,7 @@ import org.springframework.context.event.EventListener; | @@ -24,6 +24,7 @@ import org.springframework.context.event.EventListener; | ||
24 | import org.springframework.core.annotation.Order; | 24 | import org.springframework.core.annotation.Order; |
25 | import org.springframework.scheduling.annotation.Scheduled; | 25 | import org.springframework.scheduling.annotation.Scheduled; |
26 | import org.springframework.stereotype.Service; | 26 | import org.springframework.stereotype.Service; |
27 | +import org.thingsboard.common.util.JacksonUtil; | ||
27 | import org.thingsboard.common.util.ThingsBoardThreadFactory; | 28 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
28 | import org.thingsboard.rule.engine.api.RpcError; | 29 | import org.thingsboard.rule.engine.api.RpcError; |
29 | import org.thingsboard.server.actors.ActorSystemContext; | 30 | import org.thingsboard.server.actors.ActorSystemContext; |
@@ -35,7 +36,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | @@ -35,7 +36,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | ||
35 | import org.thingsboard.server.common.msg.queue.TbCallback; | 36 | import org.thingsboard.server.common.msg.queue.TbCallback; |
36 | import org.thingsboard.server.common.stats.StatsFactory; | 37 | import org.thingsboard.server.common.stats.StatsFactory; |
37 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | 38 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; |
38 | -import org.thingsboard.common.util.JacksonUtil; | 39 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
39 | import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto; | 40 | import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto; |
40 | import org.thingsboard.server.gen.transport.TransportProtos.EdgeNotificationMsgProto; | 41 | import org.thingsboard.server.gen.transport.TransportProtos.EdgeNotificationMsgProto; |
41 | import org.thingsboard.server.gen.transport.TransportProtos.FromDeviceRPCResponseProto; | 42 | import org.thingsboard.server.gen.transport.TransportProtos.FromDeviceRPCResponseProto; |
@@ -49,6 +50,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionCloseP | @@ -49,6 +50,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionCloseP | ||
49 | import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdateProto; | 50 | import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdateProto; |
50 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; | 51 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
51 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; | 52 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
53 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
52 | import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; | 54 | import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
53 | import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; | 55 | import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
54 | import org.thingsboard.server.queue.TbQueueConsumer; | 56 | import org.thingsboard.server.queue.TbQueueConsumer; |
@@ -58,8 +60,8 @@ import org.thingsboard.server.queue.provider.TbCoreQueueFactory; | @@ -58,8 +60,8 @@ import org.thingsboard.server.queue.provider.TbCoreQueueFactory; | ||
58 | import org.thingsboard.server.queue.util.TbCoreComponent; | 60 | import org.thingsboard.server.queue.util.TbCoreComponent; |
59 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | 61 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; |
60 | import org.thingsboard.server.service.edge.EdgeNotificationService; | 62 | import org.thingsboard.server.service.edge.EdgeNotificationService; |
63 | +import org.thingsboard.server.service.firmware.FirmwareStateService; | ||
61 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; | 64 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
62 | -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | ||
63 | import org.thingsboard.server.service.queue.processing.AbstractConsumerService; | 65 | import org.thingsboard.server.service.queue.processing.AbstractConsumerService; |
64 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; | 66 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; |
65 | import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; | 67 | import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; |
@@ -97,6 +99,11 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | @@ -97,6 +99,11 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | ||
97 | @Value("${queue.core.stats.enabled:false}") | 99 | @Value("${queue.core.stats.enabled:false}") |
98 | private boolean statsEnabled; | 100 | private boolean statsEnabled; |
99 | 101 | ||
102 | + @Value("${queue.core.firmware.pack-interval-ms:60000}") | ||
103 | + private long firmwarePackInterval; | ||
104 | + @Value("${queue.core.firmware.pack-size:100}") | ||
105 | + private int firmwarePackSize; | ||
106 | + | ||
100 | private final TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> mainConsumer; | 107 | private final TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> mainConsumer; |
101 | private final DeviceStateService stateService; | 108 | private final DeviceStateService stateService; |
102 | private final TbApiUsageStateService statsService; | 109 | private final TbApiUsageStateService statsService; |
@@ -104,11 +111,15 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | @@ -104,11 +111,15 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | ||
104 | private final SubscriptionManagerService subscriptionManagerService; | 111 | private final SubscriptionManagerService subscriptionManagerService; |
105 | private final TbCoreDeviceRpcService tbCoreDeviceRpcService; | 112 | private final TbCoreDeviceRpcService tbCoreDeviceRpcService; |
106 | private final EdgeNotificationService edgeNotificationService; | 113 | private final EdgeNotificationService edgeNotificationService; |
114 | + private final FirmwareStateService firmwareStateService; | ||
107 | private final TbCoreConsumerStats stats; | 115 | private final TbCoreConsumerStats stats; |
108 | protected final TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> usageStatsConsumer; | 116 | protected final TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> usageStatsConsumer; |
117 | + private final TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> firmwareStatesConsumer; | ||
109 | 118 | ||
110 | protected volatile ExecutorService usageStatsExecutor; | 119 | protected volatile ExecutorService usageStatsExecutor; |
111 | 120 | ||
121 | + private volatile ExecutorService firmwareStatesExecutor; | ||
122 | + | ||
112 | public DefaultTbCoreConsumerService(TbCoreQueueFactory tbCoreQueueFactory, | 123 | public DefaultTbCoreConsumerService(TbCoreQueueFactory tbCoreQueueFactory, |
113 | ActorSystemContext actorContext, | 124 | ActorSystemContext actorContext, |
114 | DeviceStateService stateService, | 125 | DeviceStateService stateService, |
@@ -121,10 +132,12 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | @@ -121,10 +132,12 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | ||
121 | TbApiUsageStateService statsService, | 132 | TbApiUsageStateService statsService, |
122 | TbTenantProfileCache tenantProfileCache, | 133 | TbTenantProfileCache tenantProfileCache, |
123 | TbApiUsageStateService apiUsageStateService, | 134 | TbApiUsageStateService apiUsageStateService, |
124 | - EdgeNotificationService edgeNotificationService) { | 135 | + EdgeNotificationService edgeNotificationService, |
136 | + FirmwareStateService firmwareStateService) { | ||
125 | super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, apiUsageStateService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer()); | 137 | super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, apiUsageStateService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer()); |
126 | this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer(); | 138 | this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer(); |
127 | this.usageStatsConsumer = tbCoreQueueFactory.createToUsageStatsServiceMsgConsumer(); | 139 | this.usageStatsConsumer = tbCoreQueueFactory.createToUsageStatsServiceMsgConsumer(); |
140 | + this.firmwareStatesConsumer = tbCoreQueueFactory.createToFirmwareStateServiceMsgConsumer(); | ||
128 | this.stateService = stateService; | 141 | this.stateService = stateService; |
129 | this.localSubscriptionService = localSubscriptionService; | 142 | this.localSubscriptionService = localSubscriptionService; |
130 | this.subscriptionManagerService = subscriptionManagerService; | 143 | this.subscriptionManagerService = subscriptionManagerService; |
@@ -132,12 +145,14 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | @@ -132,12 +145,14 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | ||
132 | this.edgeNotificationService = edgeNotificationService; | 145 | this.edgeNotificationService = edgeNotificationService; |
133 | this.stats = new TbCoreConsumerStats(statsFactory); | 146 | this.stats = new TbCoreConsumerStats(statsFactory); |
134 | this.statsService = statsService; | 147 | this.statsService = statsService; |
148 | + this.firmwareStateService = firmwareStateService; | ||
135 | } | 149 | } |
136 | 150 | ||
137 | @PostConstruct | 151 | @PostConstruct |
138 | public void init() { | 152 | public void init() { |
139 | super.init("tb-core-consumer", "tb-core-notifications-consumer"); | 153 | super.init("tb-core-consumer", "tb-core-notifications-consumer"); |
140 | - this.usageStatsExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("tb-core-usage-stats-consumer")); | 154 | + this.usageStatsExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-core-usage-stats-consumer")); |
155 | + this.firmwareStatesExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-core-firmware-notifications-consumer")); | ||
141 | } | 156 | } |
142 | 157 | ||
143 | @PreDestroy | 158 | @PreDestroy |
@@ -146,6 +161,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | @@ -146,6 +161,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | ||
146 | if (usageStatsExecutor != null) { | 161 | if (usageStatsExecutor != null) { |
147 | usageStatsExecutor.shutdownNow(); | 162 | usageStatsExecutor.shutdownNow(); |
148 | } | 163 | } |
164 | + if (firmwareStatesExecutor != null) { | ||
165 | + firmwareStatesExecutor.shutdownNow(); | ||
166 | + } | ||
149 | } | 167 | } |
150 | 168 | ||
151 | @EventListener(ApplicationReadyEvent.class) | 169 | @EventListener(ApplicationReadyEvent.class) |
@@ -153,6 +171,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | @@ -153,6 +171,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | ||
153 | public void onApplicationEvent(ApplicationReadyEvent event) { | 171 | public void onApplicationEvent(ApplicationReadyEvent event) { |
154 | super.onApplicationEvent(event); | 172 | super.onApplicationEvent(event); |
155 | launchUsageStatsConsumer(); | 173 | launchUsageStatsConsumer(); |
174 | + launchFirmwareUpdateNotificationConsumer(); | ||
156 | } | 175 | } |
157 | 176 | ||
158 | @Override | 177 | @Override |
@@ -167,6 +186,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | @@ -167,6 +186,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | ||
167 | .map(tpi -> tpi.newByTopic(usageStatsConsumer.getTopic())) | 186 | .map(tpi -> tpi.newByTopic(usageStatsConsumer.getTopic())) |
168 | .collect(Collectors.toSet())); | 187 | .collect(Collectors.toSet())); |
169 | } | 188 | } |
189 | + this.firmwareStatesConsumer.subscribe(); | ||
170 | } | 190 | } |
171 | 191 | ||
172 | @Override | 192 | @Override |
@@ -336,10 +356,59 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | @@ -336,10 +356,59 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | ||
336 | }); | 356 | }); |
337 | } | 357 | } |
338 | 358 | ||
359 | + private void launchFirmwareUpdateNotificationConsumer() { | ||
360 | + long maxProcessingTimeoutPerRecord = firmwarePackInterval / firmwarePackSize; | ||
361 | + firmwareStatesExecutor.submit(() -> { | ||
362 | + while (!stopped) { | ||
363 | + try { | ||
364 | + List<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> msgs = firmwareStatesConsumer.poll(getNotificationPollDuration()); | ||
365 | + if (msgs.isEmpty()) { | ||
366 | + continue; | ||
367 | + } | ||
368 | + long timeToSleep = maxProcessingTimeoutPerRecord; | ||
369 | + for (TbProtoQueueMsg<ToFirmwareStateServiceMsg> msg : msgs) { | ||
370 | + try { | ||
371 | + long startTime = System.currentTimeMillis(); | ||
372 | + boolean isSuccessUpdate = handleFirmwareUpdates(msg); | ||
373 | + long endTime = System.currentTimeMillis(); | ||
374 | + long spentTime = endTime - startTime; | ||
375 | + timeToSleep = timeToSleep - spentTime; | ||
376 | + if (isSuccessUpdate) { | ||
377 | + if (timeToSleep > 0) { | ||
378 | + log.debug("Spent time per record is: [{}]!", spentTime); | ||
379 | + Thread.sleep(timeToSleep); | ||
380 | + timeToSleep = 0; | ||
381 | + } | ||
382 | + timeToSleep += maxProcessingTimeoutPerRecord; | ||
383 | + } | ||
384 | + } catch (Throwable e) { | ||
385 | + log.warn("Failed to process firmware update msg: {}", msg, e); | ||
386 | + } | ||
387 | + } | ||
388 | + firmwareStatesConsumer.commit(); | ||
389 | + } catch (Exception e) { | ||
390 | + if (!stopped) { | ||
391 | + log.warn("Failed to obtain usage stats from queue.", e); | ||
392 | + try { | ||
393 | + Thread.sleep(getNotificationPollDuration()); | ||
394 | + } catch (InterruptedException e2) { | ||
395 | + log.trace("Failed to wait until the server has capacity to handle new firmware updates", e2); | ||
396 | + } | ||
397 | + } | ||
398 | + } | ||
399 | + } | ||
400 | + log.info("TB Firmware States Consumer stopped."); | ||
401 | + }); | ||
402 | + } | ||
403 | + | ||
339 | private void handleUsageStats(TbProtoQueueMsg<ToUsageStatsServiceMsg> msg, TbCallback callback) { | 404 | private void handleUsageStats(TbProtoQueueMsg<ToUsageStatsServiceMsg> msg, TbCallback callback) { |
340 | statsService.process(msg, callback); | 405 | statsService.process(msg, callback); |
341 | } | 406 | } |
342 | 407 | ||
408 | + private boolean handleFirmwareUpdates(TbProtoQueueMsg<ToFirmwareStateServiceMsg> msg) { | ||
409 | + return firmwareStateService.process(msg.getValue()); | ||
410 | + } | ||
411 | + | ||
343 | private void forwardToCoreRpcService(FromDeviceRPCResponseProto proto, TbCallback callback) { | 412 | private void forwardToCoreRpcService(FromDeviceRPCResponseProto proto, TbCallback callback) { |
344 | RpcError error = proto.getError() > 0 ? RpcError.values()[proto.getError()] : null; | 413 | RpcError error = proto.getError() > 0 ? RpcError.values()[proto.getError()] : null; |
345 | FromDeviceRpcResponse response = new FromDeviceRpcResponse(new UUID(proto.getRequestIdMSB(), proto.getRequestIdLSB()) | 414 | FromDeviceRpcResponse response = new FromDeviceRpcResponse(new UUID(proto.getRequestIdMSB(), proto.getRequestIdLSB()) |
@@ -448,6 +517,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | @@ -448,6 +517,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore | ||
448 | if (usageStatsConsumer != null) { | 517 | if (usageStatsConsumer != null) { |
449 | usageStatsConsumer.unsubscribe(); | 518 | usageStatsConsumer.unsubscribe(); |
450 | } | 519 | } |
520 | + if (firmwareStatesConsumer != null) { | ||
521 | + firmwareStatesConsumer.unsubscribe(); | ||
522 | + } | ||
451 | } | 523 | } |
452 | 524 | ||
453 | } | 525 | } |
@@ -31,7 +31,7 @@ public interface TbResourceService { | @@ -31,7 +31,7 @@ public interface TbResourceService { | ||
31 | 31 | ||
32 | TbResource saveResource(TbResource resource) throws ThingsboardException; | 32 | TbResource saveResource(TbResource resource) throws ThingsboardException; |
33 | 33 | ||
34 | - TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId); | 34 | + TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceKey); |
35 | 35 | ||
36 | TbResource findResourceById(TenantId tenantId, TbResourceId resourceId); | 36 | TbResource findResourceById(TenantId tenantId, TbResourceId resourceId); |
37 | 37 |
@@ -38,6 +38,7 @@ public enum Resource { | @@ -38,6 +38,7 @@ public enum Resource { | ||
38 | DEVICE_PROFILE(EntityType.DEVICE_PROFILE), | 38 | DEVICE_PROFILE(EntityType.DEVICE_PROFILE), |
39 | API_USAGE_STATE(EntityType.API_USAGE_STATE), | 39 | API_USAGE_STATE(EntityType.API_USAGE_STATE), |
40 | TB_RESOURCE(EntityType.TB_RESOURCE), | 40 | TB_RESOURCE(EntityType.TB_RESOURCE), |
41 | + FIRMWARE(EntityType.FIRMWARE), | ||
41 | EDGE(EntityType.EDGE); | 42 | EDGE(EntityType.EDGE); |
42 | 43 | ||
43 | private final EntityType entityType; | 44 | private final EntityType entityType; |
@@ -42,6 +42,7 @@ public class TenantAdminPermissions extends AbstractPermissions { | @@ -42,6 +42,7 @@ public class TenantAdminPermissions extends AbstractPermissions { | ||
42 | put(Resource.DEVICE_PROFILE, tenantEntityPermissionChecker); | 42 | put(Resource.DEVICE_PROFILE, tenantEntityPermissionChecker); |
43 | put(Resource.API_USAGE_STATE, tenantEntityPermissionChecker); | 43 | put(Resource.API_USAGE_STATE, tenantEntityPermissionChecker); |
44 | put(Resource.TB_RESOURCE, tbResourcePermissionChecker); | 44 | put(Resource.TB_RESOURCE, tbResourcePermissionChecker); |
45 | + put(Resource.FIRMWARE, tenantEntityPermissionChecker); | ||
45 | put(Resource.EDGE, tenantEntityPermissionChecker); | 46 | put(Resource.EDGE, tenantEntityPermissionChecker); |
46 | } | 47 | } |
47 | 48 |
@@ -23,16 +23,19 @@ import com.google.common.util.concurrent.ListenableFuture; | @@ -23,16 +23,19 @@ import com.google.common.util.concurrent.ListenableFuture; | ||
23 | import com.google.common.util.concurrent.MoreExecutors; | 23 | import com.google.common.util.concurrent.MoreExecutors; |
24 | import com.google.protobuf.ByteString; | 24 | import com.google.protobuf.ByteString; |
25 | import lombok.extern.slf4j.Slf4j; | 25 | import lombok.extern.slf4j.Slf4j; |
26 | +import org.springframework.cache.CacheManager; | ||
26 | import org.springframework.stereotype.Service; | 27 | import org.springframework.stereotype.Service; |
27 | import org.springframework.util.StringUtils; | 28 | import org.springframework.util.StringUtils; |
28 | import org.thingsboard.common.util.JacksonUtil; | 29 | import org.thingsboard.common.util.JacksonUtil; |
30 | +import org.thingsboard.server.cache.firmware.FirmwareCacheWriter; | ||
29 | import org.thingsboard.server.common.data.ApiUsageState; | 31 | import org.thingsboard.server.common.data.ApiUsageState; |
30 | import org.thingsboard.server.common.data.DataConstants; | 32 | import org.thingsboard.server.common.data.DataConstants; |
31 | import org.thingsboard.server.common.data.Device; | 33 | import org.thingsboard.server.common.data.Device; |
32 | import org.thingsboard.server.common.data.DeviceProfile; | 34 | import org.thingsboard.server.common.data.DeviceProfile; |
33 | import org.thingsboard.server.common.data.EntityType; | 35 | import org.thingsboard.server.common.data.EntityType; |
34 | -import org.thingsboard.server.common.data.TbResource; | 36 | +import org.thingsboard.server.common.data.Firmware; |
35 | import org.thingsboard.server.common.data.ResourceType; | 37 | import org.thingsboard.server.common.data.ResourceType; |
38 | +import org.thingsboard.server.common.data.TbResource; | ||
36 | import org.thingsboard.server.common.data.TenantProfile; | 39 | import org.thingsboard.server.common.data.TenantProfile; |
37 | import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; | 40 | import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; |
38 | import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData; | 41 | import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData; |
@@ -40,6 +43,7 @@ import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileC | @@ -40,6 +43,7 @@ import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileC | ||
40 | import org.thingsboard.server.common.data.id.CustomerId; | 43 | import org.thingsboard.server.common.data.id.CustomerId; |
41 | import org.thingsboard.server.common.data.id.DeviceId; | 44 | import org.thingsboard.server.common.data.id.DeviceId; |
42 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 45 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
46 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
43 | import org.thingsboard.server.common.data.id.TenantId; | 47 | import org.thingsboard.server.common.data.id.TenantId; |
44 | import org.thingsboard.server.common.data.relation.EntityRelation; | 48 | import org.thingsboard.server.common.data.relation.EntityRelation; |
45 | import org.thingsboard.server.common.data.security.DeviceCredentials; | 49 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
@@ -55,6 +59,7 @@ import org.thingsboard.server.dao.device.DeviceService; | @@ -55,6 +59,7 @@ import org.thingsboard.server.dao.device.DeviceService; | ||
55 | import org.thingsboard.server.dao.device.provision.ProvisionFailedException; | 59 | import org.thingsboard.server.dao.device.provision.ProvisionFailedException; |
56 | import org.thingsboard.server.dao.device.provision.ProvisionRequest; | 60 | import org.thingsboard.server.dao.device.provision.ProvisionRequest; |
57 | import org.thingsboard.server.dao.device.provision.ProvisionResponse; | 61 | import org.thingsboard.server.dao.device.provision.ProvisionResponse; |
62 | +import org.thingsboard.server.dao.firmware.FirmwareService; | ||
58 | import org.thingsboard.server.dao.relation.RelationService; | 63 | import org.thingsboard.server.dao.relation.RelationService; |
59 | import org.thingsboard.server.dao.resource.ResourceService; | 64 | import org.thingsboard.server.dao.resource.ResourceService; |
60 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | 65 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
@@ -66,7 +71,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFro | @@ -66,7 +71,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFro | ||
66 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; | 71 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; |
67 | import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg; | 72 | import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg; |
68 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; | 73 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; |
69 | -import org.thingsboard.server.gen.transport.TransportProtos.ProvisionResponseStatus; | ||
70 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; | 74 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
71 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; | 75 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
72 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; | 76 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; |
@@ -79,6 +83,7 @@ import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | @@ -79,6 +83,7 @@ import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | ||
79 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; | 83 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
80 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; | 84 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
81 | import org.thingsboard.server.service.queue.TbClusterService; | 85 | import org.thingsboard.server.service.queue.TbClusterService; |
86 | +import org.thingsboard.server.service.resource.TbResourceService; | ||
82 | import org.thingsboard.server.service.state.DeviceStateService; | 87 | import org.thingsboard.server.service.state.DeviceStateService; |
83 | 88 | ||
84 | import java.util.Optional; | 89 | import java.util.Optional; |
@@ -109,7 +114,9 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -109,7 +114,9 @@ public class DefaultTransportApiService implements TransportApiService { | ||
109 | private final TbClusterService tbClusterService; | 114 | private final TbClusterService tbClusterService; |
110 | private final DataDecodingEncodingService dataDecodingEncodingService; | 115 | private final DataDecodingEncodingService dataDecodingEncodingService; |
111 | private final DeviceProvisionService deviceProvisionService; | 116 | private final DeviceProvisionService deviceProvisionService; |
112 | - private final ResourceService resourceService; | 117 | + private final TbResourceService resourceService; |
118 | + private final FirmwareService firmwareService; | ||
119 | + private final FirmwareCacheWriter firmwareCacheWriter; | ||
113 | 120 | ||
114 | private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>(); | 121 | private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>(); |
115 | 122 | ||
@@ -118,7 +125,7 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -118,7 +125,7 @@ public class DefaultTransportApiService implements TransportApiService { | ||
118 | RelationService relationService, DeviceCredentialsService deviceCredentialsService, | 125 | RelationService relationService, DeviceCredentialsService deviceCredentialsService, |
119 | DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService, | 126 | DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService, |
120 | TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService, | 127 | TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService, |
121 | - DeviceProvisionService deviceProvisionService, ResourceService resourceService) { | 128 | + DeviceProvisionService deviceProvisionService, TbResourceService resourceService, FirmwareService firmwareService, FirmwareCacheWriter firmwareCacheWriter) { |
122 | this.deviceProfileCache = deviceProfileCache; | 129 | this.deviceProfileCache = deviceProfileCache; |
123 | this.tenantProfileCache = tenantProfileCache; | 130 | this.tenantProfileCache = tenantProfileCache; |
124 | this.apiUsageStateService = apiUsageStateService; | 131 | this.apiUsageStateService = apiUsageStateService; |
@@ -131,6 +138,8 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -131,6 +138,8 @@ public class DefaultTransportApiService implements TransportApiService { | ||
131 | this.dataDecodingEncodingService = dataDecodingEncodingService; | 138 | this.dataDecodingEncodingService = dataDecodingEncodingService; |
132 | this.deviceProvisionService = deviceProvisionService; | 139 | this.deviceProvisionService = deviceProvisionService; |
133 | this.resourceService = resourceService; | 140 | this.resourceService = resourceService; |
141 | + this.firmwareService = firmwareService; | ||
142 | + this.firmwareCacheWriter = firmwareCacheWriter; | ||
134 | } | 143 | } |
135 | 144 | ||
136 | @Override | 145 | @Override |
@@ -167,6 +176,9 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -167,6 +176,9 @@ public class DefaultTransportApiService implements TransportApiService { | ||
167 | } else if (transportApiRequestMsg.hasResourceRequestMsg()) { | 176 | } else if (transportApiRequestMsg.hasResourceRequestMsg()) { |
168 | return Futures.transform(handle(transportApiRequestMsg.getResourceRequestMsg()), | 177 | return Futures.transform(handle(transportApiRequestMsg.getResourceRequestMsg()), |
169 | value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 178 | value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); |
179 | + } else if (transportApiRequestMsg.hasFirmwareRequestMsg()) { | ||
180 | + return Futures.transform(handle(transportApiRequestMsg.getFirmwareRequestMsg()), | ||
181 | + value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | ||
170 | } | 182 | } |
171 | return Futures.transform(getEmptyTransportApiResponseFuture(), | 183 | return Futures.transform(getEmptyTransportApiResponseFuture(), |
172 | value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 184 | value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); |
@@ -314,14 +326,14 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -314,14 +326,14 @@ public class DefaultTransportApiService implements TransportApiService { | ||
314 | } catch (ProvisionFailedException e) { | 326 | } catch (ProvisionFailedException e) { |
315 | return Futures.immediateFuture(getTransportApiResponseMsg( | 327 | return Futures.immediateFuture(getTransportApiResponseMsg( |
316 | new DeviceCredentials(), | 328 | new DeviceCredentials(), |
317 | - TransportProtos.ProvisionResponseStatus.valueOf(e.getMessage()))); | 329 | + TransportProtos.ResponseStatus.valueOf(e.getMessage()))); |
318 | } | 330 | } |
319 | - return Futures.transform(provisionResponseFuture, provisionResponse -> getTransportApiResponseMsg(provisionResponse.getDeviceCredentials(), TransportProtos.ProvisionResponseStatus.SUCCESS), | 331 | + return Futures.transform(provisionResponseFuture, provisionResponse -> getTransportApiResponseMsg(provisionResponse.getDeviceCredentials(), TransportProtos.ResponseStatus.SUCCESS), |
320 | dbCallbackExecutorService); | 332 | dbCallbackExecutorService); |
321 | } | 333 | } |
322 | 334 | ||
323 | - private TransportApiResponseMsg getTransportApiResponseMsg(DeviceCredentials deviceCredentials, TransportProtos.ProvisionResponseStatus status) { | ||
324 | - if (!status.equals(ProvisionResponseStatus.SUCCESS)) { | 335 | + private TransportApiResponseMsg getTransportApiResponseMsg(DeviceCredentials deviceCredentials, TransportProtos.ResponseStatus status) { |
336 | + if (!status.equals(TransportProtos.ResponseStatus.SUCCESS)) { | ||
325 | return TransportApiResponseMsg.newBuilder().setProvisionDeviceResponseMsg(TransportProtos.ProvisionDeviceResponseMsg.newBuilder().setStatus(status).build()).build(); | 337 | return TransportApiResponseMsg.newBuilder().setProvisionDeviceResponseMsg(TransportProtos.ProvisionDeviceResponseMsg.newBuilder().setStatus(status).build()).build(); |
326 | } | 338 | } |
327 | TransportProtos.ProvisionDeviceResponseMsg.Builder provisionResponse = TransportProtos.ProvisionDeviceResponseMsg.newBuilder() | 339 | TransportProtos.ProvisionDeviceResponseMsg.Builder provisionResponse = TransportProtos.ProvisionDeviceResponseMsg.newBuilder() |
@@ -441,6 +453,48 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -441,6 +453,48 @@ public class DefaultTransportApiService implements TransportApiService { | ||
441 | } | 453 | } |
442 | } | 454 | } |
443 | 455 | ||
456 | + private ListenableFuture<TransportApiResponseMsg> handle(TransportProtos.GetFirmwareRequestMsg requestMsg) { | ||
457 | + TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); | ||
458 | + DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB())); | ||
459 | + Device device = deviceService.findDeviceById(tenantId, deviceId); | ||
460 | + | ||
461 | + if (device == null) { | ||
462 | + return getEmptyTransportApiResponseFuture(); | ||
463 | + } | ||
464 | + | ||
465 | + FirmwareId firmwareId = device.getFirmwareId(); | ||
466 | + | ||
467 | + if (firmwareId == null) { | ||
468 | + firmwareId = deviceProfileCache.find(device.getDeviceProfileId()).getFirmwareId(); | ||
469 | + } | ||
470 | + | ||
471 | + TransportProtos.GetFirmwareResponseMsg.Builder builder = TransportProtos.GetFirmwareResponseMsg.newBuilder(); | ||
472 | + | ||
473 | + if (firmwareId == null) { | ||
474 | + builder.setResponseStatus(TransportProtos.ResponseStatus.NOT_FOUND); | ||
475 | + } else { | ||
476 | + Firmware firmware = firmwareService.findFirmwareById(tenantId, firmwareId); | ||
477 | + | ||
478 | + if (firmware == null) { | ||
479 | + builder.setResponseStatus(TransportProtos.ResponseStatus.NOT_FOUND); | ||
480 | + } else { | ||
481 | + builder.setResponseStatus(TransportProtos.ResponseStatus.SUCCESS); | ||
482 | + builder.setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits()); | ||
483 | + builder.setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits()); | ||
484 | + builder.setTitle(firmware.getTitle()); | ||
485 | + builder.setVersion(firmware.getVersion()); | ||
486 | + builder.setFileName(firmware.getFileName()); | ||
487 | + builder.setContentType(firmware.getContentType()); | ||
488 | + firmwareCacheWriter.put(firmwareId.toString(), firmware.getData().array()); | ||
489 | + } | ||
490 | + } | ||
491 | + | ||
492 | + return Futures.immediateFuture( | ||
493 | + TransportApiResponseMsg.newBuilder() | ||
494 | + .setFirmwareResponseMsg(builder.build()) | ||
495 | + .build()); | ||
496 | + } | ||
497 | + | ||
444 | private ListenableFuture<TransportApiResponseMsg> handleRegistration(TransportProtos.LwM2MRegistrationRequestMsg msg) { | 498 | private ListenableFuture<TransportApiResponseMsg> handleRegistration(TransportProtos.LwM2MRegistrationRequestMsg msg) { |
445 | TenantId tenantId = new TenantId(UUID.fromString(msg.getTenantId())); | 499 | TenantId tenantId = new TenantId(UUID.fromString(msg.getTenantId())); |
446 | String deviceName = msg.getEndpoint(); | 500 | String deviceName = msg.getEndpoint(); |
@@ -371,6 +371,9 @@ caffeine: | @@ -371,6 +371,9 @@ caffeine: | ||
371 | tokensOutdatageTime: | 371 | tokensOutdatageTime: |
372 | timeToLiveInMinutes: 20000 | 372 | timeToLiveInMinutes: 20000 |
373 | maxSize: 10000 | 373 | maxSize: 10000 |
374 | + firmwares: | ||
375 | + timeToLiveInMinutes: 1440 | ||
376 | + maxSize: 100 | ||
374 | edges: | 377 | edges: |
375 | timeToLiveInMinutes: 1440 | 378 | timeToLiveInMinutes: 1440 |
376 | maxSize: 0 | 379 | maxSize: 0 |
@@ -446,6 +449,9 @@ spring.resources.chain: | @@ -446,6 +449,9 @@ spring.resources.chain: | ||
446 | content: | 449 | content: |
447 | enabled: "true" | 450 | enabled: "true" |
448 | 451 | ||
452 | +spring.servlet.multipart.max-file-size: "50MB" | ||
453 | +spring.servlet.multipart.max-request-size: "50MB" | ||
454 | + | ||
449 | spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation: "true" | 455 | spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation: "true" |
450 | spring.jpa.properties.hibernate.order_by.default_null_ordering: "last" | 456 | spring.jpa.properties.hibernate.order_by.default_null_ordering: "last" |
451 | 457 | ||
@@ -738,6 +744,10 @@ queue: | @@ -738,6 +744,10 @@ queue: | ||
738 | sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" | 744 | sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" |
739 | sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" | 745 | sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" |
740 | security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" | 746 | security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" |
747 | + consumer-properties-per-topic: | ||
748 | + tb_firmware: | ||
749 | + - key: max.poll.records | ||
750 | + value: 10 | ||
741 | other: | 751 | other: |
742 | topic-properties: | 752 | topic-properties: |
743 | rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" | 753 | rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" |
@@ -745,6 +755,7 @@ queue: | @@ -745,6 +755,7 @@ queue: | ||
745 | transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" | 755 | transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" |
746 | notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" | 756 | notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" |
747 | js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100;min.insync.replicas:1}" | 757 | js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100;min.insync.replicas:1}" |
758 | + fw-updates: "${TB_QUEUE_KAFKA_FW_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" | ||
748 | consumer-stats: | 759 | consumer-stats: |
749 | enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}" | 760 | enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}" |
750 | print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}" | 761 | print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}" |
@@ -815,6 +826,10 @@ queue: | @@ -815,6 +826,10 @@ queue: | ||
815 | poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" | 826 | poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" |
816 | partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" | 827 | partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" |
817 | pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:2000}" | 828 | pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:2000}" |
829 | + firmware: | ||
830 | + topic: "${TB_QUEUE_CORE_FW_TOPIC:tb_firmware}" | ||
831 | + pack-interval-ms: "${TB_QUEUE_CORE_FW_PACK_INTERVAL_MS:60000}" | ||
832 | + pack-size: "${TB_QUEUE_CORE_FW_PACK_SIZE:100}" | ||
818 | usage-stats-topic: "${TB_QUEUE_US_TOPIC:tb_usage_stats}" | 833 | usage-stats-topic: "${TB_QUEUE_US_TOPIC:tb_usage_stats}" |
819 | stats: | 834 | stats: |
820 | enabled: "${TB_QUEUE_CORE_STATS_ENABLED:true}" | 835 | enabled: "${TB_QUEUE_CORE_STATS_ENABLED:true}" |
application/src/test/java/org/thingsboard/server/controller/BaseFirmwareControllerTest.java
0 → 100644
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.controller; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.core.type.TypeReference; | ||
19 | +import org.junit.After; | ||
20 | +import org.junit.Assert; | ||
21 | +import org.junit.Before; | ||
22 | +import org.junit.Test; | ||
23 | +import org.springframework.mock.web.MockMultipartFile; | ||
24 | +import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; | ||
25 | +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | ||
26 | +import org.thingsboard.common.util.JacksonUtil; | ||
27 | +import org.thingsboard.server.common.data.Firmware; | ||
28 | +import org.thingsboard.server.common.data.FirmwareInfo; | ||
29 | +import org.thingsboard.server.common.data.Tenant; | ||
30 | +import org.thingsboard.server.common.data.User; | ||
31 | +import org.thingsboard.server.common.data.page.PageData; | ||
32 | +import org.thingsboard.server.common.data.page.PageLink; | ||
33 | +import org.thingsboard.server.common.data.security.Authority; | ||
34 | + | ||
35 | +import java.nio.ByteBuffer; | ||
36 | +import java.util.ArrayList; | ||
37 | +import java.util.Collections; | ||
38 | +import java.util.List; | ||
39 | + | ||
40 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
41 | + | ||
42 | +public abstract class BaseFirmwareControllerTest extends AbstractControllerTest { | ||
43 | + | ||
44 | + private IdComparator<FirmwareInfo> idComparator = new IdComparator<>(); | ||
45 | + | ||
46 | + public static final String TITLE = "My firmware"; | ||
47 | + private static final String FILE_NAME = "filename.txt"; | ||
48 | + private static final String VERSION = "v1.0"; | ||
49 | + private static final String CONTENT_TYPE = "text/plain"; | ||
50 | + private static final String CHECKSUM_ALGORITHM = "sha256"; | ||
51 | + private static final String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"; | ||
52 | + private static final ByteBuffer DATA = ByteBuffer.wrap(new byte[]{1}); | ||
53 | + | ||
54 | + private Tenant savedTenant; | ||
55 | + private User tenantAdmin; | ||
56 | + | ||
57 | + @Before | ||
58 | + public void beforeTest() throws Exception { | ||
59 | + loginSysAdmin(); | ||
60 | + | ||
61 | + Tenant tenant = new Tenant(); | ||
62 | + tenant.setTitle("My tenant"); | ||
63 | + savedTenant = doPost("/api/tenant", tenant, Tenant.class); | ||
64 | + Assert.assertNotNull(savedTenant); | ||
65 | + | ||
66 | + tenantAdmin = new User(); | ||
67 | + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | ||
68 | + tenantAdmin.setTenantId(savedTenant.getId()); | ||
69 | + tenantAdmin.setEmail("tenant2@thingsboard.org"); | ||
70 | + tenantAdmin.setFirstName("Joe"); | ||
71 | + tenantAdmin.setLastName("Downs"); | ||
72 | + | ||
73 | + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); | ||
74 | + } | ||
75 | + | ||
76 | + @After | ||
77 | + public void afterTest() throws Exception { | ||
78 | + loginSysAdmin(); | ||
79 | + | ||
80 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | ||
81 | + .andExpect(status().isOk()); | ||
82 | + } | ||
83 | + | ||
84 | + @Test | ||
85 | + public void testSaveFirmware() throws Exception { | ||
86 | + FirmwareInfo firmwareInfo = new FirmwareInfo(); | ||
87 | + firmwareInfo.setTitle(TITLE); | ||
88 | + firmwareInfo.setVersion(VERSION); | ||
89 | + | ||
90 | + FirmwareInfo savedFirmwareInfo = save(firmwareInfo); | ||
91 | + | ||
92 | + Assert.assertNotNull(savedFirmwareInfo); | ||
93 | + Assert.assertNotNull(savedFirmwareInfo.getId()); | ||
94 | + Assert.assertTrue(savedFirmwareInfo.getCreatedTime() > 0); | ||
95 | + Assert.assertEquals(savedTenant.getId(), savedFirmwareInfo.getTenantId()); | ||
96 | + Assert.assertEquals(firmwareInfo.getTitle(), savedFirmwareInfo.getTitle()); | ||
97 | + Assert.assertEquals(firmwareInfo.getVersion(), savedFirmwareInfo.getVersion()); | ||
98 | + | ||
99 | + savedFirmwareInfo.setAdditionalInfo(JacksonUtil.newObjectNode()); | ||
100 | + | ||
101 | + save(savedFirmwareInfo); | ||
102 | + | ||
103 | + FirmwareInfo foundFirmwareInfo = doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString(), FirmwareInfo.class); | ||
104 | + Assert.assertEquals(foundFirmwareInfo.getTitle(), savedFirmwareInfo.getTitle()); | ||
105 | + } | ||
106 | + | ||
107 | + @Test | ||
108 | + public void testSaveFirmwareData() throws Exception { | ||
109 | + FirmwareInfo firmwareInfo = new FirmwareInfo(); | ||
110 | + firmwareInfo.setTitle(TITLE); | ||
111 | + firmwareInfo.setVersion(VERSION); | ||
112 | + | ||
113 | + FirmwareInfo savedFirmwareInfo = save(firmwareInfo); | ||
114 | + | ||
115 | + Assert.assertNotNull(savedFirmwareInfo); | ||
116 | + Assert.assertNotNull(savedFirmwareInfo.getId()); | ||
117 | + Assert.assertTrue(savedFirmwareInfo.getCreatedTime() > 0); | ||
118 | + Assert.assertEquals(savedTenant.getId(), savedFirmwareInfo.getTenantId()); | ||
119 | + Assert.assertEquals(firmwareInfo.getTitle(), savedFirmwareInfo.getTitle()); | ||
120 | + Assert.assertEquals(firmwareInfo.getVersion(), savedFirmwareInfo.getVersion()); | ||
121 | + | ||
122 | + savedFirmwareInfo.setAdditionalInfo(JacksonUtil.newObjectNode()); | ||
123 | + | ||
124 | + save(savedFirmwareInfo); | ||
125 | + | ||
126 | + FirmwareInfo foundFirmwareInfo = doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString(), FirmwareInfo.class); | ||
127 | + Assert.assertEquals(foundFirmwareInfo.getTitle(), savedFirmwareInfo.getTitle()); | ||
128 | + | ||
129 | + MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array()); | ||
130 | + | ||
131 | + Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM); | ||
132 | + | ||
133 | + Assert.assertEquals(FILE_NAME, savedFirmware.getFileName()); | ||
134 | + Assert.assertEquals(CONTENT_TYPE, savedFirmware.getContentType()); | ||
135 | + } | ||
136 | + | ||
137 | + @Test | ||
138 | + public void testUpdateFirmwareFromDifferentTenant() throws Exception { | ||
139 | + FirmwareInfo firmwareInfo = new FirmwareInfo(); | ||
140 | + firmwareInfo.setTitle(TITLE); | ||
141 | + firmwareInfo.setVersion(VERSION); | ||
142 | + | ||
143 | + FirmwareInfo savedFirmwareInfo = save(firmwareInfo); | ||
144 | + | ||
145 | + loginDifferentTenant(); | ||
146 | + doPost("/api/firmware", savedFirmwareInfo, FirmwareInfo.class, status().isForbidden()); | ||
147 | + deleteDifferentTenant(); | ||
148 | + } | ||
149 | + | ||
150 | + @Test | ||
151 | + public void testFindFirmwareInfoById() throws Exception { | ||
152 | + FirmwareInfo firmwareInfo = new FirmwareInfo(); | ||
153 | + firmwareInfo.setTitle(TITLE); | ||
154 | + firmwareInfo.setVersion(VERSION); | ||
155 | + | ||
156 | + FirmwareInfo savedFirmwareInfo = save(firmwareInfo); | ||
157 | + | ||
158 | + FirmwareInfo foundFirmware = doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString(), FirmwareInfo.class); | ||
159 | + Assert.assertNotNull(foundFirmware); | ||
160 | + Assert.assertEquals(savedFirmwareInfo, foundFirmware); | ||
161 | + } | ||
162 | + | ||
163 | + @Test | ||
164 | + public void testFindFirmwareById() throws Exception { | ||
165 | + FirmwareInfo firmwareInfo = new FirmwareInfo(); | ||
166 | + firmwareInfo.setTitle(TITLE); | ||
167 | + firmwareInfo.setVersion(VERSION); | ||
168 | + | ||
169 | + FirmwareInfo savedFirmwareInfo = save(firmwareInfo); | ||
170 | + | ||
171 | + MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array()); | ||
172 | + | ||
173 | + Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM); | ||
174 | + | ||
175 | + Firmware foundFirmware = doGet("/api/firmware/" + savedFirmwareInfo.getId().getId().toString(), Firmware.class); | ||
176 | + Assert.assertNotNull(foundFirmware); | ||
177 | + Assert.assertEquals(savedFirmware, foundFirmware); | ||
178 | + } | ||
179 | + | ||
180 | + @Test | ||
181 | + public void testDeleteFirmware() throws Exception { | ||
182 | + FirmwareInfo firmwareInfo = new FirmwareInfo(); | ||
183 | + firmwareInfo.setTitle(TITLE); | ||
184 | + firmwareInfo.setVersion(VERSION); | ||
185 | + | ||
186 | + FirmwareInfo savedFirmwareInfo = save(firmwareInfo); | ||
187 | + | ||
188 | + doDelete("/api/firmware/" + savedFirmwareInfo.getId().getId().toString()) | ||
189 | + .andExpect(status().isOk()); | ||
190 | + | ||
191 | + doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString()) | ||
192 | + .andExpect(status().isNotFound()); | ||
193 | + } | ||
194 | + | ||
195 | + @Test | ||
196 | + public void testFindTenantFirmwares() throws Exception { | ||
197 | + List<FirmwareInfo> firmwares = new ArrayList<>(); | ||
198 | + for (int i = 0; i < 165; i++) { | ||
199 | + FirmwareInfo firmwareInfo = new FirmwareInfo(); | ||
200 | + firmwareInfo.setTitle(TITLE); | ||
201 | + firmwareInfo.setVersion(VERSION + i); | ||
202 | + | ||
203 | + FirmwareInfo savedFirmwareInfo = save(firmwareInfo); | ||
204 | + | ||
205 | + if (i > 100) { | ||
206 | + MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array()); | ||
207 | + | ||
208 | + Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM); | ||
209 | + firmwares.add(new FirmwareInfo(savedFirmware)); | ||
210 | + } else { | ||
211 | + firmwares.add(savedFirmwareInfo); | ||
212 | + } | ||
213 | + } | ||
214 | + | ||
215 | + List<FirmwareInfo> loadedFirmwares = new ArrayList<>(); | ||
216 | + PageLink pageLink = new PageLink(24); | ||
217 | + PageData<FirmwareInfo> pageData; | ||
218 | + do { | ||
219 | + pageData = doGetTypedWithPageLink("/api/firmwares?", | ||
220 | + new TypeReference<>() { | ||
221 | + }, pageLink); | ||
222 | + loadedFirmwares.addAll(pageData.getData()); | ||
223 | + if (pageData.hasNext()) { | ||
224 | + pageLink = pageLink.nextPageLink(); | ||
225 | + } | ||
226 | + } while (pageData.hasNext()); | ||
227 | + | ||
228 | + Collections.sort(firmwares, idComparator); | ||
229 | + Collections.sort(loadedFirmwares, idComparator); | ||
230 | + | ||
231 | + Assert.assertEquals(firmwares, loadedFirmwares); | ||
232 | + } | ||
233 | + | ||
234 | + @Test | ||
235 | + public void testFindTenantFirmwaresByHasData() throws Exception { | ||
236 | + List<FirmwareInfo> firmwaresWithData = new ArrayList<>(); | ||
237 | + List<FirmwareInfo> firmwaresWithoutData = new ArrayList<>(); | ||
238 | + | ||
239 | + for (int i = 0; i < 165; i++) { | ||
240 | + FirmwareInfo firmwareInfo = new FirmwareInfo(); | ||
241 | + firmwareInfo.setTitle(TITLE); | ||
242 | + firmwareInfo.setVersion(VERSION + i); | ||
243 | + | ||
244 | + FirmwareInfo savedFirmwareInfo = save(firmwareInfo); | ||
245 | + | ||
246 | + if (i > 100) { | ||
247 | + MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array()); | ||
248 | + | ||
249 | + Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM); | ||
250 | + firmwaresWithData.add(new FirmwareInfo(savedFirmware)); | ||
251 | + } else { | ||
252 | + firmwaresWithoutData.add(savedFirmwareInfo); | ||
253 | + } | ||
254 | + } | ||
255 | + | ||
256 | + List<FirmwareInfo> loadedFirmwaresWithData = new ArrayList<>(); | ||
257 | + PageLink pageLink = new PageLink(24); | ||
258 | + PageData<FirmwareInfo> pageData; | ||
259 | + do { | ||
260 | + pageData = doGetTypedWithPageLink("/api/firmwares/true?", | ||
261 | + new TypeReference<>() { | ||
262 | + }, pageLink); | ||
263 | + loadedFirmwaresWithData.addAll(pageData.getData()); | ||
264 | + if (pageData.hasNext()) { | ||
265 | + pageLink = pageLink.nextPageLink(); | ||
266 | + } | ||
267 | + } while (pageData.hasNext()); | ||
268 | + | ||
269 | + List<FirmwareInfo> loadedFirmwaresWithoutData = new ArrayList<>(); | ||
270 | + pageLink = new PageLink(24); | ||
271 | + do { | ||
272 | + pageData = doGetTypedWithPageLink("/api/firmwares/false?", | ||
273 | + new TypeReference<>() { | ||
274 | + }, pageLink); | ||
275 | + loadedFirmwaresWithoutData.addAll(pageData.getData()); | ||
276 | + if (pageData.hasNext()) { | ||
277 | + pageLink = pageLink.nextPageLink(); | ||
278 | + } | ||
279 | + } while (pageData.hasNext()); | ||
280 | + | ||
281 | + Collections.sort(firmwaresWithData, idComparator); | ||
282 | + Collections.sort(firmwaresWithoutData, idComparator); | ||
283 | + Collections.sort(loadedFirmwaresWithData, idComparator); | ||
284 | + Collections.sort(loadedFirmwaresWithoutData, idComparator); | ||
285 | + | ||
286 | + Assert.assertEquals(firmwaresWithData, loadedFirmwaresWithData); | ||
287 | + Assert.assertEquals(firmwaresWithoutData, loadedFirmwaresWithoutData); | ||
288 | + } | ||
289 | + | ||
290 | + | ||
291 | + private FirmwareInfo save(FirmwareInfo firmwareInfo) throws Exception { | ||
292 | + return doPost("/api/firmware", firmwareInfo, FirmwareInfo.class); | ||
293 | + } | ||
294 | + | ||
295 | + protected Firmware savaData(String urlTemplate, MockMultipartFile content, String... params) throws Exception { | ||
296 | + MockMultipartHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.multipart(urlTemplate, params); | ||
297 | + postRequest.file(content); | ||
298 | + setJwtToken(postRequest); | ||
299 | + return readResponse(mockMvc.perform(postRequest).andExpect(status().isOk()), Firmware.class); | ||
300 | + } | ||
301 | + | ||
302 | +} |
application/src/test/java/org/thingsboard/server/controller/sql/FirmwareControllerSqlTest.java
0 → 100644
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.controller.sql; | ||
17 | + | ||
18 | +import org.thingsboard.server.controller.BaseFirmwareControllerTest; | ||
19 | +import org.thingsboard.server.dao.service.DaoSqlTest; | ||
20 | + | ||
21 | +@DaoSqlTest | ||
22 | +public class FirmwareControllerSqlTest extends BaseFirmwareControllerTest { | ||
23 | +} |
common/cache/src/main/java/org/thingsboard/server/cache/firmware/AbstractRedisFirmwareCache.java
0 → 100644
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.cache.firmware; | ||
17 | + | ||
18 | +import org.springframework.data.redis.connection.RedisConnectionFactory; | ||
19 | + | ||
20 | +import static org.thingsboard.server.common.data.CacheConstants.FIRMWARE_CACHE; | ||
21 | + | ||
22 | +public abstract class AbstractRedisFirmwareCache { | ||
23 | + | ||
24 | + protected final RedisConnectionFactory redisConnectionFactory; | ||
25 | + | ||
26 | + protected AbstractRedisFirmwareCache(RedisConnectionFactory redisConnectionFactory) { | ||
27 | + this.redisConnectionFactory = redisConnectionFactory; | ||
28 | + } | ||
29 | + | ||
30 | + protected byte[] toFirmwareCacheKey(String key) { | ||
31 | + return String.format("%s::%s", FIRMWARE_CACHE, key).getBytes(); | ||
32 | + } | ||
33 | +} |
common/cache/src/main/java/org/thingsboard/server/cache/firmware/CaffeineFirmwareCacheReader.java
0 → 100644
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.cache.firmware; | ||
17 | + | ||
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | ||
19 | +import org.springframework.cache.CacheManager; | ||
20 | +import org.springframework.stereotype.Service; | ||
21 | + | ||
22 | +import static org.thingsboard.server.common.data.CacheConstants.FIRMWARE_CACHE; | ||
23 | + | ||
24 | +@Service | ||
25 | +@ConditionalOnExpression("(('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport') && ('${cache.type:null}'=='caffeine' || '${cache.type:null}'=='null')") | ||
26 | +public class CaffeineFirmwareCacheReader implements FirmwareCacheReader { | ||
27 | + | ||
28 | + private final CacheManager cacheManager; | ||
29 | + | ||
30 | + public CaffeineFirmwareCacheReader(CacheManager cacheManager) { | ||
31 | + this.cacheManager = cacheManager; | ||
32 | + } | ||
33 | + | ||
34 | + @Override | ||
35 | + public byte[] get(String key) { | ||
36 | + return get(key, 0, 0); | ||
37 | + } | ||
38 | + | ||
39 | + @Override | ||
40 | + public byte[] get(String key, int chunkSize, int chunk) { | ||
41 | + byte[] data = cacheManager.getCache(FIRMWARE_CACHE).get(key, byte[].class); | ||
42 | + | ||
43 | + if (chunkSize < 1) { | ||
44 | + return data; | ||
45 | + } | ||
46 | + | ||
47 | + if (data != null && data.length > 0) { | ||
48 | + int startIndex = chunkSize * chunk; | ||
49 | + | ||
50 | + int size = Math.min(data.length - startIndex, chunkSize); | ||
51 | + | ||
52 | + if (startIndex < data.length && size > 0) { | ||
53 | + byte[] result = new byte[size]; | ||
54 | + System.arraycopy(data, startIndex, result, 0, size); | ||
55 | + return result; | ||
56 | + } | ||
57 | + } | ||
58 | + return new byte[0]; | ||
59 | + } | ||
60 | +} |
common/cache/src/main/java/org/thingsboard/server/cache/firmware/CaffeineFirmwareCacheWriter.java
0 → 100644
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.cache.firmware; | ||
17 | + | ||
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | ||
19 | +import org.springframework.cache.CacheManager; | ||
20 | +import org.springframework.stereotype.Service; | ||
21 | + | ||
22 | +import static org.thingsboard.server.common.data.CacheConstants.FIRMWARE_CACHE; | ||
23 | + | ||
24 | +@Service | ||
25 | +@ConditionalOnExpression("('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core') && ('${cache.type:null}'=='caffeine' || '${cache.type:null}'=='null')") | ||
26 | +public class CaffeineFirmwareCacheWriter implements FirmwareCacheWriter { | ||
27 | + | ||
28 | + private final CacheManager cacheManager; | ||
29 | + | ||
30 | + public CaffeineFirmwareCacheWriter(CacheManager cacheManager) { | ||
31 | + this.cacheManager = cacheManager; | ||
32 | + } | ||
33 | + | ||
34 | + @Override | ||
35 | + public void put(String key, byte[] value) { | ||
36 | + cacheManager.getCache(FIRMWARE_CACHE).putIfAbsent(key, value); | ||
37 | + } | ||
38 | +} |
common/cache/src/main/java/org/thingsboard/server/cache/firmware/FirmwareCacheReader.java
0 → 100644
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.cache.firmware; | ||
17 | + | ||
18 | +public interface FirmwareCacheReader { | ||
19 | + byte[] get(String key); | ||
20 | + | ||
21 | + byte[] get(String key, int chunkSize, int chunk); | ||
22 | +} |
common/cache/src/main/java/org/thingsboard/server/cache/firmware/FirmwareCacheWriter.java
0 → 100644
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.cache.firmware; | ||
17 | + | ||
18 | +public interface FirmwareCacheWriter { | ||
19 | + void put(String key, byte[] value); | ||
20 | +} |
common/cache/src/main/java/org/thingsboard/server/cache/firmware/RedisFirmwareCacheReader.java
0 → 100644
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.cache.firmware; | ||
17 | + | ||
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | ||
19 | +import org.springframework.data.redis.connection.RedisConnection; | ||
20 | +import org.springframework.data.redis.connection.RedisConnectionFactory; | ||
21 | +import org.springframework.stereotype.Service; | ||
22 | + | ||
23 | +@Service | ||
24 | +@ConditionalOnExpression("(('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport') && '${cache.type:null}'=='redis'") | ||
25 | +public class RedisFirmwareCacheReader extends AbstractRedisFirmwareCache implements FirmwareCacheReader { | ||
26 | + | ||
27 | + public RedisFirmwareCacheReader(RedisConnectionFactory redisConnectionFactory) { | ||
28 | + super(redisConnectionFactory); | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public byte[] get(String key) { | ||
33 | + return get(key, 0, 0); | ||
34 | + } | ||
35 | + | ||
36 | + @Override | ||
37 | + public byte[] get(String key, int chunkSize, int chunk) { | ||
38 | + try (RedisConnection connection = redisConnectionFactory.getConnection()) { | ||
39 | + if (chunkSize == 0) { | ||
40 | + return connection.get(toFirmwareCacheKey(key)); | ||
41 | + } | ||
42 | + | ||
43 | + int startIndex = chunkSize * chunk; | ||
44 | + int endIndex = startIndex + chunkSize - 1; | ||
45 | + return connection.getRange(toFirmwareCacheKey(key), startIndex, endIndex); | ||
46 | + } | ||
47 | + } | ||
48 | + | ||
49 | +} |
common/cache/src/main/java/org/thingsboard/server/cache/firmware/RedisFirmwareCacheWriter.java
0 → 100644
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.cache.firmware; | ||
17 | + | ||
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | ||
19 | +import org.springframework.data.redis.connection.RedisConnection; | ||
20 | +import org.springframework.data.redis.connection.RedisConnectionFactory; | ||
21 | +import org.springframework.stereotype.Service; | ||
22 | + | ||
23 | +@Service | ||
24 | +@ConditionalOnExpression("('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core') && '${cache.type:null}'=='redis'") | ||
25 | +public class RedisFirmwareCacheWriter extends AbstractRedisFirmwareCache implements FirmwareCacheWriter { | ||
26 | + | ||
27 | + public RedisFirmwareCacheWriter(RedisConnectionFactory redisConnectionFactory) { | ||
28 | + super(redisConnectionFactory); | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public void put(String key, byte[] value) { | ||
33 | + try (RedisConnection connection = redisConnectionFactory.getConnection()) { | ||
34 | + connection.set(toFirmwareCacheKey(key), value); | ||
35 | + } | ||
36 | + } | ||
37 | + | ||
38 | +} |
@@ -61,6 +61,8 @@ public interface DeviceService { | @@ -61,6 +61,8 @@ public interface DeviceService { | ||
61 | 61 | ||
62 | PageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink); | 62 | PageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink); |
63 | 63 | ||
64 | + PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink); | ||
65 | + | ||
64 | PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink); | 66 | PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink); |
65 | 67 | ||
66 | PageData<DeviceInfo> findDeviceInfosByTenantIdAndDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId, PageLink pageLink); | 68 | PageData<DeviceInfo> findDeviceInfosByTenantIdAndDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId, PageLink pageLink); |
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.dao.firmware; | ||
17 | + | ||
18 | +import org.thingsboard.server.common.data.Firmware; | ||
19 | +import org.thingsboard.server.common.data.FirmwareInfo; | ||
20 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
21 | +import org.thingsboard.server.common.data.id.TenantId; | ||
22 | +import org.thingsboard.server.common.data.page.PageData; | ||
23 | +import org.thingsboard.server.common.data.page.PageLink; | ||
24 | + | ||
25 | +public interface FirmwareService { | ||
26 | + | ||
27 | + FirmwareInfo saveFirmwareInfo(FirmwareInfo firmwareInfo); | ||
28 | + | ||
29 | + Firmware saveFirmware(Firmware firmware); | ||
30 | + | ||
31 | + Firmware findFirmwareById(TenantId tenantId, FirmwareId firmwareId); | ||
32 | + | ||
33 | + FirmwareInfo findFirmwareInfoById(TenantId tenantId, FirmwareId firmwareId); | ||
34 | + | ||
35 | + PageData<FirmwareInfo> findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink); | ||
36 | + | ||
37 | + PageData<FirmwareInfo> findTenantFirmwaresByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink); | ||
38 | + | ||
39 | + void deleteFirmware(TenantId tenantId, FirmwareId firmwareId); | ||
40 | + | ||
41 | + void deleteFirmwaresByTenantId(TenantId tenantId); | ||
42 | +} |
@@ -29,4 +29,5 @@ public class CacheConstants { | @@ -29,4 +29,5 @@ public class CacheConstants { | ||
29 | public static final String DEVICE_PROFILE_CACHE = "deviceProfiles"; | 29 | public static final String DEVICE_PROFILE_CACHE = "deviceProfiles"; |
30 | public static final String ATTRIBUTES_CACHE = "attributes"; | 30 | public static final String ATTRIBUTES_CACHE = "attributes"; |
31 | public static final String TOKEN_OUTDATAGE_TIME_CACHE = "tokensOutdatageTime"; | 31 | public static final String TOKEN_OUTDATAGE_TIME_CACHE = "tokensOutdatageTime"; |
32 | + public static final String FIRMWARE_CACHE = "firmwares"; | ||
32 | } | 33 | } |
@@ -93,6 +93,21 @@ public class DataConstants { | @@ -93,6 +93,21 @@ public class DataConstants { | ||
93 | public static final String USERNAME = "username"; | 93 | public static final String USERNAME = "username"; |
94 | public static final String PASSWORD = "password"; | 94 | public static final String PASSWORD = "password"; |
95 | 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 FIRMWARE_STATE = "fw_state"; | ||
103 | + | ||
104 | + //attributes | ||
105 | + //telemetry | ||
106 | + public static final String FIRMWARE_TITLE = "fw_title"; | ||
107 | + public static final String FIRMWARE_VERSION = "fw_version"; | ||
108 | + public static final String FIRMWARE_SIZE = "fw_size"; | ||
109 | + public static final String FIRMWARE_CHECKSUM = "fw_checksum"; | ||
110 | + public static final String FIRMWARE_CHECKSUM_ALGORITHM = "fw_checksum_algorithm"; | ||
96 | public static final String EDGE_MSG_SOURCE = "edge"; | 111 | public static final String EDGE_MSG_SOURCE = "edge"; |
97 | public static final String MSG_SOURCE_KEY = "source"; | 112 | public static final String MSG_SOURCE_KEY = "source"; |
98 | } | 113 | } |
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.device.data.DeviceData; | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.device.data.DeviceData; | ||
23 | import org.thingsboard.server.common.data.id.CustomerId; | 23 | import org.thingsboard.server.common.data.id.CustomerId; |
24 | import org.thingsboard.server.common.data.id.DeviceId; | 24 | import org.thingsboard.server.common.data.id.DeviceId; |
25 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 25 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
26 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
26 | import org.thingsboard.server.common.data.id.TenantId; | 27 | import org.thingsboard.server.common.data.id.TenantId; |
27 | import org.thingsboard.server.common.data.validation.NoXss; | 28 | import org.thingsboard.server.common.data.validation.NoXss; |
28 | 29 | ||
@@ -48,6 +49,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | @@ -48,6 +49,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | ||
48 | @JsonIgnore | 49 | @JsonIgnore |
49 | private byte[] deviceDataBytes; | 50 | private byte[] deviceDataBytes; |
50 | 51 | ||
52 | + private FirmwareId firmwareId; | ||
53 | + | ||
51 | public Device() { | 54 | public Device() { |
52 | super(); | 55 | super(); |
53 | } | 56 | } |
@@ -65,6 +68,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | @@ -65,6 +68,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | ||
65 | this.label = device.getLabel(); | 68 | this.label = device.getLabel(); |
66 | this.deviceProfileId = device.getDeviceProfileId(); | 69 | this.deviceProfileId = device.getDeviceProfileId(); |
67 | this.setDeviceData(device.getDeviceData()); | 70 | this.setDeviceData(device.getDeviceData()); |
71 | + this.firmwareId = device.getFirmwareId(); | ||
68 | } | 72 | } |
69 | 73 | ||
70 | public Device updateDevice(Device device) { | 74 | public Device updateDevice(Device device) { |
@@ -159,6 +163,14 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | @@ -159,6 +163,14 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | ||
159 | return getName(); | 163 | return getName(); |
160 | } | 164 | } |
161 | 165 | ||
166 | + public FirmwareId getFirmwareId() { | ||
167 | + return firmwareId; | ||
168 | + } | ||
169 | + | ||
170 | + public void setFirmwareId(FirmwareId firmwareId) { | ||
171 | + this.firmwareId = firmwareId; | ||
172 | + } | ||
173 | + | ||
162 | @Override | 174 | @Override |
163 | public String toString() { | 175 | public String toString() { |
164 | StringBuilder builder = new StringBuilder(); | 176 | StringBuilder builder = new StringBuilder(); |
@@ -175,6 +187,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | @@ -175,6 +187,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | ||
175 | builder.append(", deviceProfileId="); | 187 | builder.append(", deviceProfileId="); |
176 | builder.append(deviceProfileId); | 188 | builder.append(deviceProfileId); |
177 | builder.append(", deviceData="); | 189 | builder.append(", deviceData="); |
190 | + builder.append(firmwareId); | ||
191 | + builder.append(", firmwareId="); | ||
178 | builder.append(deviceData); | 192 | builder.append(deviceData); |
179 | builder.append(", additionalInfo="); | 193 | builder.append(", additionalInfo="); |
180 | builder.append(getAdditionalInfo()); | 194 | builder.append(getAdditionalInfo()); |
@@ -22,6 +22,7 @@ import lombok.EqualsAndHashCode; | @@ -22,6 +22,7 @@ import lombok.EqualsAndHashCode; | ||
22 | import lombok.extern.slf4j.Slf4j; | 22 | import lombok.extern.slf4j.Slf4j; |
23 | import org.thingsboard.server.common.data.device.profile.DeviceProfileData; | 23 | import org.thingsboard.server.common.data.device.profile.DeviceProfileData; |
24 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 24 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
25 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
25 | import org.thingsboard.server.common.data.id.RuleChainId; | 26 | import org.thingsboard.server.common.data.id.RuleChainId; |
26 | import org.thingsboard.server.common.data.id.TenantId; | 27 | import org.thingsboard.server.common.data.id.TenantId; |
27 | import org.thingsboard.server.common.data.validation.NoXss; | 28 | import org.thingsboard.server.common.data.validation.NoXss; |
@@ -56,6 +57,8 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H | @@ -56,6 +57,8 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H | ||
56 | @NoXss | 57 | @NoXss |
57 | private String provisionDeviceKey; | 58 | private String provisionDeviceKey; |
58 | 59 | ||
60 | + private FirmwareId firmwareId; | ||
61 | + | ||
59 | public DeviceProfile() { | 62 | public DeviceProfile() { |
60 | super(); | 63 | super(); |
61 | } | 64 | } |
@@ -19,5 +19,5 @@ package org.thingsboard.server.common.data; | @@ -19,5 +19,5 @@ package org.thingsboard.server.common.data; | ||
19 | * @author Andrew Shvayka | 19 | * @author Andrew Shvayka |
20 | */ | 20 | */ |
21 | public enum EntityType { | 21 | public enum EntityType { |
22 | - TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, API_USAGE_STATE, TB_RESOURCE, EDGE; | 22 | + TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, API_USAGE_STATE, TB_RESOURCE, FIRMWARE, EDGE; |
23 | } | 23 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | +import lombok.EqualsAndHashCode; | ||
20 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
21 | + | ||
22 | +import java.nio.ByteBuffer; | ||
23 | + | ||
24 | +@Data | ||
25 | +@EqualsAndHashCode(callSuper = true) | ||
26 | +public class Firmware extends FirmwareInfo { | ||
27 | + | ||
28 | + private static final long serialVersionUID = 3091601761339422546L; | ||
29 | + | ||
30 | + private transient ByteBuffer data; | ||
31 | + | ||
32 | + public Firmware() { | ||
33 | + super(); | ||
34 | + } | ||
35 | + | ||
36 | + public Firmware(FirmwareId id) { | ||
37 | + super(id); | ||
38 | + } | ||
39 | + | ||
40 | + public Firmware(Firmware firmware) { | ||
41 | + super(firmware); | ||
42 | + this.data = firmware.getData(); | ||
43 | + } | ||
44 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | +import lombok.EqualsAndHashCode; | ||
20 | +import lombok.extern.slf4j.Slf4j; | ||
21 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
22 | +import org.thingsboard.server.common.data.id.TenantId; | ||
23 | + | ||
24 | +@Slf4j | ||
25 | +@Data | ||
26 | +@EqualsAndHashCode(callSuper = true) | ||
27 | +public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo<FirmwareId> implements HasTenantId { | ||
28 | + | ||
29 | + private static final long serialVersionUID = 3168391583570815419L; | ||
30 | + | ||
31 | + private TenantId tenantId; | ||
32 | + private String title; | ||
33 | + private String version; | ||
34 | + private boolean hasData; | ||
35 | + private String fileName; | ||
36 | + private String contentType; | ||
37 | + private String checksumAlgorithm; | ||
38 | + private String checksum; | ||
39 | + private Long dataSize; | ||
40 | + | ||
41 | + | ||
42 | + public FirmwareInfo() { | ||
43 | + super(); | ||
44 | + } | ||
45 | + | ||
46 | + public FirmwareInfo(FirmwareId id) { | ||
47 | + super(id); | ||
48 | + } | ||
49 | + | ||
50 | + public FirmwareInfo(FirmwareInfo firmwareInfo) { | ||
51 | + super(firmwareInfo); | ||
52 | + this.tenantId = firmwareInfo.getTenantId(); | ||
53 | + this.title = firmwareInfo.getTitle(); | ||
54 | + this.version = firmwareInfo.getVersion(); | ||
55 | + this.hasData = firmwareInfo.isHasData(); | ||
56 | + this.fileName = firmwareInfo.getFileName(); | ||
57 | + this.contentType = firmwareInfo.getContentType(); | ||
58 | + this.checksumAlgorithm = firmwareInfo.getChecksumAlgorithm(); | ||
59 | + this.checksum = firmwareInfo.getChecksum(); | ||
60 | + this.dataSize = firmwareInfo.getDataSize(); | ||
61 | + } | ||
62 | + | ||
63 | + @Override | ||
64 | + public String getSearchText() { | ||
65 | + return title; | ||
66 | + } | ||
67 | +} |
@@ -27,6 +27,8 @@ import org.thingsboard.server.common.data.validation.NoXss; | @@ -27,6 +27,8 @@ import org.thingsboard.server.common.data.validation.NoXss; | ||
27 | @EqualsAndHashCode(callSuper = true) | 27 | @EqualsAndHashCode(callSuper = true) |
28 | public class TbResourceInfo extends SearchTextBased<TbResourceId> implements HasTenantId { | 28 | public class TbResourceInfo extends SearchTextBased<TbResourceId> implements HasTenantId { |
29 | 29 | ||
30 | + private static final long serialVersionUID = 7282664529021651736L; | ||
31 | + | ||
30 | private TenantId tenantId; | 32 | private TenantId tenantId; |
31 | @NoXss | 33 | @NoXss |
32 | private String title; | 34 | private String title; |
@@ -30,6 +30,9 @@ public class MqttTopics { | @@ -30,6 +30,9 @@ public class MqttTopics { | ||
30 | private static final String CLAIM = "/claim"; | 30 | private static final String CLAIM = "/claim"; |
31 | private static final String SUB_TOPIC = "+"; | 31 | private static final String SUB_TOPIC = "+"; |
32 | private static final String PROVISION = "/provision"; | 32 | private static final String PROVISION = "/provision"; |
33 | + private static final String FIRMWARE = "/fw"; | ||
34 | + private static final String CHUNK = "/chunk/"; | ||
35 | + private static final String ERROR = "/error"; | ||
33 | 36 | ||
34 | private static final String ATTRIBUTES_RESPONSE = ATTRIBUTES + RESPONSE; | 37 | private static final String ATTRIBUTES_RESPONSE = ATTRIBUTES + RESPONSE; |
35 | private static final String ATTRIBUTES_REQUEST = ATTRIBUTES + REQUEST; | 38 | private static final String ATTRIBUTES_REQUEST = ATTRIBUTES + REQUEST; |
@@ -69,6 +72,13 @@ public class MqttTopics { | @@ -69,6 +72,13 @@ public class MqttTopics { | ||
69 | public static final String GATEWAY_ATTRIBUTES_REQUEST_TOPIC = BASE_GATEWAY_API_TOPIC + ATTRIBUTES_REQUEST; | 72 | public static final String GATEWAY_ATTRIBUTES_REQUEST_TOPIC = BASE_GATEWAY_API_TOPIC + ATTRIBUTES_REQUEST; |
70 | public static final String GATEWAY_ATTRIBUTES_RESPONSE_TOPIC = BASE_GATEWAY_API_TOPIC + ATTRIBUTES_RESPONSE; | 73 | public static final String GATEWAY_ATTRIBUTES_RESPONSE_TOPIC = BASE_GATEWAY_API_TOPIC + ATTRIBUTES_RESPONSE; |
71 | 74 | ||
75 | + // v2 topics | ||
76 | + public static final String BASE_DEVICE_API_TOPIC_V2 = "v2"; | ||
77 | + | ||
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; | ||
80 | + public static final String DEVICE_FIRMWARE_ERROR_TOPIC = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + ERROR; | ||
81 | + | ||
72 | private MqttTopics() { | 82 | private MqttTopics() { |
73 | } | 83 | } |
74 | } | 84 | } |
@@ -71,6 +71,8 @@ public class EntityIdFactory { | @@ -71,6 +71,8 @@ public class EntityIdFactory { | ||
71 | return new ApiUsageStateId(uuid); | 71 | return new ApiUsageStateId(uuid); |
72 | case TB_RESOURCE: | 72 | case TB_RESOURCE: |
73 | return new TbResourceId(uuid); | 73 | return new TbResourceId(uuid); |
74 | + case FIRMWARE: | ||
75 | + return new FirmwareId(uuid); | ||
74 | case EDGE: | 76 | case EDGE: |
75 | return new EdgeId(uuid); | 77 | return new EdgeId(uuid); |
76 | } | 78 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.id; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonCreator; | ||
19 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
20 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
21 | +import org.thingsboard.server.common.data.EntityType; | ||
22 | + | ||
23 | +import java.util.UUID; | ||
24 | + | ||
25 | +public class FirmwareId extends UUIDBased implements EntityId { | ||
26 | + | ||
27 | + private static final long serialVersionUID = 1L; | ||
28 | + | ||
29 | + @JsonCreator | ||
30 | + public FirmwareId(@JsonProperty("id") UUID id) { | ||
31 | + super(id); | ||
32 | + } | ||
33 | + | ||
34 | + public static FirmwareId fromString(String firmwareId) { | ||
35 | + return new FirmwareId(UUID.fromString(firmwareId)); | ||
36 | + } | ||
37 | + | ||
38 | + @JsonIgnore | ||
39 | + @Override | ||
40 | + public EntityType getEntityType() { | ||
41 | + return EntityType.FIRMWARE; | ||
42 | + } | ||
43 | + | ||
44 | +} |
@@ -69,7 +69,7 @@ public class TbKafkaConsumerStatsService { | @@ -69,7 +69,7 @@ public class TbKafkaConsumerStatsService { | ||
69 | this.adminClient = AdminClient.create(kafkaSettings.toAdminProps()); | 69 | this.adminClient = AdminClient.create(kafkaSettings.toAdminProps()); |
70 | this.statsPrintScheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("kafka-consumer-stats")); | 70 | this.statsPrintScheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("kafka-consumer-stats")); |
71 | 71 | ||
72 | - Properties consumerProps = kafkaSettings.toConsumerProps(); | 72 | + Properties consumerProps = kafkaSettings.toConsumerProps(null); |
73 | consumerProps.put(ConsumerConfig.CLIENT_ID_CONFIG, "consumer-stats-loader-client"); | 73 | consumerProps.put(ConsumerConfig.CLIENT_ID_CONFIG, "consumer-stats-loader-client"); |
74 | consumerProps.put(ConsumerConfig.GROUP_ID_CONFIG, "consumer-stats-loader-client-group"); | 74 | consumerProps.put(ConsumerConfig.GROUP_ID_CONFIG, "consumer-stats-loader-client-group"); |
75 | this.consumer = new KafkaConsumer<>(consumerProps); | 75 | this.consumer = new KafkaConsumer<>(consumerProps); |
@@ -50,7 +50,7 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue | @@ -50,7 +50,7 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue | ||
50 | String clientId, String groupId, String topic, | 50 | String clientId, String groupId, String topic, |
51 | TbQueueAdmin admin, TbKafkaConsumerStatsService statsService) { | 51 | TbQueueAdmin admin, TbKafkaConsumerStatsService statsService) { |
52 | super(topic); | 52 | super(topic); |
53 | - Properties props = settings.toConsumerProps(); | 53 | + Properties props = settings.toConsumerProps(topic); |
54 | props.put(ConsumerConfig.CLIENT_ID_CONFIG, clientId); | 54 | props.put(ConsumerConfig.CLIENT_ID_CONFIG, clientId); |
55 | if (groupId != null) { | 55 | if (groupId != null) { |
56 | props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); | 56 | props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); |
@@ -31,7 +31,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | @@ -31,7 +31,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
31 | import org.springframework.boot.context.properties.ConfigurationProperties; | 31 | import org.springframework.boot.context.properties.ConfigurationProperties; |
32 | import org.springframework.stereotype.Component; | 32 | import org.springframework.stereotype.Component; |
33 | 33 | ||
34 | +import java.util.Collections; | ||
34 | import java.util.List; | 35 | import java.util.List; |
36 | +import java.util.Map; | ||
35 | import java.util.Properties; | 37 | import java.util.Properties; |
36 | 38 | ||
37 | /** | 39 | /** |
@@ -95,6 +97,9 @@ public class TbKafkaSettings { | @@ -95,6 +97,9 @@ public class TbKafkaSettings { | ||
95 | @Setter | 97 | @Setter |
96 | private List<TbKafkaProperty> other; | 98 | private List<TbKafkaProperty> other; |
97 | 99 | ||
100 | + @Setter | ||
101 | + private Map<String, List<TbKafkaProperty>> consumerPropertiesPerTopic = Collections.emptyMap(); | ||
102 | + | ||
98 | public Properties toAdminProps() { | 103 | public Properties toAdminProps() { |
99 | Properties props = toProps(); | 104 | Properties props = toProps(); |
100 | props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, servers); | 105 | props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, servers); |
@@ -103,7 +108,7 @@ public class TbKafkaSettings { | @@ -103,7 +108,7 @@ public class TbKafkaSettings { | ||
103 | return props; | 108 | return props; |
104 | } | 109 | } |
105 | 110 | ||
106 | - public Properties toConsumerProps() { | 111 | + public Properties toConsumerProps(String topic) { |
107 | Properties props = toProps(); | 112 | Properties props = toProps(); |
108 | props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, servers); | 113 | props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, servers); |
109 | props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, maxPollRecords); | 114 | props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, maxPollRecords); |
@@ -113,6 +118,10 @@ public class TbKafkaSettings { | @@ -113,6 +118,10 @@ public class TbKafkaSettings { | ||
113 | 118 | ||
114 | props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); | 119 | props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); |
115 | props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class); | 120 | props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class); |
121 | + | ||
122 | + consumerPropertiesPerTopic | ||
123 | + .getOrDefault(topic, Collections.emptyList()) | ||
124 | + .forEach(kv -> props.put(kv.getKey(), kv.getValue())); | ||
116 | return props; | 125 | return props; |
117 | } | 126 | } |
118 | 127 |
@@ -19,6 +19,7 @@ import lombok.Getter; | @@ -19,6 +19,7 @@ import lombok.Getter; | ||
19 | import org.springframework.beans.factory.annotation.Value; | 19 | import org.springframework.beans.factory.annotation.Value; |
20 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | 20 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
21 | import org.springframework.stereotype.Component; | 21 | import org.springframework.stereotype.Component; |
22 | +import org.thingsboard.server.common.data.StringUtils; | ||
22 | 23 | ||
23 | import javax.annotation.PostConstruct; | 24 | import javax.annotation.PostConstruct; |
24 | import java.util.HashMap; | 25 | import java.util.HashMap; |
@@ -37,6 +38,8 @@ public class TbKafkaTopicConfigs { | @@ -37,6 +38,8 @@ public class TbKafkaTopicConfigs { | ||
37 | private String notificationsProperties; | 38 | private String notificationsProperties; |
38 | @Value("${queue.kafka.topic-properties.js-executor}") | 39 | @Value("${queue.kafka.topic-properties.js-executor}") |
39 | private String jsExecutorProperties; | 40 | private String jsExecutorProperties; |
41 | + @Value("${queue.kafka.topic-properties.fw-updates:}") | ||
42 | + private String fwUpdatesProperties; | ||
40 | 43 | ||
41 | @Getter | 44 | @Getter |
42 | private Map<String, String> coreConfigs; | 45 | private Map<String, String> coreConfigs; |
@@ -48,6 +51,8 @@ public class TbKafkaTopicConfigs { | @@ -48,6 +51,8 @@ public class TbKafkaTopicConfigs { | ||
48 | private Map<String, String> notificationsConfigs; | 51 | private Map<String, String> notificationsConfigs; |
49 | @Getter | 52 | @Getter |
50 | private Map<String, String> jsExecutorConfigs; | 53 | private Map<String, String> jsExecutorConfigs; |
54 | + @Getter | ||
55 | + private Map<String, String> fwUpdatesConfigs; | ||
51 | 56 | ||
52 | @PostConstruct | 57 | @PostConstruct |
53 | private void init() { | 58 | private void init() { |
@@ -56,15 +61,18 @@ public class TbKafkaTopicConfigs { | @@ -56,15 +61,18 @@ public class TbKafkaTopicConfigs { | ||
56 | transportApiConfigs = getConfigs(transportApiProperties); | 61 | transportApiConfigs = getConfigs(transportApiProperties); |
57 | notificationsConfigs = getConfigs(notificationsProperties); | 62 | notificationsConfigs = getConfigs(notificationsProperties); |
58 | jsExecutorConfigs = getConfigs(jsExecutorProperties); | 63 | jsExecutorConfigs = getConfigs(jsExecutorProperties); |
64 | + fwUpdatesConfigs = getConfigs(fwUpdatesProperties); | ||
59 | } | 65 | } |
60 | 66 | ||
61 | private Map<String, String> getConfigs(String properties) { | 67 | private Map<String, String> getConfigs(String properties) { |
62 | Map<String, String> configs = new HashMap<>(); | 68 | Map<String, String> configs = new HashMap<>(); |
63 | - for (String property : properties.split(";")) { | ||
64 | - int delimiterPosition = property.indexOf(":"); | ||
65 | - String key = property.substring(0, delimiterPosition); | ||
66 | - String value = property.substring(delimiterPosition + 1); | ||
67 | - configs.put(key, value); | 69 | + if (StringUtils.isNotEmpty(properties)) { |
70 | + for (String property : properties.split(";")) { | ||
71 | + int delimiterPosition = property.indexOf(":"); | ||
72 | + String key = property.substring(0, delimiterPosition); | ||
73 | + String value = property.substring(delimiterPosition + 1); | ||
74 | + configs.put(key, value); | ||
75 | + } | ||
68 | } | 76 | } |
69 | return configs; | 77 | return configs; |
70 | } | 78 | } |
@@ -186,6 +186,17 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng | @@ -186,6 +186,17 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng | ||
186 | msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | 186 | msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
187 | } | 187 | } |
188 | 188 | ||
189 | + @Override | ||
190 | + public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() { | ||
191 | + return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getFirmwareTopic(), | ||
192 | + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | ||
193 | + } | ||
194 | + | ||
195 | + @Override | ||
196 | + public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() { | ||
197 | + return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getFirmwareTopic()); | ||
198 | + } | ||
199 | + | ||
189 | @PreDestroy | 200 | @PreDestroy |
190 | private void destroy() { | 201 | private void destroy() { |
191 | if (coreAdmin != null) { | 202 | if (coreAdmin != null) { |
@@ -21,12 +21,13 @@ import org.springframework.context.annotation.Bean; | @@ -21,12 +21,13 @@ import org.springframework.context.annotation.Bean; | ||
21 | import org.springframework.stereotype.Component; | 21 | import org.springframework.stereotype.Component; |
22 | import org.thingsboard.server.common.msg.queue.ServiceType; | 22 | import org.thingsboard.server.common.msg.queue.ServiceType; |
23 | import org.thingsboard.server.gen.js.JsInvokeProtos; | 23 | import org.thingsboard.server.gen.js.JsInvokeProtos; |
24 | -import org.thingsboard.server.gen.transport.TransportProtos; | ||
25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
26 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; | 25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
26 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | 27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
28 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; | 28 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
29 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
30 | +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; | ||
30 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; | 31 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
31 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; | 32 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
32 | import org.thingsboard.server.queue.TbQueueAdmin; | 33 | import org.thingsboard.server.queue.TbQueueAdmin; |
@@ -165,14 +166,25 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { | @@ -165,14 +166,25 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { | ||
165 | } | 166 | } |
166 | 167 | ||
167 | @Override | 168 | @Override |
168 | - public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { | 169 | + public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
169 | return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getUsageStatsTopic()); | 170 | return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getUsageStatsTopic()); |
170 | } | 171 | } |
171 | 172 | ||
172 | @Override | 173 | @Override |
173 | - public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { | 174 | + public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { |
174 | return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getUsageStatsTopic(), | 175 | return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getUsageStatsTopic(), |
175 | - msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | 176 | + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
177 | + } | ||
178 | + | ||
179 | + @Override | ||
180 | + public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() { | ||
181 | + return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getFirmwareTopic(), | ||
182 | + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | ||
183 | + } | ||
184 | + | ||
185 | + @Override | ||
186 | + public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() { | ||
187 | + return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getFirmwareTopic()); | ||
176 | } | 188 | } |
177 | 189 | ||
178 | @PreDestroy | 190 | @PreDestroy |
@@ -131,6 +131,16 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE | @@ -131,6 +131,16 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE | ||
131 | } | 131 | } |
132 | 132 | ||
133 | @Override | 133 | @Override |
134 | + public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() { | ||
135 | + return new InMemoryTbQueueConsumer<>(coreSettings.getFirmwareTopic()); | ||
136 | + } | ||
137 | + | ||
138 | + @Override | ||
139 | + public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() { | ||
140 | + return new InMemoryTbQueueProducer<>(coreSettings.getFirmwareTopic()); | ||
141 | + } | ||
142 | + | ||
143 | + @Override | ||
134 | public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { | 144 | public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
135 | return new InMemoryTbQueueProducer<>(coreSettings.getUsageStatsTopic()); | 145 | return new InMemoryTbQueueProducer<>(coreSettings.getUsageStatsTopic()); |
136 | } | 146 | } |
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | ||
23 | import org.thingsboard.server.gen.js.JsInvokeProtos; | 23 | import org.thingsboard.server.gen.js.JsInvokeProtos; |
24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; | 25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
26 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
26 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | 27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; | 28 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
28 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
@@ -73,6 +74,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi | @@ -73,6 +74,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi | ||
73 | private final TbQueueAdmin jsExecutorAdmin; | 74 | private final TbQueueAdmin jsExecutorAdmin; |
74 | private final TbQueueAdmin transportApiAdmin; | 75 | private final TbQueueAdmin transportApiAdmin; |
75 | private final TbQueueAdmin notificationAdmin; | 76 | private final TbQueueAdmin notificationAdmin; |
77 | + private final TbQueueAdmin fwUpdatesAdmin; | ||
76 | 78 | ||
77 | public KafkaMonolithQueueFactory(PartitionService partitionService, TbKafkaSettings kafkaSettings, | 79 | public KafkaMonolithQueueFactory(PartitionService partitionService, TbKafkaSettings kafkaSettings, |
78 | TbServiceInfoProvider serviceInfoProvider, | 80 | TbServiceInfoProvider serviceInfoProvider, |
@@ -98,6 +100,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi | @@ -98,6 +100,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi | ||
98 | this.jsExecutorAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getJsExecutorConfigs()); | 100 | this.jsExecutorAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getJsExecutorConfigs()); |
99 | this.transportApiAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getTransportApiConfigs()); | 101 | this.transportApiAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getTransportApiConfigs()); |
100 | this.notificationAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getNotificationsConfigs()); | 102 | this.notificationAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getNotificationsConfigs()); |
103 | + this.fwUpdatesAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getFwUpdatesConfigs()); | ||
101 | } | 104 | } |
102 | 105 | ||
103 | @Override | 106 | @Override |
@@ -274,6 +277,29 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi | @@ -274,6 +277,29 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi | ||
274 | } | 277 | } |
275 | 278 | ||
276 | @Override | 279 | @Override |
280 | + public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() { | ||
281 | + TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> consumerBuilder = TbKafkaConsumerTemplate.builder(); | ||
282 | + consumerBuilder.settings(kafkaSettings); | ||
283 | + consumerBuilder.topic(coreSettings.getFirmwareTopic()); | ||
284 | + consumerBuilder.clientId("monolith-fw-consumer-" + serviceInfoProvider.getServiceId()); | ||
285 | + consumerBuilder.groupId("monolith-fw-consumer"); | ||
286 | + consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | ||
287 | + consumerBuilder.admin(fwUpdatesAdmin); | ||
288 | + consumerBuilder.statsService(consumerStatsService); | ||
289 | + return consumerBuilder.build(); | ||
290 | + } | ||
291 | + | ||
292 | + @Override | ||
293 | + public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() { | ||
294 | + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> requestBuilder = TbKafkaProducerTemplate.builder(); | ||
295 | + requestBuilder.settings(kafkaSettings); | ||
296 | + requestBuilder.clientId("monolith-fw-producer-" + serviceInfoProvider.getServiceId()); | ||
297 | + requestBuilder.defaultTopic(coreSettings.getFirmwareTopic()); | ||
298 | + requestBuilder.admin(fwUpdatesAdmin); | ||
299 | + return requestBuilder.build(); | ||
300 | + } | ||
301 | + | ||
302 | + @Override | ||
277 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { | 303 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
278 | TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToUsageStatsServiceMsg>> requestBuilder = TbKafkaProducerTemplate.builder(); | 304 | TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToUsageStatsServiceMsg>> requestBuilder = TbKafkaProducerTemplate.builder(); |
279 | requestBuilder.settings(kafkaSettings); | 305 | requestBuilder.settings(kafkaSettings); |
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | ||
23 | import org.thingsboard.server.gen.js.JsInvokeProtos; | 23 | import org.thingsboard.server.gen.js.JsInvokeProtos; |
24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; | 25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
26 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
26 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | 27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; | 28 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
28 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
@@ -70,6 +71,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { | @@ -70,6 +71,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { | ||
70 | private final TbQueueAdmin jsExecutorAdmin; | 71 | private final TbQueueAdmin jsExecutorAdmin; |
71 | private final TbQueueAdmin transportApiAdmin; | 72 | private final TbQueueAdmin transportApiAdmin; |
72 | private final TbQueueAdmin notificationAdmin; | 73 | private final TbQueueAdmin notificationAdmin; |
74 | + private final TbQueueAdmin fwUpdatesAdmin; | ||
73 | 75 | ||
74 | public KafkaTbCoreQueueFactory(PartitionService partitionService, TbKafkaSettings kafkaSettings, | 76 | public KafkaTbCoreQueueFactory(PartitionService partitionService, TbKafkaSettings kafkaSettings, |
75 | TbServiceInfoProvider serviceInfoProvider, | 77 | TbServiceInfoProvider serviceInfoProvider, |
@@ -93,6 +95,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { | @@ -93,6 +95,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { | ||
93 | this.jsExecutorAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getJsExecutorConfigs()); | 95 | this.jsExecutorAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getJsExecutorConfigs()); |
94 | this.transportApiAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getTransportApiConfigs()); | 96 | this.transportApiAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getTransportApiConfigs()); |
95 | this.notificationAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getNotificationsConfigs()); | 97 | this.notificationAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getNotificationsConfigs()); |
98 | + this.fwUpdatesAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getFwUpdatesConfigs()); | ||
96 | } | 99 | } |
97 | 100 | ||
98 | @Override | 101 | @Override |
@@ -242,6 +245,29 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { | @@ -242,6 +245,29 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { | ||
242 | } | 245 | } |
243 | 246 | ||
244 | @Override | 247 | @Override |
248 | + public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() { | ||
249 | + TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> consumerBuilder = TbKafkaConsumerTemplate.builder(); | ||
250 | + consumerBuilder.settings(kafkaSettings); | ||
251 | + consumerBuilder.topic(coreSettings.getFirmwareTopic()); | ||
252 | + consumerBuilder.clientId("tb-core-fw-consumer-" + serviceInfoProvider.getServiceId()); | ||
253 | + consumerBuilder.groupId("tb-core-fw-consumer"); | ||
254 | + consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | ||
255 | + consumerBuilder.admin(fwUpdatesAdmin); | ||
256 | + consumerBuilder.statsService(consumerStatsService); | ||
257 | + return consumerBuilder.build(); | ||
258 | + } | ||
259 | + | ||
260 | + @Override | ||
261 | + public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() { | ||
262 | + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> requestBuilder = TbKafkaProducerTemplate.builder(); | ||
263 | + requestBuilder.settings(kafkaSettings); | ||
264 | + requestBuilder.clientId("tb-core-fw-producer-" + serviceInfoProvider.getServiceId()); | ||
265 | + requestBuilder.defaultTopic(coreSettings.getFirmwareTopic()); | ||
266 | + requestBuilder.admin(fwUpdatesAdmin); | ||
267 | + return requestBuilder.build(); | ||
268 | + } | ||
269 | + | ||
270 | + @Override | ||
245 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { | 271 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
246 | TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToUsageStatsServiceMsg>> requestBuilder = TbKafkaProducerTemplate.builder(); | 272 | TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToUsageStatsServiceMsg>> requestBuilder = TbKafkaProducerTemplate.builder(); |
247 | requestBuilder.settings(kafkaSettings); | 273 | requestBuilder.settings(kafkaSettings); |
@@ -22,6 +22,7 @@ import org.springframework.stereotype.Component; | @@ -22,6 +22,7 @@ import org.springframework.stereotype.Component; | ||
22 | import org.thingsboard.server.common.msg.queue.ServiceType; | 22 | import org.thingsboard.server.common.msg.queue.ServiceType; |
23 | import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; | 23 | import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; |
24 | import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; | 24 | import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; |
25 | +import org.thingsboard.server.gen.transport.TransportProtos.*; | ||
25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; | 26 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
26 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; | 27 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | 28 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
@@ -191,6 +192,17 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng | @@ -191,6 +192,17 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng | ||
191 | } | 192 | } |
192 | 193 | ||
193 | @Override | 194 | @Override |
195 | + public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() { | ||
196 | + return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getFirmwareTopic(), | ||
197 | + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | ||
198 | + } | ||
199 | + | ||
200 | + @Override | ||
201 | + public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() { | ||
202 | + return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getFirmwareTopic()); | ||
203 | + } | ||
204 | + | ||
205 | + @Override | ||
194 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { | 206 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
195 | return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getUsageStatsTopic()); | 207 | return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getUsageStatsTopic()); |
196 | } | 208 | } |
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | ||
23 | import org.thingsboard.server.gen.js.JsInvokeProtos; | 23 | import org.thingsboard.server.gen.js.JsInvokeProtos; |
24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; | 25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
26 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
26 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | 27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; | 28 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
28 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
@@ -165,6 +166,17 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { | @@ -165,6 +166,17 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { | ||
165 | } | 166 | } |
166 | 167 | ||
167 | @Override | 168 | @Override |
169 | + public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() { | ||
170 | + return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getFirmwareTopic(), | ||
171 | + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | ||
172 | + } | ||
173 | + | ||
174 | + @Override | ||
175 | + public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() { | ||
176 | + return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getFirmwareTopic()); | ||
177 | + } | ||
178 | + | ||
179 | + @Override | ||
168 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { | 180 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
169 | return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getUsageStatsTopic()); | 181 | return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getUsageStatsTopic()); |
170 | } | 182 | } |
@@ -24,6 +24,7 @@ import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; | @@ -24,6 +24,7 @@ import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; | ||
24 | import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; | 24 | import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; |
25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; | 25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
26 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; | 26 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
27 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | 28 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
28 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
29 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | 30 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
@@ -189,6 +190,17 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE | @@ -189,6 +190,17 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE | ||
189 | } | 190 | } |
190 | 191 | ||
191 | @Override | 192 | @Override |
193 | + public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() { | ||
194 | + return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getFirmwareTopic(), | ||
195 | + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | ||
196 | + } | ||
197 | + | ||
198 | + @Override | ||
199 | + public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() { | ||
200 | + return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getFirmwareTopic()); | ||
201 | + } | ||
202 | + | ||
203 | + @Override | ||
192 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { | 204 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
193 | return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getUsageStatsTopic()); | 205 | return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getUsageStatsTopic()); |
194 | } | 206 | } |
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | ||
23 | import org.thingsboard.server.gen.js.JsInvokeProtos; | 23 | import org.thingsboard.server.gen.js.JsInvokeProtos; |
24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; | 25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
26 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
26 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | 27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; | 28 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
28 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
@@ -171,6 +172,17 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { | @@ -171,6 +172,17 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { | ||
171 | } | 172 | } |
172 | 173 | ||
173 | @Override | 174 | @Override |
175 | + public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() { | ||
176 | + return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getFirmwareTopic(), | ||
177 | + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | ||
178 | + } | ||
179 | + | ||
180 | + @Override | ||
181 | + public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() { | ||
182 | + return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getFirmwareTopic()); | ||
183 | + } | ||
184 | + | ||
185 | + @Override | ||
174 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { | 186 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
175 | return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getUsageStatsTopic()); | 187 | return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getUsageStatsTopic()); |
176 | } | 188 | } |
common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | ||
23 | import org.thingsboard.server.gen.js.JsInvokeProtos; | 23 | import org.thingsboard.server.gen.js.JsInvokeProtos; |
24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; | 25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
26 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
26 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | 27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; | 28 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
28 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
@@ -188,6 +189,17 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul | @@ -188,6 +189,17 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul | ||
188 | } | 189 | } |
189 | 190 | ||
190 | @Override | 191 | @Override |
192 | + public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() { | ||
193 | + return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getFirmwareTopic(), | ||
194 | + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | ||
195 | + } | ||
196 | + | ||
197 | + @Override | ||
198 | + public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() { | ||
199 | + return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getFirmwareTopic()); | ||
200 | + } | ||
201 | + | ||
202 | + @Override | ||
191 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { | 203 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
192 | return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getUsageStatsTopic()); | 204 | return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getUsageStatsTopic()); |
193 | } | 205 | } |
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | ||
23 | import org.thingsboard.server.gen.js.JsInvokeProtos; | 23 | import org.thingsboard.server.gen.js.JsInvokeProtos; |
24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; | 25 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
26 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
26 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | 27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
27 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; | 28 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
28 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
@@ -171,6 +172,17 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { | @@ -171,6 +172,17 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { | ||
171 | } | 172 | } |
172 | 173 | ||
173 | @Override | 174 | @Override |
175 | + public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() { | ||
176 | + return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getFirmwareTopic(), | ||
177 | + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); | ||
178 | + } | ||
179 | + | ||
180 | + @Override | ||
181 | + public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() { | ||
182 | + return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getFirmwareTopic()); | ||
183 | + } | ||
184 | + | ||
185 | + @Override | ||
174 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { | 186 | public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
175 | return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getUsageStatsTopic()); | 187 | return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getUsageStatsTopic()); |
176 | } | 188 | } |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | package org.thingsboard.server.queue.provider; | 16 | package org.thingsboard.server.queue.provider; |
17 | 17 | ||
18 | import org.thingsboard.server.gen.js.JsInvokeProtos; | 18 | import org.thingsboard.server.gen.js.JsInvokeProtos; |
19 | +import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; | ||
19 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; | 20 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
20 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; | 21 | import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
21 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | 22 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
@@ -86,6 +87,20 @@ public interface TbCoreQueueFactory extends TbUsageStatsClientQueueFactory { | @@ -86,6 +87,20 @@ public interface TbCoreQueueFactory extends TbUsageStatsClientQueueFactory { | ||
86 | TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer(); | 87 | TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer(); |
87 | 88 | ||
88 | /** | 89 | /** |
90 | + * Used to consume messages about firmware update notifications by TB Core Service | ||
91 | + * | ||
92 | + * @return | ||
93 | + */ | ||
94 | + TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer(); | ||
95 | + | ||
96 | + /** | ||
97 | + * Used to consume messages about firmware update notifications by TB Core Service | ||
98 | + * | ||
99 | + * @return | ||
100 | + */ | ||
101 | + TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer(); | ||
102 | + | ||
103 | + /** | ||
89 | * Used to consume high priority messages by TB Core Service | 104 | * Used to consume high priority messages by TB Core Service |
90 | * | 105 | * |
91 | * @return | 106 | * @return |
@@ -26,6 +26,9 @@ public class TbQueueCoreSettings { | @@ -26,6 +26,9 @@ public class TbQueueCoreSettings { | ||
26 | @Value("${queue.core.topic}") | 26 | @Value("${queue.core.topic}") |
27 | private String topic; | 27 | private String topic; |
28 | 28 | ||
29 | + @Value("${queue.core.firmware.topic:tb_firmware}") | ||
30 | + private String firmwareTopic; | ||
31 | + | ||
29 | @Value("${queue.core.usage-stats-topic:tb_usage_stats}") | 32 | @Value("${queue.core.usage-stats-topic:tb_usage_stats}") |
30 | private String usageStatsTopic; | 33 | private String usageStatsTopic; |
31 | 34 |
@@ -340,17 +340,35 @@ message ProvisionDeviceCredentialsMsg { | @@ -340,17 +340,35 @@ message ProvisionDeviceCredentialsMsg { | ||
340 | } | 340 | } |
341 | 341 | ||
342 | message ProvisionDeviceResponseMsg { | 342 | message ProvisionDeviceResponseMsg { |
343 | - ProvisionResponseStatus status = 1; | 343 | + ResponseStatus status = 1; |
344 | CredentialsType credentialsType = 2; | 344 | CredentialsType credentialsType = 2; |
345 | string credentialsValue = 3; | 345 | string credentialsValue = 3; |
346 | } | 346 | } |
347 | 347 | ||
348 | -enum ProvisionResponseStatus { | 348 | +enum ResponseStatus { |
349 | UNKNOWN = 0; | 349 | UNKNOWN = 0; |
350 | SUCCESS = 1; | 350 | SUCCESS = 1; |
351 | NOT_FOUND = 2; | 351 | NOT_FOUND = 2; |
352 | FAILURE = 3; | 352 | FAILURE = 3; |
353 | } | 353 | } |
354 | + | ||
355 | +message GetFirmwareRequestMsg { | ||
356 | + int64 deviceIdMSB = 1; | ||
357 | + int64 deviceIdLSB = 2; | ||
358 | + int64 tenantIdMSB = 3; | ||
359 | + int64 tenantIdLSB = 4; | ||
360 | +} | ||
361 | + | ||
362 | +message GetFirmwareResponseMsg { | ||
363 | + ResponseStatus responseStatus = 1; | ||
364 | + int64 firmwareIdMSB = 2; | ||
365 | + int64 firmwareIdLSB = 3; | ||
366 | + string title = 4; | ||
367 | + string version = 5; | ||
368 | + string contentType = 6; | ||
369 | + string fileName = 7; | ||
370 | +} | ||
371 | + | ||
354 | //Used to report session state to tb-Service and persist this state in the cache on the tb-Service level. | 372 | //Used to report session state to tb-Service and persist this state in the cache on the tb-Service level. |
355 | message SubscriptionInfoProto { | 373 | message SubscriptionInfoProto { |
356 | int64 lastActivityTime = 1; | 374 | int64 lastActivityTime = 1; |
@@ -571,6 +589,7 @@ message TransportApiRequestMsg { | @@ -571,6 +589,7 @@ message TransportApiRequestMsg { | ||
571 | ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7; | 589 | ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7; |
572 | ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8; | 590 | ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8; |
573 | GetResourceRequestMsg resourceRequestMsg = 9; | 591 | GetResourceRequestMsg resourceRequestMsg = 9; |
592 | + GetFirmwareRequestMsg firmwareRequestMsg = 10; | ||
574 | } | 593 | } |
575 | 594 | ||
576 | /* Response from ThingsBoard Core Service to Transport Service */ | 595 | /* Response from ThingsBoard Core Service to Transport Service */ |
@@ -581,6 +600,7 @@ message TransportApiResponseMsg { | @@ -581,6 +600,7 @@ message TransportApiResponseMsg { | ||
581 | ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4; | 600 | ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4; |
582 | LwM2MResponseMsg lwM2MResponseMsg = 6; | 601 | LwM2MResponseMsg lwM2MResponseMsg = 6; |
583 | GetResourceResponseMsg resourceResponseMsg = 7; | 602 | GetResourceResponseMsg resourceResponseMsg = 7; |
603 | + GetFirmwareResponseMsg firmwareResponseMsg = 8; | ||
584 | } | 604 | } |
585 | 605 | ||
586 | /* Messages that are handled by ThingsBoard Core Service */ | 606 | /* Messages that are handled by ThingsBoard Core Service */ |
@@ -645,3 +665,13 @@ message ToUsageStatsServiceMsg { | @@ -645,3 +665,13 @@ message ToUsageStatsServiceMsg { | ||
645 | int64 customerIdMSB = 6; | 665 | int64 customerIdMSB = 6; |
646 | int64 customerIdLSB = 7; | 666 | int64 customerIdLSB = 7; |
647 | } | 667 | } |
668 | + | ||
669 | +message ToFirmwareStateServiceMsg { | ||
670 | + int64 ts = 1; | ||
671 | + int64 tenantIdMSB = 2; | ||
672 | + int64 tenantIdLSB = 3; | ||
673 | + int64 deviceIdMSB = 4; | ||
674 | + int64 deviceIdLSB = 5; | ||
675 | + int64 firmwareIdMSB = 6; | ||
676 | + int64 firmwareIdLSB = 7; | ||
677 | +} |
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
@@ -407,7 +407,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource { | @@ -407,7 +407,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource { | ||
407 | @Override | 407 | @Override |
408 | public void onSuccess(TransportProtos.ProvisionDeviceResponseMsg msg) { | 408 | public void onSuccess(TransportProtos.ProvisionDeviceResponseMsg msg) { |
409 | CoAP.ResponseCode responseCode = CoAP.ResponseCode.CREATED; | 409 | CoAP.ResponseCode responseCode = CoAP.ResponseCode.CREATED; |
410 | - if (!msg.getStatus().equals(TransportProtos.ProvisionResponseStatus.SUCCESS)) { | 410 | + if (!msg.getStatus().equals(TransportProtos.ResponseStatus.SUCCESS)) { |
411 | responseCode = CoAP.ResponseCode.BAD_REQUEST; | 411 | responseCode = CoAP.ResponseCode.BAD_REQUEST; |
412 | } | 412 | } |
413 | if (payloadType.equals(TransportPayloadType.JSON)) { | 413 | if (payloadType.equals(TransportPayloadType.JSON)) { |
@@ -20,7 +20,10 @@ import com.google.gson.JsonParser; | @@ -20,7 +20,10 @@ import com.google.gson.JsonParser; | ||
20 | import lombok.extern.slf4j.Slf4j; | 20 | import lombok.extern.slf4j.Slf4j; |
21 | import org.springframework.beans.factory.annotation.Autowired; | 21 | import org.springframework.beans.factory.annotation.Autowired; |
22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
23 | +import org.springframework.core.io.ByteArrayResource; | ||
24 | +import org.springframework.http.HttpHeaders; | ||
23 | import org.springframework.http.HttpStatus; | 25 | import org.springframework.http.HttpStatus; |
26 | +import org.springframework.http.MediaType; | ||
24 | import org.springframework.http.ResponseEntity; | 27 | import org.springframework.http.ResponseEntity; |
25 | import org.springframework.util.StringUtils; | 28 | import org.springframework.util.StringUtils; |
26 | import org.springframework.web.bind.annotation.PathVariable; | 29 | import org.springframework.web.bind.annotation.PathVariable; |
@@ -41,7 +44,6 @@ import org.thingsboard.server.common.transport.auth.SessionInfoCreator; | @@ -41,7 +44,6 @@ import org.thingsboard.server.common.transport.auth.SessionInfoCreator; | ||
41 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | 44 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; |
42 | import org.thingsboard.server.gen.transport.TransportProtos; | 45 | import org.thingsboard.server.gen.transport.TransportProtos; |
43 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; | 46 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
44 | -import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; | ||
45 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; | 47 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
46 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; | 48 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; |
47 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; | 49 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; |
@@ -53,7 +55,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMs | @@ -53,7 +55,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMs | ||
53 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg; | 55 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg; |
54 | import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcRequestMsg; | 56 | import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcRequestMsg; |
55 | import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; | 57 | import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; |
56 | -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; | ||
57 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; | 58 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; |
58 | 59 | ||
59 | import javax.servlet.http.HttpServletRequest; | 60 | import javax.servlet.http.HttpServletRequest; |
@@ -204,6 +205,25 @@ public class DeviceApiController { | @@ -204,6 +205,25 @@ public class DeviceApiController { | ||
204 | return responseWriter; | 205 | return responseWriter; |
205 | } | 206 | } |
206 | 207 | ||
208 | + @RequestMapping(value = "/{deviceToken}/firmware", method = RequestMethod.GET) | ||
209 | + public DeferredResult<ResponseEntity> getFirmware(@PathVariable("deviceToken") String deviceToken, | ||
210 | + @RequestParam(value = "title") String title, | ||
211 | + @RequestParam(value = "version") String version, | ||
212 | + @RequestParam(value = "chunkSize", required = false, defaultValue = "0") int chunkSize, | ||
213 | + @RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) { | ||
214 | + DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); | ||
215 | + transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), | ||
216 | + new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | ||
217 | + TransportProtos.GetFirmwareRequestMsg requestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder() | ||
218 | + .setTenantIdMSB(sessionInfo.getTenantIdMSB()) | ||
219 | + .setTenantIdLSB(sessionInfo.getTenantIdLSB()) | ||
220 | + .setDeviceIdMSB(sessionInfo.getDeviceIdMSB()) | ||
221 | + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB()).build(); | ||
222 | + transportContext.getTransportService().process(sessionInfo, requestMsg, new GetFirmwareCallback(responseWriter, title, version, chunkSize, chunk)); | ||
223 | + })); | ||
224 | + return responseWriter; | ||
225 | + } | ||
226 | + | ||
207 | @RequestMapping(value = "/provision", method = RequestMethod.POST) | 227 | @RequestMapping(value = "/provision", method = RequestMethod.POST) |
208 | public DeferredResult<ResponseEntity> provisionDevice(@RequestBody String json, HttpServletRequest httpRequest) { | 228 | public DeferredResult<ResponseEntity> provisionDevice(@RequestBody String json, HttpServletRequest httpRequest) { |
209 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); | 229 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); |
@@ -258,6 +278,47 @@ public class DeviceApiController { | @@ -258,6 +278,47 @@ public class DeviceApiController { | ||
258 | } | 278 | } |
259 | } | 279 | } |
260 | 280 | ||
281 | + private class GetFirmwareCallback implements TransportServiceCallback<TransportProtos.GetFirmwareResponseMsg> { | ||
282 | + private final DeferredResult<ResponseEntity> responseWriter; | ||
283 | + private final String title; | ||
284 | + private final String version; | ||
285 | + private final int chuckSize; | ||
286 | + private final int chuck; | ||
287 | + | ||
288 | + GetFirmwareCallback(DeferredResult<ResponseEntity> responseWriter, String title, String version, int chuckSize, int chuck) { | ||
289 | + this.responseWriter = responseWriter; | ||
290 | + this.title = title; | ||
291 | + this.version = version; | ||
292 | + this.chuckSize = chuckSize; | ||
293 | + this.chuck = chuck; | ||
294 | + } | ||
295 | + | ||
296 | + @Override | ||
297 | + public void onSuccess(TransportProtos.GetFirmwareResponseMsg firmwareResponseMsg) { | ||
298 | + if (!TransportProtos.ResponseStatus.SUCCESS.equals(firmwareResponseMsg.getResponseStatus())) { | ||
299 | + responseWriter.setResult(new ResponseEntity<>(HttpStatus.NOT_FOUND)); | ||
300 | + } else if (title.equals(firmwareResponseMsg.getTitle()) && version.equals(firmwareResponseMsg.getVersion())) { | ||
301 | + String firmwareId = new UUID(firmwareResponseMsg.getFirmwareIdMSB(), firmwareResponseMsg.getFirmwareIdLSB()).toString(); | ||
302 | + ByteArrayResource resource = new ByteArrayResource(transportContext.getFirmwareCacheReader().get(firmwareId, chuckSize, chuck)); | ||
303 | + ResponseEntity<ByteArrayResource> response = ResponseEntity.ok() | ||
304 | + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + firmwareResponseMsg.getFileName()) | ||
305 | + .header("x-filename", firmwareResponseMsg.getFileName()) | ||
306 | + .contentLength(resource.contentLength()) | ||
307 | + .contentType(parseMediaType(firmwareResponseMsg.getContentType())) | ||
308 | + .body(resource); | ||
309 | + responseWriter.setResult(response); | ||
310 | + } else { | ||
311 | + responseWriter.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST)); | ||
312 | + } | ||
313 | + } | ||
314 | + | ||
315 | + @Override | ||
316 | + public void onError(Throwable e) { | ||
317 | + log.warn("Failed to process request", e); | ||
318 | + responseWriter.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); | ||
319 | + } | ||
320 | + } | ||
321 | + | ||
261 | private static class SessionCloseOnErrorCallback implements TransportServiceCallback<Void> { | 322 | private static class SessionCloseOnErrorCallback implements TransportServiceCallback<Void> { |
262 | private final TransportService transportService; | 323 | private final TransportService transportService; |
263 | private final SessionInfoProto sessionInfo; | 324 | private final SessionInfoProto sessionInfo; |
@@ -338,4 +399,12 @@ public class DeviceApiController { | @@ -338,4 +399,12 @@ public class DeviceApiController { | ||
338 | .build(), TransportServiceCallback.EMPTY); | 399 | .build(), TransportServiceCallback.EMPTY); |
339 | } | 400 | } |
340 | 401 | ||
402 | + private static MediaType parseMediaType(String contentType) { | ||
403 | + try { | ||
404 | + return MediaType.parseMediaType(contentType); | ||
405 | + } catch (Exception e) { | ||
406 | + return MediaType.APPLICATION_OCTET_STREAM; | ||
407 | + } | ||
408 | + } | ||
409 | + | ||
341 | } | 410 | } |
@@ -29,7 +29,6 @@ import redis.clients.jedis.ScanResult; | @@ -29,7 +29,6 @@ import redis.clients.jedis.ScanResult; | ||
29 | import java.util.Collection; | 29 | import java.util.Collection; |
30 | import java.util.LinkedList; | 30 | import java.util.LinkedList; |
31 | 31 | ||
32 | -@Service | ||
33 | public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { | 32 | public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { |
34 | private static final String SEC_EP = "SEC#EP#"; | 33 | private static final String SEC_EP = "SEC#EP#"; |
35 | 34 |
@@ -40,12 +40,14 @@ import io.netty.util.ReferenceCountUtil; | @@ -40,12 +40,14 @@ import io.netty.util.ReferenceCountUtil; | ||
40 | import io.netty.util.concurrent.Future; | 40 | import io.netty.util.concurrent.Future; |
41 | import io.netty.util.concurrent.GenericFutureListener; | 41 | import io.netty.util.concurrent.GenericFutureListener; |
42 | import lombok.extern.slf4j.Slf4j; | 42 | import lombok.extern.slf4j.Slf4j; |
43 | +import org.apache.commons.lang3.StringUtils; | ||
43 | import org.thingsboard.server.common.data.DataConstants; | 44 | import org.thingsboard.server.common.data.DataConstants; |
44 | import org.thingsboard.server.common.data.Device; | 45 | import org.thingsboard.server.common.data.Device; |
45 | import org.thingsboard.server.common.data.DeviceProfile; | 46 | import org.thingsboard.server.common.data.DeviceProfile; |
46 | import org.thingsboard.server.common.data.DeviceTransportType; | 47 | import org.thingsboard.server.common.data.DeviceTransportType; |
47 | import org.thingsboard.server.common.data.TransportPayloadType; | 48 | import org.thingsboard.server.common.data.TransportPayloadType; |
48 | import org.thingsboard.server.common.data.device.profile.MqttTopics; | 49 | import org.thingsboard.server.common.data.device.profile.MqttTopics; |
50 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
49 | import org.thingsboard.server.common.msg.EncryptionUtil; | 51 | import org.thingsboard.server.common.msg.EncryptionUtil; |
50 | import org.thingsboard.server.common.msg.tools.TbRateLimitsException; | 52 | import org.thingsboard.server.common.msg.tools.TbRateLimitsException; |
51 | import org.thingsboard.server.common.transport.SessionMsgListener; | 53 | import org.thingsboard.server.common.transport.SessionMsgListener; |
@@ -69,10 +71,10 @@ import org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher; | @@ -69,10 +71,10 @@ import org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher; | ||
69 | import org.thingsboard.server.common.transport.util.SslUtil; | 71 | import org.thingsboard.server.common.transport.util.SslUtil; |
70 | 72 | ||
71 | import javax.net.ssl.SSLPeerUnverifiedException; | 73 | import javax.net.ssl.SSLPeerUnverifiedException; |
72 | -import java.security.cert.Certificate; | ||
73 | -import java.security.cert.X509Certificate; | ||
74 | import java.io.IOException; | 74 | import java.io.IOException; |
75 | import java.net.InetSocketAddress; | 75 | import java.net.InetSocketAddress; |
76 | +import java.security.cert.Certificate; | ||
77 | +import java.security.cert.X509Certificate; | ||
76 | import java.util.ArrayList; | 78 | import java.util.ArrayList; |
77 | import java.util.List; | 79 | import java.util.List; |
78 | import java.util.Optional; | 80 | import java.util.Optional; |
@@ -80,7 +82,10 @@ import java.util.UUID; | @@ -80,7 +82,10 @@ import java.util.UUID; | ||
80 | import java.util.concurrent.ConcurrentHashMap; | 82 | import java.util.concurrent.ConcurrentHashMap; |
81 | import java.util.concurrent.ConcurrentMap; | 83 | import java.util.concurrent.ConcurrentMap; |
82 | import java.util.concurrent.TimeUnit; | 84 | import java.util.concurrent.TimeUnit; |
85 | +import java.util.regex.Matcher; | ||
86 | +import java.util.regex.Pattern; | ||
83 | 87 | ||
88 | +import static com.amazonaws.util.StringUtils.UTF8; | ||
84 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED; | 89 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED; |
85 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED; | 90 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED; |
86 | import static io.netty.handler.codec.mqtt.MqttMessageType.CONNACK; | 91 | import static io.netty.handler.codec.mqtt.MqttMessageType.CONNACK; |
@@ -99,6 +104,10 @@ import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE; | @@ -99,6 +104,10 @@ import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE; | ||
99 | @Slf4j | 104 | @Slf4j |
100 | public class MqttTransportHandler extends ChannelInboundHandlerAdapter implements GenericFutureListener<Future<? super Void>>, SessionMsgListener { | 105 | public class MqttTransportHandler extends ChannelInboundHandlerAdapter implements GenericFutureListener<Future<? super Void>>, SessionMsgListener { |
101 | 106 | ||
107 | + private static final Pattern FW_PATTERN = Pattern.compile("v2/fw/request/(?<requestId>\\d+)/chunk/(?<chunk>\\d+)"); | ||
108 | + | ||
109 | + private static final String PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE"; | ||
110 | + | ||
102 | private static final MqttQoS MAX_SUPPORTED_QOS_LVL = AT_LEAST_ONCE; | 111 | private static final MqttQoS MAX_SUPPORTED_QOS_LVL = AT_LEAST_ONCE; |
103 | 112 | ||
104 | private final UUID sessionId; | 113 | private final UUID sessionId; |
@@ -112,6 +121,9 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -112,6 +121,9 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
112 | private volatile InetSocketAddress address; | 121 | private volatile InetSocketAddress address; |
113 | private volatile GatewaySessionHandler gatewaySessionHandler; | 122 | private volatile GatewaySessionHandler gatewaySessionHandler; |
114 | 123 | ||
124 | + private final ConcurrentHashMap<String, String> fwSessions; | ||
125 | + private final ConcurrentHashMap<String, Integer> fwChunkSizes; | ||
126 | + | ||
115 | MqttTransportHandler(MqttTransportContext context, SslHandler sslHandler) { | 127 | MqttTransportHandler(MqttTransportContext context, SslHandler sslHandler) { |
116 | this.sessionId = UUID.randomUUID(); | 128 | this.sessionId = UUID.randomUUID(); |
117 | this.context = context; | 129 | this.context = context; |
@@ -120,6 +132,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -120,6 +132,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
120 | this.sslHandler = sslHandler; | 132 | this.sslHandler = sslHandler; |
121 | this.mqttQoSMap = new ConcurrentHashMap<>(); | 133 | this.mqttQoSMap = new ConcurrentHashMap<>(); |
122 | this.deviceSessionCtx = new DeviceSessionCtx(sessionId, mqttQoSMap, context); | 134 | this.deviceSessionCtx = new DeviceSessionCtx(sessionId, mqttQoSMap, context); |
135 | + this.fwSessions = new ConcurrentHashMap<>(); | ||
136 | + this.fwChunkSizes = new ConcurrentHashMap<>(); | ||
123 | } | 137 | } |
124 | 138 | ||
125 | @Override | 139 | @Override |
@@ -280,6 +294,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -280,6 +294,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
280 | 294 | ||
281 | private void processDevicePublish(ChannelHandlerContext ctx, MqttPublishMessage mqttMsg, String topicName, int msgId) { | 295 | private void processDevicePublish(ChannelHandlerContext ctx, MqttPublishMessage mqttMsg, String topicName, int msgId) { |
282 | try { | 296 | try { |
297 | + Matcher fwMatcher; | ||
283 | MqttTransportAdaptor payloadAdaptor = deviceSessionCtx.getPayloadAdaptor(); | 298 | MqttTransportAdaptor payloadAdaptor = deviceSessionCtx.getPayloadAdaptor(); |
284 | if (deviceSessionCtx.isDeviceAttributesTopic(topicName)) { | 299 | if (deviceSessionCtx.isDeviceAttributesTopic(topicName)) { |
285 | TransportProtos.PostAttributeMsg postAttributeMsg = payloadAdaptor.convertToPostAttributes(deviceSessionCtx, mqttMsg); | 300 | TransportProtos.PostAttributeMsg postAttributeMsg = payloadAdaptor.convertToPostAttributes(deviceSessionCtx, mqttMsg); |
@@ -299,6 +314,38 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -299,6 +314,38 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
299 | } else if (topicName.equals(MqttTopics.DEVICE_CLAIM_TOPIC)) { | 314 | } else if (topicName.equals(MqttTopics.DEVICE_CLAIM_TOPIC)) { |
300 | TransportProtos.ClaimDeviceMsg claimDeviceMsg = payloadAdaptor.convertToClaimDevice(deviceSessionCtx, mqttMsg); | 315 | TransportProtos.ClaimDeviceMsg claimDeviceMsg = payloadAdaptor.convertToClaimDevice(deviceSessionCtx, mqttMsg); |
301 | transportService.process(deviceSessionCtx.getSessionInfo(), claimDeviceMsg, getPubAckCallback(ctx, msgId, claimDeviceMsg)); | 316 | 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 | + } | ||
302 | } else { | 349 | } else { |
303 | transportService.reportActivity(deviceSessionCtx.getSessionInfo()); | 350 | transportService.reportActivity(deviceSessionCtx.getSessionInfo()); |
304 | ack(ctx, msgId); | 351 | ack(ctx, msgId); |
@@ -366,6 +413,65 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -366,6 +413,65 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
366 | } | 413 | } |
367 | } | 414 | } |
368 | 415 | ||
416 | + private class FirmwareCallback implements TransportServiceCallback<TransportProtos.GetFirmwareResponseMsg> { | ||
417 | + private final ChannelHandlerContext ctx; | ||
418 | + private final int msgId; | ||
419 | + private final TransportProtos.GetFirmwareRequestMsg msg; | ||
420 | + private final String requestId; | ||
421 | + private final int chunkSize; | ||
422 | + private final int chunk; | ||
423 | + | ||
424 | + FirmwareCallback(ChannelHandlerContext ctx, int msgId, TransportProtos.GetFirmwareRequestMsg msg, String requestId, int chunkSize, int chunk) { | ||
425 | + this.ctx = ctx; | ||
426 | + this.msgId = msgId; | ||
427 | + this.msg = msg; | ||
428 | + this.requestId = requestId; | ||
429 | + this.chunkSize = chunkSize; | ||
430 | + this.chunk = chunk; | ||
431 | + } | ||
432 | + | ||
433 | + @Override | ||
434 | + public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) { | ||
435 | + if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) { | ||
436 | + FirmwareId firmwareId = new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())); | ||
437 | + fwSessions.put(requestId, firmwareId.toString()); | ||
438 | + sendFirmware(ctx, msgId, firmwareId.toString(), requestId, chunkSize, chunk); | ||
439 | + } else { | ||
440 | + sendFirmwareError(ctx, response.getResponseStatus().toString()); | ||
441 | + } | ||
442 | + } | ||
443 | + | ||
444 | + @Override | ||
445 | + public void onError(Throwable e) { | ||
446 | + log.trace("[{}] Failed to get firmware: {}", sessionId, msg, e); | ||
447 | + processDisconnect(ctx); | ||
448 | + } | ||
449 | + } | ||
450 | + | ||
451 | + private void sendFirmware(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk) { | ||
452 | + log.trace("[{}] Send firmware [{}] to device!", sessionId, firmwareId); | ||
453 | + ack(ctx, msgId); | ||
454 | + try { | ||
455 | + byte[] firmwareChunk = context.getFirmwareCacheReader().get(firmwareId, chunkSize, chunk); | ||
456 | + deviceSessionCtx.getPayloadAdaptor() | ||
457 | + .convertToPublish(deviceSessionCtx, firmwareChunk, requestId, chunk) | ||
458 | + .ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); | ||
459 | + if (firmwareChunk != null && chunkSize != firmwareChunk.length) { | ||
460 | + scheduler.schedule(() -> processDisconnect(ctx), 60, TimeUnit.SECONDS); | ||
461 | + } | ||
462 | + } catch (Exception e) { | ||
463 | + log.trace("[{}] Failed to send firmware response!", sessionId, e); | ||
464 | + } | ||
465 | + } | ||
466 | + | ||
467 | + private void sendFirmwareError(ChannelHandlerContext ctx, String error) { | ||
468 | + log.warn("[{}] {}", sessionId, error); | ||
469 | + deviceSessionCtx.getChannel().writeAndFlush(deviceSessionCtx | ||
470 | + .getPayloadAdaptor() | ||
471 | + .createMqttPublishMsg(deviceSessionCtx, MqttTopics.DEVICE_FIRMWARE_ERROR_TOPIC, error.getBytes())); | ||
472 | + processDisconnect(ctx); | ||
473 | + } | ||
474 | + | ||
369 | private void processSubscribe(ChannelHandlerContext ctx, MqttSubscribeMessage mqttMsg) { | 475 | private void processSubscribe(ChannelHandlerContext ctx, MqttSubscribeMessage mqttMsg) { |
370 | if (!checkConnected(ctx, mqttMsg)) { | 476 | if (!checkConnected(ctx, mqttMsg)) { |
371 | return; | 477 | return; |
@@ -396,6 +502,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -396,6 +502,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
396 | case MqttTopics.GATEWAY_RPC_TOPIC: | 502 | case MqttTopics.GATEWAY_RPC_TOPIC: |
397 | case MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC: | 503 | case MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC: |
398 | case MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC: | 504 | case MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC: |
505 | + case MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC: | ||
506 | + case MqttTopics.DEVICE_FIRMWARE_ERROR_TOPIC: | ||
399 | registerSubQoS(topic, grantedQoSList, reqQoS); | 507 | registerSubQoS(topic, grantedQoSList, reqQoS); |
400 | break; | 508 | break; |
401 | default: | 509 | default: |
@@ -21,8 +21,6 @@ import com.google.gson.JsonObject; | @@ -21,8 +21,6 @@ import com.google.gson.JsonObject; | ||
21 | import com.google.gson.JsonParser; | 21 | import com.google.gson.JsonParser; |
22 | import com.google.gson.JsonSyntaxException; | 22 | import com.google.gson.JsonSyntaxException; |
23 | import io.netty.buffer.ByteBuf; | 23 | import io.netty.buffer.ByteBuf; |
24 | -import io.netty.buffer.ByteBufAllocator; | ||
25 | -import io.netty.buffer.UnpooledByteBufAllocator; | ||
26 | import io.netty.handler.codec.mqtt.MqttFixedHeader; | 24 | import io.netty.handler.codec.mqtt.MqttFixedHeader; |
27 | import io.netty.handler.codec.mqtt.MqttMessage; | 25 | import io.netty.handler.codec.mqtt.MqttMessage; |
28 | import io.netty.handler.codec.mqtt.MqttMessageType; | 26 | import io.netty.handler.codec.mqtt.MqttMessageType; |
@@ -31,10 +29,10 @@ import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; | @@ -31,10 +29,10 @@ import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; | ||
31 | import lombok.extern.slf4j.Slf4j; | 29 | import lombok.extern.slf4j.Slf4j; |
32 | import org.springframework.stereotype.Component; | 30 | import org.springframework.stereotype.Component; |
33 | import org.springframework.util.StringUtils; | 31 | import org.springframework.util.StringUtils; |
32 | +import org.thingsboard.server.common.data.device.profile.MqttTopics; | ||
34 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; | 33 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
35 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; | 34 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; |
36 | import org.thingsboard.server.gen.transport.TransportProtos; | 35 | import org.thingsboard.server.gen.transport.TransportProtos; |
37 | -import org.thingsboard.server.common.data.device.profile.MqttTopics; | ||
38 | import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionContext; | 36 | import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionContext; |
39 | 37 | ||
40 | import java.nio.charset.Charset; | 38 | import java.nio.charset.Charset; |
@@ -55,7 +53,6 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { | @@ -55,7 +53,6 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { | ||
55 | protected static final Charset UTF8 = StandardCharsets.UTF_8; | 53 | protected static final Charset UTF8 = StandardCharsets.UTF_8; |
56 | 54 | ||
57 | private static final Gson GSON = new Gson(); | 55 | private static final Gson GSON = new Gson(); |
58 | - private static final ByteBufAllocator ALLOCATOR = new UnpooledByteBufAllocator(false); | ||
59 | 56 | ||
60 | @Override | 57 | @Override |
61 | public TransportProtos.PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { | 58 | public TransportProtos.PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { |
@@ -153,6 +150,11 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { | @@ -153,6 +150,11 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { | ||
153 | return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC, JsonConverter.toJson(provisionResponse))); | 150 | return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC, JsonConverter.toJson(provisionResponse))); |
154 | } | 151 | } |
155 | 152 | ||
153 | + @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)); | ||
156 | + } | ||
157 | + | ||
156 | public static JsonElement validateJsonPayload(UUID sessionId, ByteBuf payloadData) throws AdaptorException { | 158 | public static JsonElement validateJsonPayload(UUID sessionId, ByteBuf payloadData) throws AdaptorException { |
157 | String payload = validatePayload(sessionId, payloadData, false); | 159 | String payload = validatePayload(sessionId, payloadData, false); |
158 | try { | 160 | try { |
@@ -15,8 +15,14 @@ | @@ -15,8 +15,14 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.transport.mqtt.adaptors; | 16 | package org.thingsboard.server.transport.mqtt.adaptors; |
17 | 17 | ||
18 | +import io.netty.buffer.ByteBuf; | ||
19 | +import io.netty.buffer.ByteBufAllocator; | ||
20 | +import io.netty.buffer.UnpooledByteBufAllocator; | ||
21 | +import io.netty.handler.codec.mqtt.MqttFixedHeader; | ||
18 | import io.netty.handler.codec.mqtt.MqttMessage; | 22 | import io.netty.handler.codec.mqtt.MqttMessage; |
23 | +import io.netty.handler.codec.mqtt.MqttMessageType; | ||
19 | import io.netty.handler.codec.mqtt.MqttPublishMessage; | 24 | import io.netty.handler.codec.mqtt.MqttPublishMessage; |
25 | +import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; | ||
20 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; | 26 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
21 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; | 27 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
22 | import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; | 28 | import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; |
@@ -39,6 +45,8 @@ import java.util.Optional; | @@ -39,6 +45,8 @@ import java.util.Optional; | ||
39 | */ | 45 | */ |
40 | public interface MqttTransportAdaptor { | 46 | public interface MqttTransportAdaptor { |
41 | 47 | ||
48 | + ByteBufAllocator ALLOCATOR = new UnpooledByteBufAllocator(false); | ||
49 | + | ||
42 | PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; | 50 | PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; |
43 | 51 | ||
44 | PostAttributeMsg convertToPostAttributes(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; | 52 | PostAttributeMsg convertToPostAttributes(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; |
@@ -69,4 +77,14 @@ public interface MqttTransportAdaptor { | @@ -69,4 +77,14 @@ public interface MqttTransportAdaptor { | ||
69 | 77 | ||
70 | Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException; | 78 | Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException; |
71 | 79 | ||
80 | + Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk) throws AdaptorException; | ||
81 | + | ||
82 | + default MqttPublishMessage createMqttPublishMsg(MqttDeviceAwareSessionContext ctx, String topic, byte[] payloadInBytes) { | ||
83 | + MqttFixedHeader mqttFixedHeader = | ||
84 | + new MqttFixedHeader(MqttMessageType.PUBLISH, false, ctx.getQoSForTopic(topic), false, 0); | ||
85 | + MqttPublishVariableHeader header = new MqttPublishVariableHeader(topic, ctx.nextMsgId()); | ||
86 | + ByteBuf payload = ALLOCATOR.buffer(); | ||
87 | + payload.writeBytes(payloadInBytes); | ||
88 | + return new MqttPublishMessage(mqttFixedHeader, header, payload); | ||
89 | + } | ||
72 | } | 90 | } |
@@ -22,13 +22,8 @@ import com.google.protobuf.DynamicMessage; | @@ -22,13 +22,8 @@ import com.google.protobuf.DynamicMessage; | ||
22 | import com.google.protobuf.InvalidProtocolBufferException; | 22 | import com.google.protobuf.InvalidProtocolBufferException; |
23 | import com.google.protobuf.util.JsonFormat; | 23 | import com.google.protobuf.util.JsonFormat; |
24 | import io.netty.buffer.ByteBuf; | 24 | import io.netty.buffer.ByteBuf; |
25 | -import io.netty.buffer.ByteBufAllocator; | ||
26 | -import io.netty.buffer.UnpooledByteBufAllocator; | ||
27 | -import io.netty.handler.codec.mqtt.MqttFixedHeader; | ||
28 | import io.netty.handler.codec.mqtt.MqttMessage; | 25 | import io.netty.handler.codec.mqtt.MqttMessage; |
29 | -import io.netty.handler.codec.mqtt.MqttMessageType; | ||
30 | import io.netty.handler.codec.mqtt.MqttPublishMessage; | 26 | import io.netty.handler.codec.mqtt.MqttPublishMessage; |
31 | -import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; | ||
32 | import lombok.extern.slf4j.Slf4j; | 27 | import lombok.extern.slf4j.Slf4j; |
33 | import org.springframework.stereotype.Component; | 28 | import org.springframework.stereotype.Component; |
34 | import org.springframework.util.StringUtils; | 29 | import org.springframework.util.StringUtils; |
@@ -47,8 +42,6 @@ import java.util.Optional; | @@ -47,8 +42,6 @@ import java.util.Optional; | ||
47 | @Slf4j | 42 | @Slf4j |
48 | public class ProtoMqttAdaptor implements MqttTransportAdaptor { | 43 | public class ProtoMqttAdaptor implements MqttTransportAdaptor { |
49 | 44 | ||
50 | - private static final ByteBufAllocator ALLOCATOR = new UnpooledByteBufAllocator(false); | ||
51 | - | ||
52 | @Override | 45 | @Override |
53 | public TransportProtos.PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { | 46 | public TransportProtos.PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { |
54 | DeviceSessionCtx deviceSessionCtx = (DeviceSessionCtx) ctx; | 47 | DeviceSessionCtx deviceSessionCtx = (DeviceSessionCtx) ctx; |
@@ -149,7 +142,6 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { | @@ -149,7 +142,6 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { | ||
149 | } | 142 | } |
150 | } | 143 | } |
151 | 144 | ||
152 | - | ||
153 | @Override | 145 | @Override |
154 | public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException { | 146 | public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException { |
155 | DeviceSessionCtx deviceSessionCtx = (DeviceSessionCtx) ctx; | 147 | DeviceSessionCtx deviceSessionCtx = (DeviceSessionCtx) ctx; |
@@ -173,6 +165,11 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { | @@ -173,6 +165,11 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { | ||
173 | } | 165 | } |
174 | 166 | ||
175 | @Override | 167 | @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)); | ||
170 | + } | ||
171 | + | ||
172 | + @Override | ||
176 | public Optional<MqttMessage> convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { | 173 | public Optional<MqttMessage> convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { |
177 | if (!StringUtils.isEmpty(responseMsg.getError())) { | 174 | if (!StringUtils.isEmpty(responseMsg.getError())) { |
178 | throw new AdaptorException(responseMsg.getError()); | 175 | throw new AdaptorException(responseMsg.getError()); |
@@ -210,15 +207,6 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { | @@ -210,15 +207,6 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { | ||
210 | return bytes; | 207 | return bytes; |
211 | } | 208 | } |
212 | 209 | ||
213 | - private MqttPublishMessage createMqttPublishMsg(MqttDeviceAwareSessionContext ctx, String topic, byte[] payloadBytes) { | ||
214 | - MqttFixedHeader mqttFixedHeader = | ||
215 | - new MqttFixedHeader(MqttMessageType.PUBLISH, false, ctx.getQoSForTopic(topic), false, 0); | ||
216 | - MqttPublishVariableHeader header = new MqttPublishVariableHeader(topic, ctx.nextMsgId()); | ||
217 | - ByteBuf payload = ALLOCATOR.buffer(); | ||
218 | - payload.writeBytes(payloadBytes); | ||
219 | - return new MqttPublishMessage(mqttFixedHeader, header, payload); | ||
220 | - } | ||
221 | - | ||
222 | private int getRequestId(String topicName, String topic) { | 210 | private int getRequestId(String topicName, String topic) { |
223 | return Integer.parseInt(topicName.substring(topic.length())); | 211 | return Integer.parseInt(topicName.substring(topic.length())); |
224 | } | 212 | } |
@@ -20,10 +20,9 @@ import lombok.Data; | @@ -20,10 +20,9 @@ import lombok.Data; | ||
20 | import lombok.Getter; | 20 | import lombok.Getter; |
21 | import lombok.extern.slf4j.Slf4j; | 21 | import lombok.extern.slf4j.Slf4j; |
22 | import org.springframework.beans.factory.annotation.Autowired; | 22 | import org.springframework.beans.factory.annotation.Autowired; |
23 | -import org.springframework.stereotype.Service; | 23 | +import org.thingsboard.server.cache.firmware.FirmwareCacheReader; |
24 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; | 24 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
25 | import org.thingsboard.server.queue.scheduler.SchedulerComponent; | 25 | import org.thingsboard.server.queue.scheduler.SchedulerComponent; |
26 | -import org.thingsboard.server.queue.util.TbTransportComponent; | ||
27 | 26 | ||
28 | import javax.annotation.PostConstruct; | 27 | import javax.annotation.PostConstruct; |
29 | import javax.annotation.PreDestroy; | 28 | import javax.annotation.PreDestroy; |
@@ -51,6 +50,11 @@ public abstract class TransportContext { | @@ -51,6 +50,11 @@ public abstract class TransportContext { | ||
51 | @Getter | 50 | @Getter |
52 | private ExecutorService executor; | 51 | private ExecutorService executor; |
53 | 52 | ||
53 | + | ||
54 | + @Getter | ||
55 | + @Autowired | ||
56 | + private FirmwareCacheReader firmwareCacheReader; | ||
57 | + | ||
54 | @PostConstruct | 58 | @PostConstruct |
55 | public void init() { | 59 | public void init() { |
56 | executor = Executors.newWorkStealingPool(50); | 60 | executor = Executors.newWorkStealingPool(50); |
@@ -24,6 +24,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; | @@ -24,6 +24,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; | ||
24 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; | 24 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
25 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; | 25 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; |
26 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; | 26 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; |
27 | +import org.thingsboard.server.gen.transport.TransportProtos.GetFirmwareRequestMsg; | ||
28 | +import org.thingsboard.server.gen.transport.TransportProtos.GetFirmwareResponseMsg; | ||
27 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; | 29 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; |
28 | import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg; | 30 | import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg; |
29 | import org.thingsboard.server.gen.transport.TransportProtos.GetResourceResponseMsg; | 31 | import org.thingsboard.server.gen.transport.TransportProtos.GetResourceResponseMsg; |
@@ -98,6 +100,8 @@ public interface TransportService { | @@ -98,6 +100,8 @@ public interface TransportService { | ||
98 | 100 | ||
99 | void process(SessionInfoProto sessionInfo, ClaimDeviceMsg msg, TransportServiceCallback<Void> callback); | 101 | void process(SessionInfoProto sessionInfo, ClaimDeviceMsg msg, TransportServiceCallback<Void> callback); |
100 | 102 | ||
103 | + void process(SessionInfoProto sessionInfoProto, GetFirmwareRequestMsg msg, TransportServiceCallback<GetFirmwareResponseMsg> callback); | ||
104 | + | ||
101 | SessionMetaData registerAsyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener); | 105 | SessionMetaData registerAsyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener); |
102 | 106 | ||
103 | SessionMetaData registerSyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener, long timeout); | 107 | SessionMetaData registerSyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener, long timeout); |
@@ -44,7 +44,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.KeyValueType; | @@ -44,7 +44,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.KeyValueType; | ||
44 | import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; | 44 | import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; |
45 | import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; | 45 | import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; |
46 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; | 46 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; |
47 | -import org.thingsboard.server.gen.transport.TransportProtos.ProvisionResponseStatus; | 47 | +import org.thingsboard.server.gen.transport.TransportProtos.ResponseStatus; |
48 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvListProto; | 48 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvListProto; |
49 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; | 49 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; |
50 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateBasicMqttCredRequestMsg; | 50 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateBasicMqttCredRequestMsg; |
@@ -427,12 +427,12 @@ public class JsonConverter { | @@ -427,12 +427,12 @@ public class JsonConverter { | ||
427 | 427 | ||
428 | private static JsonObject toJson(ProvisionDeviceResponseMsg payload, boolean toGateway, int requestId) { | 428 | private static JsonObject toJson(ProvisionDeviceResponseMsg payload, boolean toGateway, int requestId) { |
429 | JsonObject result = new JsonObject(); | 429 | JsonObject result = new JsonObject(); |
430 | - if (payload.getStatus() == TransportProtos.ProvisionResponseStatus.NOT_FOUND) { | 430 | + if (payload.getStatus() == ResponseStatus.NOT_FOUND) { |
431 | result.addProperty("errorMsg", "Provision data was not found!"); | 431 | result.addProperty("errorMsg", "Provision data was not found!"); |
432 | - result.addProperty("status", ProvisionResponseStatus.NOT_FOUND.name()); | ||
433 | - } else if (payload.getStatus() == TransportProtos.ProvisionResponseStatus.FAILURE) { | 432 | + result.addProperty("status", ResponseStatus.NOT_FOUND.name()); |
433 | + } else if (payload.getStatus() == TransportProtos.ResponseStatus.FAILURE) { | ||
434 | result.addProperty("errorMsg", "Failed to provision device!"); | 434 | result.addProperty("errorMsg", "Failed to provision device!"); |
435 | - result.addProperty("status", ProvisionResponseStatus.FAILURE.name()); | 435 | + result.addProperty("status", ResponseStatus.FAILURE.name()); |
436 | } else { | 436 | } else { |
437 | if (toGateway) { | 437 | if (toGateway) { |
438 | result.addProperty("id", requestId); | 438 | result.addProperty("id", requestId); |
@@ -449,7 +449,7 @@ public class JsonConverter { | @@ -449,7 +449,7 @@ public class JsonConverter { | ||
449 | break; | 449 | break; |
450 | } | 450 | } |
451 | result.addProperty("credentialsType", payload.getCredentialsType().name()); | 451 | result.addProperty("credentialsType", payload.getCredentialsType().name()); |
452 | - result.addProperty("status", ProvisionResponseStatus.SUCCESS.name()); | 452 | + result.addProperty("status", ResponseStatus.SUCCESS.name()); |
453 | } | 453 | } |
454 | return result; | 454 | return result; |
455 | } | 455 | } |
@@ -380,7 +380,6 @@ public class DefaultTransportService implements TransportService { | @@ -380,7 +380,6 @@ public class DefaultTransportService implements TransportService { | ||
380 | AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor); | 380 | AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor); |
381 | } | 381 | } |
382 | 382 | ||
383 | - | ||
384 | @Override | 383 | @Override |
385 | public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.SubscriptionInfoProto msg, TransportServiceCallback<Void> callback) { | 384 | public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.SubscriptionInfoProto msg, TransportServiceCallback<Void> callback) { |
386 | if (log.isTraceEnabled()) { | 385 | if (log.isTraceEnabled()) { |
@@ -534,6 +533,19 @@ public class DefaultTransportService implements TransportService { | @@ -534,6 +533,19 @@ public class DefaultTransportService implements TransportService { | ||
534 | } | 533 | } |
535 | 534 | ||
536 | @Override | 535 | @Override |
536 | + public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.GetFirmwareRequestMsg msg, TransportServiceCallback<TransportProtos.GetFirmwareResponseMsg> callback) { | ||
537 | + if (checkLimits(sessionInfo, msg, callback)) { | ||
538 | + TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg> protoMsg = | ||
539 | + new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setFirmwareRequestMsg(msg).build()); | ||
540 | + | ||
541 | + AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg), response -> { | ||
542 | + TransportProtos.GetFirmwareResponseMsg firmwareResponseMsg = response.getValue().getFirmwareResponseMsg(); | ||
543 | + callback.onSuccess(firmwareResponseMsg); | ||
544 | + }, callback::onError, transportCallbackExecutor); | ||
545 | + } | ||
546 | + } | ||
547 | + | ||
548 | + @Override | ||
537 | public SessionMetaData reportActivity(TransportProtos.SessionInfoProto sessionInfo) { | 549 | public SessionMetaData reportActivity(TransportProtos.SessionInfoProto sessionInfo) { |
538 | return reportActivityInternal(sessionInfo); | 550 | return reportActivityInternal(sessionInfo); |
539 | } | 551 | } |
@@ -612,11 +624,11 @@ public class DefaultTransportService implements TransportService { | @@ -612,11 +624,11 @@ public class DefaultTransportService implements TransportService { | ||
612 | sessions.remove(toSessionId(sessionInfo)); | 624 | sessions.remove(toSessionId(sessionInfo)); |
613 | } | 625 | } |
614 | 626 | ||
615 | - private boolean checkLimits(TransportProtos.SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<Void> callback) { | 627 | + private boolean checkLimits(TransportProtos.SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<?> callback) { |
616 | return checkLimits(sessionInfo, msg, callback, 0); | 628 | return checkLimits(sessionInfo, msg, callback, 0); |
617 | } | 629 | } |
618 | 630 | ||
619 | - private boolean checkLimits(TransportProtos.SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<Void> callback, int dataPoints) { | 631 | + private boolean checkLimits(TransportProtos.SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<?> callback, int dataPoints) { |
620 | if (log.isTraceEnabled()) { | 632 | if (log.isTraceEnabled()) { |
621 | log.trace("[{}] Processing msg: {}", toSessionId(sessionInfo), msg); | 633 | log.trace("[{}] Processing msg: {}", toSessionId(sessionInfo), msg); |
622 | } | 634 | } |
@@ -81,6 +81,8 @@ public interface DeviceDao extends Dao<Device>, TenantEntityDao { | @@ -81,6 +81,8 @@ public interface DeviceDao extends Dao<Device>, TenantEntityDao { | ||
81 | */ | 81 | */ |
82 | PageData<Device> findDevicesByTenantIdAndType(UUID tenantId, String type, PageLink pageLink); | 82 | PageData<Device> findDevicesByTenantIdAndType(UUID tenantId, String type, PageLink pageLink); |
83 | 83 | ||
84 | + PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(UUID tenantId, String type, PageLink pageLink); | ||
85 | + | ||
84 | /** | 86 | /** |
85 | * Find device infos by tenantId, type and page link. | 87 | * Find device infos by tenantId, type and page link. |
86 | * | 88 | * |
@@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.DeviceProfileInfo; | @@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.DeviceProfileInfo; | ||
42 | import org.thingsboard.server.common.data.DeviceProfileProvisionType; | 42 | import org.thingsboard.server.common.data.DeviceProfileProvisionType; |
43 | import org.thingsboard.server.common.data.DeviceProfileType; | 43 | import org.thingsboard.server.common.data.DeviceProfileType; |
44 | import org.thingsboard.server.common.data.DeviceTransportType; | 44 | import org.thingsboard.server.common.data.DeviceTransportType; |
45 | +import org.thingsboard.server.common.data.Firmware; | ||
45 | import org.thingsboard.server.common.data.Tenant; | 46 | import org.thingsboard.server.common.data.Tenant; |
46 | import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; | 47 | import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; |
47 | import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; | 48 | import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; |
@@ -61,6 +62,7 @@ import org.thingsboard.server.common.data.page.PageData; | @@ -61,6 +62,7 @@ import org.thingsboard.server.common.data.page.PageData; | ||
61 | import org.thingsboard.server.common.data.page.PageLink; | 62 | import org.thingsboard.server.common.data.page.PageLink; |
62 | import org.thingsboard.server.dao.entity.AbstractEntityService; | 63 | import org.thingsboard.server.dao.entity.AbstractEntityService; |
63 | import org.thingsboard.server.dao.exception.DataValidationException; | 64 | import org.thingsboard.server.dao.exception.DataValidationException; |
65 | +import org.thingsboard.server.dao.firmware.FirmwareService; | ||
64 | import org.thingsboard.server.dao.service.DataValidator; | 66 | import org.thingsboard.server.dao.service.DataValidator; |
65 | import org.thingsboard.server.dao.service.PaginatedRemover; | 67 | import org.thingsboard.server.dao.service.PaginatedRemover; |
66 | import org.thingsboard.server.dao.service.Validator; | 68 | import org.thingsboard.server.dao.service.Validator; |
@@ -111,6 +113,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | @@ -111,6 +113,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | ||
111 | @Autowired | 113 | @Autowired |
112 | private CacheManager cacheManager; | 114 | private CacheManager cacheManager; |
113 | 115 | ||
116 | + @Autowired | ||
117 | + private FirmwareService firmwareService; | ||
118 | + | ||
114 | private final Lock findOrCreateLock = new ReentrantLock(); | 119 | private final Lock findOrCreateLock = new ReentrantLock(); |
115 | 120 | ||
116 | @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}") | 121 | @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}") |
@@ -395,6 +400,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | @@ -395,6 +400,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | ||
395 | } | 400 | } |
396 | } | 401 | } |
397 | 402 | ||
403 | + if (deviceProfile.getFirmwareId() != null) { | ||
404 | + Firmware firmware = firmwareService.findFirmwareById(tenantId, deviceProfile.getFirmwareId()); | ||
405 | + if (firmware == null) { | ||
406 | + throw new DataValidationException("Can't assign non-existent firmware!"); | ||
407 | + } | ||
408 | + if (firmware.getData() == null) { | ||
409 | + throw new DataValidationException("Can't assign firmware with empty data!"); | ||
410 | + } | ||
411 | + } | ||
398 | } | 412 | } |
399 | 413 | ||
400 | @Override | 414 | @Override |
@@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.DeviceProfile; | @@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.DeviceProfile; | ||
39 | import org.thingsboard.server.common.data.EntitySubtype; | 39 | import org.thingsboard.server.common.data.EntitySubtype; |
40 | import org.thingsboard.server.common.data.EntityType; | 40 | import org.thingsboard.server.common.data.EntityType; |
41 | import org.thingsboard.server.common.data.EntityView; | 41 | import org.thingsboard.server.common.data.EntityView; |
42 | +import org.thingsboard.server.common.data.Firmware; | ||
42 | import org.thingsboard.server.common.data.Tenant; | 43 | import org.thingsboard.server.common.data.Tenant; |
43 | import org.thingsboard.server.common.data.asset.Asset; | 44 | import org.thingsboard.server.common.data.asset.Asset; |
44 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; | 45 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; |
@@ -72,6 +73,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus; | @@ -72,6 +73,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus; | ||
72 | import org.thingsboard.server.dao.entity.AbstractEntityService; | 73 | import org.thingsboard.server.dao.entity.AbstractEntityService; |
73 | import org.thingsboard.server.dao.event.EventService; | 74 | import org.thingsboard.server.dao.event.EventService; |
74 | import org.thingsboard.server.dao.exception.DataValidationException; | 75 | import org.thingsboard.server.dao.exception.DataValidationException; |
76 | +import org.thingsboard.server.dao.firmware.FirmwareService; | ||
75 | import org.thingsboard.server.dao.service.DataValidator; | 77 | import org.thingsboard.server.dao.service.DataValidator; |
76 | import org.thingsboard.server.dao.service.PaginatedRemover; | 78 | import org.thingsboard.server.dao.service.PaginatedRemover; |
77 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | 79 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
@@ -131,6 +133,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | @@ -131,6 +133,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | ||
131 | @Lazy | 133 | @Lazy |
132 | private TbTenantProfileCache tenantProfileCache; | 134 | private TbTenantProfileCache tenantProfileCache; |
133 | 135 | ||
136 | + @Autowired | ||
137 | + private FirmwareService firmwareService; | ||
138 | + | ||
134 | @Override | 139 | @Override |
135 | public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) { | 140 | public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) { |
136 | log.trace("Executing findDeviceInfoById [{}]", deviceId); | 141 | log.trace("Executing findDeviceInfoById [{}]", deviceId); |
@@ -350,6 +355,15 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | @@ -350,6 +355,15 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | ||
350 | } | 355 | } |
351 | 356 | ||
352 | @Override | 357 | @Override |
358 | + public PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink) { | ||
359 | + log.trace("Executing findDevicesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); | ||
360 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
361 | + validateString(type, "Incorrect type " + type); | ||
362 | + validatePageLink(pageLink); | ||
363 | + return deviceDao.findDevicesByTenantIdAndTypeAndEmptyFirmware(tenantId.getId(), type, pageLink); | ||
364 | + } | ||
365 | + | ||
366 | + @Override | ||
353 | public PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) { | 367 | public PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) { |
354 | log.trace("Executing findDeviceInfosByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); | 368 | log.trace("Executing findDeviceInfosByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); |
355 | validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | 369 | validateId(tenantId, INCORRECT_TENANT_ID + tenantId); |
@@ -663,6 +677,16 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | @@ -663,6 +677,16 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | ||
663 | throw new DataValidationException("Can't assign device to customer from different tenant!"); | 677 | throw new DataValidationException("Can't assign device to customer from different tenant!"); |
664 | } | 678 | } |
665 | } | 679 | } |
680 | + | ||
681 | + if (device.getFirmwareId() != null) { | ||
682 | + Firmware firmware = firmwareService.findFirmwareById(tenantId, device.getFirmwareId()); | ||
683 | + if (firmware == null) { | ||
684 | + throw new DataValidationException("Can't assign non-existent firmware!"); | ||
685 | + } | ||
686 | + if (firmware.getData() == null) { | ||
687 | + throw new DataValidationException("Can't assign firmware with empty data!"); | ||
688 | + } | ||
689 | + } | ||
666 | } | 690 | } |
667 | }; | 691 | }; |
668 | 692 |
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.dao.firmware; | ||
17 | + | ||
18 | +import com.google.common.hash.HashFunction; | ||
19 | +import com.google.common.hash.Hashing; | ||
20 | +import lombok.extern.slf4j.Slf4j; | ||
21 | +import org.apache.commons.lang3.StringUtils; | ||
22 | +import org.hibernate.exception.ConstraintViolationException; | ||
23 | +import org.springframework.cache.Cache; | ||
24 | +import org.springframework.cache.CacheManager; | ||
25 | +import org.springframework.stereotype.Service; | ||
26 | +import org.thingsboard.server.common.data.Firmware; | ||
27 | +import org.thingsboard.server.common.data.FirmwareInfo; | ||
28 | +import org.thingsboard.server.common.data.Tenant; | ||
29 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
30 | +import org.thingsboard.server.common.data.id.TenantId; | ||
31 | +import org.thingsboard.server.common.data.page.PageData; | ||
32 | +import org.thingsboard.server.common.data.page.PageLink; | ||
33 | +import org.thingsboard.server.dao.exception.DataValidationException; | ||
34 | +import org.thingsboard.server.dao.service.DataValidator; | ||
35 | +import org.thingsboard.server.dao.service.PaginatedRemover; | ||
36 | +import org.thingsboard.server.dao.tenant.TenantDao; | ||
37 | + | ||
38 | +import java.nio.ByteBuffer; | ||
39 | +import java.util.Collections; | ||
40 | +import java.util.Optional; | ||
41 | + | ||
42 | +import static org.thingsboard.server.common.data.CacheConstants.FIRMWARE_CACHE; | ||
43 | +import static org.thingsboard.server.dao.service.Validator.validateId; | ||
44 | +import static org.thingsboard.server.dao.service.Validator.validatePageLink; | ||
45 | + | ||
46 | +@Service | ||
47 | +@Slf4j | ||
48 | +public class BaseFirmwareService implements FirmwareService { | ||
49 | + public static final String INCORRECT_FIRMWARE_ID = "Incorrect firmwareId "; | ||
50 | + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; | ||
51 | + | ||
52 | + private final TenantDao tenantDao; | ||
53 | + private final FirmwareDao firmwareDao; | ||
54 | + private final FirmwareInfoDao firmwareInfoDao; | ||
55 | + private final CacheManager cacheManager; | ||
56 | + | ||
57 | + public BaseFirmwareService(TenantDao tenantDao, FirmwareDao firmwareDao, FirmwareInfoDao firmwareInfoDao, CacheManager cacheManager) { | ||
58 | + this.tenantDao = tenantDao; | ||
59 | + this.firmwareDao = firmwareDao; | ||
60 | + this.firmwareInfoDao = firmwareInfoDao; | ||
61 | + this.cacheManager = cacheManager; | ||
62 | + } | ||
63 | + | ||
64 | + @Override | ||
65 | + public FirmwareInfo saveFirmwareInfo(FirmwareInfo firmwareInfo) { | ||
66 | + log.trace("Executing saveFirmwareInfo [{}]", firmwareInfo); | ||
67 | + firmwareInfoValidator.validate(firmwareInfo, FirmwareInfo::getTenantId); | ||
68 | + try { | ||
69 | + FirmwareId firmwareId = firmwareInfo.getId(); | ||
70 | + if (firmwareId != null) { | ||
71 | + cacheManager.getCache(FIRMWARE_CACHE).evict(firmwareId.toString()); | ||
72 | + } | ||
73 | + return firmwareInfoDao.save(firmwareInfo.getTenantId(), firmwareInfo); | ||
74 | + } catch (Exception t) { | ||
75 | + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); | ||
76 | + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("firmware_tenant_title_version_unq_key")) { | ||
77 | + throw new DataValidationException("Firmware with such title and version already exists!"); | ||
78 | + } else { | ||
79 | + throw t; | ||
80 | + } | ||
81 | + } | ||
82 | + } | ||
83 | + | ||
84 | + @Override | ||
85 | + public Firmware saveFirmware(Firmware firmware) { | ||
86 | + log.trace("Executing saveFirmware [{}]", firmware); | ||
87 | + firmwareValidator.validate(firmware, FirmwareInfo::getTenantId); | ||
88 | + try { | ||
89 | + FirmwareId firmwareId = firmware.getId(); | ||
90 | + if (firmwareId != null) { | ||
91 | + cacheManager.getCache(FIRMWARE_CACHE).evict(firmwareId.toString()); | ||
92 | + } | ||
93 | + return firmwareDao.save(firmware.getTenantId(), firmware); | ||
94 | + } catch (Exception t) { | ||
95 | + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); | ||
96 | + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("firmware_tenant_title_version_unq_key")) { | ||
97 | + throw new DataValidationException("Firmware with such title and version already exists!"); | ||
98 | + } else { | ||
99 | + throw t; | ||
100 | + } | ||
101 | + } | ||
102 | + } | ||
103 | + | ||
104 | + @Override | ||
105 | + public Firmware findFirmwareById(TenantId tenantId, FirmwareId firmwareId) { | ||
106 | + log.trace("Executing findFirmwareById [{}]", firmwareId); | ||
107 | + validateId(firmwareId, INCORRECT_FIRMWARE_ID + firmwareId); | ||
108 | + return firmwareDao.findById(tenantId, firmwareId.getId()); | ||
109 | + } | ||
110 | + | ||
111 | + @Override | ||
112 | + public FirmwareInfo findFirmwareInfoById(TenantId tenantId, FirmwareId firmwareId) { | ||
113 | + log.trace("Executing findFirmwareInfoById [{}]", firmwareId); | ||
114 | + validateId(firmwareId, INCORRECT_FIRMWARE_ID + firmwareId); | ||
115 | + return firmwareInfoDao.findById(tenantId, firmwareId.getId()); | ||
116 | + } | ||
117 | + | ||
118 | + @Override | ||
119 | + public PageData<FirmwareInfo> findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink) { | ||
120 | + log.trace("Executing findTenantFirmwaresByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); | ||
121 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
122 | + validatePageLink(pageLink); | ||
123 | + return firmwareInfoDao.findFirmwareInfoByTenantId(tenantId, pageLink); | ||
124 | + } | ||
125 | + | ||
126 | + @Override | ||
127 | + public PageData<FirmwareInfo> findTenantFirmwaresByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink) { | ||
128 | + log.trace("Executing findTenantFirmwaresByTenantIdAndHasData, tenantId [{}], hasData [{}] pageLink [{}]", tenantId, hasData, pageLink); | ||
129 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
130 | + validatePageLink(pageLink); | ||
131 | + return firmwareInfoDao.findFirmwareInfoByTenantIdAndHasData(tenantId, hasData, pageLink); | ||
132 | + } | ||
133 | + | ||
134 | + @Override | ||
135 | + public void deleteFirmware(TenantId tenantId, FirmwareId firmwareId) { | ||
136 | + log.trace("Executing deleteFirmware [{}]", firmwareId); | ||
137 | + validateId(firmwareId, INCORRECT_FIRMWARE_ID + firmwareId); | ||
138 | + try { | ||
139 | + Cache cache = cacheManager.getCache(FIRMWARE_CACHE); | ||
140 | + cache.evict(Collections.singletonList(firmwareId)); | ||
141 | + firmwareDao.removeById(tenantId, firmwareId.getId()); | ||
142 | + } catch (Exception t) { | ||
143 | + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); | ||
144 | + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_firmware_device")) { | ||
145 | + throw new DataValidationException("The firmware referenced by the devices cannot be deleted!"); | ||
146 | + } else if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_firmware_device_profile")) { | ||
147 | + throw new DataValidationException("The firmware referenced by the device profile cannot be deleted!"); | ||
148 | + } else { | ||
149 | + throw t; | ||
150 | + } | ||
151 | + } | ||
152 | + } | ||
153 | + | ||
154 | + @Override | ||
155 | + public void deleteFirmwaresByTenantId(TenantId tenantId) { | ||
156 | + log.trace("Executing deleteFirmwaresByTenantId, tenantId [{}]", tenantId); | ||
157 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
158 | + tenantFirmwareRemover.removeEntities(tenantId, tenantId); | ||
159 | + } | ||
160 | + | ||
161 | + private DataValidator<FirmwareInfo> firmwareInfoValidator = new DataValidator<>() { | ||
162 | + | ||
163 | + @Override | ||
164 | + protected void validateDataImpl(TenantId tenantId, FirmwareInfo firmware) { | ||
165 | + if (firmware.getTenantId() == null) { | ||
166 | + throw new DataValidationException("Firmware should be assigned to tenant!"); | ||
167 | + } else { | ||
168 | + Tenant tenant = tenantDao.findById(firmware.getTenantId(), firmware.getTenantId().getId()); | ||
169 | + if (tenant == null) { | ||
170 | + throw new DataValidationException("Firmware is referencing to non-existent tenant!"); | ||
171 | + } | ||
172 | + } | ||
173 | + | ||
174 | + if (StringUtils.isEmpty(firmware.getTitle())) { | ||
175 | + throw new DataValidationException("Firmware title should be specified!"); | ||
176 | + } | ||
177 | + | ||
178 | + if (StringUtils.isEmpty(firmware.getVersion())) { | ||
179 | + throw new DataValidationException("Firmware version should be specified!"); | ||
180 | + } | ||
181 | + } | ||
182 | + | ||
183 | + @Override | ||
184 | + protected void validateUpdate(TenantId tenantId, FirmwareInfo firmware) { | ||
185 | + FirmwareInfo firmwareOld = firmwareInfoDao.findById(tenantId, firmware.getUuidId()); | ||
186 | + | ||
187 | + BaseFirmwareService.validateUpdate(firmware, firmwareOld); | ||
188 | + } | ||
189 | + }; | ||
190 | + | ||
191 | + private DataValidator<Firmware> firmwareValidator = new DataValidator<>() { | ||
192 | + | ||
193 | + @Override | ||
194 | + protected void validateDataImpl(TenantId tenantId, Firmware firmware) { | ||
195 | + if (firmware.getTenantId() == null) { | ||
196 | + throw new DataValidationException("Firmware should be assigned to tenant!"); | ||
197 | + } else { | ||
198 | + Tenant tenant = tenantDao.findById(firmware.getTenantId(), firmware.getTenantId().getId()); | ||
199 | + if (tenant == null) { | ||
200 | + throw new DataValidationException("Firmware is referencing to non-existent tenant!"); | ||
201 | + } | ||
202 | + } | ||
203 | + | ||
204 | + if (StringUtils.isEmpty(firmware.getTitle())) { | ||
205 | + throw new DataValidationException("Firmware title should be specified!"); | ||
206 | + } | ||
207 | + | ||
208 | + if (StringUtils.isEmpty(firmware.getVersion())) { | ||
209 | + throw new DataValidationException("Firmware version should be specified!"); | ||
210 | + } | ||
211 | + | ||
212 | + if (StringUtils.isEmpty(firmware.getFileName())) { | ||
213 | + throw new DataValidationException("Firmware file name should be specified!"); | ||
214 | + } | ||
215 | + | ||
216 | + if (StringUtils.isEmpty(firmware.getContentType())) { | ||
217 | + throw new DataValidationException("Firmware content type should be specified!"); | ||
218 | + } | ||
219 | + | ||
220 | + ByteBuffer data = firmware.getData(); | ||
221 | + if (data == null || !data.hasArray() || data.array().length == 0) { | ||
222 | + throw new DataValidationException("Firmware data should be specified!"); | ||
223 | + } | ||
224 | + | ||
225 | + if (StringUtils.isEmpty(firmware.getChecksumAlgorithm())) { | ||
226 | + throw new DataValidationException("Firmware checksum algorithm should be specified!"); | ||
227 | + } | ||
228 | + if (StringUtils.isEmpty(firmware.getChecksum())) { | ||
229 | + throw new DataValidationException("Firmware checksum should be specified!"); | ||
230 | + } | ||
231 | + | ||
232 | + HashFunction hashFunction; | ||
233 | + switch (firmware.getChecksumAlgorithm()) { | ||
234 | + case "sha256": | ||
235 | + hashFunction = Hashing.sha256(); | ||
236 | + break; | ||
237 | + case "md5": | ||
238 | + hashFunction = Hashing.md5(); | ||
239 | + break; | ||
240 | + case "crc32": | ||
241 | + hashFunction = Hashing.crc32(); | ||
242 | + break; | ||
243 | + default: | ||
244 | + throw new DataValidationException("Unknown checksum algorithm!"); | ||
245 | + } | ||
246 | + | ||
247 | + String currentChecksum = hashFunction.hashBytes(data.array()).toString(); | ||
248 | + | ||
249 | + if (!currentChecksum.equals(firmware.getChecksum())) { | ||
250 | + throw new DataValidationException("Wrong firmware file!"); | ||
251 | + } | ||
252 | + } | ||
253 | + | ||
254 | + @Override | ||
255 | + protected void validateUpdate(TenantId tenantId, Firmware firmware) { | ||
256 | + Firmware firmwareOld = firmwareDao.findById(tenantId, firmware.getUuidId()); | ||
257 | + | ||
258 | + BaseFirmwareService.validateUpdate(firmware, firmwareOld); | ||
259 | + | ||
260 | + if (firmwareOld.getData() != null && !firmwareOld.getData().equals(firmware.getData())) { | ||
261 | + throw new DataValidationException("Updating firmware data is prohibited!"); | ||
262 | + } | ||
263 | + } | ||
264 | + }; | ||
265 | + | ||
266 | + private static void validateUpdate(FirmwareInfo firmware, FirmwareInfo firmwareOld) { | ||
267 | + if (!firmwareOld.getTitle().equals(firmware.getTitle())) { | ||
268 | + throw new DataValidationException("Updating firmware title is prohibited!"); | ||
269 | + } | ||
270 | + | ||
271 | + if (!firmwareOld.getVersion().equals(firmware.getVersion())) { | ||
272 | + throw new DataValidationException("Updating firmware version is prohibited!"); | ||
273 | + } | ||
274 | + | ||
275 | + if (firmwareOld.getFileName() != null && !firmwareOld.getFileName().equals(firmware.getFileName())) { | ||
276 | + throw new DataValidationException("Updating firmware file name is prohibited!"); | ||
277 | + } | ||
278 | + | ||
279 | + if (firmwareOld.getContentType() != null && !firmwareOld.getContentType().equals(firmware.getContentType())) { | ||
280 | + throw new DataValidationException("Updating firmware content type is prohibited!"); | ||
281 | + } | ||
282 | + | ||
283 | + if (firmwareOld.getChecksumAlgorithm() != null && !firmwareOld.getChecksumAlgorithm().equals(firmware.getChecksumAlgorithm())) { | ||
284 | + throw new DataValidationException("Updating firmware content type is prohibited!"); | ||
285 | + } | ||
286 | + | ||
287 | + if (firmwareOld.getChecksum() != null && !firmwareOld.getChecksum().equals(firmware.getChecksum())) { | ||
288 | + throw new DataValidationException("Updating firmware content type is prohibited!"); | ||
289 | + } | ||
290 | + | ||
291 | + if (firmwareOld.getDataSize() != null && !firmwareOld.getDataSize().equals(firmware.getDataSize())) { | ||
292 | + throw new DataValidationException("Updating firmware data size is prohibited!"); | ||
293 | + } | ||
294 | + } | ||
295 | + | ||
296 | + private PaginatedRemover<TenantId, FirmwareInfo> tenantFirmwareRemover = | ||
297 | + new PaginatedRemover<>() { | ||
298 | + | ||
299 | + @Override | ||
300 | + protected PageData<FirmwareInfo> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { | ||
301 | + return firmwareInfoDao.findFirmwareInfoByTenantId(id, pageLink); | ||
302 | + } | ||
303 | + | ||
304 | + @Override | ||
305 | + protected void removeEntity(TenantId tenantId, FirmwareInfo entity) { | ||
306 | + deleteFirmware(tenantId, entity.getId()); | ||
307 | + } | ||
308 | + }; | ||
309 | + | ||
310 | + protected Optional<ConstraintViolationException> extractConstraintViolationException(Exception t) { | ||
311 | + if (t instanceof ConstraintViolationException) { | ||
312 | + return Optional.of((ConstraintViolationException) t); | ||
313 | + } else if (t.getCause() instanceof ConstraintViolationException) { | ||
314 | + return Optional.of((ConstraintViolationException) (t.getCause())); | ||
315 | + } else { | ||
316 | + return Optional.empty(); | ||
317 | + } | ||
318 | + } | ||
319 | +} |
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.dao.firmware; | ||
17 | + | ||
18 | +import org.thingsboard.server.common.data.Firmware; | ||
19 | +import org.thingsboard.server.dao.Dao; | ||
20 | + | ||
21 | +public interface FirmwareDao extends Dao<Firmware> { | ||
22 | + | ||
23 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.dao.firmware; | ||
17 | + | ||
18 | +import org.thingsboard.server.common.data.FirmwareInfo; | ||
19 | +import org.thingsboard.server.common.data.id.TenantId; | ||
20 | +import org.thingsboard.server.common.data.page.PageData; | ||
21 | +import org.thingsboard.server.common.data.page.PageLink; | ||
22 | +import org.thingsboard.server.dao.Dao; | ||
23 | + | ||
24 | +import java.util.UUID; | ||
25 | + | ||
26 | +public interface FirmwareInfoDao extends Dao<FirmwareInfo> { | ||
27 | + | ||
28 | + PageData<FirmwareInfo> findFirmwareInfoByTenantId(TenantId tenantId, PageLink pageLink); | ||
29 | + | ||
30 | + PageData<FirmwareInfo> findFirmwareInfoByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink); | ||
31 | + | ||
32 | +} |
@@ -153,6 +153,7 @@ public class ModelConstants { | @@ -153,6 +153,7 @@ public class ModelConstants { | ||
153 | public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; | 153 | public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; |
154 | public static final String DEVICE_DEVICE_PROFILE_ID_PROPERTY = "device_profile_id"; | 154 | public static final String DEVICE_DEVICE_PROFILE_ID_PROPERTY = "device_profile_id"; |
155 | public static final String DEVICE_DEVICE_DATA_PROPERTY = "device_data"; | 155 | public static final String DEVICE_DEVICE_DATA_PROPERTY = "device_data"; |
156 | + public static final String DEVICE_FIRMWARE_ID_PROPERTY = "firmware_id"; | ||
156 | 157 | ||
157 | public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text"; | 158 | public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text"; |
158 | public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text"; | 159 | public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text"; |
@@ -176,6 +177,7 @@ public class ModelConstants { | @@ -176,6 +177,7 @@ public class ModelConstants { | ||
176 | public static final String DEVICE_PROFILE_DEFAULT_RULE_CHAIN_ID_PROPERTY = "default_rule_chain_id"; | 177 | public static final String DEVICE_PROFILE_DEFAULT_RULE_CHAIN_ID_PROPERTY = "default_rule_chain_id"; |
177 | public static final String DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY = "default_queue_name"; | 178 | public static final String DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY = "default_queue_name"; |
178 | public static final String DEVICE_PROFILE_PROVISION_DEVICE_KEY = "provision_device_key"; | 179 | public static final String DEVICE_PROFILE_PROVISION_DEVICE_KEY = "provision_device_key"; |
180 | + public static final String DEVICE_PROFILE_FIRMWARE_ID_PROPERTY = "firmware_id"; | ||
179 | 181 | ||
180 | /** | 182 | /** |
181 | * Cassandra entityView constants. | 183 | * Cassandra entityView constants. |
@@ -470,6 +472,22 @@ public class ModelConstants { | @@ -470,6 +472,22 @@ public class ModelConstants { | ||
470 | public static final String RESOURCE_DATA_COLUMN = "data"; | 472 | public static final String RESOURCE_DATA_COLUMN = "data"; |
471 | 473 | ||
472 | /** | 474 | /** |
475 | + * Firmware constants. | ||
476 | + */ | ||
477 | + public static final String FIRMWARE_TABLE_NAME = "firmware"; | ||
478 | + public static final String FIRMWARE_TENANT_ID_COLUMN = TENANT_ID_COLUMN; | ||
479 | + public static final String FIRMWARE_TITLE_COLUMN = TITLE_PROPERTY; | ||
480 | + public static final String FIRMWARE_VERSION_COLUMN = "version"; | ||
481 | + public static final String FIRMWARE_FILE_NAME_COLUMN = "file_name"; | ||
482 | + public static final String FIRMWARE_CONTENT_TYPE_COLUMN = "content_type"; | ||
483 | + public static final String FIRMWARE_CHECKSUM_ALGORITHM_COLUMN = "checksum_algorithm"; | ||
484 | + public static final String FIRMWARE_CHECKSUM_COLUMN = "checksum"; | ||
485 | + public static final String FIRMWARE_DATA_COLUMN = "data"; | ||
486 | + public static final String FIRMWARE_DATA_SIZE_COLUMN = "data_size"; | ||
487 | + public static final String FIRMWARE_ADDITIONAL_INFO_COLUMN = ADDITIONAL_INFO_PROPERTY; | ||
488 | + public static final String FIRMWARE_HAS_DATA_PROPERTY = "has_data"; | ||
489 | + | ||
490 | + /** | ||
473 | * Edge constants. | 491 | * Edge constants. |
474 | */ | 492 | */ |
475 | public static final String EDGE_COLUMN_FAMILY_NAME = "edge"; | 493 | public static final String EDGE_COLUMN_FAMILY_NAME = "edge"; |
@@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.device.data.DeviceData; | @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.device.data.DeviceData; | ||
27 | import org.thingsboard.server.common.data.id.CustomerId; | 27 | import org.thingsboard.server.common.data.id.CustomerId; |
28 | import org.thingsboard.server.common.data.id.DeviceId; | 28 | import org.thingsboard.server.common.data.id.DeviceId; |
29 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 29 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
30 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
30 | import org.thingsboard.server.common.data.id.TenantId; | 31 | import org.thingsboard.server.common.data.id.TenantId; |
31 | import org.thingsboard.server.dao.model.BaseSqlEntity; | 32 | import org.thingsboard.server.dao.model.BaseSqlEntity; |
32 | import org.thingsboard.server.dao.model.ModelConstants; | 33 | import org.thingsboard.server.dao.model.ModelConstants; |
@@ -73,6 +74,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti | @@ -73,6 +74,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti | ||
73 | @Column(name = ModelConstants.DEVICE_DEVICE_PROFILE_ID_PROPERTY, columnDefinition = "uuid") | 74 | @Column(name = ModelConstants.DEVICE_DEVICE_PROFILE_ID_PROPERTY, columnDefinition = "uuid") |
74 | private UUID deviceProfileId; | 75 | private UUID deviceProfileId; |
75 | 76 | ||
77 | + @Column(name = ModelConstants.DEVICE_FIRMWARE_ID_PROPERTY, columnDefinition = "uuid") | ||
78 | + private UUID firmwareId; | ||
79 | + | ||
76 | @Type(type = "jsonb") | 80 | @Type(type = "jsonb") |
77 | @Column(name = ModelConstants.DEVICE_DEVICE_DATA_PROPERTY, columnDefinition = "jsonb") | 81 | @Column(name = ModelConstants.DEVICE_DEVICE_DATA_PROPERTY, columnDefinition = "jsonb") |
78 | private JsonNode deviceData; | 82 | private JsonNode deviceData; |
@@ -95,6 +99,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti | @@ -95,6 +99,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti | ||
95 | if (device.getDeviceProfileId() != null) { | 99 | if (device.getDeviceProfileId() != null) { |
96 | this.deviceProfileId = device.getDeviceProfileId().getId(); | 100 | this.deviceProfileId = device.getDeviceProfileId().getId(); |
97 | } | 101 | } |
102 | + if (device.getFirmwareId() != null) { | ||
103 | + this.firmwareId = device.getFirmwareId().getId(); | ||
104 | + } | ||
98 | this.deviceData = JacksonUtil.convertValue(device.getDeviceData(), ObjectNode.class); | 105 | this.deviceData = JacksonUtil.convertValue(device.getDeviceData(), ObjectNode.class); |
99 | this.name = device.getName(); | 106 | this.name = device.getName(); |
100 | this.type = device.getType(); | 107 | this.type = device.getType(); |
@@ -114,6 +121,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti | @@ -114,6 +121,7 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti | ||
114 | this.label = deviceEntity.getLabel(); | 121 | this.label = deviceEntity.getLabel(); |
115 | this.searchText = deviceEntity.getSearchText(); | 122 | this.searchText = deviceEntity.getSearchText(); |
116 | this.additionalInfo = deviceEntity.getAdditionalInfo(); | 123 | this.additionalInfo = deviceEntity.getAdditionalInfo(); |
124 | + this.firmwareId = deviceEntity.getFirmwareId(); | ||
117 | } | 125 | } |
118 | 126 | ||
119 | @Override | 127 | @Override |
@@ -138,6 +146,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti | @@ -138,6 +146,9 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti | ||
138 | if (deviceProfileId != null) { | 146 | if (deviceProfileId != null) { |
139 | device.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); | 147 | device.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); |
140 | } | 148 | } |
149 | + if (firmwareId != null) { | ||
150 | + device.setFirmwareId(new FirmwareId(firmwareId)); | ||
151 | + } | ||
141 | device.setDeviceData(JacksonUtil.convertValue(deviceData, DeviceData.class)); | 152 | device.setDeviceData(JacksonUtil.convertValue(deviceData, DeviceData.class)); |
142 | device.setName(name); | 153 | device.setName(name); |
143 | device.setType(type); | 154 | device.setType(type); |
@@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.DeviceProfileProvisionType; | @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.DeviceProfileProvisionType; | ||
27 | import org.thingsboard.server.common.data.DeviceTransportType; | 27 | import org.thingsboard.server.common.data.DeviceTransportType; |
28 | import org.thingsboard.server.common.data.device.profile.DeviceProfileData; | 28 | import org.thingsboard.server.common.data.device.profile.DeviceProfileData; |
29 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 29 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
30 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
30 | import org.thingsboard.server.common.data.id.RuleChainId; | 31 | import org.thingsboard.server.common.data.id.RuleChainId; |
31 | import org.thingsboard.server.common.data.id.TenantId; | 32 | import org.thingsboard.server.common.data.id.TenantId; |
32 | import org.thingsboard.server.dao.model.BaseSqlEntity; | 33 | import org.thingsboard.server.dao.model.BaseSqlEntity; |
@@ -89,6 +90,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl | @@ -89,6 +90,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl | ||
89 | @Column(name=ModelConstants.DEVICE_PROFILE_PROVISION_DEVICE_KEY) | 90 | @Column(name=ModelConstants.DEVICE_PROFILE_PROVISION_DEVICE_KEY) |
90 | private String provisionDeviceKey; | 91 | private String provisionDeviceKey; |
91 | 92 | ||
93 | + @Column(name=ModelConstants.DEVICE_PROFILE_FIRMWARE_ID_PROPERTY) | ||
94 | + private UUID firmwareId; | ||
95 | + | ||
92 | public DeviceProfileEntity() { | 96 | public DeviceProfileEntity() { |
93 | super(); | 97 | super(); |
94 | } | 98 | } |
@@ -113,6 +117,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl | @@ -113,6 +117,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl | ||
113 | } | 117 | } |
114 | this.defaultQueueName = deviceProfile.getDefaultQueueName(); | 118 | this.defaultQueueName = deviceProfile.getDefaultQueueName(); |
115 | this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey(); | 119 | this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey(); |
120 | + if (deviceProfile.getFirmwareId() != null) { | ||
121 | + this.firmwareId = deviceProfile.getFirmwareId().getId(); | ||
122 | + } | ||
116 | } | 123 | } |
117 | 124 | ||
118 | @Override | 125 | @Override |
@@ -148,6 +155,11 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl | @@ -148,6 +155,11 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl | ||
148 | } | 155 | } |
149 | deviceProfile.setDefaultQueueName(defaultQueueName); | 156 | deviceProfile.setDefaultQueueName(defaultQueueName); |
150 | deviceProfile.setProvisionDeviceKey(provisionDeviceKey); | 157 | deviceProfile.setProvisionDeviceKey(provisionDeviceKey); |
158 | + | ||
159 | + if (firmwareId != null) { | ||
160 | + deviceProfile.setFirmwareId(new FirmwareId(firmwareId)); | ||
161 | + } | ||
162 | + | ||
151 | return deviceProfile; | 163 | return deviceProfile; |
152 | } | 164 | } |
153 | } | 165 | } |
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.dao.model.sql; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.JsonNode; | ||
19 | +import lombok.Data; | ||
20 | +import lombok.EqualsAndHashCode; | ||
21 | +import org.hibernate.annotations.Type; | ||
22 | +import org.hibernate.annotations.TypeDef; | ||
23 | +import org.thingsboard.server.common.data.Firmware; | ||
24 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
25 | +import org.thingsboard.server.common.data.id.TenantId; | ||
26 | +import org.thingsboard.server.dao.model.BaseSqlEntity; | ||
27 | +import org.thingsboard.server.dao.model.ModelConstants; | ||
28 | +import org.thingsboard.server.dao.model.SearchTextEntity; | ||
29 | +import org.thingsboard.server.dao.util.mapping.JsonStringType; | ||
30 | + | ||
31 | +import javax.persistence.Column; | ||
32 | +import javax.persistence.Entity; | ||
33 | +import javax.persistence.Table; | ||
34 | +import java.nio.ByteBuffer; | ||
35 | +import java.util.UUID; | ||
36 | + | ||
37 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_ALGORITHM_COLUMN; | ||
38 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_COLUMN; | ||
39 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CONTENT_TYPE_COLUMN; | ||
40 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_COLUMN; | ||
41 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_SIZE_COLUMN; | ||
42 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME_COLUMN; | ||
43 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME; | ||
44 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN; | ||
45 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN; | ||
46 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_VERSION_COLUMN; | ||
47 | +import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; | ||
48 | + | ||
49 | +@Data | ||
50 | +@EqualsAndHashCode(callSuper = true) | ||
51 | +@Entity | ||
52 | +@TypeDef(name = "json", typeClass = JsonStringType.class) | ||
53 | +@Table(name = FIRMWARE_TABLE_NAME) | ||
54 | +public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTextEntity<Firmware> { | ||
55 | + | ||
56 | + @Column(name = FIRMWARE_TENANT_ID_COLUMN) | ||
57 | + private UUID tenantId; | ||
58 | + | ||
59 | + @Column(name = FIRMWARE_TITLE_COLUMN) | ||
60 | + private String title; | ||
61 | + | ||
62 | + @Column(name = FIRMWARE_VERSION_COLUMN) | ||
63 | + private String version; | ||
64 | + | ||
65 | + @Column(name = FIRMWARE_FILE_NAME_COLUMN) | ||
66 | + private String fileName; | ||
67 | + | ||
68 | + @Column(name = FIRMWARE_CONTENT_TYPE_COLUMN) | ||
69 | + private String contentType; | ||
70 | + | ||
71 | + @Column(name = FIRMWARE_CHECKSUM_ALGORITHM_COLUMN) | ||
72 | + private String checksumAlgorithm; | ||
73 | + | ||
74 | + @Column(name = FIRMWARE_CHECKSUM_COLUMN) | ||
75 | + private String checksum; | ||
76 | + | ||
77 | + @Column(name = FIRMWARE_DATA_COLUMN, columnDefinition = "BINARY") | ||
78 | + private byte[] data; | ||
79 | + | ||
80 | + @Column(name = FIRMWARE_DATA_SIZE_COLUMN) | ||
81 | + private Long dataSize; | ||
82 | + | ||
83 | + @Type(type = "json") | ||
84 | + @Column(name = ModelConstants.FIRMWARE_ADDITIONAL_INFO_COLUMN) | ||
85 | + private JsonNode additionalInfo; | ||
86 | + | ||
87 | + @Column(name = SEARCH_TEXT_PROPERTY) | ||
88 | + private String searchText; | ||
89 | + | ||
90 | + public FirmwareEntity() { | ||
91 | + super(); | ||
92 | + } | ||
93 | + | ||
94 | + public FirmwareEntity(Firmware firmware) { | ||
95 | + this.createdTime = firmware.getCreatedTime(); | ||
96 | + this.setUuid(firmware.getUuidId()); | ||
97 | + this.tenantId = firmware.getTenantId().getId(); | ||
98 | + this.title = firmware.getTitle(); | ||
99 | + this.version = firmware.getVersion(); | ||
100 | + this.fileName = firmware.getFileName(); | ||
101 | + this.contentType = firmware.getContentType(); | ||
102 | + this.checksumAlgorithm = firmware.getChecksumAlgorithm(); | ||
103 | + this.checksum = firmware.getChecksum(); | ||
104 | + this.data = firmware.getData().array(); | ||
105 | + this.dataSize = firmware.getDataSize(); | ||
106 | + this.additionalInfo = firmware.getAdditionalInfo(); | ||
107 | + } | ||
108 | + | ||
109 | + @Override | ||
110 | + public String getSearchTextSource() { | ||
111 | + return title; | ||
112 | + } | ||
113 | + | ||
114 | + @Override | ||
115 | + public void setSearchText(String searchText) { | ||
116 | + this.searchText = searchText; | ||
117 | + } | ||
118 | + | ||
119 | + @Override | ||
120 | + public Firmware toData() { | ||
121 | + Firmware firmware = new Firmware(new FirmwareId(id)); | ||
122 | + firmware.setCreatedTime(createdTime); | ||
123 | + firmware.setTenantId(new TenantId(tenantId)); | ||
124 | + firmware.setTitle(title); | ||
125 | + firmware.setVersion(version); | ||
126 | + firmware.setFileName(fileName); | ||
127 | + firmware.setContentType(contentType); | ||
128 | + firmware.setChecksumAlgorithm(checksumAlgorithm); | ||
129 | + firmware.setChecksum(checksum); | ||
130 | + firmware.setDataSize(dataSize); | ||
131 | + if (data != null) { | ||
132 | + firmware.setData(ByteBuffer.wrap(data)); | ||
133 | + firmware.setHasData(true); | ||
134 | + } | ||
135 | + firmware.setAdditionalInfo(additionalInfo); | ||
136 | + return firmware; | ||
137 | + } | ||
138 | +} |
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.dao.model.sql; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.JsonNode; | ||
19 | +import lombok.Data; | ||
20 | +import lombok.EqualsAndHashCode; | ||
21 | +import org.hibernate.annotations.Type; | ||
22 | +import org.hibernate.annotations.TypeDef; | ||
23 | +import org.thingsboard.common.util.JacksonUtil; | ||
24 | +import org.thingsboard.server.common.data.FirmwareInfo; | ||
25 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
26 | +import org.thingsboard.server.common.data.id.TenantId; | ||
27 | +import org.thingsboard.server.dao.model.BaseSqlEntity; | ||
28 | +import org.thingsboard.server.dao.model.ModelConstants; | ||
29 | +import org.thingsboard.server.dao.model.SearchTextEntity; | ||
30 | +import org.thingsboard.server.dao.util.mapping.JsonStringType; | ||
31 | + | ||
32 | +import javax.persistence.Column; | ||
33 | +import javax.persistence.Entity; | ||
34 | +import javax.persistence.Table; | ||
35 | +import javax.persistence.Transient; | ||
36 | +import java.util.UUID; | ||
37 | + | ||
38 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_ALGORITHM_COLUMN; | ||
39 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_COLUMN; | ||
40 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CONTENT_TYPE_COLUMN; | ||
41 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_COLUMN; | ||
42 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_SIZE_COLUMN; | ||
43 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME_COLUMN; | ||
44 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_HAS_DATA_PROPERTY; | ||
45 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME; | ||
46 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN; | ||
47 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN; | ||
48 | +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_VERSION_COLUMN; | ||
49 | +import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; | ||
50 | + | ||
51 | +@Data | ||
52 | +@EqualsAndHashCode(callSuper = true) | ||
53 | +@Entity | ||
54 | +@TypeDef(name = "json", typeClass = JsonStringType.class) | ||
55 | +@Table(name = FIRMWARE_TABLE_NAME) | ||
56 | +public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements SearchTextEntity<FirmwareInfo> { | ||
57 | + | ||
58 | + @Column(name = FIRMWARE_TENANT_ID_COLUMN) | ||
59 | + private UUID tenantId; | ||
60 | + | ||
61 | + @Column(name = FIRMWARE_TITLE_COLUMN) | ||
62 | + private String title; | ||
63 | + | ||
64 | + @Column(name = FIRMWARE_VERSION_COLUMN) | ||
65 | + private String version; | ||
66 | + | ||
67 | + @Column(name = FIRMWARE_FILE_NAME_COLUMN) | ||
68 | + private String fileName; | ||
69 | + | ||
70 | + @Column(name = FIRMWARE_CONTENT_TYPE_COLUMN) | ||
71 | + private String contentType; | ||
72 | + | ||
73 | + @Column(name = FIRMWARE_CHECKSUM_ALGORITHM_COLUMN) | ||
74 | + private String checksumAlgorithm; | ||
75 | + | ||
76 | + @Column(name = FIRMWARE_CHECKSUM_COLUMN) | ||
77 | + private String checksum; | ||
78 | + | ||
79 | + @Column(name = FIRMWARE_DATA_SIZE_COLUMN) | ||
80 | + private Long dataSize; | ||
81 | + | ||
82 | + @Type(type = "json") | ||
83 | + @Column(name = ModelConstants.FIRMWARE_ADDITIONAL_INFO_COLUMN) | ||
84 | + private JsonNode additionalInfo; | ||
85 | + | ||
86 | + @Column(name = SEARCH_TEXT_PROPERTY) | ||
87 | + private String searchText; | ||
88 | + | ||
89 | + @Transient | ||
90 | + private boolean hasData; | ||
91 | + | ||
92 | + public FirmwareInfoEntity() { | ||
93 | + super(); | ||
94 | + } | ||
95 | + | ||
96 | + public FirmwareInfoEntity(FirmwareInfo firmware) { | ||
97 | + this.createdTime = firmware.getCreatedTime(); | ||
98 | + this.setUuid(firmware.getUuidId()); | ||
99 | + this.tenantId = firmware.getTenantId().getId(); | ||
100 | + this.title = firmware.getTitle(); | ||
101 | + this.version = firmware.getVersion(); | ||
102 | + this.fileName = firmware.getFileName(); | ||
103 | + this.contentType = firmware.getContentType(); | ||
104 | + this.checksumAlgorithm = firmware.getChecksumAlgorithm(); | ||
105 | + this.checksum = firmware.getChecksum(); | ||
106 | + this.dataSize = firmware.getDataSize(); | ||
107 | + this.additionalInfo = firmware.getAdditionalInfo(); | ||
108 | + } | ||
109 | + | ||
110 | + public FirmwareInfoEntity(UUID id, long createdTime, UUID tenantId, String title, String version, | ||
111 | + String fileName, String contentType, String checksumAlgorithm, String checksum, Long dataSize, | ||
112 | + Object additionalInfo, boolean hasData) { | ||
113 | + this.id = id; | ||
114 | + this.createdTime = createdTime; | ||
115 | + this.tenantId = tenantId; | ||
116 | + this.title = title; | ||
117 | + this.version = version; | ||
118 | + this.fileName = fileName; | ||
119 | + this.contentType = contentType; | ||
120 | + this.checksumAlgorithm = checksumAlgorithm; | ||
121 | + this.checksum = checksum; | ||
122 | + this.dataSize = dataSize; | ||
123 | + this.hasData = hasData; | ||
124 | + this.additionalInfo = JacksonUtil.convertValue(additionalInfo, JsonNode.class); | ||
125 | + } | ||
126 | + | ||
127 | + @Override | ||
128 | + public String getSearchTextSource() { | ||
129 | + return title; | ||
130 | + } | ||
131 | + | ||
132 | + @Override | ||
133 | + public void setSearchText(String searchText) { | ||
134 | + this.searchText = searchText; | ||
135 | + } | ||
136 | + | ||
137 | + @Override | ||
138 | + public FirmwareInfo toData() { | ||
139 | + FirmwareInfo firmware = new FirmwareInfo(new FirmwareId(id)); | ||
140 | + firmware.setCreatedTime(createdTime); | ||
141 | + firmware.setTenantId(new TenantId(tenantId)); | ||
142 | + firmware.setTitle(title); | ||
143 | + firmware.setVersion(version); | ||
144 | + firmware.setFileName(fileName); | ||
145 | + firmware.setContentType(contentType); | ||
146 | + firmware.setChecksumAlgorithm(checksumAlgorithm); | ||
147 | + firmware.setChecksum(checksum); | ||
148 | + firmware.setDataSize(dataSize); | ||
149 | + firmware.setAdditionalInfo(additionalInfo); | ||
150 | + firmware.setHasData(hasData); | ||
151 | + return firmware; | ||
152 | + } | ||
153 | +} |
@@ -94,6 +94,15 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit | @@ -94,6 +94,15 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit | ||
94 | @Param("textSearch") String textSearch, | 94 | @Param("textSearch") String textSearch, |
95 | Pageable pageable); | 95 | Pageable pageable); |
96 | 96 | ||
97 | + @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + | ||
98 | + "AND d.type = :type " + | ||
99 | + "AND d.firmwareId = null " + | ||
100 | + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") | ||
101 | + Page<DeviceEntity> findByTenantIdAndTypeAndFirmwareIdIsNull(@Param("tenantId") UUID tenantId, | ||
102 | + @Param("type") String type, | ||
103 | + @Param("textSearch") String textSearch, | ||
104 | + Pageable pageable); | ||
105 | + | ||
97 | @Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo, p.name) " + | 106 | @Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo, p.name) " + |
98 | "FROM DeviceEntity d " + | 107 | "FROM DeviceEntity d " + |
99 | "LEFT JOIN CustomerEntity c on c.id = d.customerId " + | 108 | "LEFT JOIN CustomerEntity c on c.id = d.customerId " + |
@@ -150,6 +150,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> | @@ -150,6 +150,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> | ||
150 | } | 150 | } |
151 | 151 | ||
152 | @Override | 152 | @Override |
153 | + public PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(UUID tenantId, String type, PageLink pageLink) { | ||
154 | + return DaoUtil.toPageData( | ||
155 | + deviceRepository.findByTenantIdAndTypeAndFirmwareIdIsNull( | ||
156 | + tenantId, | ||
157 | + type, | ||
158 | + Objects.toString(pageLink.getTextSearch(), ""), | ||
159 | + DaoUtil.toPageable(pageLink))); | ||
160 | + } | ||
161 | + | ||
162 | + @Override | ||
153 | public PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(UUID tenantId, String type, PageLink pageLink) { | 163 | public PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(UUID tenantId, String type, PageLink pageLink) { |
154 | return DaoUtil.toPageData( | 164 | return DaoUtil.toPageData( |
155 | deviceRepository.findDeviceInfosByTenantIdAndType( | 165 | deviceRepository.findDeviceInfosByTenantIdAndType( |
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.dao.sql.firmware; | ||
17 | + | ||
18 | +import org.springframework.data.domain.Page; | ||
19 | +import org.springframework.data.domain.Pageable; | ||
20 | +import org.springframework.data.jpa.repository.Query; | ||
21 | +import org.springframework.data.repository.CrudRepository; | ||
22 | +import org.springframework.data.repository.query.Param; | ||
23 | +import org.thingsboard.server.dao.model.sql.FirmwareInfoEntity; | ||
24 | + | ||
25 | +import java.util.UUID; | ||
26 | + | ||
27 | +public interface FirmwareInfoRepository extends CrudRepository<FirmwareInfoEntity, UUID> { | ||
28 | + @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE " + | ||
29 | + "f.tenantId = :tenantId " + | ||
30 | + "AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") | ||
31 | + Page<FirmwareInfoEntity> findAllByTenantId(@Param("tenantId") UUID tenantId, | ||
32 | + @Param("searchText") String searchText, | ||
33 | + Pageable pageable); | ||
34 | + | ||
35 | + @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE " + | ||
36 | + "f.tenantId = :tenantId " + | ||
37 | + "AND ((f.data IS NOT NULL AND :hasData = true) OR (f.data IS NULL AND :hasData = false ))" + | ||
38 | + "AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") | ||
39 | + Page<FirmwareInfoEntity> findAllByTenantIdAndHasData(@Param("tenantId") UUID tenantId, | ||
40 | + @Param("hasData") boolean hasData, | ||
41 | + @Param("searchText") String searchText, | ||
42 | + Pageable pageable); | ||
43 | + | ||
44 | + @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE f.id = :id") | ||
45 | + FirmwareInfoEntity findFirmwareInfoById(@Param("id") UUID id); | ||
46 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.dao.sql.firmware; | ||
17 | + | ||
18 | +import org.springframework.data.repository.CrudRepository; | ||
19 | +import org.thingsboard.server.dao.model.sql.FirmwareEntity; | ||
20 | + | ||
21 | +import java.util.UUID; | ||
22 | + | ||
23 | +public interface FirmwareRepository extends CrudRepository<FirmwareEntity, UUID> { | ||
24 | +} |
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.dao.sql.firmware; | ||
17 | + | ||
18 | +import lombok.extern.slf4j.Slf4j; | ||
19 | +import org.springframework.beans.factory.annotation.Autowired; | ||
20 | +import org.springframework.data.repository.CrudRepository; | ||
21 | +import org.springframework.stereotype.Component; | ||
22 | +import org.thingsboard.server.common.data.Firmware; | ||
23 | +import org.thingsboard.server.dao.firmware.FirmwareDao; | ||
24 | +import org.thingsboard.server.dao.model.sql.FirmwareEntity; | ||
25 | +import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; | ||
26 | + | ||
27 | +import java.util.UUID; | ||
28 | + | ||
29 | +@Slf4j | ||
30 | +@Component | ||
31 | +public class JpaFirmwareDao extends JpaAbstractSearchTextDao<FirmwareEntity, Firmware> implements FirmwareDao { | ||
32 | + | ||
33 | + @Autowired | ||
34 | + private FirmwareRepository firmwareRepository; | ||
35 | + | ||
36 | + @Override | ||
37 | + protected Class<FirmwareEntity> getEntityClass() { | ||
38 | + return FirmwareEntity.class; | ||
39 | + } | ||
40 | + | ||
41 | + @Override | ||
42 | + protected CrudRepository<FirmwareEntity, UUID> getCrudRepository() { | ||
43 | + return firmwareRepository; | ||
44 | + } | ||
45 | + | ||
46 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.dao.sql.firmware; | ||
17 | + | ||
18 | +import lombok.extern.slf4j.Slf4j; | ||
19 | +import org.springframework.beans.factory.annotation.Autowired; | ||
20 | +import org.springframework.data.repository.CrudRepository; | ||
21 | +import org.springframework.stereotype.Component; | ||
22 | +import org.thingsboard.server.common.data.FirmwareInfo; | ||
23 | +import org.thingsboard.server.common.data.id.TenantId; | ||
24 | +import org.thingsboard.server.common.data.page.PageData; | ||
25 | +import org.thingsboard.server.common.data.page.PageLink; | ||
26 | +import org.thingsboard.server.dao.DaoUtil; | ||
27 | +import org.thingsboard.server.dao.firmware.FirmwareInfoDao; | ||
28 | +import org.thingsboard.server.dao.model.sql.FirmwareInfoEntity; | ||
29 | +import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; | ||
30 | + | ||
31 | +import java.util.Objects; | ||
32 | +import java.util.UUID; | ||
33 | + | ||
34 | +@Slf4j | ||
35 | +@Component | ||
36 | +public class JpaFirmwareInfoDao extends JpaAbstractSearchTextDao<FirmwareInfoEntity, FirmwareInfo> implements FirmwareInfoDao { | ||
37 | + | ||
38 | + @Autowired | ||
39 | + private FirmwareInfoRepository firmwareInfoRepository; | ||
40 | + | ||
41 | + @Override | ||
42 | + protected Class<FirmwareInfoEntity> getEntityClass() { | ||
43 | + return FirmwareInfoEntity.class; | ||
44 | + } | ||
45 | + | ||
46 | + @Override | ||
47 | + protected CrudRepository<FirmwareInfoEntity, UUID> getCrudRepository() { | ||
48 | + return firmwareInfoRepository; | ||
49 | + } | ||
50 | + | ||
51 | + @Override | ||
52 | + public FirmwareInfo findById(TenantId tenantId, UUID id) { | ||
53 | + return DaoUtil.getData(firmwareInfoRepository.findFirmwareInfoById(id)); | ||
54 | + } | ||
55 | + | ||
56 | + @Override | ||
57 | + public FirmwareInfo save(TenantId tenantId, FirmwareInfo firmwareInfo) { | ||
58 | + FirmwareInfo savedFirmware = super.save(tenantId, firmwareInfo); | ||
59 | + if (firmwareInfo.getId() == null) { | ||
60 | + return savedFirmware; | ||
61 | + } else { | ||
62 | + return findById(tenantId, savedFirmware.getId().getId()); | ||
63 | + } | ||
64 | + } | ||
65 | + | ||
66 | + @Override | ||
67 | + public PageData<FirmwareInfo> findFirmwareInfoByTenantId(TenantId tenantId, PageLink pageLink) { | ||
68 | + return DaoUtil.toPageData(firmwareInfoRepository | ||
69 | + .findAllByTenantId( | ||
70 | + tenantId.getId(), | ||
71 | + Objects.toString(pageLink.getTextSearch(), ""), | ||
72 | + DaoUtil.toPageable(pageLink))); | ||
73 | + } | ||
74 | + | ||
75 | + @Override | ||
76 | + public PageData<FirmwareInfo> findFirmwareInfoByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink) { | ||
77 | + return DaoUtil.toPageData(firmwareInfoRepository | ||
78 | + .findAllByTenantIdAndHasData( | ||
79 | + tenantId.getId(), | ||
80 | + hasData, | ||
81 | + Objects.toString(pageLink.getTextSearch(), ""), | ||
82 | + DaoUtil.toPageable(pageLink))); | ||
83 | + } | ||
84 | +} |
@@ -48,8 +48,6 @@ public interface TbResourceRepository extends CrudRepository<TbResourceEntity, U | @@ -48,8 +48,6 @@ public interface TbResourceRepository extends CrudRepository<TbResourceEntity, U | ||
48 | @Param("searchText") String search, | 48 | @Param("searchText") String search, |
49 | Pageable pageable); | 49 | Pageable pageable); |
50 | 50 | ||
51 | - void removeAllByTenantId(UUID tenantId); | ||
52 | - | ||
53 | @Query("SELECT tr FROM TbResourceEntity tr " + | 51 | @Query("SELECT tr FROM TbResourceEntity tr " + |
54 | "WHERE tr.resourceType = :resourceType " + | 52 | "WHERE tr.resourceType = :resourceType " + |
55 | "AND LOWER(tr.searchText) LIKE LOWER(CONCAT('%', :searchText, '%')) " + | 53 | "AND LOWER(tr.searchText) LIKE LOWER(CONCAT('%', :searchText, '%')) " + |
@@ -158,6 +158,23 @@ CREATE TABLE IF NOT EXISTS rule_node_state ( | @@ -158,6 +158,23 @@ CREATE TABLE IF NOT EXISTS rule_node_state ( | ||
158 | CONSTRAINT fk_rule_node_state_node_id FOREIGN KEY (rule_node_id) REFERENCES rule_node(id) ON DELETE CASCADE | 158 | CONSTRAINT fk_rule_node_state_node_id FOREIGN KEY (rule_node_id) REFERENCES rule_node(id) ON DELETE CASCADE |
159 | ); | 159 | ); |
160 | 160 | ||
161 | +CREATE TABLE IF NOT EXISTS firmware ( | ||
162 | + id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY, | ||
163 | + created_time bigint NOT NULL, | ||
164 | + tenant_id uuid NOT NULL, | ||
165 | + title varchar(255) NOT NULL, | ||
166 | + version varchar(255) NOT NULL, | ||
167 | + file_name varchar(255), | ||
168 | + content_type varchar(255), | ||
169 | + checksum_algorithm varchar(32), | ||
170 | + checksum varchar(1020), | ||
171 | + data binary, | ||
172 | + data_size bigint, | ||
173 | + additional_info varchar, | ||
174 | + search_text varchar(255), | ||
175 | + CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version) | ||
176 | +); | ||
177 | + | ||
161 | CREATE TABLE IF NOT EXISTS device_profile ( | 178 | CREATE TABLE IF NOT EXISTS device_profile ( |
162 | id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY, | 179 | id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY, |
163 | created_time bigint NOT NULL, | 180 | created_time bigint NOT NULL, |
@@ -170,12 +187,14 @@ CREATE TABLE IF NOT EXISTS device_profile ( | @@ -170,12 +187,14 @@ CREATE TABLE IF NOT EXISTS device_profile ( | ||
170 | search_text varchar(255), | 187 | search_text varchar(255), |
171 | is_default boolean, | 188 | is_default boolean, |
172 | tenant_id uuid, | 189 | tenant_id uuid, |
190 | + firmware_id uuid, | ||
173 | default_rule_chain_id uuid, | 191 | default_rule_chain_id uuid, |
174 | default_queue_name varchar(255), | 192 | default_queue_name varchar(255), |
175 | provision_device_key varchar, | 193 | provision_device_key varchar, |
176 | CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), | 194 | CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), |
177 | CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key), | 195 | CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key), |
178 | - CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id) | 196 | + CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id), |
197 | + CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id) | ||
179 | ); | 198 | ); |
180 | 199 | ||
181 | CREATE TABLE IF NOT EXISTS device ( | 200 | CREATE TABLE IF NOT EXISTS device ( |
@@ -190,8 +209,10 @@ CREATE TABLE IF NOT EXISTS device ( | @@ -190,8 +209,10 @@ CREATE TABLE IF NOT EXISTS device ( | ||
190 | label varchar(255), | 209 | label varchar(255), |
191 | search_text varchar(255), | 210 | search_text varchar(255), |
192 | tenant_id uuid, | 211 | tenant_id uuid, |
212 | + firmware_id uuid, | ||
193 | CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name), | 213 | CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name), |
194 | - CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id) | 214 | + CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id), |
215 | + CONSTRAINT fk_firmware_device FOREIGN KEY (firmware_id) REFERENCES firmware(id) | ||
195 | ); | 216 | ); |
196 | 217 | ||
197 | CREATE TABLE IF NOT EXISTS device_credentials ( | 218 | CREATE TABLE IF NOT EXISTS device_credentials ( |
@@ -25,7 +25,7 @@ CREATE OR REPLACE PROCEDURE insert_tb_schema_settings() | @@ -25,7 +25,7 @@ CREATE OR REPLACE PROCEDURE insert_tb_schema_settings() | ||
25 | $$ | 25 | $$ |
26 | BEGIN | 26 | BEGIN |
27 | IF (SELECT COUNT(*) FROM tb_schema_settings) = 0 THEN | 27 | IF (SELECT COUNT(*) FROM tb_schema_settings) = 0 THEN |
28 | - INSERT INTO tb_schema_settings (schema_version) VALUES (3002000); | 28 | + INSERT INTO tb_schema_settings (schema_version) VALUES (3003000); |
29 | END IF; | 29 | END IF; |
30 | END; | 30 | END; |
31 | $$; | 31 | $$; |
@@ -176,6 +176,23 @@ CREATE TABLE IF NOT EXISTS rule_node_state ( | @@ -176,6 +176,23 @@ CREATE TABLE IF NOT EXISTS rule_node_state ( | ||
176 | CONSTRAINT fk_rule_node_state_node_id FOREIGN KEY (rule_node_id) REFERENCES rule_node(id) ON DELETE CASCADE | 176 | CONSTRAINT fk_rule_node_state_node_id FOREIGN KEY (rule_node_id) REFERENCES rule_node(id) ON DELETE CASCADE |
177 | ); | 177 | ); |
178 | 178 | ||
179 | +CREATE TABLE IF NOT EXISTS firmware ( | ||
180 | + id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY, | ||
181 | + created_time bigint NOT NULL, | ||
182 | + tenant_id uuid NOT NULL, | ||
183 | + title varchar(255) NOT NULL, | ||
184 | + version varchar(255) NOT NULL, | ||
185 | + file_name varchar(255), | ||
186 | + content_type varchar(255), | ||
187 | + checksum_algorithm varchar(32), | ||
188 | + checksum varchar(1020), | ||
189 | + data bytea, | ||
190 | + data_size bigint, | ||
191 | + additional_info varchar, | ||
192 | + search_text varchar(255), | ||
193 | + CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version) | ||
194 | +); | ||
195 | + | ||
179 | CREATE TABLE IF NOT EXISTS device_profile ( | 196 | CREATE TABLE IF NOT EXISTS device_profile ( |
180 | id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY, | 197 | id uuid NOT NULL CONSTRAINT device_profile_pkey PRIMARY KEY, |
181 | created_time bigint NOT NULL, | 198 | created_time bigint NOT NULL, |
@@ -188,12 +205,14 @@ CREATE TABLE IF NOT EXISTS device_profile ( | @@ -188,12 +205,14 @@ CREATE TABLE IF NOT EXISTS device_profile ( | ||
188 | search_text varchar(255), | 205 | search_text varchar(255), |
189 | is_default boolean, | 206 | is_default boolean, |
190 | tenant_id uuid, | 207 | tenant_id uuid, |
208 | + firmware_id uuid, | ||
191 | default_rule_chain_id uuid, | 209 | default_rule_chain_id uuid, |
192 | default_queue_name varchar(255), | 210 | default_queue_name varchar(255), |
193 | provision_device_key varchar, | 211 | provision_device_key varchar, |
194 | CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), | 212 | CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), |
195 | CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key), | 213 | CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key), |
196 | - CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id) | 214 | + CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id), |
215 | + CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id) | ||
197 | ); | 216 | ); |
198 | 217 | ||
199 | CREATE TABLE IF NOT EXISTS device ( | 218 | CREATE TABLE IF NOT EXISTS device ( |
@@ -208,8 +227,10 @@ CREATE TABLE IF NOT EXISTS device ( | @@ -208,8 +227,10 @@ CREATE TABLE IF NOT EXISTS device ( | ||
208 | label varchar(255), | 227 | label varchar(255), |
209 | search_text varchar(255), | 228 | search_text varchar(255), |
210 | tenant_id uuid, | 229 | tenant_id uuid, |
230 | + firmware_id uuid, | ||
211 | CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name), | 231 | CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name), |
212 | - CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id) | 232 | + CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id), |
233 | + CONSTRAINT fk_firmware_device FOREIGN KEY (firmware_id) REFERENCES firmware(id) | ||
213 | ); | 234 | ); |
214 | 235 | ||
215 | CREATE TABLE IF NOT EXISTS device_credentials ( | 236 | CREATE TABLE IF NOT EXISTS device_credentials ( |
@@ -28,6 +28,7 @@ import java.util.Arrays; | @@ -28,6 +28,7 @@ import java.util.Arrays; | ||
28 | "org.thingsboard.server.dao.service.attributes.sql.*SqlTest", | 28 | "org.thingsboard.server.dao.service.attributes.sql.*SqlTest", |
29 | "org.thingsboard.server.dao.service.event.sql.*SqlTest", | 29 | "org.thingsboard.server.dao.service.event.sql.*SqlTest", |
30 | "org.thingsboard.server.dao.service.timeseries.sql.*SqlTest" | 30 | "org.thingsboard.server.dao.service.timeseries.sql.*SqlTest" |
31 | + | ||
31 | }) | 32 | }) |
32 | public class SqlDaoServiceTestSuite { | 33 | public class SqlDaoServiceTestSuite { |
33 | 34 |
@@ -54,6 +54,7 @@ import org.thingsboard.server.dao.edge.EdgeService; | @@ -54,6 +54,7 @@ import org.thingsboard.server.dao.edge.EdgeService; | ||
54 | import org.thingsboard.server.dao.entity.EntityService; | 54 | import org.thingsboard.server.dao.entity.EntityService; |
55 | import org.thingsboard.server.dao.entityview.EntityViewService; | 55 | import org.thingsboard.server.dao.entityview.EntityViewService; |
56 | import org.thingsboard.server.dao.event.EventService; | 56 | import org.thingsboard.server.dao.event.EventService; |
57 | +import org.thingsboard.server.dao.firmware.FirmwareService; | ||
57 | import org.thingsboard.server.dao.relation.RelationService; | 58 | import org.thingsboard.server.dao.relation.RelationService; |
58 | import org.thingsboard.server.dao.resource.ResourceService; | 59 | import org.thingsboard.server.dao.resource.ResourceService; |
59 | import org.thingsboard.server.dao.rule.RuleChainService; | 60 | import org.thingsboard.server.dao.rule.RuleChainService; |
@@ -157,6 +158,10 @@ public abstract class AbstractServiceTest { | @@ -157,6 +158,10 @@ public abstract class AbstractServiceTest { | ||
157 | @Autowired | 158 | @Autowired |
158 | protected ResourceService resourceService; | 159 | protected ResourceService resourceService; |
159 | 160 | ||
161 | + | ||
162 | + @Autowired | ||
163 | + protected FirmwareService firmwareService; | ||
164 | + | ||
160 | public class IdComparator<D extends HasId> implements Comparator<D> { | 165 | public class IdComparator<D extends HasId> implements Comparator<D> { |
161 | @Override | 166 | @Override |
162 | public int compare(D o1, D o2) { | 167 | public int compare(D o1, D o2) { |
@@ -203,7 +208,7 @@ public abstract class AbstractServiceTest { | @@ -203,7 +208,7 @@ public abstract class AbstractServiceTest { | ||
203 | 208 | ||
204 | @Bean | 209 | @Bean |
205 | public AuditLogLevelFilter auditLogLevelFilter() { | 210 | public AuditLogLevelFilter auditLogLevelFilter() { |
206 | - Map<String,String> mask = new HashMap<>(); | 211 | + Map<String, String> mask = new HashMap<>(); |
207 | for (EntityType entityType : EntityType.values()) { | 212 | for (EntityType entityType : EntityType.values()) { |
208 | mask.put(entityType.name().toLowerCase(), AuditLogLevelMask.RW.name()); | 213 | mask.put(entityType.name().toLowerCase(), AuditLogLevelMask.RW.name()); |
209 | } | 214 | } |