1221 changed files with 49933 additions and 20720 deletions
File diff suppressed because it is too large
@ -1,162 +0,0 @@ |
|||
{ |
|||
"ruleChain": { |
|||
"additionalInfo": null, |
|||
"name": "Edge Root Rule Chain", |
|||
"type": "EDGE", |
|||
"firstRuleNodeId": null, |
|||
"root": true, |
|||
"debugMode": false, |
|||
"configuration": null |
|||
}, |
|||
"metadata": { |
|||
"firstNodeIndex": 0, |
|||
"nodes": [ |
|||
{ |
|||
"additionalInfo": { |
|||
"description": "Process incoming messages from devices with the alarm rules defined in the device profile. Dispatch all incoming messages with \"Success\" relation type.", |
|||
"layoutX": 203, |
|||
"layoutY": 259 |
|||
}, |
|||
"type": "org.thingsboard.rule.engine.profile.TbDeviceProfileNode", |
|||
"name": "Device Profile Node", |
|||
"debugMode": false, |
|||
"configuration": { |
|||
"persistAlarmRulesState": false, |
|||
"fetchAlarmRulesStateOnStart": false |
|||
} |
|||
}, |
|||
{ |
|||
"additionalInfo": { |
|||
"layoutX": 823, |
|||
"layoutY": 157 |
|||
}, |
|||
"type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", |
|||
"name": "Save Timeseries", |
|||
"debugMode": false, |
|||
"configuration": { |
|||
"defaultTTL": 0 |
|||
} |
|||
}, |
|||
{ |
|||
"additionalInfo": { |
|||
"layoutX": 824, |
|||
"layoutY": 52 |
|||
}, |
|||
"type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", |
|||
"name": "Save Client Attributes", |
|||
"debugMode": false, |
|||
"configuration": { |
|||
"scope": "CLIENT_SCOPE" |
|||
} |
|||
}, |
|||
{ |
|||
"additionalInfo": { |
|||
"layoutX": 347, |
|||
"layoutY": 149 |
|||
}, |
|||
"type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", |
|||
"name": "Message Type Switch", |
|||
"debugMode": false, |
|||
"configuration": { |
|||
"version": 0 |
|||
} |
|||
}, |
|||
{ |
|||
"additionalInfo": { |
|||
"layoutX": 825, |
|||
"layoutY": 266 |
|||
}, |
|||
"type": "org.thingsboard.rule.engine.action.TbLogNode", |
|||
"name": "Log RPC from Device", |
|||
"debugMode": false, |
|||
"configuration": { |
|||
"jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" |
|||
} |
|||
}, |
|||
{ |
|||
"additionalInfo": { |
|||
"layoutX": 824, |
|||
"layoutY": 378 |
|||
}, |
|||
"type": "org.thingsboard.rule.engine.action.TbLogNode", |
|||
"name": "Log Other", |
|||
"debugMode": false, |
|||
"configuration": { |
|||
"jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" |
|||
} |
|||
}, |
|||
{ |
|||
"additionalInfo": { |
|||
"layoutX": 824, |
|||
"layoutY": 466 |
|||
}, |
|||
"type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", |
|||
"name": "RPC Call Request", |
|||
"debugMode": false, |
|||
"configuration": { |
|||
"timeoutInSeconds": 60 |
|||
} |
|||
}, |
|||
{ |
|||
"additionalInfo": { |
|||
"layoutX": 1134, |
|||
"layoutY": 132 |
|||
}, |
|||
"type": "org.thingsboard.rule.engine.edge.TbMsgPushToCloudNode", |
|||
"name": "Push to cloud", |
|||
"debugMode": false, |
|||
"configuration": { |
|||
"version": 0 |
|||
} |
|||
} |
|||
], |
|||
"connections": [ |
|||
{ |
|||
"fromIndex": 0, |
|||
"toIndex": 3, |
|||
"type": "Success" |
|||
}, |
|||
{ |
|||
"fromIndex": 1, |
|||
"toIndex": 7, |
|||
"type": "Success" |
|||
}, |
|||
{ |
|||
"fromIndex": 2, |
|||
"toIndex": 7, |
|||
"type": "Success" |
|||
}, |
|||
{ |
|||
"fromIndex": 3, |
|||
"toIndex": 6, |
|||
"type": "RPC Request to Device" |
|||
}, |
|||
{ |
|||
"fromIndex": 3, |
|||
"toIndex": 5, |
|||
"type": "Other" |
|||
}, |
|||
{ |
|||
"fromIndex": 3, |
|||
"toIndex": 2, |
|||
"type": "Post attributes" |
|||
}, |
|||
{ |
|||
"fromIndex": 3, |
|||
"toIndex": 1, |
|||
"type": "Post telemetry" |
|||
}, |
|||
{ |
|||
"fromIndex": 3, |
|||
"toIndex": 4, |
|||
"type": "RPC Request from Device" |
|||
}, |
|||
{ |
|||
"fromIndex": 4, |
|||
"toIndex": 7, |
|||
"type": "Success" |
|||
} |
|||
], |
|||
"ruleChainConnections": null |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
{ |
|||
"providerId": "Apple", |
|||
"additionalInfo": null, |
|||
"accessTokenUri": "https://appleid.apple.com/auth/token", |
|||
"authorizationUri": "https://appleid.apple.com/auth/authorize?response_mode=form_post", |
|||
"scope": ["email","openid","name"], |
|||
"jwkSetUri": "https://appleid.apple.com/auth/keys", |
|||
"userInfoUri": null, |
|||
"clientAuthenticationMethod": "POST", |
|||
"userNameAttributeName": "email", |
|||
"mapperConfig": { |
|||
"type": "APPLE", |
|||
"basic": { |
|||
"emailAttributeKey": "email", |
|||
"firstNameAttributeKey": "firstName", |
|||
"lastNameAttributeKey": "lastName", |
|||
"tenantNameStrategy": "DOMAIN" |
|||
} |
|||
}, |
|||
"comment": null, |
|||
"loginButtonIcon": "apple-logo", |
|||
"loginButtonLabel": "Apple", |
|||
"helpLink": "https://developer.apple.com/sign-in-with-apple/get-started/" |
|||
} |
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,90 @@ |
|||
-- |
|||
-- Copyright © 2016-2021 The Thingsboard Authors |
|||
-- |
|||
-- Licensed under the Apache License, Version 2.0 (the "License"); |
|||
-- you may not use this file except in compliance with the License. |
|||
-- You may obtain a copy of the License at |
|||
-- |
|||
-- http://www.apache.org/licenses/LICENSE-2.0 |
|||
-- |
|||
-- Unless required by applicable law or agreed to in writing, software |
|||
-- distributed under the License is distributed on an "AS IS" BASIS, |
|||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
-- See the License for the specific language governing permissions and |
|||
-- limitations under the License. |
|||
-- |
|||
|
|||
-- PROCEDURE: public.cleanup_events_by_ttl(bigint, bigint, bigint) |
|||
|
|||
DROP PROCEDURE IF EXISTS public.cleanup_events_by_ttl(bigint, bigint, bigint); |
|||
|
|||
CREATE OR REPLACE PROCEDURE public.cleanup_events_by_ttl( |
|||
ttl bigint, |
|||
debug_ttl bigint, |
|||
INOUT deleted bigint) |
|||
LANGUAGE 'plpgsql' |
|||
AS $BODY$ |
|||
DECLARE |
|||
ttl_ts bigint; |
|||
debug_ttl_ts bigint; |
|||
ttl_deleted_count bigint DEFAULT 0; |
|||
debug_ttl_deleted_count bigint DEFAULT 0; |
|||
BEGIN |
|||
IF ttl > 0 THEN |
|||
ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - ttl::bigint * 1000)::bigint; |
|||
|
|||
DELETE FROM event |
|||
WHERE ts < ttl_ts |
|||
AND NOT event_type IN ('DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN', 'DEBUG_CONVERTER', 'DEBUG_INTEGRATION'); |
|||
|
|||
GET DIAGNOSTICS ttl_deleted_count = ROW_COUNT; |
|||
END IF; |
|||
|
|||
IF debug_ttl > 0 THEN |
|||
debug_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - debug_ttl::bigint * 1000)::bigint; |
|||
|
|||
DELETE FROM event |
|||
WHERE ts < debug_ttl_ts |
|||
AND event_type IN ('DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN', 'DEBUG_CONVERTER', 'DEBUG_INTEGRATION'); |
|||
|
|||
GET DIAGNOSTICS debug_ttl_deleted_count = ROW_COUNT; |
|||
END IF; |
|||
|
|||
RAISE NOTICE 'Events removed by ttl: %', ttl_deleted_count; |
|||
RAISE NOTICE 'Debug Events removed by ttl: %', debug_ttl_deleted_count; |
|||
deleted := ttl_deleted_count + debug_ttl_deleted_count; |
|||
END |
|||
$BODY$; |
|||
|
|||
|
|||
-- Index: idx_event_ts |
|||
|
|||
DROP INDEX IF EXISTS public.idx_event_ts; |
|||
|
|||
-- Hint: add CONCURRENTLY to CREATE INDEX query in case of more then 1 million records or during live update |
|||
-- CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_event_ts |
|||
CREATE INDEX IF NOT EXISTS idx_event_ts |
|||
ON public.event |
|||
(ts DESC NULLS LAST) |
|||
WITH (FILLFACTOR=95); |
|||
|
|||
COMMENT ON INDEX public.idx_event_ts |
|||
IS 'This index helps to delete events by TTL using timestamp'; |
|||
|
|||
|
|||
-- Index: idx_event_tenant_entity_type_entity_event_type_created_time_des |
|||
|
|||
DROP INDEX IF EXISTS public.idx_event_tenant_entity_type_entity_event_type_created_time_des; |
|||
|
|||
-- CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_event_tenant_entity_type_entity_event_type_created_time_des |
|||
CREATE INDEX IF NOT EXISTS idx_event_tenant_entity_type_entity_event_type_created_time_des |
|||
ON public.event |
|||
(tenant_id ASC, entity_type ASC, entity_id ASC, event_type ASC, created_time DESC NULLS LAST) |
|||
WITH (FILLFACTOR=95); |
|||
|
|||
COMMENT ON INDEX public.idx_event_tenant_entity_type_entity_event_type_created_time_des |
|||
IS 'This index helps to open latest events on UI fast'; |
|||
|
|||
-- Index: idx_event_type_entity_id |
|||
-- Description: replaced with more suitable idx_event_tenant_entity_type_entity_event_type_created_time_des |
|||
DROP INDEX IF EXISTS public.idx_event_type_entity_id; |
|||
@ -1,222 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.controller; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.core.io.ByteArrayResource; |
|||
import org.springframework.http.HttpHeaders; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.PathVariable; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestMethod; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.ResponseBody; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.Firmware; |
|||
import org.thingsboard.server.common.data.FirmwareInfo; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.firmware.ChecksumAlgorithm; |
|||
import org.thingsboard.server.common.data.firmware.FirmwareType; |
|||
import org.thingsboard.server.common.data.id.DeviceProfileId; |
|||
import org.thingsboard.server.common.data.id.FirmwareId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.security.permission.Operation; |
|||
import org.thingsboard.server.service.security.permission.Resource; |
|||
|
|||
import java.nio.ByteBuffer; |
|||
|
|||
@Slf4j |
|||
@RestController |
|||
@TbCoreComponent |
|||
@RequestMapping("/api") |
|||
public class FirmwareController extends BaseController { |
|||
|
|||
public static final String FIRMWARE_ID = "firmwareId"; |
|||
public static final String CHECKSUM_ALGORITHM = "checksumAlgorithm"; |
|||
|
|||
@PreAuthorize("hasAnyAuthority( 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/firmware/{firmwareId}/download", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public ResponseEntity<org.springframework.core.io.Resource> downloadFirmware(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException { |
|||
checkParameter(FIRMWARE_ID, strFirmwareId); |
|||
try { |
|||
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); |
|||
Firmware firmware = checkFirmwareId(firmwareId, Operation.READ); |
|||
|
|||
ByteArrayResource resource = new ByteArrayResource(firmware.getData().array()); |
|||
return ResponseEntity.ok() |
|||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + firmware.getFileName()) |
|||
.header("x-filename", firmware.getFileName()) |
|||
.contentLength(resource.contentLength()) |
|||
.contentType(parseMediaType(firmware.getContentType())) |
|||
.body(resource); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/firmware/info/{firmwareId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public FirmwareInfo getFirmwareInfoById(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException { |
|||
checkParameter(FIRMWARE_ID, strFirmwareId); |
|||
try { |
|||
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); |
|||
return checkNotNull(firmwareService.findFirmwareInfoById(getTenantId(), firmwareId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public Firmware getFirmwareById(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException { |
|||
checkParameter(FIRMWARE_ID, strFirmwareId); |
|||
try { |
|||
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); |
|||
return checkFirmwareId(firmwareId, Operation.READ); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/firmware", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public FirmwareInfo saveFirmwareInfo(@RequestBody FirmwareInfo firmwareInfo) throws ThingsboardException { |
|||
boolean created = firmwareInfo.getId() == null; |
|||
try { |
|||
firmwareInfo.setTenantId(getTenantId()); |
|||
checkEntity(firmwareInfo.getId(), firmwareInfo, Resource.FIRMWARE); |
|||
FirmwareInfo savedFirmwareInfo = firmwareService.saveFirmwareInfo(firmwareInfo); |
|||
logEntityAction(savedFirmwareInfo.getId(), savedFirmwareInfo, |
|||
null, created ? ActionType.ADDED : ActionType.UPDATED, null); |
|||
return savedFirmwareInfo; |
|||
} catch (Exception e) { |
|||
logEntityAction(emptyId(EntityType.FIRMWARE), firmwareInfo, |
|||
null, created ? ActionType.ADDED : ActionType.UPDATED, e); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public Firmware saveFirmwareData(@PathVariable(FIRMWARE_ID) String strFirmwareId, |
|||
@RequestParam(required = false) String checksum, |
|||
@RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr, |
|||
@RequestBody MultipartFile file) throws ThingsboardException { |
|||
checkParameter(FIRMWARE_ID, strFirmwareId); |
|||
checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr); |
|||
try { |
|||
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); |
|||
FirmwareInfo info = checkFirmwareInfoId(firmwareId, Operation.READ); |
|||
|
|||
Firmware firmware = new Firmware(firmwareId); |
|||
firmware.setCreatedTime(info.getCreatedTime()); |
|||
firmware.setTenantId(getTenantId()); |
|||
firmware.setDeviceProfileId(info.getDeviceProfileId()); |
|||
firmware.setType(info.getType()); |
|||
firmware.setTitle(info.getTitle()); |
|||
firmware.setVersion(info.getVersion()); |
|||
firmware.setAdditionalInfo(info.getAdditionalInfo()); |
|||
|
|||
ChecksumAlgorithm checksumAlgorithm = ChecksumAlgorithm.valueOf(checksumAlgorithmStr.toUpperCase()); |
|||
|
|||
byte[] bytes = file.getBytes(); |
|||
if (StringUtils.isEmpty(checksum)) { |
|||
checksum = firmwareService.generateChecksum(checksumAlgorithm, ByteBuffer.wrap(bytes)); |
|||
} |
|||
|
|||
firmware.setChecksumAlgorithm(checksumAlgorithm); |
|||
firmware.setChecksum(checksum); |
|||
firmware.setFileName(file.getOriginalFilename()); |
|||
firmware.setContentType(file.getContentType()); |
|||
firmware.setData(ByteBuffer.wrap(bytes)); |
|||
firmware.setDataSize((long) bytes.length); |
|||
Firmware savedFirmware = firmwareService.saveFirmware(firmware); |
|||
logEntityAction(savedFirmware.getId(), savedFirmware, null, ActionType.UPDATED, null); |
|||
return savedFirmware; |
|||
} catch (Exception e) { |
|||
logEntityAction(emptyId(EntityType.FIRMWARE), null, null, ActionType.UPDATED, e, strFirmwareId); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/firmwares", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public PageData<FirmwareInfo> getFirmwares(@RequestParam int pageSize, |
|||
@RequestParam int page, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String sortProperty, |
|||
@RequestParam(required = false) String sortOrder) throws ThingsboardException { |
|||
try { |
|||
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
|||
return checkNotNull(firmwareService.findTenantFirmwaresByTenantId(getTenantId(), pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/firmwares/{deviceProfileId}/{type}/{hasData}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public PageData<FirmwareInfo> getFirmwares(@PathVariable("deviceProfileId") String strDeviceProfileId, |
|||
@PathVariable("type") String strType, |
|||
@PathVariable("hasData") boolean hasData, |
|||
@RequestParam int pageSize, |
|||
@RequestParam int page, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String sortProperty, |
|||
@RequestParam(required = false) String sortOrder) throws ThingsboardException { |
|||
checkParameter("deviceProfileId", strDeviceProfileId); |
|||
checkParameter("type", strType); |
|||
try { |
|||
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
|||
return checkNotNull(firmwareService.findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(getTenantId(), |
|||
new DeviceProfileId(toUUID(strDeviceProfileId)), FirmwareType.valueOf(strType), hasData, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.DELETE) |
|||
@ResponseBody |
|||
public void deleteFirmware(@PathVariable("firmwareId") String strFirmwareId) throws ThingsboardException { |
|||
checkParameter(FIRMWARE_ID, strFirmwareId); |
|||
try { |
|||
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); |
|||
FirmwareInfo info = checkFirmwareInfoId(firmwareId, Operation.DELETE); |
|||
firmwareService.deleteFirmware(getTenantId(), firmwareId); |
|||
logEntityAction(firmwareId, info, null, ActionType.DELETED, null, strFirmwareId); |
|||
} catch (Exception e) { |
|||
logEntityAction(emptyId(EntityType.FIRMWARE), null, null, ActionType.DELETED, e, strFirmwareId); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,227 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.controller; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.core.io.ByteArrayResource; |
|||
import org.springframework.http.HttpHeaders; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.PathVariable; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestMethod; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.ResponseBody; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.OtaPackage; |
|||
import org.thingsboard.server.common.data.OtaPackageInfo; |
|||
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.DeviceProfileId; |
|||
import org.thingsboard.server.common.data.id.OtaPackageId; |
|||
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; |
|||
import org.thingsboard.server.common.data.ota.OtaPackageType; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.security.permission.Operation; |
|||
import org.thingsboard.server.service.security.permission.Resource; |
|||
|
|||
import java.nio.ByteBuffer; |
|||
|
|||
@Slf4j |
|||
@RestController |
|||
@TbCoreComponent |
|||
@RequestMapping("/api") |
|||
public class OtaPackageController extends BaseController { |
|||
|
|||
public static final String OTA_PACKAGE_ID = "otaPackageId"; |
|||
public static final String CHECKSUM_ALGORITHM = "checksumAlgorithm"; |
|||
|
|||
@PreAuthorize("hasAnyAuthority( 'TENANT_ADMIN')") |
|||
@RequestMapping(value = "/otaPackage/{otaPackageId}/download", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public ResponseEntity<org.springframework.core.io.Resource> downloadOtaPackage(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException { |
|||
checkParameter(OTA_PACKAGE_ID, strOtaPackageId); |
|||
try { |
|||
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId)); |
|||
OtaPackage otaPackage = checkOtaPackageId(otaPackageId, Operation.READ); |
|||
|
|||
if (otaPackage.hasUrl()) { |
|||
return ResponseEntity.badRequest().build(); |
|||
} |
|||
|
|||
ByteArrayResource resource = new ByteArrayResource(otaPackage.getData().array()); |
|||
return ResponseEntity.ok() |
|||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + otaPackage.getFileName()) |
|||
.header("x-filename", otaPackage.getFileName()) |
|||
.contentLength(resource.contentLength()) |
|||
.contentType(parseMediaType(otaPackage.getContentType())) |
|||
.body(resource); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/otaPackage/info/{otaPackageId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public OtaPackageInfo getOtaPackageInfoById(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException { |
|||
checkParameter(OTA_PACKAGE_ID, strOtaPackageId); |
|||
try { |
|||
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId)); |
|||
return checkNotNull(otaPackageService.findOtaPackageInfoById(getTenantId(), otaPackageId)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public OtaPackage getOtaPackageById(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException { |
|||
checkParameter(OTA_PACKAGE_ID, strOtaPackageId); |
|||
try { |
|||
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId)); |
|||
return checkOtaPackageId(otaPackageId, Operation.READ); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/otaPackage", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public OtaPackageInfo saveOtaPackageInfo(@RequestBody SaveOtaPackageInfoRequest otaPackageInfo) throws ThingsboardException { |
|||
boolean created = otaPackageInfo.getId() == null; |
|||
try { |
|||
otaPackageInfo.setTenantId(getTenantId()); |
|||
checkEntity(otaPackageInfo.getId(), otaPackageInfo, Resource.OTA_PACKAGE); |
|||
OtaPackageInfo savedOtaPackageInfo = otaPackageService.saveOtaPackageInfo(new OtaPackageInfo(otaPackageInfo), otaPackageInfo.isUsesUrl()); |
|||
logEntityAction(savedOtaPackageInfo.getId(), savedOtaPackageInfo, |
|||
null, created ? ActionType.ADDED : ActionType.UPDATED, null); |
|||
return savedOtaPackageInfo; |
|||
} catch (Exception e) { |
|||
logEntityAction(emptyId(EntityType.OTA_PACKAGE), otaPackageInfo, |
|||
null, created ? ActionType.ADDED : ActionType.UPDATED, e); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public OtaPackageInfo saveOtaPackageData(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId, |
|||
@RequestParam(required = false) String checksum, |
|||
@RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr, |
|||
@RequestBody MultipartFile file) throws ThingsboardException { |
|||
checkParameter(OTA_PACKAGE_ID, strOtaPackageId); |
|||
checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr); |
|||
try { |
|||
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId)); |
|||
OtaPackageInfo info = checkOtaPackageInfoId(otaPackageId, Operation.READ); |
|||
|
|||
OtaPackage otaPackage = new OtaPackage(otaPackageId); |
|||
otaPackage.setCreatedTime(info.getCreatedTime()); |
|||
otaPackage.setTenantId(getTenantId()); |
|||
otaPackage.setDeviceProfileId(info.getDeviceProfileId()); |
|||
otaPackage.setType(info.getType()); |
|||
otaPackage.setTitle(info.getTitle()); |
|||
otaPackage.setVersion(info.getVersion()); |
|||
otaPackage.setTag(info.getTag()); |
|||
otaPackage.setAdditionalInfo(info.getAdditionalInfo()); |
|||
|
|||
ChecksumAlgorithm checksumAlgorithm = ChecksumAlgorithm.valueOf(checksumAlgorithmStr.toUpperCase()); |
|||
|
|||
byte[] bytes = file.getBytes(); |
|||
if (StringUtils.isEmpty(checksum)) { |
|||
checksum = otaPackageService.generateChecksum(checksumAlgorithm, ByteBuffer.wrap(bytes)); |
|||
} |
|||
|
|||
otaPackage.setChecksumAlgorithm(checksumAlgorithm); |
|||
otaPackage.setChecksum(checksum); |
|||
otaPackage.setFileName(file.getOriginalFilename()); |
|||
otaPackage.setContentType(file.getContentType()); |
|||
otaPackage.setData(ByteBuffer.wrap(bytes)); |
|||
otaPackage.setDataSize((long) bytes.length); |
|||
OtaPackageInfo savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage); |
|||
logEntityAction(savedOtaPackage.getId(), savedOtaPackage, null, ActionType.UPDATED, null); |
|||
return savedOtaPackage; |
|||
} catch (Exception e) { |
|||
logEntityAction(emptyId(EntityType.OTA_PACKAGE), null, null, ActionType.UPDATED, e, strOtaPackageId); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/otaPackages", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public PageData<OtaPackageInfo> getOtaPackages(@RequestParam int pageSize, |
|||
@RequestParam int page, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String sortProperty, |
|||
@RequestParam(required = false) String sortOrder) throws ThingsboardException { |
|||
try { |
|||
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
|||
return checkNotNull(otaPackageService.findTenantOtaPackagesByTenantId(getTenantId(), pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/otaPackages/{deviceProfileId}/{type}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public PageData<OtaPackageInfo> getOtaPackages(@PathVariable("deviceProfileId") String strDeviceProfileId, |
|||
@PathVariable("type") String strType, |
|||
@RequestParam int pageSize, |
|||
@RequestParam int page, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String sortProperty, |
|||
@RequestParam(required = false) String sortOrder) throws ThingsboardException { |
|||
checkParameter("deviceProfileId", strDeviceProfileId); |
|||
checkParameter("type", strType); |
|||
try { |
|||
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
|||
return checkNotNull(otaPackageService.findTenantOtaPackagesByTenantIdAndDeviceProfileIdAndTypeAndHasData(getTenantId(), |
|||
new DeviceProfileId(toUUID(strDeviceProfileId)), OtaPackageType.valueOf(strType), pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.DELETE) |
|||
@ResponseBody |
|||
public void deleteOtaPackage(@PathVariable("otaPackageId") String strOtaPackageId) throws ThingsboardException { |
|||
checkParameter(OTA_PACKAGE_ID, strOtaPackageId); |
|||
try { |
|||
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId)); |
|||
OtaPackageInfo info = checkOtaPackageInfoId(otaPackageId, Operation.DELETE); |
|||
otaPackageService.deleteOtaPackage(getTenantId(), otaPackageId); |
|||
logEntityAction(otaPackageId, info, null, ActionType.DELETED, null, strOtaPackageId); |
|||
} catch (Exception e) { |
|||
logEntityAction(emptyId(EntityType.OTA_PACKAGE), null, null, ActionType.DELETED, e, strOtaPackageId); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.controller; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.PathVariable; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestMethod; |
|||
import org.springframework.web.bind.annotation.ResponseBody; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.context.request.async.DeferredResult; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@RestController |
|||
@TbCoreComponent |
|||
@RequestMapping(TbUrlConstants.RPC_V1_URL_PREFIX) |
|||
@Slf4j |
|||
public class RpcV1Controller extends AbstractRpcController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public DeferredResult<ResponseEntity> handleOneWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { |
|||
return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.REQUEST_TIMEOUT, HttpStatus.CONFLICT); |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public DeferredResult<ResponseEntity> handleTwoWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { |
|||
return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.REQUEST_TIMEOUT, HttpStatus.CONFLICT); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,128 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.controller; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.PathVariable; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestMethod; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.ResponseBody; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.context.request.async.DeferredResult; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.RpcId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.rpc.Rpc; |
|||
import org.thingsboard.server.common.data.rpc.RpcStatus; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
import org.thingsboard.server.common.msg.TbMsgMetaData; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.rpc.RemoveRpcActorMsg; |
|||
import org.thingsboard.server.service.security.permission.Operation; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.common.data.DataConstants.RPC_DELETED; |
|||
|
|||
@RestController |
|||
@TbCoreComponent |
|||
@RequestMapping(TbUrlConstants.RPC_V2_URL_PREFIX) |
|||
@Slf4j |
|||
public class RpcV2Controller extends AbstractRpcController { |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public DeferredResult<ResponseEntity> handleOneWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { |
|||
return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT); |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST) |
|||
@ResponseBody |
|||
public DeferredResult<ResponseEntity> handleTwoWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { |
|||
return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT); |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public Rpc getPersistedRpc(@PathVariable("rpcId") String strRpc) throws ThingsboardException { |
|||
checkParameter("RpcId", strRpc); |
|||
try { |
|||
RpcId rpcId = new RpcId(UUID.fromString(strRpc)); |
|||
return checkRpcId(rpcId, Operation.READ); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
|||
@RequestMapping(value = "/persistent/device/{deviceId}", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public PageData<Rpc> getPersistedRpcByDevice(@PathVariable("deviceId") String strDeviceId, |
|||
@RequestParam int pageSize, |
|||
@RequestParam int page, |
|||
@RequestParam RpcStatus rpcStatus, |
|||
@RequestParam(required = false) String textSearch, |
|||
@RequestParam(required = false) String sortProperty, |
|||
@RequestParam(required = false) String sortOrder) throws ThingsboardException { |
|||
checkParameter("DeviceId", strDeviceId); |
|||
try { |
|||
TenantId tenantId = getCurrentUser().getTenantId(); |
|||
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
|||
DeviceId deviceId = new DeviceId(UUID.fromString(strDeviceId)); |
|||
return checkNotNull(rpcService.findAllByDeviceIdAndStatus(tenantId, deviceId, rpcStatus, pageLink)); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
|||
@RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.DELETE) |
|||
@ResponseBody |
|||
public void deleteResource(@PathVariable("rpcId") String strRpc) throws ThingsboardException { |
|||
checkParameter("RpcId", strRpc); |
|||
try { |
|||
RpcId rpcId = new RpcId(UUID.fromString(strRpc)); |
|||
Rpc rpc = checkRpcId(rpcId, Operation.DELETE); |
|||
|
|||
if (rpc != null) { |
|||
if (rpc.getStatus().equals(RpcStatus.QUEUED)) { |
|||
RemoveRpcActorMsg removeMsg = new RemoveRpcActorMsg(getTenantId(), rpc.getDeviceId(), rpc.getUuidId()); |
|||
log.trace("[{}] Forwarding msg {} to queue actor!", rpc.getDeviceId(), rpc); |
|||
tbClusterService.pushMsgToCore(removeMsg, null); |
|||
} |
|||
|
|||
rpcService.deleteRpc(getTenantId(), rpcId); |
|||
|
|||
TbMsg msg = TbMsg.newMsg(RPC_DELETED, rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc)); |
|||
tbClusterService.pushMsgToRuleEngine(getTenantId(), rpc.getDeviceId(), msg, null); |
|||
} |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,270 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.action; |
|||
|
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import com.fasterxml.jackson.databind.node.ArrayNode; |
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.DataConstants; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.HasName; |
|||
import org.thingsboard.server.common.data.HasTenantId; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|||
import org.thingsboard.server.common.data.kv.DataType; |
|||
import org.thingsboard.server.common.data.kv.KvEntry; |
|||
import org.thingsboard.server.common.data.kv.TsKvEntry; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
import org.thingsboard.server.common.msg.TbMsgDataType; |
|||
import org.thingsboard.server.common.msg.TbMsgMetaData; |
|||
import org.thingsboard.server.dao.audit.AuditLogService; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.cluster.TbClusterService; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@TbCoreComponent |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
@Slf4j |
|||
public class EntityActionService { |
|||
private final TbClusterService tbClusterService; |
|||
private final AuditLogService auditLogService; |
|||
|
|||
private static final ObjectMapper json = new ObjectMapper(); |
|||
|
|||
public void pushEntityActionToRuleEngine(EntityId entityId, HasName entity, TenantId tenantId, CustomerId customerId, |
|||
ActionType actionType, User user, Object... additionalInfo) { |
|||
String msgType = null; |
|||
switch (actionType) { |
|||
case ADDED: |
|||
msgType = DataConstants.ENTITY_CREATED; |
|||
break; |
|||
case DELETED: |
|||
msgType = DataConstants.ENTITY_DELETED; |
|||
break; |
|||
case UPDATED: |
|||
msgType = DataConstants.ENTITY_UPDATED; |
|||
break; |
|||
case ASSIGNED_TO_CUSTOMER: |
|||
msgType = DataConstants.ENTITY_ASSIGNED; |
|||
break; |
|||
case UNASSIGNED_FROM_CUSTOMER: |
|||
msgType = DataConstants.ENTITY_UNASSIGNED; |
|||
break; |
|||
case ATTRIBUTES_UPDATED: |
|||
msgType = DataConstants.ATTRIBUTES_UPDATED; |
|||
break; |
|||
case ATTRIBUTES_DELETED: |
|||
msgType = DataConstants.ATTRIBUTES_DELETED; |
|||
break; |
|||
case ALARM_ACK: |
|||
msgType = DataConstants.ALARM_ACK; |
|||
break; |
|||
case ALARM_CLEAR: |
|||
msgType = DataConstants.ALARM_CLEAR; |
|||
break; |
|||
case ALARM_DELETE: |
|||
msgType = DataConstants.ALARM_DELETE; |
|||
break; |
|||
case ASSIGNED_FROM_TENANT: |
|||
msgType = DataConstants.ENTITY_ASSIGNED_FROM_TENANT; |
|||
break; |
|||
case ASSIGNED_TO_TENANT: |
|||
msgType = DataConstants.ENTITY_ASSIGNED_TO_TENANT; |
|||
break; |
|||
case PROVISION_SUCCESS: |
|||
msgType = DataConstants.PROVISION_SUCCESS; |
|||
break; |
|||
case PROVISION_FAILURE: |
|||
msgType = DataConstants.PROVISION_FAILURE; |
|||
break; |
|||
case TIMESERIES_UPDATED: |
|||
msgType = DataConstants.TIMESERIES_UPDATED; |
|||
break; |
|||
case TIMESERIES_DELETED: |
|||
msgType = DataConstants.TIMESERIES_DELETED; |
|||
break; |
|||
case ASSIGNED_TO_EDGE: |
|||
msgType = DataConstants.ENTITY_ASSIGNED_TO_EDGE; |
|||
break; |
|||
case UNASSIGNED_FROM_EDGE: |
|||
msgType = DataConstants.ENTITY_UNASSIGNED_FROM_EDGE; |
|||
break; |
|||
} |
|||
if (!StringUtils.isEmpty(msgType)) { |
|||
try { |
|||
TbMsgMetaData metaData = new TbMsgMetaData(); |
|||
if (user != null) { |
|||
metaData.putValue("userId", user.getId().toString()); |
|||
metaData.putValue("userName", user.getName()); |
|||
} |
|||
if (customerId != null && !customerId.isNullUid()) { |
|||
metaData.putValue("customerId", customerId.toString()); |
|||
} |
|||
if (actionType == ActionType.ASSIGNED_TO_CUSTOMER) { |
|||
String strCustomerId = extractParameter(String.class, 1, additionalInfo); |
|||
String strCustomerName = extractParameter(String.class, 2, additionalInfo); |
|||
metaData.putValue("assignedCustomerId", strCustomerId); |
|||
metaData.putValue("assignedCustomerName", strCustomerName); |
|||
} else if (actionType == ActionType.UNASSIGNED_FROM_CUSTOMER) { |
|||
String strCustomerId = extractParameter(String.class, 1, additionalInfo); |
|||
String strCustomerName = extractParameter(String.class, 2, additionalInfo); |
|||
metaData.putValue("unassignedCustomerId", strCustomerId); |
|||
metaData.putValue("unassignedCustomerName", strCustomerName); |
|||
} else if (actionType == ActionType.ASSIGNED_FROM_TENANT) { |
|||
String strTenantId = extractParameter(String.class, 0, additionalInfo); |
|||
String strTenantName = extractParameter(String.class, 1, additionalInfo); |
|||
metaData.putValue("assignedFromTenantId", strTenantId); |
|||
metaData.putValue("assignedFromTenantName", strTenantName); |
|||
} else if (actionType == ActionType.ASSIGNED_TO_TENANT) { |
|||
String strTenantId = extractParameter(String.class, 0, additionalInfo); |
|||
String strTenantName = extractParameter(String.class, 1, additionalInfo); |
|||
metaData.putValue("assignedToTenantId", strTenantId); |
|||
metaData.putValue("assignedToTenantName", strTenantName); |
|||
} else if (actionType == ActionType.ASSIGNED_TO_EDGE) { |
|||
String strEdgeId = extractParameter(String.class, 1, additionalInfo); |
|||
String strEdgeName = extractParameter(String.class, 2, additionalInfo); |
|||
metaData.putValue("assignedEdgeId", strEdgeId); |
|||
metaData.putValue("assignedEdgeName", strEdgeName); |
|||
} else if (actionType == ActionType.UNASSIGNED_FROM_EDGE) { |
|||
String strEdgeId = extractParameter(String.class, 1, additionalInfo); |
|||
String strEdgeName = extractParameter(String.class, 2, additionalInfo); |
|||
metaData.putValue("unassignedEdgeId", strEdgeId); |
|||
metaData.putValue("unassignedEdgeName", strEdgeName); |
|||
} |
|||
ObjectNode entityNode; |
|||
if (entity != null) { |
|||
entityNode = json.valueToTree(entity); |
|||
if (entityId.getEntityType() == EntityType.DASHBOARD) { |
|||
entityNode.put("configuration", ""); |
|||
} |
|||
} else { |
|||
entityNode = json.createObjectNode(); |
|||
if (actionType == ActionType.ATTRIBUTES_UPDATED) { |
|||
String scope = extractParameter(String.class, 0, additionalInfo); |
|||
@SuppressWarnings("unchecked") |
|||
List<AttributeKvEntry> attributes = extractParameter(List.class, 1, additionalInfo); |
|||
metaData.putValue(DataConstants.SCOPE, scope); |
|||
if (attributes != null) { |
|||
for (AttributeKvEntry attr : attributes) { |
|||
addKvEntry(entityNode, attr); |
|||
} |
|||
} |
|||
} else if (actionType == ActionType.ATTRIBUTES_DELETED) { |
|||
String scope = extractParameter(String.class, 0, additionalInfo); |
|||
@SuppressWarnings("unchecked") |
|||
List<String> keys = extractParameter(List.class, 1, additionalInfo); |
|||
metaData.putValue(DataConstants.SCOPE, scope); |
|||
ArrayNode attrsArrayNode = entityNode.putArray("attributes"); |
|||
if (keys != null) { |
|||
keys.forEach(attrsArrayNode::add); |
|||
} |
|||
} else if (actionType == ActionType.TIMESERIES_UPDATED) { |
|||
@SuppressWarnings("unchecked") |
|||
List<TsKvEntry> timeseries = extractParameter(List.class, 0, additionalInfo); |
|||
addTimeseries(entityNode, timeseries); |
|||
} else if (actionType == ActionType.TIMESERIES_DELETED) { |
|||
@SuppressWarnings("unchecked") |
|||
List<String> keys = extractParameter(List.class, 0, additionalInfo); |
|||
if (keys != null) { |
|||
ArrayNode timeseriesArrayNode = entityNode.putArray("timeseries"); |
|||
keys.forEach(timeseriesArrayNode::add); |
|||
} |
|||
entityNode.put("startTs", extractParameter(Long.class, 1, additionalInfo)); |
|||
entityNode.put("endTs", extractParameter(Long.class, 2, additionalInfo)); |
|||
} |
|||
} |
|||
TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode)); |
|||
if (tenantId.isNullUid()) { |
|||
if (entity instanceof HasTenantId) { |
|||
tenantId = ((HasTenantId) entity).getTenantId(); |
|||
} |
|||
} |
|||
tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, null); |
|||
} catch (Exception e) { |
|||
log.warn("[{}] Failed to push entity action to rule engine: {}", entityId, actionType, e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public <E extends HasName, I extends EntityId> void logEntityAction(User user, I entityId, E entity, CustomerId customerId, |
|||
ActionType actionType, Exception e, Object... additionalInfo) { |
|||
if (customerId == null || customerId.isNullUid()) { |
|||
customerId = user.getCustomerId(); |
|||
} |
|||
if (e == null) { |
|||
pushEntityActionToRuleEngine(entityId, entity, user.getTenantId(), customerId, actionType, user, additionalInfo); |
|||
} |
|||
auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo); |
|||
} |
|||
|
|||
|
|||
private <T> T extractParameter(Class<T> clazz, int index, Object... additionalInfo) { |
|||
T result = null; |
|||
if (additionalInfo != null && additionalInfo.length > index) { |
|||
Object paramObject = additionalInfo[index]; |
|||
if (clazz.isInstance(paramObject)) { |
|||
result = clazz.cast(paramObject); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
private void addTimeseries(ObjectNode entityNode, List<TsKvEntry> timeseries) throws Exception { |
|||
if (timeseries != null && !timeseries.isEmpty()) { |
|||
ArrayNode result = entityNode.putArray("timeseries"); |
|||
Map<Long, List<TsKvEntry>> groupedTelemetry = timeseries.stream() |
|||
.collect(Collectors.groupingBy(TsKvEntry::getTs)); |
|||
for (Map.Entry<Long, List<TsKvEntry>> entry : groupedTelemetry.entrySet()) { |
|||
ObjectNode element = json.createObjectNode(); |
|||
element.put("ts", entry.getKey()); |
|||
ObjectNode values = element.putObject("values"); |
|||
for (TsKvEntry tsKvEntry : entry.getValue()) { |
|||
addKvEntry(values, tsKvEntry); |
|||
} |
|||
result.add(element); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void addKvEntry(ObjectNode entityNode, KvEntry kvEntry) throws Exception { |
|||
if (kvEntry.getDataType() == DataType.BOOLEAN) { |
|||
kvEntry.getBooleanValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); |
|||
} else if (kvEntry.getDataType() == DataType.DOUBLE) { |
|||
kvEntry.getDoubleValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); |
|||
} else if (kvEntry.getDataType() == DataType.LONG) { |
|||
kvEntry.getLongValue().ifPresent(value -> entityNode.put(kvEntry.getKey(), value)); |
|||
} else if (kvEntry.getDataType() == DataType.JSON) { |
|||
if (kvEntry.getJsonValue().isPresent()) { |
|||
entityNode.set(kvEntry.getKey(), json.readTree(kvEntry.getJsonValue().get())); |
|||
} |
|||
} else { |
|||
entityNode.put(kvEntry.getKey(), kvEntry.getValueAsString()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,94 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.asset; |
|||
|
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import com.fasterxml.jackson.databind.node.TextNode; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.cluster.TbClusterService; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.dao.asset.AssetService; |
|||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.action.EntityActionService; |
|||
import org.thingsboard.server.service.importing.AbstractBulkImportService; |
|||
import org.thingsboard.server.service.importing.BulkImportColumnType; |
|||
import org.thingsboard.server.service.importing.BulkImportRequest; |
|||
import org.thingsboard.server.service.importing.ImportedEntityInfo; |
|||
import org.thingsboard.server.service.security.AccessValidator; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.permission.AccessControlService; |
|||
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
|||
|
|||
import java.util.Map; |
|||
import java.util.Optional; |
|||
|
|||
@Service |
|||
@TbCoreComponent |
|||
public class AssetBulkImportService extends AbstractBulkImportService<Asset> { |
|||
private final AssetService assetService; |
|||
|
|||
public AssetBulkImportService(TelemetrySubscriptionService tsSubscriptionService, TbTenantProfileCache tenantProfileCache, |
|||
AccessControlService accessControlService, AccessValidator accessValidator, |
|||
EntityActionService entityActionService, TbClusterService clusterService, AssetService assetService) { |
|||
super(tsSubscriptionService, tenantProfileCache, accessControlService, accessValidator, entityActionService, clusterService); |
|||
this.assetService = assetService; |
|||
} |
|||
|
|||
@Override |
|||
protected ImportedEntityInfo<Asset> saveEntity(BulkImportRequest importRequest, Map<BulkImportColumnType, String> fields, SecurityUser user) { |
|||
ImportedEntityInfo<Asset> importedEntityInfo = new ImportedEntityInfo<>(); |
|||
|
|||
Asset asset = new Asset(); |
|||
asset.setTenantId(user.getTenantId()); |
|||
setAssetFields(asset, fields); |
|||
|
|||
Asset existingAsset = assetService.findAssetByTenantIdAndName(user.getTenantId(), asset.getName()); |
|||
if (existingAsset != null && importRequest.getMapping().getUpdate()) { |
|||
importedEntityInfo.setOldEntity(new Asset(existingAsset)); |
|||
importedEntityInfo.setUpdated(true); |
|||
existingAsset.update(asset); |
|||
asset = existingAsset; |
|||
} |
|||
asset = assetService.saveAsset(asset); |
|||
|
|||
importedEntityInfo.setEntity(asset); |
|||
return importedEntityInfo; |
|||
} |
|||
|
|||
private void setAssetFields(Asset asset, Map<BulkImportColumnType, String> fields) { |
|||
ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(asset.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); |
|||
fields.forEach((columnType, value) -> { |
|||
switch (columnType) { |
|||
case NAME: |
|||
asset.setName(value); |
|||
break; |
|||
case TYPE: |
|||
asset.setType(value); |
|||
break; |
|||
case LABEL: |
|||
asset.setLabel(value); |
|||
break; |
|||
case DESCRIPTION: |
|||
additionalInfo.set("description", new TextNode(value)); |
|||
break; |
|||
} |
|||
}); |
|||
asset.setAdditionalInfo(additionalInfo); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,259 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.device; |
|||
|
|||
import com.fasterxml.jackson.databind.node.BooleanNode; |
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import com.fasterxml.jackson.databind.node.TextNode; |
|||
import lombok.SneakyThrows; |
|||
import org.apache.commons.collections.CollectionUtils; |
|||
import org.apache.commons.lang3.RandomStringUtils; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.cluster.TbClusterService; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.DeviceProfile; |
|||
import org.thingsboard.server.common.data.DeviceProfileProvisionType; |
|||
import org.thingsboard.server.common.data.DeviceProfileType; |
|||
import org.thingsboard.server.common.data.DeviceTransportType; |
|||
import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; |
|||
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; |
|||
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; |
|||
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; |
|||
import org.thingsboard.server.common.data.device.profile.DeviceProfileData; |
|||
import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; |
|||
import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; |
|||
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
|||
import org.thingsboard.server.dao.device.DeviceCredentialsService; |
|||
import org.thingsboard.server.dao.device.DeviceProfileService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; |
|||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.action.EntityActionService; |
|||
import org.thingsboard.server.service.importing.AbstractBulkImportService; |
|||
import org.thingsboard.server.service.importing.BulkImportColumnType; |
|||
import org.thingsboard.server.service.importing.BulkImportRequest; |
|||
import org.thingsboard.server.service.importing.ImportedEntityInfo; |
|||
import org.thingsboard.server.service.security.AccessValidator; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.permission.AccessControlService; |
|||
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.EnumSet; |
|||
import java.util.Map; |
|||
import java.util.Objects; |
|||
import java.util.Optional; |
|||
import java.util.Set; |
|||
|
|||
@Service |
|||
@TbCoreComponent |
|||
public class DeviceBulkImportService extends AbstractBulkImportService<Device> { |
|||
protected final DeviceService deviceService; |
|||
protected final DeviceCredentialsService deviceCredentialsService; |
|||
protected final DeviceProfileService deviceProfileService; |
|||
|
|||
public DeviceBulkImportService(TelemetrySubscriptionService tsSubscriptionService, TbTenantProfileCache tenantProfileCache, |
|||
AccessControlService accessControlService, AccessValidator accessValidator, |
|||
EntityActionService entityActionService, TbClusterService clusterService, |
|||
DeviceService deviceService, DeviceCredentialsService deviceCredentialsService, |
|||
DeviceProfileService deviceProfileService) { |
|||
super(tsSubscriptionService, tenantProfileCache, accessControlService, accessValidator, entityActionService, clusterService); |
|||
this.deviceService = deviceService; |
|||
this.deviceCredentialsService = deviceCredentialsService; |
|||
this.deviceProfileService = deviceProfileService; |
|||
} |
|||
|
|||
@Override |
|||
protected ImportedEntityInfo<Device> saveEntity(BulkImportRequest importRequest, Map<BulkImportColumnType, String> fields, SecurityUser user) { |
|||
ImportedEntityInfo<Device> importedEntityInfo = new ImportedEntityInfo<>(); |
|||
|
|||
Device device = new Device(); |
|||
device.setTenantId(user.getTenantId()); |
|||
setDeviceFields(device, fields); |
|||
|
|||
Device existingDevice = deviceService.findDeviceByTenantIdAndName(user.getTenantId(), device.getName()); |
|||
if (existingDevice != null && importRequest.getMapping().getUpdate()) { |
|||
importedEntityInfo.setOldEntity(new Device(existingDevice)); |
|||
importedEntityInfo.setUpdated(true); |
|||
existingDevice.updateDevice(device); |
|||
device = existingDevice; |
|||
} |
|||
|
|||
DeviceCredentials deviceCredentials; |
|||
try { |
|||
deviceCredentials = createDeviceCredentials(fields); |
|||
deviceCredentialsService.formatCredentials(deviceCredentials); |
|||
} catch (Exception e) { |
|||
throw new DeviceCredentialsValidationException("Invalid device credentials: " + e.getMessage()); |
|||
} |
|||
|
|||
if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) { |
|||
setUpLwM2mDeviceProfile(user.getTenantId(), device); |
|||
} |
|||
|
|||
device = deviceService.saveDeviceWithCredentials(device, deviceCredentials); |
|||
|
|||
importedEntityInfo.setEntity(device); |
|||
return importedEntityInfo; |
|||
} |
|||
|
|||
private void setDeviceFields(Device device, Map<BulkImportColumnType, String> fields) { |
|||
ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(device.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); |
|||
fields.forEach((columnType, value) -> { |
|||
switch (columnType) { |
|||
case NAME: |
|||
device.setName(value); |
|||
break; |
|||
case TYPE: |
|||
device.setType(value); |
|||
break; |
|||
case LABEL: |
|||
device.setLabel(value); |
|||
break; |
|||
case DESCRIPTION: |
|||
additionalInfo.set("description", new TextNode(value)); |
|||
break; |
|||
case IS_GATEWAY: |
|||
additionalInfo.set("gateway", BooleanNode.valueOf(Boolean.parseBoolean(value))); |
|||
break; |
|||
} |
|||
device.setAdditionalInfo(additionalInfo); |
|||
}); |
|||
} |
|||
|
|||
@SneakyThrows |
|||
private DeviceCredentials createDeviceCredentials(Map<BulkImportColumnType, String> fields) { |
|||
DeviceCredentials credentials = new DeviceCredentials(); |
|||
if (fields.containsKey(BulkImportColumnType.LWM2M_CLIENT_ENDPOINT)) { |
|||
credentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS); |
|||
setUpLwm2mCredentials(fields, credentials); |
|||
} else if (fields.containsKey(BulkImportColumnType.X509)) { |
|||
credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE); |
|||
setUpX509CertificateCredentials(fields, credentials); |
|||
} else if (CollectionUtils.containsAny(fields.keySet(), EnumSet.of(BulkImportColumnType.MQTT_CLIENT_ID, BulkImportColumnType.MQTT_USER_NAME, BulkImportColumnType.MQTT_PASSWORD))) { |
|||
credentials.setCredentialsType(DeviceCredentialsType.MQTT_BASIC); |
|||
setUpBasicMqttCredentials(fields, credentials); |
|||
} else { |
|||
credentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); |
|||
setUpAccessTokenCredentials(fields, credentials); |
|||
} |
|||
return credentials; |
|||
} |
|||
|
|||
private void setUpAccessTokenCredentials(Map<BulkImportColumnType, String> fields, DeviceCredentials credentials) { |
|||
credentials.setCredentialsId(Optional.ofNullable(fields.get(BulkImportColumnType.ACCESS_TOKEN)) |
|||
.orElseGet(() -> RandomStringUtils.randomAlphanumeric(20))); |
|||
} |
|||
|
|||
private void setUpBasicMqttCredentials(Map<BulkImportColumnType, String> fields, DeviceCredentials credentials) { |
|||
BasicMqttCredentials basicMqttCredentials = new BasicMqttCredentials(); |
|||
basicMqttCredentials.setClientId(fields.get(BulkImportColumnType.MQTT_CLIENT_ID)); |
|||
basicMqttCredentials.setUserName(fields.get(BulkImportColumnType.MQTT_USER_NAME)); |
|||
basicMqttCredentials.setPassword(fields.get(BulkImportColumnType.MQTT_PASSWORD)); |
|||
credentials.setCredentialsValue(JacksonUtil.toString(basicMqttCredentials)); |
|||
} |
|||
|
|||
private void setUpX509CertificateCredentials(Map<BulkImportColumnType, String> fields, DeviceCredentials credentials) { |
|||
credentials.setCredentialsValue(fields.get(BulkImportColumnType.X509)); |
|||
} |
|||
|
|||
private void setUpLwm2mCredentials(Map<BulkImportColumnType, String> fields, DeviceCredentials credentials) throws com.fasterxml.jackson.core.JsonProcessingException { |
|||
ObjectNode lwm2mCredentials = JacksonUtil.newObjectNode(); |
|||
|
|||
Set.of(BulkImportColumnType.LWM2M_CLIENT_SECURITY_CONFIG_MODE, BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECURITY_MODE, |
|||
BulkImportColumnType.LWM2M_SERVER_SECURITY_MODE).stream() |
|||
.map(fields::get) |
|||
.filter(Objects::nonNull) |
|||
.forEach(securityMode -> { |
|||
try { |
|||
LwM2MSecurityMode.valueOf(securityMode.toUpperCase()); |
|||
} catch (IllegalArgumentException e) { |
|||
throw new DeviceCredentialsValidationException("Unknown LwM2M security mode: " + securityMode + ", (the mode should be: NO_SEC, PSK, RPK, X509)!"); |
|||
} |
|||
}); |
|||
|
|||
ObjectNode client = JacksonUtil.newObjectNode(); |
|||
setValues(client, fields, Set.of(BulkImportColumnType.LWM2M_CLIENT_SECURITY_CONFIG_MODE, |
|||
BulkImportColumnType.LWM2M_CLIENT_ENDPOINT, BulkImportColumnType.LWM2M_CLIENT_IDENTITY, |
|||
BulkImportColumnType.LWM2M_CLIENT_KEY, BulkImportColumnType.LWM2M_CLIENT_CERT)); |
|||
LwM2MClientCredentials lwM2MClientCredentials = JacksonUtil.treeToValue(client, LwM2MClientCredentials.class); |
|||
// so that only fields needed for specific type of lwM2MClientCredentials were saved in json
|
|||
lwm2mCredentials.set("client", JacksonUtil.valueToTree(lwM2MClientCredentials)); |
|||
|
|||
ObjectNode bootstrapServer = JacksonUtil.newObjectNode(); |
|||
setValues(bootstrapServer, fields, Set.of(BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECURITY_MODE, |
|||
BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_PUBLIC_KEY_OR_ID, BulkImportColumnType.LWM2M_BOOTSTRAP_SERVER_SECRET_KEY)); |
|||
|
|||
ObjectNode lwm2mServer = JacksonUtil.newObjectNode(); |
|||
setValues(lwm2mServer, fields, Set.of(BulkImportColumnType.LWM2M_SERVER_SECURITY_MODE, |
|||
BulkImportColumnType.LWM2M_SERVER_CLIENT_PUBLIC_KEY_OR_ID, BulkImportColumnType.LWM2M_SERVER_CLIENT_SECRET_KEY)); |
|||
|
|||
ObjectNode bootstrap = JacksonUtil.newObjectNode(); |
|||
bootstrap.set("bootstrapServer", bootstrapServer); |
|||
bootstrap.set("lwm2mServer", lwm2mServer); |
|||
lwm2mCredentials.set("bootstrap", bootstrap); |
|||
|
|||
credentials.setCredentialsValue(lwm2mCredentials.toString()); |
|||
} |
|||
|
|||
private void setUpLwM2mDeviceProfile(TenantId tenantId, Device device) { |
|||
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileByName(tenantId, device.getType()); |
|||
if (deviceProfile != null) { |
|||
if (deviceProfile.getTransportType() != DeviceTransportType.LWM2M) { |
|||
deviceProfile.setTransportType(DeviceTransportType.LWM2M); |
|||
deviceProfile.getProfileData().setTransportConfiguration(new Lwm2mDeviceProfileTransportConfiguration()); |
|||
deviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); |
|||
device.setDeviceProfileId(deviceProfile.getId()); |
|||
} |
|||
} else { |
|||
deviceProfile = new DeviceProfile(); |
|||
deviceProfile.setTenantId(tenantId); |
|||
deviceProfile.setType(DeviceProfileType.DEFAULT); |
|||
deviceProfile.setName(device.getType()); |
|||
deviceProfile.setTransportType(DeviceTransportType.LWM2M); |
|||
deviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED); |
|||
|
|||
DeviceProfileData deviceProfileData = new DeviceProfileData(); |
|||
DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); |
|||
DeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration(); |
|||
DisabledDeviceProfileProvisionConfiguration provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(null); |
|||
|
|||
deviceProfileData.setConfiguration(configuration); |
|||
deviceProfileData.setTransportConfiguration(transportConfiguration); |
|||
deviceProfileData.setProvisionConfiguration(provisionConfiguration); |
|||
deviceProfile.setProfileData(deviceProfileData); |
|||
|
|||
deviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); |
|||
device.setDeviceProfileId(deviceProfile.getId()); |
|||
} |
|||
} |
|||
|
|||
private void setValues(ObjectNode objectNode, Map<BulkImportColumnType, String> data, Collection<BulkImportColumnType> columns) { |
|||
for (BulkImportColumnType column : columns) { |
|||
String value = StringUtils.defaultString(data.get(column), column.getDefaultValue()); |
|||
if (value != null && column.getKey() != null) { |
|||
objectNode.set(column.getKey(), new TextNode(value)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,110 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.http.HttpHost; |
|||
import org.apache.http.conn.ssl.DefaultHostnameVerifier; |
|||
import org.apache.http.impl.client.CloseableHttpClient; |
|||
import org.apache.http.impl.client.HttpClients; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; |
|||
import org.springframework.http.client.SimpleClientHttpRequestFactory; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.web.client.RestTemplate; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
import java.net.InetSocketAddress; |
|||
import java.net.Proxy; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
import static org.apache.commons.lang3.StringUtils.isNotEmpty; |
|||
|
|||
@Service |
|||
@TbCoreComponent |
|||
@Slf4j |
|||
public class DefaultEdgeLicenseService implements EdgeLicenseService { |
|||
|
|||
private RestTemplate restTemplate; |
|||
|
|||
private static final String EDGE_LICENSE_SERVER_ENDPOINT = "https://license.thingsboard.io"; |
|||
|
|||
@Value("${edges.enabled:false}") |
|||
private boolean edgesEnabled; |
|||
|
|||
@PostConstruct |
|||
public void init() { |
|||
if (edgesEnabled) { |
|||
initRestTemplate(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public ResponseEntity<JsonNode> checkInstance(JsonNode request) { |
|||
return this.restTemplate.postForEntity(EDGE_LICENSE_SERVER_ENDPOINT + "/api/license/checkInstance", request, JsonNode.class); |
|||
} |
|||
|
|||
@Override |
|||
public ResponseEntity<JsonNode> activateInstance(String edgeLicenseSecret, String releaseDate) { |
|||
Map<String, String> params = new HashMap<>(); |
|||
params.put("licenseSecret", edgeLicenseSecret); |
|||
params.put("releaseDate", releaseDate); |
|||
return this.restTemplate.postForEntity(EDGE_LICENSE_SERVER_ENDPOINT + "/api/license/activateInstance?licenseSecret={licenseSecret}&releaseDate={releaseDate}", null, JsonNode.class, params); |
|||
} |
|||
|
|||
private void initRestTemplate() { |
|||
boolean jdkHttpClientEnabled = isNotEmpty(System.getProperty("tb.proxy.jdk")) && System.getProperty("tb.proxy.jdk").equalsIgnoreCase("true"); |
|||
boolean systemProxyEnabled = isNotEmpty(System.getProperty("tb.proxy.system")) && System.getProperty("tb.proxy.system").equalsIgnoreCase("true"); |
|||
boolean proxyEnabled = isNotEmpty(System.getProperty("tb.proxy.host")) && isNotEmpty(System.getProperty("tb.proxy.port")); |
|||
if (jdkHttpClientEnabled) { |
|||
log.warn("Going to use plain JDK Http Client!"); |
|||
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); |
|||
if (proxyEnabled) { |
|||
log.warn("Going to use Proxy Server: [{}:{}]", System.getProperty("tb.proxy.host"), System.getProperty("tb.proxy.port")); |
|||
factory.setProxy(new Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved(System.getProperty("tb.proxy.host"), Integer.parseInt(System.getProperty("tb.proxy.port"))))); |
|||
} |
|||
|
|||
this.restTemplate = new RestTemplate(new SimpleClientHttpRequestFactory()); |
|||
} else { |
|||
CloseableHttpClient httpClient; |
|||
HttpComponentsClientHttpRequestFactory requestFactory; |
|||
if (systemProxyEnabled) { |
|||
log.warn("Going to use System Proxy Server!"); |
|||
httpClient = HttpClients.createSystem(); |
|||
requestFactory = new HttpComponentsClientHttpRequestFactory(); |
|||
requestFactory.setHttpClient(httpClient); |
|||
this.restTemplate = new RestTemplate(requestFactory); |
|||
} else if (proxyEnabled) { |
|||
log.warn("Going to use Proxy Server: [{}:{}]", System.getProperty("tb.proxy.host"), System.getProperty("tb.proxy.port")); |
|||
httpClient = HttpClients.custom().setSSLHostnameVerifier(new DefaultHostnameVerifier()).setProxy(new HttpHost(System.getProperty("tb.proxy.host"), Integer.parseInt(System.getProperty("tb.proxy.port")), "https")).build(); |
|||
requestFactory = new HttpComponentsClientHttpRequestFactory(); |
|||
requestFactory.setHttpClient(httpClient); |
|||
this.restTemplate = new RestTemplate(requestFactory); |
|||
} else { |
|||
httpClient = HttpClients.custom().setSSLHostnameVerifier(new DefaultHostnameVerifier()).build(); |
|||
requestFactory = new HttpComponentsClientHttpRequestFactory(); |
|||
requestFactory.setHttpClient(httpClient); |
|||
this.restTemplate = new RestTemplate(requestFactory); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,106 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge; |
|||
|
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import com.fasterxml.jackson.databind.node.TextNode; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.cluster.TbClusterService; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.dao.edge.EdgeService; |
|||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.action.EntityActionService; |
|||
import org.thingsboard.server.service.importing.AbstractBulkImportService; |
|||
import org.thingsboard.server.service.importing.BulkImportColumnType; |
|||
import org.thingsboard.server.service.importing.BulkImportRequest; |
|||
import org.thingsboard.server.service.importing.ImportedEntityInfo; |
|||
import org.thingsboard.server.service.security.AccessValidator; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.permission.AccessControlService; |
|||
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
|||
|
|||
import java.util.Map; |
|||
import java.util.Optional; |
|||
|
|||
@Service |
|||
@TbCoreComponent |
|||
public class EdgeBulkImportService extends AbstractBulkImportService<Edge> { |
|||
private final EdgeService edgeService; |
|||
|
|||
public EdgeBulkImportService(TelemetrySubscriptionService tsSubscriptionService, TbTenantProfileCache tenantProfileCache, |
|||
AccessControlService accessControlService, AccessValidator accessValidator, |
|||
EntityActionService entityActionService, TbClusterService clusterService, EdgeService edgeService) { |
|||
super(tsSubscriptionService, tenantProfileCache, accessControlService, accessValidator, entityActionService, clusterService); |
|||
this.edgeService = edgeService; |
|||
} |
|||
|
|||
@Override |
|||
protected ImportedEntityInfo<Edge> saveEntity(BulkImportRequest importRequest, Map<BulkImportColumnType, String> fields, SecurityUser user) { |
|||
ImportedEntityInfo<Edge> importedEntityInfo = new ImportedEntityInfo<>(); |
|||
|
|||
Edge edge = new Edge(); |
|||
edge.setTenantId(user.getTenantId()); |
|||
setEdgeFields(edge, fields); |
|||
|
|||
Edge existingEdge = edgeService.findEdgeByTenantIdAndName(user.getTenantId(), edge.getName()); |
|||
if (existingEdge != null && importRequest.getMapping().getUpdate()) { |
|||
importedEntityInfo.setOldEntity(new Edge(existingEdge)); |
|||
importedEntityInfo.setUpdated(true); |
|||
existingEdge.update(edge); |
|||
edge = existingEdge; |
|||
} |
|||
edge = edgeService.saveEdge(edge, true); |
|||
|
|||
importedEntityInfo.setEntity(edge); |
|||
return importedEntityInfo; |
|||
} |
|||
|
|||
private void setEdgeFields(Edge edge, Map<BulkImportColumnType, String> fields) { |
|||
ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(edge.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); |
|||
fields.forEach((columnType, value) -> { |
|||
switch (columnType) { |
|||
case NAME: |
|||
edge.setName(value); |
|||
break; |
|||
case TYPE: |
|||
edge.setType(value); |
|||
break; |
|||
case LABEL: |
|||
edge.setLabel(value); |
|||
break; |
|||
case DESCRIPTION: |
|||
additionalInfo.set("description", new TextNode(value)); |
|||
break; |
|||
case EDGE_LICENSE_KEY: |
|||
edge.setEdgeLicenseKey(value); |
|||
break; |
|||
case CLOUD_ENDPOINT: |
|||
edge.setCloudEndpoint(value); |
|||
break; |
|||
case ROUTING_KEY: |
|||
edge.setRoutingKey(value); |
|||
break; |
|||
case SECRET: |
|||
edge.setSecret(value); |
|||
break; |
|||
} |
|||
}); |
|||
edge.setAdditionalInfo(additionalInfo); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import org.springframework.http.ResponseEntity; |
|||
|
|||
public interface EdgeLicenseService { |
|||
|
|||
ResponseEntity<JsonNode> checkInstance(JsonNode request); |
|||
|
|||
ResponseEntity<JsonNode> activateInstance(String licenseSecret, String releaseDate); |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
|
|||
public final class EdgeEventUtils { |
|||
|
|||
private EdgeEventUtils() { |
|||
} |
|||
|
|||
public static EdgeEvent constructEdgeEvent(TenantId tenantId, |
|||
EdgeId edgeId, |
|||
EdgeEventType type, |
|||
EdgeEventActionType action, |
|||
EntityId entityId, |
|||
JsonNode body) { |
|||
EdgeEvent edgeEvent = new EdgeEvent(); |
|||
edgeEvent.setTenantId(tenantId); |
|||
edgeEvent.setEdgeId(edgeId); |
|||
edgeEvent.setType(type); |
|||
edgeEvent.setAction(action); |
|||
if (entityId != null) { |
|||
edgeEvent.setEntityId(entityId.getId()); |
|||
} |
|||
edgeEvent.setBody(body); |
|||
return edgeEvent; |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc; |
|||
|
|||
import com.google.common.util.concurrent.SettableFuture; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.gen.edge.v1.DownlinkMsg; |
|||
|
|||
import java.util.LinkedHashMap; |
|||
import java.util.Map; |
|||
import java.util.concurrent.ScheduledFuture; |
|||
|
|||
@Data |
|||
public class EdgeSessionState { |
|||
|
|||
private final Map<Integer, DownlinkMsg> pendingMsgsMap = new LinkedHashMap<>(); |
|||
private SettableFuture<Void> sendDownlinkMsgsFuture; |
|||
private ScheduledFuture<?> scheduledSendDownlinkTask; |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc; |
|||
|
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.service.edge.EdgeContextComponent; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.AdminSettingsEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.AssetsEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.CustomerEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.CustomerUsersEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.DashboardsEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.DeviceProfilesEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.EdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.RuleChainsEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.SystemWidgetsBundlesEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.TenantAdminUsersEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.TenantWidgetsBundlesEdgeEventFetcher; |
|||
|
|||
import java.util.LinkedList; |
|||
import java.util.List; |
|||
import java.util.NoSuchElementException; |
|||
|
|||
public class EdgeSyncCursor { |
|||
|
|||
List<EdgeEventFetcher> fetchers = new LinkedList<>(); |
|||
|
|||
int currentIdx = 0; |
|||
|
|||
public EdgeSyncCursor(EdgeContextComponent ctx, Edge edge) { |
|||
fetchers.add(new SystemWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService())); |
|||
fetchers.add(new TenantWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService())); |
|||
fetchers.add(new DeviceProfilesEdgeEventFetcher(ctx.getDeviceProfileService())); |
|||
fetchers.add(new RuleChainsEdgeEventFetcher(ctx.getRuleChainService())); |
|||
fetchers.add(new TenantAdminUsersEdgeEventFetcher(ctx.getUserService())); |
|||
if (edge.getCustomerId() != null && !EntityId.NULL_UUID.equals(edge.getCustomerId().getId())) { |
|||
fetchers.add(new CustomerEdgeEventFetcher()); |
|||
fetchers.add(new CustomerUsersEdgeEventFetcher(ctx.getUserService(), edge.getCustomerId())); |
|||
} |
|||
fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService(), ctx.getFreemarkerConfig())); |
|||
fetchers.add(new AssetsEdgeEventFetcher(ctx.getAssetService())); |
|||
fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService())); |
|||
} |
|||
|
|||
public boolean hasNext() { |
|||
return fetchers.size() > currentIdx; |
|||
} |
|||
|
|||
public EdgeEventFetcher getNext() { |
|||
if (!hasNext()) { |
|||
throw new NoSuchElementException(); |
|||
} |
|||
EdgeEventFetcher edgeEventFetcher = fetchers.get(currentIdx); |
|||
currentIdx++; |
|||
return edgeEventFetcher; |
|||
} |
|||
|
|||
public int getCurrentIdx() { |
|||
return currentIdx; |
|||
} |
|||
} |
|||
@ -0,0 +1,161 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import com.datastax.oss.driver.api.core.uuid.Uuids; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import freemarker.template.Configuration; |
|||
import freemarker.template.Template; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.apache.commons.lang3.text.WordUtils; |
|||
import org.thingsboard.server.common.data.AdminSettings; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.AdminSettingsId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.dao.settings.AdminSettingsService; |
|||
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Arrays; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.regex.Matcher; |
|||
import java.util.regex.Pattern; |
|||
|
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher { |
|||
|
|||
private static final ObjectMapper mapper = new ObjectMapper(); |
|||
|
|||
private final AdminSettingsService adminSettingsService; |
|||
private final Configuration freemarkerConfig; |
|||
|
|||
private static Pattern startPattern = Pattern.compile("<div class=\"content\".*?>"); |
|||
private static Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>"); |
|||
|
|||
private static List<String> templatesNames = Arrays.asList( |
|||
"account.activated.ftl", |
|||
"account.lockout.ftl", |
|||
"activation.ftl", |
|||
"password.was.reset.ftl", |
|||
"reset.password.ftl", |
|||
"test.ftl"); |
|||
|
|||
// TODO: fix format of next templates
|
|||
// "state.disabled.ftl",
|
|||
// "state.enabled.ftl",
|
|||
// "state.warning.ftl",
|
|||
|
|||
@Override |
|||
public PageLink getPageLink(int pageSize) { |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) throws Exception { |
|||
List<EdgeEvent> result = new ArrayList<>(); |
|||
|
|||
AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail"); |
|||
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, |
|||
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings))); |
|||
|
|||
AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue()); |
|||
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, |
|||
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings))); |
|||
|
|||
AdminSettings systemMailTemplates = loadMailTemplates(); |
|||
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, |
|||
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates))); |
|||
|
|||
AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue()); |
|||
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, |
|||
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates))); |
|||
|
|||
// @voba - returns PageData object to be in sync with other fetchers
|
|||
return new PageData<>(result, 1, result.size(), false); |
|||
} |
|||
|
|||
private AdminSettings loadMailTemplates() throws Exception { |
|||
Map<String, Object> mailTemplates = new HashMap<>(); |
|||
for (String templatesName : templatesNames) { |
|||
Template template = freemarkerConfig.getTemplate(templatesName); |
|||
if (template != null) { |
|||
String name = validateName(template.getName()); |
|||
Map<String, String> mailTemplate = getMailTemplateFromFile(template.toString()); |
|||
if (mailTemplate != null) { |
|||
mailTemplates.put(name, mailTemplate); |
|||
} else { |
|||
log.error("Can't load mail template from file {}", template.getName()); |
|||
} |
|||
} |
|||
} |
|||
AdminSettings adminSettings = new AdminSettings(); |
|||
adminSettings.setId(new AdminSettingsId(Uuids.timeBased())); |
|||
adminSettings.setKey("mailTemplates"); |
|||
adminSettings.setJsonValue(mapper.convertValue(mailTemplates, JsonNode.class)); |
|||
return adminSettings; |
|||
} |
|||
|
|||
private Map<String, String> getMailTemplateFromFile(String stringTemplate) { |
|||
Map<String, String> mailTemplate = new HashMap<>(); |
|||
Matcher start = startPattern.matcher(stringTemplate); |
|||
Matcher end = endPattern.matcher(stringTemplate); |
|||
if (start.find() && end.find()) { |
|||
String body = StringUtils.substringBetween(stringTemplate, start.group(), end.group()).replaceAll("\t", ""); |
|||
String subject = StringUtils.substringBetween(body, "<h2>", "</h2>"); |
|||
mailTemplate.put("subject", subject); |
|||
mailTemplate.put("body", body); |
|||
} else { |
|||
return null; |
|||
} |
|||
return mailTemplate; |
|||
} |
|||
|
|||
private String validateName(String name) throws Exception { |
|||
StringBuilder nameBuilder = new StringBuilder(); |
|||
name = name.replace(".ftl", ""); |
|||
String[] nameParts = name.split("\\."); |
|||
if (nameParts.length >= 1) { |
|||
nameBuilder.append(nameParts[0]); |
|||
for (int i = 1; i < nameParts.length; i++) { |
|||
String word = WordUtils.capitalize(nameParts[i]); |
|||
nameBuilder.append(word); |
|||
} |
|||
return nameBuilder.toString(); |
|||
} else { |
|||
throw new Exception("Error during filename validation"); |
|||
} |
|||
} |
|||
|
|||
private AdminSettings convertToTenantAdminSettings(String key, ObjectNode jsonValue) { |
|||
AdminSettings tenantMailSettings = new AdminSettings(); |
|||
jsonValue.put("useSystemMailSettings", true); |
|||
tenantMailSettings.setJsonValue(jsonValue); |
|||
tenantMailSettings.setKey(key); |
|||
return tenantMailSettings; |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.dao.asset.AssetService; |
|||
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; |
|||
|
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class AssetsEdgeEventFetcher extends BasePageableEdgeEventFetcher<Asset> { |
|||
|
|||
private final AssetService assetService; |
|||
|
|||
@Override |
|||
PageData<Asset> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return assetService.findAssetsByTenantIdAndEdgeId(tenantId, edge.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, Asset asset) { |
|||
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET, |
|||
EdgeEventActionType.ADDED, asset.getId(), null); |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.BaseData; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EventId; |
|||
import org.thingsboard.server.common.data.id.HasId; |
|||
import org.thingsboard.server.common.data.id.HasUUID; |
|||
import org.thingsboard.server.common.data.id.IdBased; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.id.UUIDBased; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.rule.RuleChain; |
|||
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
public abstract class BasePageableEdgeEventFetcher<T> implements EdgeEventFetcher { |
|||
|
|||
@Override |
|||
public PageLink getPageLink(int pageSize) { |
|||
return new PageLink(pageSize); |
|||
} |
|||
|
|||
@Override |
|||
public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
log.trace("[{}] start fetching edge events [{}]", tenantId, edge.getId()); |
|||
PageData<T> pageData = fetchPageData(tenantId, edge, pageLink); |
|||
List<EdgeEvent> result = new ArrayList<>(); |
|||
if (!pageData.getData().isEmpty()) { |
|||
for (T entity : pageData.getData()) { |
|||
result.add(constructEdgeEvent(tenantId, edge, entity)); |
|||
} |
|||
} |
|||
return new PageData<>(result, pageData.getTotalPages(), pageData.getTotalElements(), pageData.hasNext()); |
|||
} |
|||
|
|||
abstract PageData<T> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink); |
|||
|
|||
abstract EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, T entity); |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.dao.user.UserService; |
|||
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; |
|||
|
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
public abstract class BaseUsersEdgeEventFetcher extends BasePageableEdgeEventFetcher<User> { |
|||
|
|||
protected final UserService userService; |
|||
|
|||
@Override |
|||
PageData<User> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return findUsers(tenantId, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, User user) { |
|||
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER, |
|||
EdgeEventActionType.ADDED, user.getId(), null); |
|||
} |
|||
|
|||
protected abstract PageData<User> findUsers(TenantId tenantId, PageLink pageLink); |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.widget.WidgetsBundle; |
|||
import org.thingsboard.server.dao.widget.WidgetsBundleService; |
|||
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; |
|||
|
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
public abstract class BaseWidgetsBundlesEdgeEventFetcher extends BasePageableEdgeEventFetcher<WidgetsBundle> { |
|||
|
|||
protected final WidgetsBundleService widgetsBundleService; |
|||
|
|||
@Override |
|||
PageData<WidgetsBundle> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return findWidgetsBundles(tenantId, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, WidgetsBundle widgetsBundle) { |
|||
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGETS_BUNDLE, |
|||
EdgeEventActionType.ADDED, widgetsBundle.getId(), null); |
|||
} |
|||
|
|||
protected abstract PageData<WidgetsBundle> findWidgetsBundles(TenantId tenantId, PageLink pageLink); |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class CustomerEdgeEventFetcher implements EdgeEventFetcher { |
|||
|
|||
@Override |
|||
public PageLink getPageLink(int pageSize) { |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
List<EdgeEvent> result = new ArrayList<>(); |
|||
result.add(EdgeEventUtils.constructEdgeEvent(edge.getTenantId(), edge.getId(), |
|||
EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, edge.getCustomerId(), null)); |
|||
// @voba - returns PageData object to be in sync with other fetchers
|
|||
return new PageData<>(result, 1, result.size(), false); |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.dao.user.UserService; |
|||
|
|||
public class CustomerUsersEdgeEventFetcher extends BaseUsersEdgeEventFetcher { |
|||
|
|||
private final CustomerId customerId; |
|||
|
|||
public CustomerUsersEdgeEventFetcher(UserService userService, CustomerId customerId) { |
|||
super(userService); |
|||
this.customerId = customerId; |
|||
} |
|||
|
|||
@Override |
|||
protected PageData<User> findUsers(TenantId tenantId, PageLink pageLink) { |
|||
return userService.findCustomerUsers(tenantId, customerId, pageLink); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.DashboardInfo; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.dao.dashboard.DashboardService; |
|||
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; |
|||
|
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class DashboardsEdgeEventFetcher extends BasePageableEdgeEventFetcher<DashboardInfo> { |
|||
|
|||
private final DashboardService dashboardService; |
|||
|
|||
@Override |
|||
PageData<DashboardInfo> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return dashboardService.findDashboardsByTenantIdAndEdgeId(tenantId, edge.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, DashboardInfo dashboardInfo) { |
|||
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.DASHBOARD, |
|||
EdgeEventActionType.ADDED, dashboardInfo.getId(), null); |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.DeviceProfile; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.dao.device.DeviceProfileService; |
|||
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; |
|||
|
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class DeviceProfilesEdgeEventFetcher extends BasePageableEdgeEventFetcher<DeviceProfile> { |
|||
|
|||
private final DeviceProfileService deviceProfileService; |
|||
|
|||
@Override |
|||
PageData<DeviceProfile> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return deviceProfileService.findDeviceProfiles(tenantId, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, DeviceProfile deviceProfile) { |
|||
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE_PROFILE, |
|||
EdgeEventActionType.ADDED, deviceProfile.getId(), null); |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
|
|||
public interface EdgeEventFetcher { |
|||
|
|||
PageLink getPageLink(int pageSize); |
|||
|
|||
PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) throws Exception; |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.page.SortOrder; |
|||
import org.thingsboard.server.common.data.page.TimePageLink; |
|||
import org.thingsboard.server.dao.edge.EdgeEventService; |
|||
|
|||
@AllArgsConstructor |
|||
public class GeneralEdgeEventFetcher implements EdgeEventFetcher { |
|||
|
|||
private final Long queueStartTs; |
|||
private final EdgeEventService edgeEventService; |
|||
|
|||
@Override |
|||
public PageLink getPageLink(int pageSize) { |
|||
return new TimePageLink( |
|||
pageSize, |
|||
0, |
|||
null, |
|||
new SortOrder("createdTime", SortOrder.Direction.ASC), |
|||
queueStartTs, |
|||
null); |
|||
} |
|||
|
|||
@Override |
|||
public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return edgeEventService.findEdgeEvents(tenantId, edge.getId(), (TimePageLink) pageLink, true); |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.rule.RuleChain; |
|||
import org.thingsboard.server.dao.rule.RuleChainService; |
|||
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; |
|||
|
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
public class RuleChainsEdgeEventFetcher extends BasePageableEdgeEventFetcher<RuleChain> { |
|||
|
|||
private final RuleChainService ruleChainService; |
|||
|
|||
@Override |
|||
PageData<RuleChain> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edge.getId(), pageLink); |
|||
} |
|||
|
|||
@Override |
|||
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, RuleChain ruleChain) { |
|||
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, |
|||
EdgeEventActionType.ADDED, ruleChain.getId(), null); |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.widget.WidgetsBundle; |
|||
import org.thingsboard.server.dao.widget.WidgetsBundleService; |
|||
|
|||
@Slf4j |
|||
public class SystemWidgetsBundlesEdgeEventFetcher extends BaseWidgetsBundlesEdgeEventFetcher { |
|||
|
|||
public SystemWidgetsBundlesEdgeEventFetcher(WidgetsBundleService widgetsBundleService) { |
|||
super(widgetsBundleService); |
|||
} |
|||
|
|||
@Override |
|||
protected PageData<WidgetsBundle> findWidgetsBundles(TenantId tenantId, PageLink pageLink) { |
|||
return widgetsBundleService.findSystemWidgetsBundlesByPageLink(tenantId, pageLink); |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.dao.user.UserService; |
|||
|
|||
public class TenantAdminUsersEdgeEventFetcher extends BaseUsersEdgeEventFetcher { |
|||
|
|||
public TenantAdminUsersEdgeEventFetcher(UserService userService) { |
|||
super(userService); |
|||
} |
|||
|
|||
@Override |
|||
protected PageData<User> findUsers(TenantId tenantId, PageLink pageLink) { |
|||
return userService.findTenantAdmins(tenantId, pageLink); |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.fetch; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.widget.WidgetsBundle; |
|||
import org.thingsboard.server.dao.widget.WidgetsBundleService; |
|||
|
|||
@Slf4j |
|||
public class TenantWidgetsBundlesEdgeEventFetcher extends BaseWidgetsBundlesEdgeEventFetcher { |
|||
|
|||
public TenantWidgetsBundlesEdgeEventFetcher(WidgetsBundleService widgetsBundleService) { |
|||
super(widgetsBundleService); |
|||
} |
|||
@Override |
|||
protected PageData<WidgetsBundle> findWidgetsBundles(TenantId tenantId, PageLink pageLink) { |
|||
return widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink); |
|||
} |
|||
} |
|||
@ -1,671 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2021 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.edge.rpc.init; |
|||
|
|||
import com.datastax.oss.driver.api.core.uuid.Uuids; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import com.google.common.util.concurrent.FutureCallback; |
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import com.google.common.util.concurrent.SettableFuture; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.io.FileUtils; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.apache.commons.lang3.text.WordUtils; |
|||
import org.checkerframework.checker.nullness.qual.Nullable; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.core.io.DefaultResourceLoader; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.AdminSettings; |
|||
import org.thingsboard.server.common.data.DashboardInfo; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.DeviceProfile; |
|||
import org.thingsboard.server.common.data.EdgeUtils; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.EntityView; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.AdminSettingsId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.id.UserId; |
|||
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|||
import org.thingsboard.server.common.data.kv.DataType; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.relation.EntityRelation; |
|||
import org.thingsboard.server.common.data.relation.EntityRelationsQuery; |
|||
import org.thingsboard.server.common.data.relation.EntitySearchDirection; |
|||
import org.thingsboard.server.common.data.relation.RelationsSearchParameters; |
|||
import org.thingsboard.server.common.data.rule.RuleChain; |
|||
import org.thingsboard.server.common.data.widget.WidgetType; |
|||
import org.thingsboard.server.common.data.widget.WidgetsBundle; |
|||
import org.thingsboard.server.dao.asset.AssetService; |
|||
import org.thingsboard.server.dao.attributes.AttributesService; |
|||
import org.thingsboard.server.dao.dashboard.DashboardService; |
|||
import org.thingsboard.server.dao.device.DeviceProfileService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
import org.thingsboard.server.dao.edge.EdgeEventService; |
|||
import org.thingsboard.server.dao.entityview.EntityViewService; |
|||
import org.thingsboard.server.dao.relation.RelationService; |
|||
import org.thingsboard.server.dao.rule.RuleChainService; |
|||
import org.thingsboard.server.dao.settings.AdminSettingsService; |
|||
import org.thingsboard.server.dao.user.UserService; |
|||
import org.thingsboard.server.dao.widget.WidgetTypeService; |
|||
import org.thingsboard.server.dao.widget.WidgetsBundleService; |
|||
import org.thingsboard.server.gen.edge.AttributesRequestMsg; |
|||
import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg; |
|||
import org.thingsboard.server.gen.edge.RelationRequestMsg; |
|||
import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg; |
|||
import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg; |
|||
import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
|||
import org.thingsboard.server.service.queue.TbClusterService; |
|||
|
|||
import java.io.File; |
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.ArrayList; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.UUID; |
|||
import java.util.regex.Matcher; |
|||
import java.util.regex.Pattern; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
public class DefaultSyncEdgeService implements SyncEdgeService { |
|||
|
|||
private static final ObjectMapper mapper = new ObjectMapper(); |
|||
|
|||
private static final int DEFAULT_LIMIT = 100; |
|||
|
|||
@Autowired |
|||
private EdgeEventService edgeEventService; |
|||
|
|||
@Autowired |
|||
private AttributesService attributesService; |
|||
|
|||
@Autowired |
|||
private RuleChainService ruleChainService; |
|||
|
|||
@Autowired |
|||
private RelationService relationService; |
|||
|
|||
@Autowired |
|||
private DeviceService deviceService; |
|||
|
|||
@Autowired |
|||
private DeviceProfileService deviceProfileService; |
|||
|
|||
@Autowired |
|||
private AssetService assetService; |
|||
|
|||
@Autowired |
|||
private EntityViewService entityViewService; |
|||
|
|||
@Autowired |
|||
private DashboardService dashboardService; |
|||
|
|||
@Autowired |
|||
private UserService userService; |
|||
|
|||
@Autowired |
|||
private WidgetsBundleService widgetsBundleService; |
|||
|
|||
@Autowired |
|||
private WidgetTypeService widgetTypeService; |
|||
|
|||
@Autowired |
|||
private AdminSettingsService adminSettingsService; |
|||
|
|||
@Autowired |
|||
private DbCallbackExecutorService dbCallbackExecutorService; |
|||
|
|||
@Autowired |
|||
private TbClusterService tbClusterService; |
|||
|
|||
@Override |
|||
public void sync(TenantId tenantId, Edge edge) { |
|||
log.trace("[{}][{}] Staring edge sync process", tenantId, edge.getId()); |
|||
try { |
|||
syncWidgetsBundles(tenantId, edge); |
|||
// TODO: voba - implement this functionality
|
|||
// syncAdminSettings(edge);
|
|||
syncDeviceProfiles(tenantId, edge); |
|||
syncRuleChains(tenantId, edge); |
|||
syncUsers(tenantId, edge); |
|||
syncAssets(tenantId, edge); |
|||
syncEntityViews(tenantId, edge); |
|||
syncDashboards(tenantId, edge); |
|||
syncWidgetsTypes(tenantId, edge); |
|||
syncDevices(tenantId, edge); |
|||
} catch (Exception e) { |
|||
log.error("[{}][{}] Exception during sync process", tenantId, edge.getId(), e); |
|||
} |
|||
} |
|||
|
|||
private void syncRuleChains(TenantId tenantId, Edge edge) { |
|||
log.trace("[{}] syncRuleChains [{}]", tenantId, edge.getName()); |
|||
try { |
|||
PageLink pageLink = new PageLink(DEFAULT_LIMIT); |
|||
PageData<RuleChain> pageData; |
|||
do { |
|||
pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edge.getId(), pageLink); |
|||
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { |
|||
log.trace("[{}] [{}] rule chains(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); |
|||
for (RuleChain ruleChain : pageData.getData()) { |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, EdgeEventActionType.ADDED, ruleChain.getId(), null); |
|||
} |
|||
if (pageData.hasNext()) { |
|||
pageLink = pageLink.nextPageLink(); |
|||
} |
|||
} |
|||
} while (pageData != null && pageData.hasNext()); |
|||
} catch (Exception e) { |
|||
log.error("Exception during loading edge rule chain(s) on sync!", e); |
|||
} |
|||
} |
|||
|
|||
private void syncDevices(TenantId tenantId, Edge edge) { |
|||
log.trace("[{}] syncDevices [{}]", tenantId, edge.getName()); |
|||
try { |
|||
PageLink pageLink = new PageLink(DEFAULT_LIMIT); |
|||
PageData<Device> pageData; |
|||
do { |
|||
pageData = deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edge.getId(), pageLink); |
|||
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { |
|||
log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); |
|||
for (Device device : pageData.getData()) { |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ADDED, device.getId(), null); |
|||
} |
|||
if (pageData.hasNext()) { |
|||
pageLink = pageLink.nextPageLink(); |
|||
} |
|||
} |
|||
} while (pageData != null && pageData.hasNext()); |
|||
} catch (Exception e) { |
|||
log.error("Exception during loading edge device(s) on sync!", e); |
|||
} |
|||
} |
|||
|
|||
private void syncDeviceProfiles(TenantId tenantId, Edge edge) { |
|||
log.trace("[{}] syncDeviceProfiles [{}]", tenantId, edge.getName()); |
|||
try { |
|||
PageLink pageLink = new PageLink(DEFAULT_LIMIT); |
|||
PageData<DeviceProfile> pageData; |
|||
do { |
|||
pageData = deviceProfileService.findDeviceProfiles(tenantId, pageLink); |
|||
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { |
|||
log.trace("[{}] [{}] user(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); |
|||
for (DeviceProfile deviceProfile : pageData.getData()) { |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE_PROFILE, EdgeEventActionType.ADDED, deviceProfile.getId(), null); |
|||
} |
|||
if (pageData.hasNext()) { |
|||
pageLink = pageLink.nextPageLink(); |
|||
} |
|||
} |
|||
} while (pageData != null && pageData.hasNext()); |
|||
} catch (Exception e) { |
|||
log.error("Exception during loading device profile(s) on sync!", e); |
|||
} |
|||
} |
|||
|
|||
private void syncAssets(TenantId tenantId, Edge edge) { |
|||
log.trace("[{}] syncAssets [{}]", tenantId, edge.getName()); |
|||
try { |
|||
PageLink pageLink = new PageLink(DEFAULT_LIMIT); |
|||
PageData<Asset> pageData; |
|||
do { |
|||
pageData = assetService.findAssetsByTenantIdAndEdgeId(tenantId, edge.getId(), pageLink); |
|||
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { |
|||
log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); |
|||
for (Asset asset : pageData.getData()) { |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET, EdgeEventActionType.ADDED, asset.getId(), null); |
|||
} |
|||
if (pageData.hasNext()) { |
|||
pageLink = pageLink.nextPageLink(); |
|||
} |
|||
} |
|||
} while (pageData != null && pageData.hasNext()); |
|||
} catch (Exception e) { |
|||
log.error("Exception during loading edge asset(s) on sync!", e); |
|||
} |
|||
} |
|||
|
|||
private void syncEntityViews(TenantId tenantId, Edge edge) { |
|||
log.trace("[{}] syncEntityViews [{}]", tenantId, edge.getName()); |
|||
try { |
|||
PageLink pageLink = new PageLink(DEFAULT_LIMIT); |
|||
PageData<EntityView> pageData; |
|||
do { |
|||
pageData = entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edge.getId(), pageLink); |
|||
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { |
|||
log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); |
|||
for (EntityView entityView : pageData.getData()) { |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ENTITY_VIEW, EdgeEventActionType.ADDED, entityView.getId(), null); |
|||
} |
|||
if (pageData.hasNext()) { |
|||
pageLink = pageLink.nextPageLink(); |
|||
} |
|||
} |
|||
} while (pageData != null && pageData.hasNext()); |
|||
} catch (Exception e) { |
|||
log.error("Exception during loading edge entity view(s) on sync!", e); |
|||
} |
|||
} |
|||
|
|||
private void syncDashboards(TenantId tenantId, Edge edge) { |
|||
log.trace("[{}] syncDashboards [{}]", tenantId, edge.getName()); |
|||
try { |
|||
PageLink pageLink = new PageLink(DEFAULT_LIMIT); |
|||
PageData<DashboardInfo> pageData; |
|||
do { |
|||
pageData = dashboardService.findDashboardsByTenantIdAndEdgeId(tenantId, edge.getId(), pageLink); |
|||
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { |
|||
log.trace("[{}] [{}] dashboard(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); |
|||
for (DashboardInfo dashboardInfo : pageData.getData()) { |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DASHBOARD, EdgeEventActionType.ADDED, dashboardInfo.getId(), null); |
|||
} |
|||
if (pageData.hasNext()) { |
|||
pageLink = pageLink.nextPageLink(); |
|||
} |
|||
} |
|||
} while (pageData != null && pageData.hasNext()); |
|||
} catch (Exception e) { |
|||
log.error("Exception during loading edge dashboard(s) on sync!", e); |
|||
} |
|||
} |
|||
|
|||
private void syncUsers(TenantId tenantId, Edge edge) { |
|||
log.trace("[{}] syncUsers [{}]", tenantId, edge.getName()); |
|||
try { |
|||
PageLink pageLink = new PageLink(DEFAULT_LIMIT); |
|||
PageData<User> pageData; |
|||
do { |
|||
pageData = userService.findTenantAdmins(tenantId, pageLink); |
|||
pushUsersToEdge(tenantId, pageData, edge); |
|||
if (pageData.hasNext()) { |
|||
pageLink = pageLink.nextPageLink(); |
|||
} |
|||
} while (pageData.hasNext()); |
|||
syncCustomerUsers(tenantId, edge); |
|||
} catch (Exception e) { |
|||
log.error("Exception during loading edge user(s) on sync!", e); |
|||
} |
|||
} |
|||
|
|||
private void syncCustomerUsers(TenantId tenantId, Edge edge) { |
|||
if (edge.getCustomerId() != null && !EntityId.NULL_UUID.equals(edge.getCustomerId().getId())) { |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, edge.getCustomerId(), null); |
|||
PageLink pageLink = new PageLink(DEFAULT_LIMIT); |
|||
PageData<User> pageData; |
|||
do { |
|||
pageData = userService.findCustomerUsers(tenantId, edge.getCustomerId(), pageLink); |
|||
pushUsersToEdge(tenantId, pageData, edge); |
|||
if (pageData != null && pageData.hasNext()) { |
|||
pageLink = pageLink.nextPageLink(); |
|||
} |
|||
} while (pageData != null && pageData.hasNext()); |
|||
} |
|||
} |
|||
|
|||
private void pushUsersToEdge(TenantId tenantId, PageData<User> pageData, Edge edge) { |
|||
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { |
|||
log.trace("[{}] [{}] user(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); |
|||
for (User user : pageData.getData()) { |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER, EdgeEventActionType.ADDED, user.getId(), null); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void syncWidgetsBundles(TenantId tenantId, Edge edge) { |
|||
log.trace("[{}] syncWidgetsBundles [{}]", tenantId, edge.getName()); |
|||
List<WidgetsBundle> widgetsBundlesToPush = new ArrayList<>(); |
|||
widgetsBundlesToPush.addAll(widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(tenantId)); |
|||
widgetsBundlesToPush.addAll(widgetsBundleService.findSystemWidgetsBundles(tenantId)); |
|||
try { |
|||
for (WidgetsBundle widgetsBundle : widgetsBundlesToPush) { |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGETS_BUNDLE, EdgeEventActionType.ADDED, widgetsBundle.getId(), null); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("Exception during loading widgets bundle(s) on sync!", e); |
|||
} |
|||
} |
|||
|
|||
private void syncWidgetsTypes(TenantId tenantId, Edge edge) { |
|||
log.trace("[{}] syncWidgetsTypes [{}]", tenantId, edge.getName()); |
|||
List<WidgetsBundle> widgetsBundlesToPush = new ArrayList<>(); |
|||
widgetsBundlesToPush.addAll(widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(tenantId)); |
|||
widgetsBundlesToPush.addAll(widgetsBundleService.findSystemWidgetsBundles(tenantId)); |
|||
try { |
|||
for (WidgetsBundle widgetsBundle : widgetsBundlesToPush) { |
|||
List<WidgetType> widgetTypesToPush = |
|||
widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(widgetsBundle.getTenantId(), widgetsBundle.getAlias()); |
|||
for (WidgetType widgetType : widgetTypesToPush) { |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGET_TYPE, EdgeEventActionType.ADDED, widgetType.getId(), null); |
|||
} |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("Exception during loading widgets type(s) on sync!", e); |
|||
} |
|||
} |
|||
|
|||
private void syncAdminSettings(TenantId tenantId, Edge edge) { |
|||
log.trace("[{}] syncAdminSettings [{}]", tenantId, edge.getName()); |
|||
try { |
|||
AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail"); |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings)); |
|||
AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue()); |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings)); |
|||
AdminSettings systemMailTemplates = loadMailTemplates(); |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates)); |
|||
AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue()); |
|||
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates)); |
|||
} catch (Exception e) { |
|||
log.error("Can't load admin settings", e); |
|||
} |
|||
} |
|||
|
|||
private AdminSettings loadMailTemplates() throws Exception { |
|||
Map<String, Object> mailTemplates = new HashMap<>(); |
|||
Pattern startPattern = Pattern.compile("<div class=\"content\".*?>"); |
|||
Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>"); |
|||
File[] files = new DefaultResourceLoader().getResource("classpath:/templates/").getFile().listFiles(); |
|||
for (File file : files) { |
|||
Map<String, String> mailTemplate = new HashMap<>(); |
|||
String name = validateName(file.getName()); |
|||
String stringTemplate = FileUtils.readFileToString(file, StandardCharsets.UTF_8); |
|||
Matcher start = startPattern.matcher(stringTemplate); |
|||
Matcher end = endPattern.matcher(stringTemplate); |
|||
if (start.find() && end.find()) { |
|||
String body = StringUtils.substringBetween(stringTemplate, start.group(), end.group()).replaceAll("\t", ""); |
|||
String subject = StringUtils.substringBetween(body, "<h2>", "</h2>"); |
|||
mailTemplate.put("subject", subject); |
|||
mailTemplate.put("body", body); |
|||
mailTemplates.put(name, mailTemplate); |
|||
} else { |
|||
log.error("Can't load mail template from file {}", file.getName()); |
|||
} |
|||
} |
|||
AdminSettings adminSettings = new AdminSettings(); |
|||
adminSettings.setId(new AdminSettingsId(Uuids.timeBased())); |
|||
adminSettings.setKey("mailTemplates"); |
|||
adminSettings.setJsonValue(mapper.convertValue(mailTemplates, JsonNode.class)); |
|||
return adminSettings; |
|||
} |
|||
|
|||
private String validateName(String name) throws Exception { |
|||
StringBuilder nameBuilder = new StringBuilder(); |
|||
name = name.replace(".vm", ""); |
|||
String[] nameParts = name.split("\\."); |
|||
if (nameParts.length >= 1) { |
|||
nameBuilder.append(nameParts[0]); |
|||
for (int i = 1; i < nameParts.length; i++) { |
|||
String word = WordUtils.capitalize(nameParts[i]); |
|||
nameBuilder.append(word); |
|||
} |
|||
return nameBuilder.toString(); |
|||
} else { |
|||
throw new Exception("Error during filename validation"); |
|||
} |
|||
} |
|||
|
|||
private AdminSettings convertToTenantAdminSettings(String key, ObjectNode jsonValue) { |
|||
AdminSettings tenantMailSettings = new AdminSettings(); |
|||
jsonValue.put("useSystemMailSettings", true); |
|||
tenantMailSettings.setJsonValue(jsonValue); |
|||
tenantMailSettings.setKey(key); |
|||
return tenantMailSettings; |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Void> processRuleChainMetadataRequestMsg(TenantId tenantId, Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg) { |
|||
log.trace("[{}] processRuleChainMetadataRequestMsg [{}][{}]", tenantId, edge.getName(), ruleChainMetadataRequestMsg); |
|||
SettableFuture<Void> futureToSet = SettableFuture.create(); |
|||
if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) { |
|||
RuleChainId ruleChainId = |
|||
new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB())); |
|||
ListenableFuture<EdgeEvent> future = saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN_METADATA, EdgeEventActionType.ADDED, ruleChainId, null); |
|||
Futures.addCallback(future, new FutureCallback<EdgeEvent>() { |
|||
@Override |
|||
public void onSuccess(@Nullable EdgeEvent result) { |
|||
futureToSet.set(null); |
|||
} |
|||
|
|||
@Override |
|||
public void onFailure(Throwable t) { |
|||
log.error("Can't save edge event [{}]", ruleChainMetadataRequestMsg, t); |
|||
futureToSet.setException(t); |
|||
} |
|||
}, dbCallbackExecutorService); |
|||
} |
|||
return futureToSet; |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Void> processAttributesRequestMsg(TenantId tenantId, Edge edge, AttributesRequestMsg attributesRequestMsg) { |
|||
log.trace("[{}] processAttributesRequestMsg [{}][{}]", tenantId, edge.getName(), attributesRequestMsg); |
|||
EntityId entityId = EntityIdFactory.getByTypeAndUuid( |
|||
EntityType.valueOf(attributesRequestMsg.getEntityType()), |
|||
new UUID(attributesRequestMsg.getEntityIdMSB(), attributesRequestMsg.getEntityIdLSB())); |
|||
final EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType()); |
|||
if (type != null) { |
|||
SettableFuture<Void> futureToSet = SettableFuture.create(); |
|||
String scope = attributesRequestMsg.getScope(); |
|||
ListenableFuture<List<AttributeKvEntry>> ssAttrFuture = attributesService.findAll(tenantId, entityId, scope); |
|||
Futures.addCallback(ssAttrFuture, new FutureCallback<List<AttributeKvEntry>>() { |
|||
@Override |
|||
public void onSuccess(@Nullable List<AttributeKvEntry> ssAttributes) { |
|||
if (ssAttributes != null && !ssAttributes.isEmpty()) { |
|||
try { |
|||
Map<String, Object> entityData = new HashMap<>(); |
|||
ObjectNode attributes = mapper.createObjectNode(); |
|||
for (AttributeKvEntry attr : ssAttributes) { |
|||
if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) { |
|||
attributes.put(attr.getKey(), attr.getBooleanValue().get()); |
|||
} else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) { |
|||
attributes.put(attr.getKey(), attr.getDoubleValue().get()); |
|||
} else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) { |
|||
attributes.put(attr.getKey(), attr.getLongValue().get()); |
|||
} else { |
|||
attributes.put(attr.getKey(), attr.getValueAsString()); |
|||
} |
|||
} |
|||
entityData.put("kv", attributes); |
|||
entityData.put("scope", scope); |
|||
JsonNode body = mapper.valueToTree(entityData); |
|||
log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, body); |
|||
saveEdgeEvent(tenantId, |
|||
edge.getId(), |
|||
type, |
|||
EdgeEventActionType.ATTRIBUTES_UPDATED, |
|||
entityId, |
|||
body); |
|||
} catch (Exception e) { |
|||
log.error("[{}] Failed to send attribute updates to the edge", edge.getName(), e); |
|||
throw new RuntimeException("[" + edge.getName() + "] Failed to send attribute updates to the edge", e); |
|||
} |
|||
} else { |
|||
log.trace("[{}][{}] No attributes found for entity {} [{}]", tenantId, |
|||
edge.getName(), |
|||
entityId.getEntityType(), |
|||
entityId.getId()); |
|||
} |
|||
futureToSet.set(null); |
|||
} |
|||
|
|||
@Override |
|||
public void onFailure(Throwable t) { |
|||
log.error("Can't save attributes [{}]", attributesRequestMsg, t); |
|||
futureToSet.setException(t); |
|||
} |
|||
}, dbCallbackExecutorService); |
|||
return futureToSet; |
|||
} else { |
|||
log.warn("[{}] Type doesn't supported {}", tenantId, entityId.getEntityType()); |
|||
return Futures.immediateFuture(null); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Void> processRelationRequestMsg(TenantId tenantId, Edge edge, RelationRequestMsg relationRequestMsg) { |
|||
log.trace("[{}] processRelationRequestMsg [{}][{}]", tenantId, edge.getName(), relationRequestMsg); |
|||
EntityId entityId = EntityIdFactory.getByTypeAndUuid( |
|||
EntityType.valueOf(relationRequestMsg.getEntityType()), |
|||
new UUID(relationRequestMsg.getEntityIdMSB(), relationRequestMsg.getEntityIdLSB())); |
|||
|
|||
List<ListenableFuture<List<EntityRelation>>> futures = new ArrayList<>(); |
|||
futures.add(findRelationByQuery(tenantId, edge, entityId, EntitySearchDirection.FROM)); |
|||
futures.add(findRelationByQuery(tenantId, edge, entityId, EntitySearchDirection.TO)); |
|||
ListenableFuture<List<List<EntityRelation>>> relationsListFuture = Futures.allAsList(futures); |
|||
SettableFuture<Void> futureToSet = SettableFuture.create(); |
|||
Futures.addCallback(relationsListFuture, new FutureCallback<List<List<EntityRelation>>>() { |
|||
@Override |
|||
public void onSuccess(@Nullable List<List<EntityRelation>> relationsList) { |
|||
try { |
|||
if (relationsList != null && !relationsList.isEmpty()) { |
|||
for (List<EntityRelation> entityRelations : relationsList) { |
|||
log.trace("[{}] [{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), entityId, entityRelations.size()); |
|||
for (EntityRelation relation : entityRelations) { |
|||
try { |
|||
if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) && |
|||
!relation.getTo().getEntityType().equals(EntityType.EDGE)) { |
|||
saveEdgeEvent(tenantId, |
|||
edge.getId(), |
|||
EdgeEventType.RELATION, |
|||
EdgeEventActionType.ADDED, |
|||
null, |
|||
mapper.valueToTree(relation)); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("Exception during loading relation [{}] to edge on sync!", relation, e); |
|||
futureToSet.setException(e); |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
futureToSet.set(null); |
|||
} catch (Exception e) { |
|||
log.error("Exception during loading relation(s) to edge on sync!", e); |
|||
futureToSet.setException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void onFailure(Throwable t) { |
|||
log.error("[{}] Can't find relation by query. Entity id [{}]", tenantId, entityId, t); |
|||
futureToSet.setException(t); |
|||
} |
|||
}, dbCallbackExecutorService); |
|||
return futureToSet; |
|||
} |
|||
|
|||
private ListenableFuture<List<EntityRelation>> findRelationByQuery(TenantId tenantId, Edge edge, EntityId entityId, EntitySearchDirection direction) { |
|||
EntityRelationsQuery query = new EntityRelationsQuery(); |
|||
query.setParameters(new RelationsSearchParameters(entityId, direction, -1, false)); |
|||
return relationService.findByQuery(tenantId, query); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Void> processDeviceCredentialsRequestMsg(TenantId tenantId, Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg) { |
|||
log.trace("[{}] processDeviceCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), deviceCredentialsRequestMsg); |
|||
SettableFuture<Void> futureToSet = SettableFuture.create(); |
|||
if (deviceCredentialsRequestMsg.getDeviceIdMSB() != 0 && deviceCredentialsRequestMsg.getDeviceIdLSB() != 0) { |
|||
DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsRequestMsg.getDeviceIdMSB(), deviceCredentialsRequestMsg.getDeviceIdLSB())); |
|||
ListenableFuture<EdgeEvent> future = saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_UPDATED, deviceId, null); |
|||
Futures.addCallback(future, new FutureCallback<EdgeEvent>() { |
|||
@Override |
|||
public void onSuccess(@Nullable EdgeEvent result) { |
|||
futureToSet.set(null); |
|||
} |
|||
|
|||
@Override |
|||
public void onFailure(Throwable t) { |
|||
log.error("Can't save edge event [{}]", deviceCredentialsRequestMsg, t); |
|||
futureToSet.setException(t); |
|||
} |
|||
}, dbCallbackExecutorService); |
|||
} |
|||
return futureToSet; |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Void> processUserCredentialsRequestMsg(TenantId tenantId, Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg) { |
|||
log.trace("[{}] processUserCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), userCredentialsRequestMsg); |
|||
SettableFuture<Void> futureToSet = SettableFuture.create(); |
|||
if (userCredentialsRequestMsg.getUserIdMSB() != 0 && userCredentialsRequestMsg.getUserIdLSB() != 0) { |
|||
UserId userId = new UserId(new UUID(userCredentialsRequestMsg.getUserIdMSB(), userCredentialsRequestMsg.getUserIdLSB())); |
|||
ListenableFuture<EdgeEvent> future = saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER, EdgeEventActionType.CREDENTIALS_UPDATED, userId, null); |
|||
Futures.addCallback(future, new FutureCallback<EdgeEvent>() { |
|||
@Override |
|||
public void onSuccess(@Nullable EdgeEvent result) { |
|||
futureToSet.set(null); |
|||
} |
|||
|
|||
@Override |
|||
public void onFailure(Throwable t) { |
|||
log.error("Can't save edge event [{}]", userCredentialsRequestMsg, t); |
|||
futureToSet.setException(t); |
|||
} |
|||
}, dbCallbackExecutorService); |
|||
} |
|||
return futureToSet; |
|||
} |
|||
|
|||
private ListenableFuture<EdgeEvent> saveEdgeEvent(TenantId tenantId, |
|||
EdgeId edgeId, |
|||
EdgeEventType type, |
|||
EdgeEventActionType action, |
|||
EntityId entityId, |
|||
JsonNode body) { |
|||
log.trace("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]", |
|||
tenantId, edgeId, type, action, entityId, body); |
|||
|
|||
EdgeEvent edgeEvent = new EdgeEvent(); |
|||
edgeEvent.setTenantId(tenantId); |
|||
edgeEvent.setEdgeId(edgeId); |
|||
edgeEvent.setType(type); |
|||
edgeEvent.setAction(action); |
|||
if (entityId != null) { |
|||
edgeEvent.setEntityId(entityId.getId()); |
|||
} |
|||
edgeEvent.setBody(body); |
|||
ListenableFuture<EdgeEvent> future = edgeEventService.saveAsync(edgeEvent); |
|||
Futures.addCallback(future, new FutureCallback<EdgeEvent>() { |
|||
@Override |
|||
public void onSuccess(@Nullable EdgeEvent result) { |
|||
tbClusterService.onEdgeEventUpdate(tenantId, edgeId); |
|||
} |
|||
|
|||
@Override |
|||
public void onFailure(Throwable t) { |
|||
log.warn("[{}] Can't save edge event [{}] for edge [{}]", tenantId.getId(), edgeEvent, edgeId.getId(), t); |
|||
} |
|||
}, dbCallbackExecutorService); |
|||
return future; |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue