916 changed files with 38322 additions and 10043 deletions
@ -1,49 +0,0 @@ |
|||
-- |
|||
-- Copyright © 2016-2022 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. |
|||
-- |
|||
|
|||
ALTER TABLE device_profile |
|||
ADD COLUMN IF NOT EXISTS default_queue_id uuid; |
|||
|
|||
DO |
|||
$$ |
|||
BEGIN |
|||
IF EXISTS |
|||
(SELECT column_name |
|||
FROM information_schema.columns |
|||
WHERE table_name = 'device_profile' |
|||
AND column_name = 'default_queue_name' |
|||
) |
|||
THEN |
|||
UPDATE device_profile |
|||
SET default_queue_id = q.id |
|||
FROM queue as q |
|||
WHERE default_queue_name = q.name; |
|||
END IF; |
|||
END |
|||
$$; |
|||
|
|||
DO |
|||
$$ |
|||
BEGIN |
|||
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'fk_default_queue_device_profile') THEN |
|||
ALTER TABLE device_profile |
|||
ADD CONSTRAINT fk_default_queue_device_profile FOREIGN KEY (default_queue_id) REFERENCES queue (id); |
|||
END IF; |
|||
END; |
|||
$$; |
|||
|
|||
ALTER TABLE device_profile |
|||
DROP COLUMN IF EXISTS default_queue_name; |
|||
@ -0,0 +1,42 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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 com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
public class AutoCommitController extends BaseController { |
|||
|
|||
@Autowired |
|||
private EntitiesVersionControlService vcService; |
|||
|
|||
protected ListenableFuture<UUID> autoCommit(User user, EntityId entityId) throws Exception { |
|||
if (vcService != null) { |
|||
return vcService.autoCommit(user, entityId); |
|||
} else { |
|||
// We do not support auto-commit for rule engine
|
|||
return Futures.immediateFailedFuture(new RuntimeException("Operation not supported!")); |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,519 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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 com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import com.google.common.util.concurrent.MoreExecutors; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import io.swagger.annotations.ApiParam; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.PathVariable; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.context.request.async.DeferredResult; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.StringUtils; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|||
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.sync.vc.BranchInfo; |
|||
import org.thingsboard.server.common.data.sync.vc.EntityDataDiff; |
|||
import org.thingsboard.server.common.data.sync.vc.EntityDataInfo; |
|||
import org.thingsboard.server.common.data.sync.vc.EntityVersion; |
|||
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult; |
|||
import org.thingsboard.server.common.data.sync.vc.VersionLoadResult; |
|||
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo; |
|||
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest; |
|||
import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadRequest; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
import org.thingsboard.server.service.security.permission.Operation; |
|||
import org.thingsboard.server.service.security.permission.Resource; |
|||
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
import java.util.stream.Collectors; |
|||
|
|||
import static org.thingsboard.server.controller.ControllerConstants.BRANCH_PARAM_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END; |
|||
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START; |
|||
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; |
|||
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; |
|||
import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; |
|||
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH; |
|||
import static org.thingsboard.server.controller.ControllerConstants.VC_REQUEST_ID_PARAM_DESCRIPTION; |
|||
import static org.thingsboard.server.controller.ControllerConstants.VERSION_ID_PARAM_DESCRIPTION; |
|||
|
|||
@RestController |
|||
@TbCoreComponent |
|||
@RequestMapping("/api/entities/vc") |
|||
@PreAuthorize("hasAuthority('TENANT_ADMIN')") |
|||
@RequiredArgsConstructor |
|||
public class EntitiesVersionControlController extends BaseController { |
|||
|
|||
private final EntitiesVersionControlService versionControlService; |
|||
|
|||
|
|||
@ApiOperation(value = "Save entities version (saveEntitiesVersion)", notes = "" + |
|||
"Creates a new version of entities (or a single entity) by request.\n" + |
|||
"Supported entity types: CUSTOMER, ASSET, RULE_CHAIN, DASHBOARD, DEVICE_PROFILE, DEVICE, ENTITY_VIEW, WIDGETS_BUNDLE." + NEW_LINE + |
|||
"There are two available types of request: `SINGLE_ENTITY` and `COMPLEX`. " + |
|||
"Each of them contains version name (`versionName`) and name of a branch (`branch`) to create version (commit) in. " + |
|||
"If specified branch does not exists in a remote repo, then new empty branch will be created. " + |
|||
"Request of the `SINGLE_ENTITY` type has id of an entity (`entityId`) and additional configuration (`config`) " + |
|||
"which has following options: \n" + |
|||
"- `saveRelations` - whether to add inbound and outbound relations of type COMMON to created entity version;\n" + |
|||
"- `saveAttributes` - to save attributes of server scope (and also shared scope for devices);\n" + |
|||
"- `saveCredentials` - when saving a version of a device, to add its credentials to the version." + NEW_LINE + |
|||
"An example of a `SINGLE_ENTITY` version create request:\n" + |
|||
MARKDOWN_CODE_BLOCK_START + |
|||
"{\n" + |
|||
" \"type\": \"SINGLE_ENTITY\",\n" + |
|||
"\n" + |
|||
" \"versionName\": \"Version 1.0\",\n" + |
|||
" \"branch\": \"dev\",\n" + |
|||
"\n" + |
|||
" \"entityId\": {\n" + |
|||
" \"entityType\": \"DEVICE\",\n" + |
|||
" \"id\": \"b79448e0-d4f4-11ec-847b-0f432358ab48\"\n" + |
|||
" },\n" + |
|||
" \"config\": {\n" + |
|||
" \"saveRelations\": true,\n" + |
|||
" \"saveAttributes\": true,\n" + |
|||
" \"saveCredentials\": false\n" + |
|||
" }\n" + |
|||
"}" + |
|||
MARKDOWN_CODE_BLOCK_END + NEW_LINE + |
|||
"Second request type (`COMPLEX`), additionally to `branch` and `versionName`, contains following properties:\n" + |
|||
"- `entityTypes` - a structure with entity types to export and configuration for each entity type; " + |
|||
" this configuration has all the options available for `SINGLE_ENTITY` and additionally has these ones: \n" + |
|||
" - `allEntities` and `entityIds` - if you want to save the version of all entities of the entity type " + |
|||
" then set `allEntities` param to true, otherwise set it to false and specify the list of specific entities (`entityIds`);\n" + |
|||
" - `syncStrategy` - synchronization strategy to use for this entity type: when set to `OVERWRITE` " + |
|||
" then the list of remote entities of this type will be overwritten by newly added entities. If set to " + |
|||
" `MERGE` - existing remote entities of this entity type will not be removed, new entities will just " + |
|||
" be added on top (or existing remote entities will be updated).\n" + |
|||
"- `syncStrategy` - default synchronization strategy to use when it is not specified for an entity type." + NEW_LINE + |
|||
"Example for this type of request:\n" + |
|||
MARKDOWN_CODE_BLOCK_START + |
|||
"{\n" + |
|||
" \"type\": \"COMPLEX\",\n" + |
|||
"\n" + |
|||
" \"versionName\": \"Devices and profiles: release 2\",\n" + |
|||
" \"branch\": \"master\",\n" + |
|||
"\n" + |
|||
" \"syncStrategy\": \"OVERWRITE\",\n" + |
|||
" \"entityTypes\": {\n" + |
|||
" \"DEVICE\": {\n" + |
|||
" \"syncStrategy\": null,\n" + |
|||
" \"allEntities\": true,\n" + |
|||
" \"saveRelations\": true,\n" + |
|||
" \"saveAttributes\": true,\n" + |
|||
" \"saveCredentials\": true\n" + |
|||
" },\n" + |
|||
" \"DEVICE_PROFILE\": {\n" + |
|||
" \"syncStrategy\": \"MERGE\",\n" + |
|||
" \"allEntities\": false,\n" + |
|||
" \"entityIds\": [\n" + |
|||
" \"b79448e0-d4f4-11ec-847b-0f432358ab48\"\n" + |
|||
" ],\n" + |
|||
" \"saveRelations\": true\n" + |
|||
" }\n" + |
|||
" }\n" + |
|||
"}" + |
|||
MARKDOWN_CODE_BLOCK_END + NEW_LINE + |
|||
"Response wil contain generated request UUID, that can be then used to retrieve " + |
|||
"status of operation via `getVersionCreateRequestStatus`.\n" + |
|||
TENANT_AUTHORITY_PARAGRAPH) |
|||
@PostMapping("/version") |
|||
public DeferredResult<UUID> saveEntitiesVersion(@RequestBody VersionCreateRequest request) throws Exception { |
|||
SecurityUser user = getCurrentUser(); |
|||
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE); |
|||
return wrapFuture(versionControlService.saveEntitiesVersion(user, request)); |
|||
} |
|||
|
|||
@ApiOperation(value = "Get version create request status (getVersionCreateRequestStatus)", notes = "" + |
|||
"Returns the status of previously made version create request. " + NEW_LINE + |
|||
"This status contains following properties:\n" + |
|||
"- `done` - whether request processing is finished;\n" + |
|||
"- `version` - created version info: timestamp, version id (commit hash), commit name and commit author;\n" + |
|||
"- `added` - count of items that were created in the remote repo;\n" + |
|||
"- `modified` - modified items count;\n" + |
|||
"- `removed` - removed items count;\n" + |
|||
"- `error` - error message, if an error occurred while handling the request." + NEW_LINE + |
|||
"An example of successful status:\n" + |
|||
MARKDOWN_CODE_BLOCK_START + |
|||
"{\n" + |
|||
" \"done\": true,\n" + |
|||
" \"added\": 10,\n" + |
|||
" \"modified\": 2,\n" + |
|||
" \"removed\": 5,\n" + |
|||
" \"version\": {\n" + |
|||
" \"timestamp\": 1655198528000,\n" + |
|||
" \"id\":\"8a834dd389ed80e0759ba8ee338b3f1fd160a114\",\n" + |
|||
" \"name\": \"My devices v2.0\",\n" + |
|||
" \"author\": \"John Doe\"\n" + |
|||
" },\n" + |
|||
" \"error\": null\n" + |
|||
"}" + |
|||
MARKDOWN_CODE_BLOCK_END + |
|||
TENANT_AUTHORITY_PARAGRAPH) |
|||
@GetMapping(value = "/version/{requestId}/status") |
|||
public VersionCreationResult getVersionCreateRequestStatus(@ApiParam(value = VC_REQUEST_ID_PARAM_DESCRIPTION, required = true) |
|||
@PathVariable UUID requestId) throws Exception { |
|||
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE); |
|||
return versionControlService.getVersionCreateStatus(getCurrentUser(), requestId); |
|||
} |
|||
|
|||
@ApiOperation(value = "List entity versions (listEntityVersions)", notes = "" + |
|||
"Returns list of versions for a specific entity in a concrete branch. \n" + |
|||
"You need to specify external id of an entity to list versions for. This is `externalId` property of an entity, " + |
|||
"or otherwise if not set - simply id of this entity. \n" + |
|||
"If specified branch does not exist - empty page data will be returned. " + NEW_LINE + |
|||
"Each version info item has timestamp, id, name and author. Version id can then be used to restore the version. " + |
|||
PAGE_DATA_PARAMETERS + NEW_LINE + |
|||
"Response example: \n" + |
|||
MARKDOWN_CODE_BLOCK_START + |
|||
"{\n" + |
|||
" \"data\": [\n" + |
|||
" {\n" + |
|||
" \"timestamp\": 1655198593000,\n" + |
|||
" \"id\": \"fd82625bdd7d6131cf8027b44ee967012ecaf990\",\n" + |
|||
" \"name\": \"Devices and assets - v2.0\",\n" + |
|||
" \"author\": \"John Doe <johndoe@gmail.com>\"\n" + |
|||
" },\n" + |
|||
" {\n" + |
|||
" \"timestamp\": 1655198528000,\n" + |
|||
" \"id\": \"682adcffa9c8a2f863af6f00c4850323acbd4219\",\n" + |
|||
" \"name\": \"Update my device\",\n" + |
|||
" \"author\": \"John Doe <johndoe@gmail.com>\"\n" + |
|||
" },\n" + |
|||
" {\n" + |
|||
" \"timestamp\": 1655198280000,\n" + |
|||
" \"id\": \"d2a6087c2b30e18cc55e7cdda345a8d0dfb959a4\",\n" + |
|||
" \"name\": \"Devices and assets - v1.0\",\n" + |
|||
" \"author\": \"John Doe <johndoe@gmail.com>\"\n" + |
|||
" }\n" + |
|||
" ],\n" + |
|||
" \"totalPages\": 1,\n" + |
|||
" \"totalElements\": 3,\n" + |
|||
" \"hasNext\": false\n" + |
|||
"}" + |
|||
MARKDOWN_CODE_BLOCK_END + |
|||
TENANT_AUTHORITY_PARAGRAPH) |
|||
@GetMapping(value = "/version/{entityType}/{externalEntityUuid}", params = {"branch", "pageSize", "page"}) |
|||
public DeferredResult<PageData<EntityVersion>> listEntityVersions(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) |
|||
@PathVariable EntityType entityType, |
|||
@ApiParam(value = "A string value representing external entity id. This is `externalId` property of an entity, or otherwise if not set - simply id of this entity.") |
|||
@PathVariable UUID externalEntityUuid, |
|||
@ApiParam(value = BRANCH_PARAM_DESCRIPTION) |
|||
@RequestParam String branch, |
|||
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) |
|||
@RequestParam int pageSize, |
|||
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) |
|||
@RequestParam int page, |
|||
@ApiParam(value = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION) |
|||
@RequestParam(required = false) String textSearch, |
|||
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp") |
|||
@RequestParam(required = false) String sortProperty, |
|||
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) |
|||
@RequestParam(required = false) String sortOrder) throws Exception { |
|||
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); |
|||
EntityId externalEntityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid); |
|||
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
|||
return wrapFuture(versionControlService.listEntityVersions(getTenantId(), branch, externalEntityId, pageLink)); |
|||
} |
|||
|
|||
@ApiOperation(value = "List entity type versions (listEntityTypeVersions)", notes = "" + |
|||
"Returns list of versions of an entity type in a branch. This is a collected list of versions that were created " + |
|||
"for entities of this type in a remote branch. \n" + |
|||
"If specified branch does not exist - empty page data will be returned. " + |
|||
"The response structure is the same as for `listEntityVersions` API method." + |
|||
TENANT_AUTHORITY_PARAGRAPH) |
|||
@GetMapping(value = "/version/{entityType}", params = {"branch", "pageSize", "page"}) |
|||
public DeferredResult<PageData<EntityVersion>> listEntityTypeVersions(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) |
|||
@PathVariable EntityType entityType, |
|||
@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true) |
|||
@RequestParam String branch, |
|||
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) |
|||
@RequestParam int pageSize, |
|||
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) |
|||
@RequestParam int page, |
|||
@ApiParam(value = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION) |
|||
@RequestParam(required = false) String textSearch, |
|||
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp") |
|||
@RequestParam(required = false) String sortProperty, |
|||
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) |
|||
@RequestParam(required = false) String sortOrder) throws Exception { |
|||
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); |
|||
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
|||
return wrapFuture(versionControlService.listEntityTypeVersions(getTenantId(), branch, entityType, pageLink)); |
|||
} |
|||
|
|||
@ApiOperation(value = "List all versions (listVersions)", notes = "" + |
|||
"Lists all available versions in a branch for all entity types. \n" + |
|||
"If specified branch does not exist - empty page data will be returned. " + |
|||
"The response format is the same as for `listEntityVersions` API method." + |
|||
TENANT_AUTHORITY_PARAGRAPH) |
|||
@GetMapping(value = "/version", params = {"branch", "pageSize", "page"}) |
|||
public DeferredResult<PageData<EntityVersion>> listVersions(@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true) |
|||
@RequestParam String branch, |
|||
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) |
|||
@RequestParam int pageSize, |
|||
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) |
|||
@RequestParam int page, |
|||
@ApiParam(value = ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION) |
|||
@RequestParam(required = false) String textSearch, |
|||
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = "timestamp") |
|||
@RequestParam(required = false) String sortProperty, |
|||
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) |
|||
@RequestParam(required = false) String sortOrder) throws Exception { |
|||
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); |
|||
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
|||
return wrapFuture(versionControlService.listVersions(getTenantId(), branch, pageLink)); |
|||
} |
|||
|
|||
|
|||
@ApiOperation(value = "List entities at version (listEntitiesAtVersion)", notes = "" + |
|||
"Returns a list of remote entities of a specific entity type that are available at a concrete version. \n" + |
|||
"Each entity item in the result has `externalId` property. " + |
|||
"Entities order will be the same as in the repository." + |
|||
TENANT_AUTHORITY_PARAGRAPH) |
|||
@GetMapping(value = "/entity/{entityType}/{versionId}") |
|||
public DeferredResult<List<VersionedEntityInfo>> listEntitiesAtVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) |
|||
@PathVariable EntityType entityType, |
|||
@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true) |
|||
@PathVariable String versionId) throws Exception { |
|||
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); |
|||
return wrapFuture(versionControlService.listEntitiesAtVersion(getTenantId(), versionId, entityType)); |
|||
} |
|||
|
|||
@ApiOperation(value = "List all entities at version (listAllEntitiesAtVersion)", notes = "" + |
|||
"Returns a list of all remote entities available in a specific version. " + |
|||
"Response type is the same as for listAllEntitiesAtVersion API method. \n" + |
|||
"Returned entities order will be the same as in the repository." + |
|||
TENANT_AUTHORITY_PARAGRAPH) |
|||
@GetMapping(value = "/entity/{versionId}") |
|||
public DeferredResult<List<VersionedEntityInfo>> listAllEntitiesAtVersion(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true) |
|||
@PathVariable String versionId) throws Exception { |
|||
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); |
|||
return wrapFuture(versionControlService.listAllEntitiesAtVersion(getTenantId(), versionId)); |
|||
} |
|||
|
|||
@ApiOperation(value = "Get entity data info (getEntityDataInfo)", notes = "" + |
|||
"Retrieves short info about the remote entity by external id at a concrete version. \n" + |
|||
"Returned entity data info contains following properties: " + |
|||
"`hasRelations` (whether stored entity data contains relations), `hasAttributes` (contains attributes) and " + |
|||
"`hasCredentials` (whether stored device data has credentials)." + |
|||
TENANT_AUTHORITY_PARAGRAPH) |
|||
@GetMapping("/info/{versionId}/{entityType}/{externalEntityUuid}") |
|||
public DeferredResult<EntityDataInfo> getEntityDataInfo(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true) |
|||
@PathVariable String versionId, |
|||
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) |
|||
@PathVariable EntityType entityType, |
|||
@ApiParam(value = "A string value representing external entity id", required = true) |
|||
@PathVariable UUID externalEntityUuid) throws Exception { |
|||
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); |
|||
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid); |
|||
return wrapFuture(versionControlService.getEntityDataInfo(getCurrentUser(), entityId, versionId)); |
|||
} |
|||
|
|||
@ApiOperation(value = "Compare entity data to version (compareEntityDataToVersion)", notes = "" + |
|||
"Returns an object with current entity data and the one at a specific version. " + |
|||
"Entity data structure is the same as stored in a repository. " + |
|||
TENANT_AUTHORITY_PARAGRAPH) |
|||
@GetMapping(value = "/diff/{entityType}/{internalEntityUuid}", params = {"versionId"}) |
|||
public DeferredResult<EntityDataDiff> compareEntityDataToVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) |
|||
@PathVariable EntityType entityType, |
|||
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) |
|||
@PathVariable UUID internalEntityUuid, |
|||
@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true) |
|||
@RequestParam String versionId) throws Exception { |
|||
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); |
|||
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, internalEntityUuid); |
|||
return wrapFuture(versionControlService.compareEntityDataToVersion(getCurrentUser(), entityId, versionId)); |
|||
} |
|||
|
|||
@ApiOperation(value = "Load entities version (loadEntitiesVersion)", notes = "" + |
|||
"Loads specific version of remote entities (or single entity) by request. " + |
|||
"Supported entity types: CUSTOMER, ASSET, RULE_CHAIN, DASHBOARD, DEVICE_PROFILE, DEVICE, ENTITY_VIEW, WIDGETS_BUNDLE." + NEW_LINE + |
|||
"There are multiple types of request. Each of them requires branch name (`branch`) and version id (`versionId`). " + |
|||
"Request of type `SINGLE_ENTITY` is needed to restore a concrete version of a specific entity. It contains " + |
|||
"id of a remote entity (`externalEntityId`) and additional configuration (`config`):\n" + |
|||
"- `loadRelations` - to update relations list (in case `saveRelations` option was enabled during version creation);\n" + |
|||
"- `loadAttributes` - to load entity attributes (if `saveAttributes` config option was enabled);\n" + |
|||
"- `loadCredentials` - to update device credentials (if `saveCredentials` option was enabled during version creation)." + NEW_LINE + |
|||
"An example of such request:\n" + |
|||
MARKDOWN_CODE_BLOCK_START + |
|||
"{\n" + |
|||
" \"type\": \"SINGLE_ENTITY\",\n" + |
|||
" \n" + |
|||
" \"branch\": \"dev\",\n" + |
|||
" \"versionId\": \"b3c28d722d328324c7c15b0b30047b0c40011cf7\",\n" + |
|||
" \n" + |
|||
" \"externalEntityId\": {\n" + |
|||
" \"entityType\": \"DEVICE\",\n" + |
|||
" \"id\": \"b7944123-d4f4-11ec-847b-0f432358ab48\"\n" + |
|||
" },\n" + |
|||
" \"config\": {\n" + |
|||
" \"loadRelations\": false,\n" + |
|||
" \"loadAttributes\": true,\n" + |
|||
" \"loadCredentials\": true\n" + |
|||
" }\n" + |
|||
"}" + |
|||
MARKDOWN_CODE_BLOCK_END + NEW_LINE + |
|||
"Another request type (`ENTITY_TYPE`) is needed to load specific version of the whole entity types. " + |
|||
"It contains a structure with entity types to load and configs for each entity type (`entityTypes`). " + |
|||
"For each specified entity type, the method will load all remote entities of this type that are present " + |
|||
"at the version. A config for each entity type contains the same options as in `SINGLE_ENTITY` request type, and " + |
|||
"additionally contains following options:\n" + |
|||
"- `removeOtherEntities` - to remove local entities that are not present on the remote - basically to " + |
|||
" overwrite local entity type with the remote one;\n" + |
|||
"- `findExistingEntityByName` - when you are loading some remote entities that are not yet present at this tenant, " + |
|||
" try to find existing entity by name and update it rather than create new." + NEW_LINE + |
|||
"Here is an example of the request to completely restore version of the whole device entity type:\n" + |
|||
MARKDOWN_CODE_BLOCK_START + |
|||
"{\n" + |
|||
" \"type\": \"ENTITY_TYPE\",\n" + |
|||
"\n" + |
|||
" \"branch\": \"dev\",\n" + |
|||
" \"versionId\": \"b3c28d722d328324c7c15b0b30047b0c40011cf7\",\n" + |
|||
"\n" + |
|||
" \"entityTypes\": {\n" + |
|||
" \"DEVICE\": {\n" + |
|||
" \"removeOtherEntities\": true,\n" + |
|||
" \"findExistingEntityByName\": false,\n" + |
|||
" \"loadRelations\": true,\n" + |
|||
" \"loadAttributes\": true,\n" + |
|||
" \"loadCredentials\": true\n" + |
|||
" }\n" + |
|||
" }\n" + |
|||
"}" + |
|||
MARKDOWN_CODE_BLOCK_END + NEW_LINE + |
|||
"The response will contain generated request UUID that is to be used to check the status of operation " + |
|||
"via `getVersionLoadRequestStatus`." + |
|||
TENANT_AUTHORITY_PARAGRAPH) |
|||
@PostMapping("/entity") |
|||
public UUID loadEntitiesVersion(@RequestBody VersionLoadRequest request) throws Exception { |
|||
SecurityUser user = getCurrentUser(); |
|||
accessControlService.checkPermission(user, Resource.VERSION_CONTROL, Operation.WRITE); |
|||
return versionControlService.loadEntitiesVersion(user, request); |
|||
} |
|||
|
|||
@ApiOperation(value = "Get version load request status (getVersionLoadRequestStatus)", notes = "" + |
|||
"Returns the status of previously made version load request. " + |
|||
"The structure contains following parameters:\n" + |
|||
"- `done` - if the request was successfully processed;\n" + |
|||
"- `result` - a list of load results for each entity type:\n" + |
|||
" - `created` - created entities count;\n" + |
|||
" - `updated` - updated entities count;\n" + |
|||
" - `deleted` - removed entities count.\n" + |
|||
"- `error` - if an error occurred during processing, error info:\n" + |
|||
" - `type` - error type;\n" + |
|||
" - `source` - an external id of remote entity;\n" + |
|||
" - `target` - if failed to find referenced entity by external id - this external id;\n" + |
|||
" - `message` - error message." + NEW_LINE + |
|||
"An example of successfully processed request status:\n" + |
|||
MARKDOWN_CODE_BLOCK_START + |
|||
"{\n" + |
|||
" \"done\": true,\n" + |
|||
" \"result\": [\n" + |
|||
" {\n" + |
|||
" \"entityType\": \"DEVICE\",\n" + |
|||
" \"created\": 10,\n" + |
|||
" \"updated\": 5,\n" + |
|||
" \"deleted\": 5\n" + |
|||
" },\n" + |
|||
" {\n" + |
|||
" \"entityType\": \"ASSET\",\n" + |
|||
" \"created\": 4,\n" + |
|||
" \"updated\": 0,\n" + |
|||
" \"deleted\": 8\n" + |
|||
" }\n" + |
|||
" ]\n" + |
|||
"}" + |
|||
MARKDOWN_CODE_BLOCK_END + |
|||
TENANT_AUTHORITY_PARAGRAPH |
|||
) |
|||
@GetMapping(value = "/entity/{requestId}/status") |
|||
public VersionLoadResult getVersionLoadRequestStatus(@ApiParam(value = VC_REQUEST_ID_PARAM_DESCRIPTION, required = true) |
|||
@PathVariable UUID requestId) throws Exception { |
|||
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE); |
|||
return versionControlService.getVersionLoadStatus(getCurrentUser(), requestId); |
|||
} |
|||
|
|||
|
|||
@ApiOperation(value = "List branches (listBranches)", notes = "" + |
|||
"Lists branches available in the remote repository. \n\n" + |
|||
"Response example: \n" + |
|||
MARKDOWN_CODE_BLOCK_START + |
|||
"[\n" + |
|||
" {\n" + |
|||
" \"name\": \"master\",\n" + |
|||
" \"default\": true\n" + |
|||
" },\n" + |
|||
" {\n" + |
|||
" \"name\": \"dev\",\n" + |
|||
" \"default\": false\n" + |
|||
" },\n" + |
|||
" {\n" + |
|||
" \"name\": \"dev-2\",\n" + |
|||
" \"default\": false\n" + |
|||
" }\n" + |
|||
"]" + |
|||
MARKDOWN_CODE_BLOCK_END) |
|||
@GetMapping("/branches") |
|||
public DeferredResult<List<BranchInfo>> listBranches() throws Exception { |
|||
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); |
|||
final TenantId tenantId = getTenantId(); |
|||
ListenableFuture<List<BranchInfo>> branches = versionControlService.listBranches(tenantId); |
|||
return wrapFuture(Futures.transform(branches, remoteBranches -> { |
|||
List<BranchInfo> infos = new ArrayList<>(); |
|||
BranchInfo defaultBranch; |
|||
String defaultBranchName = versionControlService.getVersionControlSettings(tenantId).getDefaultBranch(); |
|||
if (StringUtils.isNotEmpty(defaultBranchName)) { |
|||
defaultBranch = new BranchInfo(defaultBranchName, true); |
|||
} else { |
|||
defaultBranch = remoteBranches.stream().filter(BranchInfo::isDefault).findFirst().orElse(null); |
|||
} |
|||
if (defaultBranch != null) { |
|||
infos.add(defaultBranch); |
|||
} |
|||
infos.addAll(remoteBranches.stream().filter(b -> !b.equals(defaultBranch)) |
|||
.map(b -> new BranchInfo(b.getName(), false)).collect(Collectors.toList())); |
|||
return infos; |
|||
}, MoreExecutors.directExecutor())); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,76 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.apiusage; |
|||
|
|||
import lombok.RequiredArgsConstructor; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; |
|||
import org.thingsboard.server.common.msg.tools.TbRateLimits; |
|||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
|||
|
|||
import java.util.Map; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.function.Function; |
|||
|
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class DefaultRateLimitService implements RateLimitService { |
|||
|
|||
private final TbTenantProfileCache tenantProfileCache; |
|||
|
|||
private final Map<String, Map<TenantId, TbRateLimits>> rateLimits = new ConcurrentHashMap<>(); |
|||
|
|||
@Override |
|||
public boolean checkEntityExportLimit(TenantId tenantId) { |
|||
return checkLimit(tenantId, "entityExport", DefaultTenantProfileConfiguration::getTenantEntityExportRateLimit); |
|||
} |
|||
|
|||
@Override |
|||
public boolean checkEntityImportLimit(TenantId tenantId) { |
|||
return checkLimit(tenantId, "entityImport", DefaultTenantProfileConfiguration::getTenantEntityImportRateLimit); |
|||
} |
|||
|
|||
private boolean checkLimit(TenantId tenantId, String rateLimitsKey, Function<DefaultTenantProfileConfiguration, String> rateLimitConfigExtractor) { |
|||
String rateLimitConfig = tenantProfileCache.get(tenantId).getProfileConfiguration() |
|||
.map(rateLimitConfigExtractor).orElse(null); |
|||
|
|||
Map<TenantId, TbRateLimits> rateLimits = this.rateLimits.get(rateLimitsKey); |
|||
if (StringUtils.isEmpty(rateLimitConfig)) { |
|||
if (rateLimits != null) { |
|||
rateLimits.remove(tenantId); |
|||
if (rateLimits.isEmpty()) { |
|||
this.rateLimits.remove(rateLimitsKey); |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
if (rateLimits == null) { |
|||
rateLimits = new ConcurrentHashMap<>(); |
|||
this.rateLimits.put(rateLimitsKey, rateLimits); |
|||
} |
|||
TbRateLimits rateLimit = rateLimits.get(tenantId); |
|||
if (rateLimit == null || !rateLimit.getConfiguration().equals(rateLimitConfig)) { |
|||
rateLimit = new TbRateLimits(rateLimitConfig); |
|||
rateLimits.put(tenantId, rateLimit); |
|||
} |
|||
|
|||
return rateLimit.tryConsume(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.constructor; |
|||
|
|||
import com.google.protobuf.ByteString; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.common.data.OtaPackage; |
|||
import org.thingsboard.server.common.data.id.OtaPackageId; |
|||
import org.thingsboard.server.gen.edge.v1.OtaPackageUpdateMsg; |
|||
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
@Component |
|||
@TbCoreComponent |
|||
public class OtaPackageMsgConstructor { |
|||
|
|||
public OtaPackageUpdateMsg constructOtaPackageUpdatedMsg(UpdateMsgType msgType, OtaPackage otaPackage) { |
|||
OtaPackageUpdateMsg.Builder builder = OtaPackageUpdateMsg.newBuilder() |
|||
.setMsgType(msgType) |
|||
.setIdMSB(otaPackage.getId().getId().getMostSignificantBits()) |
|||
.setIdLSB(otaPackage.getId().getId().getLeastSignificantBits()) |
|||
.setDeviceProfileIdMSB(otaPackage.getDeviceProfileId().getId().getMostSignificantBits()) |
|||
.setDeviceProfileIdLSB(otaPackage.getDeviceProfileId().getId().getLeastSignificantBits()) |
|||
.setType(otaPackage.getType().name()) |
|||
.setTitle(otaPackage.getTitle()) |
|||
.setVersion(otaPackage.getVersion()) |
|||
.setTag(otaPackage.getTag()); |
|||
|
|||
if (otaPackage.getUrl() != null) { |
|||
builder.setUrl(otaPackage.getUrl()); |
|||
} |
|||
if (otaPackage.getAdditionalInfo() != null) { |
|||
builder.setAdditionalInfo(JacksonUtil.toString(otaPackage.getAdditionalInfo())); |
|||
} |
|||
if (otaPackage.getFileName() != null) { |
|||
builder.setFileName(otaPackage.getFileName()); |
|||
} |
|||
if (otaPackage.getContentType() != null) { |
|||
builder.setContentType(otaPackage.getContentType()); |
|||
} |
|||
if (otaPackage.getChecksumAlgorithm() != null) { |
|||
builder.setChecksumAlgorithm(otaPackage.getChecksumAlgorithm().name()); |
|||
} |
|||
if (otaPackage.getChecksum() != null) { |
|||
builder.setChecksum(otaPackage.getChecksum()); |
|||
} |
|||
if (otaPackage.getDataSize() != null) { |
|||
builder.setDataSize(otaPackage.getDataSize()); |
|||
} |
|||
if (otaPackage.getData() != null) { |
|||
builder.setData(ByteString.copyFrom(otaPackage.getData().array())); |
|||
} |
|||
return builder.build(); |
|||
} |
|||
|
|||
public OtaPackageUpdateMsg constructOtaPackageDeleteMsg(OtaPackageId otaPackageId) { |
|||
return OtaPackageUpdateMsg.newBuilder() |
|||
.setMsgType(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE) |
|||
.setIdMSB(otaPackageId.getId().getMostSignificantBits()) |
|||
.setIdLSB(otaPackageId.getId().getLeastSignificantBits()).build(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.constructor; |
|||
|
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.id.QueueId; |
|||
import org.thingsboard.server.common.data.queue.ProcessingStrategy; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.data.queue.SubmitStrategy; |
|||
import org.thingsboard.server.gen.edge.v1.ProcessingStrategyProto; |
|||
import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg; |
|||
import org.thingsboard.server.gen.edge.v1.SubmitStrategyProto; |
|||
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
@Component |
|||
@TbCoreComponent |
|||
public class QueueMsgConstructor { |
|||
|
|||
public QueueUpdateMsg constructQueueUpdatedMsg(UpdateMsgType msgType, Queue queue) { |
|||
QueueUpdateMsg.Builder builder = QueueUpdateMsg.newBuilder() |
|||
.setMsgType(msgType) |
|||
.setIdMSB(queue.getId().getId().getMostSignificantBits()) |
|||
.setIdLSB(queue.getId().getId().getLeastSignificantBits()) |
|||
.setTenantIdMSB(queue.getTenantId().getId().getMostSignificantBits()) |
|||
.setTenantIdLSB(queue.getTenantId().getId().getLeastSignificantBits()) |
|||
.setName(queue.getName()) |
|||
.setTopic(queue.getTopic()) |
|||
.setPollInterval(queue.getPollInterval()) |
|||
.setPartitions(queue.getPartitions()) |
|||
.setConsumerPerPartition(queue.isConsumerPerPartition()) |
|||
.setPackProcessingTimeout(queue.getPackProcessingTimeout()) |
|||
.setSubmitStrategy(createSubmitStrategyProto(queue.getSubmitStrategy())) |
|||
.setProcessingStrategy(createProcessingStrategyProto(queue.getProcessingStrategy())); |
|||
return builder.build(); |
|||
} |
|||
|
|||
private ProcessingStrategyProto createProcessingStrategyProto(ProcessingStrategy processingStrategy) { |
|||
return ProcessingStrategyProto.newBuilder() |
|||
.setType(processingStrategy.getType().name()) |
|||
.setRetries(processingStrategy.getRetries()) |
|||
.setFailurePercentage(processingStrategy.getFailurePercentage()) |
|||
.setPauseBetweenRetries(processingStrategy.getPauseBetweenRetries()) |
|||
.setMaxPauseBetweenRetries(processingStrategy.getMaxPauseBetweenRetries()) |
|||
.build(); |
|||
} |
|||
|
|||
private SubmitStrategyProto createSubmitStrategyProto(SubmitStrategy submitStrategy) { |
|||
return SubmitStrategyProto.newBuilder() |
|||
.setType(submitStrategy.getType().name()) |
|||
.setBatchSize(submitStrategy.getBatchSize()) |
|||
.build(); |
|||
} |
|||
|
|||
public QueueUpdateMsg constructQueueDeleteMsg(QueueId queueId) { |
|||
return QueueUpdateMsg.newBuilder() |
|||
.setMsgType(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE) |
|||
.setIdMSB(queueId.getId().getMostSignificantBits()) |
|||
.setIdLSB(queueId.getId().getLeastSignificantBits()).build(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,137 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.constructor.rule; |
|||
|
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.rule.NodeConnectionInfo; |
|||
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; |
|||
import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
|||
import org.thingsboard.server.common.data.rule.RuleNode; |
|||
import org.thingsboard.server.gen.edge.v1.NodeConnectionInfoProto; |
|||
import org.thingsboard.server.gen.edge.v1.RuleChainConnectionInfoProto; |
|||
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; |
|||
import org.thingsboard.server.gen.edge.v1.RuleNodeProto; |
|||
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.NavigableSet; |
|||
|
|||
@Slf4j |
|||
@AllArgsConstructor |
|||
public abstract class AbstractRuleChainMetadataConstructor implements RuleChainMetadataConstructor { |
|||
|
|||
@Override |
|||
public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(TenantId tenantId, |
|||
UpdateMsgType msgType, |
|||
RuleChainMetaData ruleChainMetaData) { |
|||
try { |
|||
RuleChainMetadataUpdateMsg.Builder builder = RuleChainMetadataUpdateMsg.newBuilder(); |
|||
builder.setRuleChainIdMSB(ruleChainMetaData.getRuleChainId().getId().getMostSignificantBits()) |
|||
.setRuleChainIdLSB(ruleChainMetaData.getRuleChainId().getId().getLeastSignificantBits()); |
|||
constructRuleChainMetadataUpdatedMsg(tenantId, builder, ruleChainMetaData); |
|||
builder.setMsgType(msgType); |
|||
return builder.build(); |
|||
} catch (JsonProcessingException ex) { |
|||
log.error("Can't construct RuleChainMetadataUpdateMsg", ex); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
protected abstract void constructRuleChainMetadataUpdatedMsg(TenantId tenantId, |
|||
RuleChainMetadataUpdateMsg.Builder builder, |
|||
RuleChainMetaData ruleChainMetaData) throws JsonProcessingException; |
|||
|
|||
protected List<NodeConnectionInfoProto> constructConnections(List<NodeConnectionInfo> connections) { |
|||
List<NodeConnectionInfoProto> result = new ArrayList<>(); |
|||
if (connections != null && !connections.isEmpty()) { |
|||
for (NodeConnectionInfo connection : connections) { |
|||
result.add(constructConnection(connection)); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
private NodeConnectionInfoProto constructConnection(NodeConnectionInfo connection) { |
|||
return NodeConnectionInfoProto.newBuilder() |
|||
.setFromIndex(connection.getFromIndex()) |
|||
.setToIndex(connection.getToIndex()) |
|||
.setType(connection.getType()) |
|||
.build(); |
|||
} |
|||
|
|||
protected List<RuleNodeProto> constructNodes(List<RuleNode> nodes) throws JsonProcessingException { |
|||
List<RuleNodeProto> result = new ArrayList<>(); |
|||
if (nodes != null && !nodes.isEmpty()) { |
|||
for (RuleNode node : nodes) { |
|||
result.add(constructNode(node)); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
private RuleNodeProto constructNode(RuleNode node) throws JsonProcessingException { |
|||
return RuleNodeProto.newBuilder() |
|||
.setIdMSB(node.getId().getId().getMostSignificantBits()) |
|||
.setIdLSB(node.getId().getId().getLeastSignificantBits()) |
|||
.setType(node.getType()) |
|||
.setName(node.getName()) |
|||
.setDebugMode(node.isDebugMode()) |
|||
.setConfiguration(JacksonUtil.OBJECT_MAPPER.writeValueAsString(node.getConfiguration())) |
|||
.setAdditionalInfo(JacksonUtil.OBJECT_MAPPER.writeValueAsString(node.getAdditionalInfo())) |
|||
.build(); |
|||
} |
|||
|
|||
protected List<RuleChainConnectionInfoProto> constructRuleChainConnections(List<RuleChainConnectionInfo> ruleChainConnections, |
|||
NavigableSet<Integer> removedNodeIndexes) throws JsonProcessingException { |
|||
List<RuleChainConnectionInfoProto> result = new ArrayList<>(); |
|||
if (ruleChainConnections != null && !ruleChainConnections.isEmpty()) { |
|||
for (RuleChainConnectionInfo ruleChainConnectionInfo : ruleChainConnections) { |
|||
if (!removedNodeIndexes.isEmpty()) { // 3_3_0 only
|
|||
int fromIndex = ruleChainConnectionInfo.getFromIndex(); |
|||
// decrease index because of removed nodes
|
|||
for (Integer removedIndex : removedNodeIndexes) { |
|||
if (fromIndex > removedIndex) { |
|||
fromIndex = fromIndex - 1; |
|||
} |
|||
} |
|||
ruleChainConnectionInfo.setFromIndex(fromIndex); |
|||
ObjectNode additionalInfo = (ObjectNode) ruleChainConnectionInfo.getAdditionalInfo(); |
|||
if (additionalInfo.get("ruleChainNodeId") == null) { |
|||
additionalInfo.put("ruleChainNodeId", "rule-chain-node-UNDEFINED"); |
|||
} |
|||
} |
|||
result.add(constructRuleChainConnection(ruleChainConnectionInfo)); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
private RuleChainConnectionInfoProto constructRuleChainConnection(RuleChainConnectionInfo ruleChainConnectionInfo) throws JsonProcessingException { |
|||
return RuleChainConnectionInfoProto.newBuilder() |
|||
.setFromIndex(ruleChainConnectionInfo.getFromIndex()) |
|||
.setTargetRuleChainIdMSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getMostSignificantBits()) |
|||
.setTargetRuleChainIdLSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getLeastSignificantBits()) |
|||
.setType(ruleChainConnectionInfo.getType()) |
|||
.setAdditionalInfo(JacksonUtil.OBJECT_MAPPER.writeValueAsString(ruleChainConnectionInfo.getAdditionalInfo())) |
|||
.build(); |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.constructor.rule; |
|||
|
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
|||
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; |
|||
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; |
|||
|
|||
public interface RuleChainMetadataConstructor { |
|||
|
|||
RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(TenantId tenantId, |
|||
UpdateMsgType msgType, |
|||
RuleChainMetaData ruleChainMetaData); |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.constructor.rule; |
|||
|
|||
import org.thingsboard.server.gen.edge.v1.EdgeVersion; |
|||
|
|||
public final class RuleChainMetadataConstructorFactory { |
|||
|
|||
public static RuleChainMetadataConstructor getByEdgeVersion(EdgeVersion edgeVersion) { |
|||
switch (edgeVersion) { |
|||
case V_3_3_0: |
|||
return new RuleChainMetadataConstructorV330(); |
|||
case V_3_3_3: |
|||
case V_3_4_0: |
|||
default: |
|||
return new RuleChainMetadataConstructorV340(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,165 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.constructor.rule; |
|||
|
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; |
|||
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; |
|||
import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.rule.NodeConnectionInfo; |
|||
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; |
|||
import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
|||
import org.thingsboard.server.common.data.rule.RuleNode; |
|||
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.NavigableSet; |
|||
import java.util.TreeSet; |
|||
import java.util.UUID; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Slf4j |
|||
public class RuleChainMetadataConstructorV330 extends AbstractRuleChainMetadataConstructor { |
|||
|
|||
private static final String RULE_CHAIN_INPUT_NODE = TbRuleChainInputNode.class.getName(); |
|||
private static final String TB_RULE_CHAIN_OUTPUT_NODE = TbRuleChainOutputNode.class.getName(); |
|||
|
|||
@Override |
|||
protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId, |
|||
RuleChainMetadataUpdateMsg.Builder builder, |
|||
RuleChainMetaData ruleChainMetaData) throws JsonProcessingException { |
|||
List<RuleNode> supportedNodes = filterNodes(ruleChainMetaData.getNodes()); |
|||
|
|||
NavigableSet<Integer> removedNodeIndexes = getRemovedNodeIndexes(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections()); |
|||
List<NodeConnectionInfo> connections = filterConnections(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections(), removedNodeIndexes); |
|||
|
|||
List<RuleChainConnectionInfo> ruleChainConnections = new ArrayList<>(); |
|||
if (ruleChainMetaData.getRuleChainConnections() != null) { |
|||
ruleChainConnections.addAll(ruleChainMetaData.getRuleChainConnections()); |
|||
} |
|||
ruleChainConnections.addAll(addRuleChainConnections(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections())); |
|||
builder.addAllNodes(constructNodes(supportedNodes)) |
|||
.addAllConnections(constructConnections(connections)) |
|||
.addAllRuleChainConnections(constructRuleChainConnections(ruleChainConnections, removedNodeIndexes)); |
|||
if (ruleChainMetaData.getFirstNodeIndex() != null) { |
|||
Integer firstNodeIndex = ruleChainMetaData.getFirstNodeIndex(); |
|||
// decrease index because of removed nodes
|
|||
for (Integer removedIndex : removedNodeIndexes) { |
|||
if (firstNodeIndex > removedIndex) { |
|||
firstNodeIndex = firstNodeIndex - 1; |
|||
} |
|||
} |
|||
builder.setFirstNodeIndex(firstNodeIndex); |
|||
} else { |
|||
builder.setFirstNodeIndex(-1); |
|||
} |
|||
} |
|||
|
|||
private NavigableSet<Integer> getRemovedNodeIndexes(List<RuleNode> nodes, List<NodeConnectionInfo> connections) { |
|||
TreeSet<Integer> removedIndexes = new TreeSet<>(); |
|||
for (NodeConnectionInfo connection : connections) { |
|||
for (int i = 0; i < nodes.size(); i++) { |
|||
RuleNode node = nodes.get(i); |
|||
if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE) |
|||
|| node.getType().equalsIgnoreCase(TB_RULE_CHAIN_OUTPUT_NODE)) { |
|||
if (connection.getFromIndex() == i || connection.getToIndex() == i) { |
|||
removedIndexes.add(i); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return removedIndexes.descendingSet(); |
|||
} |
|||
|
|||
private List<NodeConnectionInfo> filterConnections(List<RuleNode> nodes, |
|||
List<NodeConnectionInfo> connections, |
|||
NavigableSet<Integer> removedNodeIndexes) { |
|||
List<NodeConnectionInfo> result = new ArrayList<>(); |
|||
if (connections != null) { |
|||
result = connections.stream().filter(conn -> { |
|||
for (int i = 0; i < nodes.size(); i++) { |
|||
RuleNode node = nodes.get(i); |
|||
if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE) |
|||
|| node.getType().equalsIgnoreCase(TB_RULE_CHAIN_OUTPUT_NODE)) { |
|||
if (conn.getFromIndex() == i || conn.getToIndex() == i) { |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
return true; |
|||
}).map(conn -> { |
|||
NodeConnectionInfo newConn = new NodeConnectionInfo(); |
|||
newConn.setFromIndex(conn.getFromIndex()); |
|||
newConn.setToIndex(conn.getToIndex()); |
|||
newConn.setType(conn.getType()); |
|||
return newConn; |
|||
}).collect(Collectors.toList()); |
|||
} |
|||
|
|||
// decrease index because of removed nodes
|
|||
for (Integer removedIndex : removedNodeIndexes) { |
|||
for (NodeConnectionInfo newConn : result) { |
|||
if (newConn.getToIndex() > removedIndex) { |
|||
newConn.setToIndex(newConn.getToIndex() - 1); |
|||
} |
|||
if (newConn.getFromIndex() > removedIndex) { |
|||
newConn.setFromIndex(newConn.getFromIndex() - 1); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
private List<RuleNode> filterNodes(List<RuleNode> nodes) { |
|||
List<RuleNode> result = new ArrayList<>(); |
|||
for (RuleNode node : nodes) { |
|||
if (RULE_CHAIN_INPUT_NODE.equals(node.getType()) |
|||
|| TB_RULE_CHAIN_OUTPUT_NODE.equals(node.getType())) { |
|||
log.trace("Skipping not supported rule node {}", node); |
|||
} else { |
|||
result.add(node); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
private List<RuleChainConnectionInfo> addRuleChainConnections(List<RuleNode> nodes, List<NodeConnectionInfo> connections) { |
|||
List<RuleChainConnectionInfo> result = new ArrayList<>(); |
|||
for (int i = 0; i < nodes.size(); i++) { |
|||
RuleNode node = nodes.get(i); |
|||
if (node.getType().equalsIgnoreCase(RULE_CHAIN_INPUT_NODE)) { |
|||
for (NodeConnectionInfo connection : connections) { |
|||
if (connection.getToIndex() == i) { |
|||
RuleChainConnectionInfo e = new RuleChainConnectionInfo(); |
|||
e.setFromIndex(connection.getFromIndex()); |
|||
TbRuleChainInputNodeConfiguration configuration = JacksonUtil.treeToValue(node.getConfiguration(), TbRuleChainInputNodeConfiguration.class); |
|||
e.setTargetRuleChainId(new RuleChainId(UUID.fromString(configuration.getRuleChainId()))); |
|||
e.setAdditionalInfo(node.getAdditionalInfo()); |
|||
e.setType(connection.getType()); |
|||
result.add(e); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.constructor.rule; |
|||
|
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
|||
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; |
|||
|
|||
import java.util.TreeSet; |
|||
|
|||
@Slf4j |
|||
public class RuleChainMetadataConstructorV340 extends AbstractRuleChainMetadataConstructor { |
|||
|
|||
@Override |
|||
protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId, |
|||
RuleChainMetadataUpdateMsg.Builder builder, |
|||
RuleChainMetaData ruleChainMetaData) throws JsonProcessingException { |
|||
builder.addAllNodes(constructNodes(ruleChainMetaData.getNodes())) |
|||
.addAllConnections(constructConnections(ruleChainMetaData.getConnections())) |
|||
.addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections(), new TreeSet<>())); |
|||
if (ruleChainMetaData.getFirstNodeIndex() != null) { |
|||
builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex()); |
|||
} else { |
|||
builder.setFirstNodeIndex(-1); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.EdgeUtils; |
|||
import org.thingsboard.server.common.data.OtaPackageInfo; |
|||
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.ota.OtaPackageService; |
|||
|
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class OtaPackagesEdgeEventFetcher extends BasePageableEdgeEventFetcher<OtaPackageInfo> { |
|||
|
|||
private final OtaPackageService otaPackageService; |
|||
|
|||
@Override |
|||
PageData<OtaPackageInfo> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return otaPackageService.findTenantOtaPackagesByTenantId(tenantId, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, OtaPackageInfo otaPackageInfo) { |
|||
return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.OTA_PACKAGE, |
|||
EdgeEventActionType.ADDED, otaPackageInfo.getId(), null); |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.EdgeUtils; |
|||
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.queue.Queue; |
|||
import org.thingsboard.server.dao.queue.QueueService; |
|||
|
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class QueuesEdgeEventFetcher extends BasePageableEdgeEventFetcher<Queue> { |
|||
|
|||
private final QueueService queueService; |
|||
|
|||
@Override |
|||
PageData<Queue> fetchPageData(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
return queueService.findQueuesByTenantId(tenantId, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, Queue queue) { |
|||
return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.QUEUE, |
|||
EdgeEventActionType.ADDED, queue.getId(), null); |
|||
} |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.processor; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.EdgeUtils; |
|||
import org.thingsboard.server.common.data.OtaPackage; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.id.OtaPackageId; |
|||
import org.thingsboard.server.gen.edge.v1.DownlinkMsg; |
|||
import org.thingsboard.server.gen.edge.v1.OtaPackageUpdateMsg; |
|||
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
@Component |
|||
@Slf4j |
|||
@TbCoreComponent |
|||
public class OtaPackageEdgeProcessor extends BaseEdgeProcessor { |
|||
|
|||
public DownlinkMsg processOtaPackageToEdge(EdgeEvent edgeEvent, UpdateMsgType msgType, EdgeEventActionType action) { |
|||
OtaPackageId otaPackageId = new OtaPackageId(edgeEvent.getEntityId()); |
|||
DownlinkMsg downlinkMsg = null; |
|||
switch (action) { |
|||
case ADDED: |
|||
case UPDATED: |
|||
OtaPackage otaPackage = otaPackageService.findOtaPackageById(edgeEvent.getTenantId(), otaPackageId); |
|||
if (otaPackage != null) { |
|||
OtaPackageUpdateMsg otaPackageUpdateMsg = |
|||
otaPackageMsgConstructor.constructOtaPackageUpdatedMsg(msgType, otaPackage); |
|||
downlinkMsg = DownlinkMsg.newBuilder() |
|||
.setDownlinkMsgId(EdgeUtils.nextPositiveInt()) |
|||
.addOtaPackageUpdateMsg(otaPackageUpdateMsg) |
|||
.build(); |
|||
} |
|||
break; |
|||
case DELETED: |
|||
OtaPackageUpdateMsg otaPackageUpdateMsg = |
|||
otaPackageMsgConstructor.constructOtaPackageDeleteMsg(otaPackageId); |
|||
downlinkMsg = DownlinkMsg.newBuilder() |
|||
.setDownlinkMsgId(EdgeUtils.nextPositiveInt()) |
|||
.addOtaPackageUpdateMsg(otaPackageUpdateMsg) |
|||
.build(); |
|||
break; |
|||
} |
|||
return downlinkMsg; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.processor; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.EdgeUtils; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.id.QueueId; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.gen.edge.v1.DownlinkMsg; |
|||
import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg; |
|||
import org.thingsboard.server.gen.edge.v1.UpdateMsgType; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
@Component |
|||
@Slf4j |
|||
@TbCoreComponent |
|||
public class QueueEdgeProcessor extends BaseEdgeProcessor { |
|||
|
|||
public DownlinkMsg processQueueToEdge(EdgeEvent edgeEvent, UpdateMsgType msgType, EdgeEventActionType action) { |
|||
QueueId queueId = new QueueId(edgeEvent.getEntityId()); |
|||
DownlinkMsg downlinkMsg = null; |
|||
switch (action) { |
|||
case ADDED: |
|||
case UPDATED: |
|||
Queue queue = queueService.findQueueById(edgeEvent.getTenantId(), queueId); |
|||
if (queue != null) { |
|||
QueueUpdateMsg queueUpdateMsg = |
|||
queueMsgConstructor.constructQueueUpdatedMsg(msgType, queue); |
|||
downlinkMsg = DownlinkMsg.newBuilder() |
|||
.setDownlinkMsgId(EdgeUtils.nextPositiveInt()) |
|||
.addQueueUpdateMsg(queueUpdateMsg) |
|||
.build(); |
|||
} |
|||
break; |
|||
case DELETED: |
|||
QueueUpdateMsg queueDeleteMsg = |
|||
queueMsgConstructor.constructQueueDeleteMsg(queueId); |
|||
downlinkMsg = DownlinkMsg.newBuilder() |
|||
.setDownlinkMsgId(EdgeUtils.nextPositiveInt()) |
|||
.addQueueUpdateMsg(queueDeleteMsg) |
|||
.build(); |
|||
break; |
|||
} |
|||
return downlinkMsg; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.entitiy.tenant.profile; |
|||
|
|||
import org.thingsboard.server.common.data.TenantProfile; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
|
|||
public interface TbTenantProfileService { |
|||
TenantProfile save(TenantId tenantId, TenantProfile tenantProfile, TenantProfile oldTenantProfile) throws ThingsboardException; |
|||
|
|||
void delete(TenantId tenantId, TenantProfile tenantProfile) throws ThingsboardException; |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue