Browse Source

VC refactoring

pull/6558/head
Viacheslav Klimov 4 years ago
parent
commit
074ea8af6c
  1. 4
      application/src/main/java/org/thingsboard/server/controller/AssetController.java
  2. 4
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  3. 4
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  4. 206
      application/src/main/java/org/thingsboard/server/controller/EntitiesExportImportController.java
  5. 293
      application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
  6. 4
      application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java
  7. 4
      application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java
  8. 4
      application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java
  9. 30
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/DefaultEntitiesExportImportService.java
  10. 10
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/EntitiesExportImportService.java
  11. 56
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/DefaultExportableEntitiesService.java
  12. 6
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/EntityExportService.java
  13. 12
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/ExportableEntitiesService.java
  14. 2
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/DeviceExportData.java
  15. 2
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/EntityExportData.java
  16. 2
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/EntityExportSettings.java
  17. 2
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/RuleChainExportData.java
  18. 6
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/BaseEntityExportService.java
  19. 10
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/DefaultEntityExportService.java
  20. 4
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/DeviceExportService.java
  21. 4
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/RuleChainExportService.java
  22. 8
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/EntityImportService.java
  23. 9
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/AbstractBulkImportService.java
  24. 2
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/BulkImportColumnType.java
  25. 2
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/BulkImportRequest.java
  26. 2
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/BulkImportResult.java
  27. 2
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/ImportedEntityInfo.java
  28. 2
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/data/EntityImportResult.java
  29. 2
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/data/EntityImportSettings.java
  30. 4
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/AssetImportService.java
  31. 12
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/BaseEntityImportService.java
  32. 4
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/CustomerImportService.java
  33. 6
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/DashboardImportService.java
  34. 4
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/DeviceImportService.java
  35. 4
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/DeviceProfileImportService.java
  36. 6
      application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/RuleChainImportService.java
  37. 32
      application/src/main/java/org/thingsboard/server/service/sync/importing/data/request/ImportRequest.java
  38. 463
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java
  39. 27
      application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java
  40. 10
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesVersionControlSettings.java
  41. 11
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/VersionCreationResult.java
  42. 8
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/VersionLoadResult.java
  43. 14
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/EntitiesByCustomFilterVersionCreateConfig.java
  44. 12
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/EntitiesByCustomQueryVersionCreateConfig.java
  45. 10
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/EntityListVersionCreateConfig.java
  46. 14
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/EntityTypeVersionCreateConfig.java
  47. 10
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/SingleEntityVersionCreateConfig.java
  48. 18
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/VersionCreateConfig.java
  49. 4
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/VersionCreateConfigType.java
  50. 14
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/VersionCreateRequest.java
  51. 12
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/EntityTypeVersionLoadConfig.java
  52. 20
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/EntityTypeVersionLoadRequest.java
  53. 11
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/EntityVersionLoadConfig.java
  54. 20
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/SingleEntityVersionLoadRequest.java
  55. 11
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/VersionLoadRequest.java
  56. 6
      application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/VersionLoadRequestType.java
  57. 39
      application/src/main/java/org/thingsboard/server/utils/GitRepository.java
  58. 20
      application/src/test/java/org/thingsboard/server/controller/BaseEntitiesExportImportControllerTest.java
  59. 53
      application/src/test/java/org/thingsboard/server/controller/sql/EntitiesExportImportControllerSqlTest.java
  60. 20
      dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java
  61. 4
      dao/src/main/java/org/thingsboard/server/dao/ExportableEntityDao.java
  62. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java
  63. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java
  64. 4
      dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardRepository.java
  65. 7
      dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java
  66. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java
  67. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java
  68. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java

4
application/src/main/java/org/thingsboard/server/controller/AssetController.java

@ -54,8 +54,8 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.asset.AssetBulkImportService;
import org.thingsboard.server.service.sync.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.importing.csv.BulkImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;

4
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -74,8 +74,8 @@ import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.device.DeviceBulkImportService;
import org.thingsboard.server.service.gateway_device.GatewayNotificationsService;
import org.thingsboard.server.service.sync.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.importing.csv.BulkImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;

4
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -55,8 +55,8 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.EdgeBulkImportService;
import org.thingsboard.server.service.sync.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.importing.csv.BulkImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;

206
application/src/main/java/org/thingsboard/server/controller/EntitiesExportImportController.java

@ -1,206 +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.
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
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.RestController;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.EntitiesExportImportService;
import org.thingsboard.server.service.sync.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import org.thingsboard.server.service.sync.exporting.data.request.ExportRequest;
import org.thingsboard.server.service.sync.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.importing.data.request.ImportRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
@RestController
@RequestMapping("/api/entities")
@TbCoreComponent
@RequiredArgsConstructor
@Slf4j
public class EntitiesExportImportController extends BaseController {
private final EntitiesExportImportService exportImportService;
private final ExportableEntitiesService exportableEntitiesService;
@ApiOperation(value = "Export entities by request", notes = "" +
"Takes export request and returns list of export data for each entity found by request. " +
"Supported entity types for export, hence for import, are **DEVICE**, **DEVICE_PROFILE**, **ASSET**, " +
"**CUSTOMER**, **RULE_CHAIN** and **DASHBOARD**." + NEW_LINE +
"For each type of export request, you can set some export settings: \n" +
"- **exportRelations** - whether to export inbound and outbound relations for an entity " +
"(only relations of type group COMMON can be exported)" + NEW_LINE +
"Supported export requests:\n" +
"- **SINGLE_ENTITY**:" + NEW_LINE +
" To export a single entity by id. Example:" + NEW_LINE +
"```\n{\n \"type\": \"SINGLE_ENTITY\",\n \"entityId\": {\n \"entityType\": \"DEVICE\",\n \"id\": \"2eb16d70-989d-11ec-93b5-6de6c2b68078\"\n },\n \"exportSettings\": {\n \"exportRelations\": false\n }\n}\n```" + NEW_LINE +
"- **ENTITY_LIST**:" + NEW_LINE +
" To export a list of entities by their ids. Example:" + NEW_LINE +
"```\n{\n \"type\": \"ENTITY_LIST\",\n \"entitiesIds\": [\n {\n \"entityType\": \"DEVICE\",\n \"id\": \"2eb16d70-989d-11ec-93b5-6de6c2b68078\"\n },\n {\n \"entityType\": \"ASSET\",\n \"id\": \"2f0a3bd0-989d-11ec-93b5-6de6c2b68078\"\n }\n ],\n \"exportSettings\": {\n \"exportRelations\": true\n }\n}\n```" + NEW_LINE +
"- **ENTITY_TYPE**:" + NEW_LINE +
" To export entities of specified entity type. You need to specify page size, " +
"and may specify page index and customer id (to limit the list of entities to the ones owned by a customer). " +
"Entities are ordered by created time descendingly. Example:" + NEW_LINE +
"```\n{\n \"type\": \"ENTITY_TYPE\",\n \"entityType\": \"ASSET\",\n \"page\": 0,\n \"pageSize\": 100,\n \"customerId\": \"2eb16d70-989d-11ec-93b5-6de6c2b68078\"\n}\n```" + NEW_LINE +
"- **CUSTOM_ENTITY_FILTER**:" + NEW_LINE +
" To export entities by custom entity filter. The order used is the same as for ENTITY_TYPE export request. Example:" + NEW_LINE +
"```\n{\n \"type\": \"CUSTOM_ENTITY_FILTER\",\n \"filter\": {\n \"type\": \"deviceType\",\n \"deviceType\": \"Thermostats\",\n \"deviceNameFilter\": \"\"\n },\n \"page\": 0,\n \"pageSize\": 100,\n \"customerId\": null,\n \"exportSettings\": {\n \"exportRelations\": false\n }\n}\n```" + NEW_LINE +
"- **CUSTOM_ENTITY_QUERY**:" + NEW_LINE +
" To export entities by custom entity query. Example: " + NEW_LINE +
"```\n{\n \"type\": \"CUSTOM_ENTITY_QUERY\",\n \"query\": {\n \"entityFilter\": {\n \"type\": \"entityType\",\n \"entityType\": \"DEVICE\"\n },\n \"pageLink\": {\n \"page\": 0,\n \"pageSize\": 200,\n \"textSearch\": \"THB_\",\n \"sortOrder\": {\n \"key\": {\n \"type\": \"ENTITY_FIELD\",\n \"key\": \"name\"\n },\n \"direction\": \"DESC\"\n }\n },\n \"entityFields\": [\n {\n \"type\": \"ENTITY_FIELD\",\n \"key\": \"name\"\n }\n ],\n \"latestValues\": [\n {\n \"type\": \"SERVER_ATTRIBUTE\",\n \"key\": \"lastActivityTime\"\n }\n ],\n \"keyFilters\": [\n {\n \"key\": {\n \"type\": \"SERVER_ATTRIBUTE\",\n \"key\": \"lastActivityTime\"\n },\n \"valueType\": \"NUMERIC\",\n \"predicate\": {\n \"type\": \"NUMERIC\",\n \"operation\": \"GREATER\",\n \"value\": {\n \"defaultValue\": 0\n }\n }\n }\n ]\n },\n \"customerId\": null,\n \"exportSettings\": {\n \"exportRelations\": false\n }\n}\n```" + NEW_LINE +
"Mostly, export data of an entity contains the whole entity itself and its relations " +
"(if option to export relations was enabled):" + NEW_LINE +
"```\n[\n {\n \"entityType\": \"ASSET\",\n \"entity\": {\n \"id\": { ... },\n \"createdTime\": 1648204424029,\n \"additionalInfo\": {\n \"description\": \"\"\n },\n \"tenantId\": { ... },\n \"customerId\": { ... },\n \"name\": \"Asset 1\",\n \"type\": \"A\",\n ...\n },\n \"relations\": [\n {\n \"from\": {\n \"entityType\": \"ASSET\",\n \"id\": ...\n },\n \"to\": {\n \"entityType\": \"DEVICE\",\n \"id\": ...\n },\n \"type\": \"Contains\",\n \"typeGroup\": \"COMMON\",\n \"additionalInfo\": {\n \"a\": \"b\"\n }\n }\n ]\n }\n]\n```" + NEW_LINE +
"For devices, export data will additionally contain device's credentials; for rule chains - its metadata:" + NEW_LINE +
"```\n[\n {\n \"entityType\": \"DEVICE\",\n \"entity\": { ... },\n \"credentials\": {\n \"id\": { ... },\n \"createdTime\": 1648829321209,\n \"deviceId\": { ... },\n \"credentialsType\": \"ACCESS_TOKEN\",\n \"credentialsId\": \"5cZEDo45KGW7JgVNv4Ko\",\n \"credentialsValue\": null\n }\n }\n]\n```" + NEW_LINE +
"```\n[\n {\n \"entityType\": \"RULE_CHAIN\",\n \"entity\": {\n \"id\": { ... },\n \"createdTime\": 1646056614257,\n \"additionalInfo\": null,\n \"tenantId\": { ... },\n \"name\": \"Rule Chain 2\",\n \"type\": \"CORE\",\n \"firstRuleNodeId\": { ... },\n \"root\": false,\n ...\n },\n \"metaData\": {\n \"ruleChainId\": { ... },\n \"firstNodeIndex\": 7,\n \"nodes\": [ ... ],\n \"connections\": [ ... ],\n \"ruleChainConnections\": null\n }\n }\n]\n```" + NEW_LINE +
"Returned export data is to be used later for import request." + NEW_LINE +
"If any entity found by request is of unsupported type - an error will be returned.\n" +
"Also, if a user does not have a READ permission for an entity (or, if relations are exported, for a bounded entity), " +
"access will be denied." +
ControllerConstants.TENANT_AUTHORITY_PARAGRAPH)
@PostMapping("/export")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
public List<EntityExportData<?>> exportEntities(@RequestBody ExportRequest exportRequest) throws ThingsboardException {
SecurityUser user = getCurrentUser();
try {
return exportEntitiesByRequest(user, exportRequest);
} catch (Exception e) {
log.warn("Failed to export entities for request {}", exportRequest, e);
throw handleException(e);
}
}
@ApiOperation(value = "Export entities by multiple requests", notes = "" +
"The API behaviour is the same as for exporting entities by single request, " +
"except that this method takes an array of export requests as a request body." + NEW_LINE +
"Example:" + NEW_LINE +
"```\n[\n {\n \"type\": \"SINGLE_ENTITY\",\n \"entityId\": {\n \"entityType\": \"DEVICE_PROFILE\",\n \"id\": \"5f9eda10-b442-11ec-bbf5-adec34031568\"\n }\n },\n {\n \"type\": \"CUSTOM_ENTITY_FILTER\",\n \"filter\": {\n \"type\": \"deviceType\",\n \"deviceType\": \"thermostat\",\n \"deviceNameFilter\": \"\"\n },\n \"pageSize\": 1000\n },\n {\n \"type\": \"ENTITY_TYPE\",\n \"entityType\": \"ASSET\",\n \"pageSize\": 1000,\n \"exportSettings\": {\n \"exportRelations\": true\n }\n },\n {\n \"type\": \"ENTITY_LIST\",\n \"entitiesIds\": [\n {\n \"entityType\": \"RULE_CHAIN\",\n \"id\": \"2ef13590-989d-11ec-93b5-6de6c2b68078\"\n },\n {\n \"entityType\": \"RULE_CHAIN\",\n \"id\": \"e7311ec0-b442-11ec-bbf5-adec34031568\"\n }\n ]\n }\n]\n```" +
ControllerConstants.TENANT_AUTHORITY_PARAGRAPH)
@PostMapping(value = "/export", params = {"multiple"})
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
public List<EntityExportData<?>> exportEntities(@RequestBody List<ExportRequest> exportRequests) throws ThingsboardException {
SecurityUser user = getCurrentUser();
try {
List<EntityExportData<?>> result = new ArrayList<>();
for (ExportRequest exportRequest : exportRequests) {
List<EntityExportData<?>> exportDataList = exportEntitiesByRequest(user, exportRequest);
result.addAll(exportDataList);
}
return result;
} catch (Exception e) {
log.warn("Failed to export entities for requests {}", exportRequests, e);
throw handleException(e);
}
}
private List<EntityExportData<?>> exportEntitiesByRequest(SecurityUser user, ExportRequest exportRequest) throws ThingsboardException {
List<EntityId> entities = exportableEntitiesService.findEntitiesForRequest(user.getTenantId(), exportRequest);
EntityExportSettings exportSettings = exportRequest.getExportSettings();
if (exportSettings == null) {
exportSettings = EntityExportSettings.builder()
.exportRelations(false)
.build();
}
List<EntityExportData<?>> exportDataList = new ArrayList<>();
for (EntityId entityId : entities) {
EntityExportData<?> exportData = exportImportService.exportEntity(user, entityId, exportSettings);
exportDataList.add(exportData);
}
return exportDataList;
}
@ApiOperation(value = "Import entities by request", notes = "" +
"Takes import request and returns the list of import results. " +
"Import request must contain the list of export data and might contain import settings. " + NEW_LINE +
"The method creates an entity if it is new in the scope of a tenant, or otherwise updates an existing one. " +
"On entity import request, we first try to find an entity within a tenant that has externalId equal " +
"to the id in the export data. If the platform fails to do that, we then search for an entity with " +
"regular (internal) id like the one in the export data (this is useful in case we are exporting and " +
"importing entities within the same tenant). Then, if we still haven't found any entity, if findExistingByName " +
"option of the EntityImportSettings is enabled, we will search for the one by its name (this is also useful " +
"for avoiding conflicts with default device profile or Root Rule Chain when importing all entities from another " +
"tenant). After, if the exported entity is new for this tenant, we simply save it with external id " +
"from the export data, and also create relations if any (if updateRelations option is enabled). " +
"Otherwise, we will reset all fields of the existing entity to the ones from the export data and save it, " +
"and also will update the list of relations (remove the ones that aren't present in the export data, " +
"and update or create others), if updateRelations option is enabled." + NEW_LINE +
"If an entity contains references to some other entities, like device references certain device profile, " +
"we will find this other entity within the tenant by this principle: look for an entity with " +
"such external id, or otherwise, internal id. This requires referenced entities to be imported " +
"before the referencing entity (if we are importing to another tenant). So, when receiving the list " +
"of entities' export data for import, we first try to fix the data order to import 'standalone' entities first." + NEW_LINE +
"As for relations importing, they are processed after all entities in the import batch are already saved, " +
"and the internal id of a bounded entity is found with the regular principle." + NEW_LINE +
"Import of all entities and their relations from the import request is processed in the single transaction, " +
"and so everything will be rolled back if the platform fails to e.g. find internal entity by external id. \n" +
"Example of import request:\n" +
"```\n{\n \"importSettings\": {\n \"findExistingByName\": false,\n \"updateRelations\": false\n },\n \"exportDataList\": [\n {\n \"entityType\": \"DEVICE_PROFILE\",\n \"entity\": {\n \"id\": {\n \"entityType\": \"DEVICE_PROFILE\",\n \"id\": \"f84363d0-b442-11ec-bbf5-adec34031568\"\n },\n \"createdTime\": 1649096026765,\n \"tenantId\": {\n \"entityType\": \"TENANT\",\n \"id\": \"4c9001b0-b442-11ec-bbf5-adec34031568\"\n },\n \"name\": \"Profile 1\",\n ...\n }\n },\n {\n \"entityType\": \"DEVICE\",\n \"entity\": {\n \"id\": {\n \"entityType\": \"DEVICE\",\n \"id\": \"98161420-b4ca-11ec-ab0c-e7744c90d468\"\n },\n \"createdTime\": 1649154276962,\n \"tenantId\": {\n \"entityType\": \"TENANT\",\n \"id\": \"4c9001b0-b442-11ec-bbf5-adec34031568\"\n },\n \"customerId\": {\n \"entityType\": \"CUSTOMER\",\n \"id\": \"13814000-1dd2-11b2-8080-808080808080\"\n },\n \"name\": \"Device 1\",\n \"type\": \"Profile 1\",\n \"label\": \"v1.0\",\n \"deviceProfileId\": {\n \"entityType\": \"DEVICE_PROFILE\",\n \"id\": \"f84363d0-b442-11ec-bbf5-adec34031568\"\n },\n ...\n },\n \"credentials\": {\n \"id\": {\n \"id\": \"981e0360-b4ca-11ec-ab0c-e7744c90d468\"\n },\n \"createdTime\": 1649154277014,\n \"deviceId\": {\n \"entityType\": \"DEVICE\",\n \"id\": \"98161420-b4ca-11ec-ab0c-e7744c90d468\"\n },\n \"credentialsType\": \"ACCESS_TOKEN\",\n \"credentialsId\": \"sGExNdnl71uKmkNvtNdp\",\n \"credentialsValue\": null\n }\n }\n ]\n}\n```" + NEW_LINE +
"The response contains a list of EntityImportResult which has values of savedEntity and oldEntity:\n" +
"```\n[\n {\n \"savedEntity\": {\n \"id\": {\n \"entityType\": \"ASSET\",\n \"id\": \"d73d7690-b4e6-11ec-b9eb-0562e1a20a1b\"\n },\n \"createdTime\": 1649166408825,\n \"additionalInfo\": {\n \"description\": \"\"\n },\n \"tenantId\": {\n \"entityType\": \"TENANT\",\n \"id\": \"c0b2e4f0-b4e6-11ec-b9eb-0562e1a20a1b\"\n },\n \"name\": \"Asset 1\",\n \"type\": \"A\",\n \"label\": \"v2.0\",\n ...\n \"externalId\": {\n \"entityType\": \"ASSET\",\n \"id\": \"6b03ab20-989e-11ec-b446-89df822d7fa2\"\n }\n },\n \"oldEntity\": {\n \"id\": {\n \"entityType\": \"ASSET\",\n \"id\": \"d73d7690-b4e6-11ec-b9eb-0562e1a20a1b\"\n },\n \"createdTime\": 1649166408825,\n \"tenantId\": {\n \"entityType\": \"TENANT\",\n \"id\": \"c0b2e4f0-b4e6-11ec-b9eb-0562e1a20a1b\"\n },\n \"name\": \"Asset 1\",\n \"type\": \"A\",\n \"label\": \"v1.0\",\n ...\n \"externalId\": null\n },\n \"entityType\": \"ASSET\"\n },\n {\n \"savedEntity\": {\n \"id\": {\n \"entityType\": \"ASSET\",\n \"id\": \"387213f0-b4ea-11ec-abfc-6dcc6508d0b5\"\n },\n \"createdTime\": 1649167860399,\n \"tenantId\": {\n \"entityType\": \"TENANT\",\n \"id\": \"c0b2e4f0-b4e6-11ec-b9eb-0562e1a20a1b\"\n },\n \"name\": \"Asset 2\",\n \"type\": \"B\",\n ...\n \"externalId\": {\n \"entityType\": \"ASSET\",\n \"id\": \"0b9ea0d0-ac27-11ec-a2a6-89d15eae3b21\"\n }\n },\n \"oldEntity\": null,\n \"entityType\": \"ASSET\"\n }\n]\n```")
@PostMapping("/import")
public List<EntityImportResult<?>> importEntities(@RequestBody ImportRequest importRequest) throws ThingsboardException {
SecurityUser user = getCurrentUser();
try {
EntityImportSettings importSettings = importRequest.getImportSettings();
if (importSettings == null) {
importSettings = EntityImportSettings.builder()
.findExistingByName(false)
.updateRelations(false)
.build();
}
List<EntityImportResult<?>> importResults = exportImportService.importEntities(user, importRequest.getExportDataList(), importSettings);
importResults.stream()
.map(EntityImportResult::getSendEventsCallback)
.filter(Objects::nonNull)
.forEach(sendEventsCallback -> {
try {
sendEventsCallback.run();
} catch (Exception e) {
log.error("Failed to send event for entity", e);
}
});
return importResults;
} catch (Exception e) {
log.warn("Failed to import entities for request {}", importRequest, e);
throw handleException(e);
}
}
}

293
application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java

@ -15,140 +15,189 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
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.RestController;
import org.thingsboard.server.common.data.EntityType;
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.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService;
import org.thingsboard.server.service.sync.vc.data.EntitiesVersionControlSettings;
import org.thingsboard.server.service.sync.vc.data.EntityVersion;
import org.thingsboard.server.service.sync.vc.data.VersionCreationResult;
import org.thingsboard.server.service.sync.vc.data.VersionLoadResult;
import org.thingsboard.server.service.sync.vc.data.VersionedEntityInfo;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateRequest;
import org.thingsboard.server.service.sync.vc.data.request.load.VersionLoadRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@RestController
@RequestMapping("/api/entities/vc")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequiredArgsConstructor
public class EntitiesVersionControlController extends BaseController {
private final EntitiesVersionControlService versionControlService;
// search request - export request with settings
//
// @PostMapping("/version/{entityType}/{entityId}")
// @PreAuthorize("hasAuthority('TENANT_ADMIN')")
// public EntityVersion saveEntityVersion(@PathVariable EntityType entityType,
// @PathVariable("entityId") UUID id,
// @RequestParam String branch,
// @RequestBody String versionName) throws Exception {
// EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, id);
// return versionControlService.saveEntityVersion(getTenantId(), entityId, branch, versionName);
// }
//
// @PostMapping("/version/{entityType}")
// @PreAuthorize("hasAuthority('TENANT_ADMIN')")
// public EntityVersion saveEntitiesVersion(@PathVariable EntityType entityType,
// @RequestParam UUID[] ids,
// @RequestParam String branch,
// @RequestBody String versionName) throws Exception {
// List<EntityId> entitiesIds = Arrays.stream(ids)
// .map(id -> EntityIdFactory.getByTypeAndUuid(entityType, id))
// .collect(Collectors.toList());
// return versionControlService.saveEntitiesVersion(getTenantId(), entitiesIds, branch, versionName);
// }
//
//
//
// @GetMapping("/version/{entityType}/{entityId}")
// @PreAuthorize("hasAuthority('TENANT_ADMIN')")
// public List<EntityVersion> listEntityVersions(@PathVariable EntityType entityType,
// @PathVariable("entityId") UUID entityUuid,
// @RequestParam String branch) throws Exception {
// EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, entityUuid);
// return versionControlService.listEntityVersions(getTenantId(), entityId, branch, Integer.MAX_VALUE);
// }
//
// @GetMapping("/version/{entityType}")
// @PreAuthorize("hasAuthority('TENANT_ADMIN')")
// public List<EntityVersion> listEntityTypeVersions(@PathVariable EntityType entityType,
// @RequestParam String branch) throws Exception {
// return versionControlService.listEntityTypeVersions(getTenantId(), entityType, branch, Integer.MAX_VALUE);
// }
//
// @GetMapping("/version")
// @PreAuthorize("hasAuthority('TENANT_ADMIN')")
// public List<EntityVersion> listVersions(@RequestParam String branch) throws Exception {
// return versionControlService.listVersions(getTenantId(), branch, Integer.MAX_VALUE);
// }
//
//
//
// @GetMapping("/files/version/{versionId}")
// @PreAuthorize("hasAuthority('TENANT_ADMIN')")
// public List<String> listFilesAtVersion(@RequestParam String branch,
// @PathVariable String versionId) throws Exception {
// return versionControlService.listFilesAtVersion(getTenantId(), branch, versionId);
// }
//
//
//
// @GetMapping("/entity/{entityType}/{entityId}/{versionId}")
// @PreAuthorize("hasAuthority('TENANT_ADMIN')")
// public EntityExportData<ExportableEntity<EntityId>> getEntityAtVersion(@PathVariable EntityType entityType,
// @PathVariable("entityId") UUID entityUuid,
// @RequestParam String branch,
// @PathVariable String versionId) throws Exception {
// EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, entityUuid);
// return versionControlService.getEntityAtVersion(getTenantId(), entityId, branch, versionId);
// }
//
// @PostMapping("/entity/{entityType}/{entityId}/{versionId}")
// @PreAuthorize("hasAuthority('TENANT_ADMIN')")
// public EntityImportResult<ExportableEntity<EntityId>> loadEntityVersion(@PathVariable EntityType entityType,
// @PathVariable("entityId") UUID entityUuid,
// @RequestParam String branch,
// @PathVariable String versionId) throws Exception {
// EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, entityUuid);
// EntityImportResult<ExportableEntity<EntityId>> result = versionControlService.loadEntityVersion(getTenantId(), entityId, branch, versionId);
// onEntityUpdatedOrCreated(getCurrentUser(), result.getSavedEntity(), result.getOldEntity(), result.getOldEntity() == null);
// return result;
// }
//
// @PostMapping("/entity/{versionId}")
// @PreAuthorize("hasAuthority('TENANT_ADMIN')")
// public List<EntityImportResult<ExportableEntity<EntityId>>> loadAllAtVersion(@RequestParam String branch,
// @PathVariable String versionId) throws Exception {
// SecurityUser user = getCurrentUser();
// List<EntityImportResult<ExportableEntity<EntityId>>> resultList = versionControlService.loadAllAtVersion(user.getTenantId(), branch, versionId);
// resultList.forEach(result -> {
// onEntityUpdatedOrCreated(user, result.getSavedEntity(), result.getOldEntity(), result.getOldEntity() == null);
// });
// return resultList;
// }
//
//
//
// @GetMapping("/branches")
// @PreAuthorize("hasAuthority('TENANT_ADMIN')")
// public Set<String> getAllowedBranches() throws ThingsboardException {
// return versionControlService.getAllowedBranches(getTenantId());
// }
//
//
// @PostMapping("/settings")
// @PreAuthorize("hasAuthority('SYS_ADMIN')")
// public void saveSettings(@RequestBody EntitiesVersionControlSettings settings) throws Exception {
// versionControlService.saveSettings(settings);
// }
//
// @GetMapping("/settings")
// @PreAuthorize("hasAuthority('SYS_ADMIN')")
// public EntitiesVersionControlSettings getSettings() {
// return versionControlService.getSettings();
// }
//
//
//
// @PostMapping("/repository/reset")
// @PreAuthorize("hasAuthority('SYS_ADMIN')")
// public void resetLocalRepository() throws Exception {
// versionControlService.resetRepository();
// }
@PostMapping("/version")
public VersionCreationResult saveEntitiesVersion(@RequestBody VersionCreateRequest request) throws ThingsboardException {
SecurityUser user = getCurrentUser();
try {
return versionControlService.saveEntitiesVersion(user, request);
} catch (Exception e) {
throw handleException(e);
}
}
@GetMapping("/version/{branch}/{entityType}/{externalEntityUuid}")
public List<EntityVersion> listEntityVersions(@PathVariable String branch,
@PathVariable EntityType entityType,
@PathVariable UUID externalEntityUuid) throws ThingsboardException {
try {
EntityId externalEntityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid);
return versionControlService.listEntityVersions(getTenantId(), branch, externalEntityId);
} catch (Exception e) {
throw handleException(e);
}
}
@GetMapping("/version/{branch}/{entityType}")
public List<EntityVersion> listEntityTypeVersions(@PathVariable String branch,
@PathVariable EntityType entityType) throws ThingsboardException {
try {
return versionControlService.listEntityTypeVersions(getTenantId(), branch, entityType);
} catch (Exception e) {
throw handleException(e);
}
}
@GetMapping("/version/{branch}")
public List<EntityVersion> listVersions(@PathVariable String branch) throws ThingsboardException {
try {
return versionControlService.listVersions(getTenantId(), branch);
} catch (Exception e) {
throw handleException(e);
}
}
@GetMapping("/entity/{branch}/{entityType}/{versionId}")
public List<VersionedEntityInfo> listEntitiesAtVersion(@PathVariable String branch,
@PathVariable EntityType entityType,
@PathVariable String versionId) throws ThingsboardException {
try {
return versionControlService.listEntitiesAtVersion(getTenantId(), entityType, branch, versionId);
} catch (Exception e) {
throw handleException(e);
}
}
@GetMapping("/entity/{branch}/{versionId}")
public List<VersionedEntityInfo> listAllEntitiesAtVersion(@PathVariable String branch,
@PathVariable String versionId) throws ThingsboardException {
try {
return versionControlService.listAllEntitiesAtVersion(getTenantId(), branch, versionId);
} catch (Exception e) {
throw handleException(e);
}
}
@PostMapping("/entity")
public List<VersionLoadResult> loadEntitiesVersion(@RequestBody VersionLoadRequest request) throws ThingsboardException {
SecurityUser user = getCurrentUser();
try {
String versionId = request.getVersionId();
if (versionId == null) {
List<EntityVersion> versions = versionControlService.listVersions(user.getTenantId(), request.getBranch());
if (versions.size() > 0) {
versionId = versions.get(0).getId();
} else {
throw new IllegalArgumentException("No versions available in branch");
}
}
return versionControlService.loadEntitiesVersion(user, request);
} catch (Exception e) {
throw handleException(e);
}
}
@ApiModelProperty(notes = "" +
"")
@GetMapping("/branches")
public List<BranchInfo> listBranches() throws ThingsboardException {
try {
List<String> remoteBranches = versionControlService.listBranches(getTenantId());
List<BranchInfo> infos = new ArrayList<>();
String defaultBranch = getSettings().getDefaultBranch();
if (StringUtils.isNotEmpty(defaultBranch)) {
remoteBranches.remove(defaultBranch);
infos.add(new BranchInfo(defaultBranch, true));
}
remoteBranches.forEach(branch -> infos.add(new BranchInfo(branch, false)));
return infos;
} catch (Exception e) {
throw handleException(e);
}
}
@ApiModelProperty(notes = "" +
"```\n{\n" +
" \"repositoryUri\": \"https://github.com/User/repo.git\",\n" +
" \"username\": \"User\",\n" +
" \"password\": \"api_key\",\n" +
" \"defaultBranch\": \"master\"\n" +
"}\n```")
@GetMapping("/settings")
public EntitiesVersionControlSettings getSettings() throws ThingsboardException {
try {
return versionControlService.getSettings(getTenantId());
} catch (Exception e) {
throw handleException(e);
}
}
@ApiModelProperty(notes = "" +
"```\n{\n" +
" \"repositoryUri\": \"https://github.com/User/repo.git\",\n" +
" \"username\": \"User\",\n" +
" \"password\": \"api_key\",\n" +
" \"defaultBranch\": \"master\"\n" +
"}\n```")
@PostMapping("/settings")
public void saveSettings(@RequestBody EntitiesVersionControlSettings settings) throws ThingsboardException {
try {
versionControlService.saveSettings(getTenantId(), settings);
} catch (Exception e) {
throw handleException(e);
}
}
@Data
public static class BranchInfo {
private final String name;
private final boolean isDefault;
}
}

4
application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java

@ -25,8 +25,8 @@ import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.sync.exportimport.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Map;

4
application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java

@ -49,8 +49,8 @@ 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.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.sync.exportimport.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Collection;

4
application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java

@ -25,8 +25,8 @@ import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.sync.exportimport.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.exportimport.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Map;

30
application/src/main/java/org/thingsboard/server/service/sync/DefaultEntitiesExportImportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/DefaultEntitiesExportImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync;
package org.thingsboard.server.service.sync.exportimport;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -27,14 +27,14 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exporting.EntityExportService;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import org.thingsboard.server.service.sync.exporting.impl.BaseEntityExportService;
import org.thingsboard.server.service.sync.exporting.impl.DefaultEntityExportService;
import org.thingsboard.server.service.sync.importing.EntityImportService;
import org.thingsboard.server.service.sync.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.EntityExportService;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.impl.BaseEntityExportService;
import org.thingsboard.server.service.sync.exportimport.exporting.impl.DefaultEntityExportService;
import org.thingsboard.server.service.sync.exportimport.importing.EntityImportService;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings;
import org.thingsboard.server.utils.ThrowingRunnable;
import java.util.ArrayList;
@ -74,6 +74,7 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
@Override
public List<EntityImportResult<?>> importEntities(SecurityUser user, List<EntityExportData<?>> exportDataList, EntityImportSettings importSettings) throws ThingsboardException {
fixOrder(exportDataList);
List<EntityImportResult<?>> importResults = new ArrayList<>();
for (EntityExportData exportData : exportDataList) {
@ -88,6 +89,17 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
saveReferencesCallback.run();
}
importResults.stream()
.map(EntityImportResult::getSendEventsCallback)
.filter(Objects::nonNull)
.forEach(sendEventsCallback -> {
try {
sendEventsCallback.run();
} catch (Exception e) {
log.error("Failed to send event for entity", e);
}
});
return importResults;
}

10
application/src/main/java/org/thingsboard/server/service/sync/EntitiesExportImportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/EntitiesExportImportService.java

@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync;
package org.thingsboard.server.service.sync.exportimport;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import org.thingsboard.server.service.sync.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings;
import java.util.List;

56
application/src/main/java/org/thingsboard/server/service/sync/exporting/DefaultExportableEntitiesService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/DefaultExportableEntitiesService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting;
package org.thingsboard.server.service.sync.exportimport.exporting;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -30,6 +30,8 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
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.query.EntityData;
import org.thingsboard.server.common.data.query.EntityDataPageLink;
import org.thingsboard.server.common.data.query.EntityDataQuery;
@ -37,7 +39,6 @@ import org.thingsboard.server.common.data.query.EntityDataSortOrder;
import org.thingsboard.server.common.data.query.EntityFilter;
import org.thingsboard.server.common.data.query.EntityKey;
import org.thingsboard.server.common.data.query.EntityKeyType;
import org.thingsboard.server.common.data.query.EntityTypeFilter;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.ExportableEntityDao;
import org.thingsboard.server.dao.entity.EntityService;
@ -46,12 +47,12 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.AccessControlService;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import org.thingsboard.server.service.sync.exporting.data.request.CustomEntityFilterExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.CustomEntityQueryExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.EntityListExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.EntityTypeExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.ExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.SingleEntityExportRequest;
import org.thingsboard.server.service.sync.vc.data.request.create.EntitiesByCustomFilterVersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.EntitiesByCustomQueryVersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.EntityListVersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.EntityTypeVersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.SingleEntityVersionCreateConfig;
import java.util.Collection;
import java.util.Collections;
@ -129,6 +130,16 @@ public class DefaultExportableEntitiesService implements ExportableEntitiesServi
return entity;
}
@Override
public <E extends ExportableEntity<I>, I extends EntityId> PageData<E> findEntitiesByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink) {
Dao<E> dao = getDao(entityType);
if (dao instanceof ExportableEntityDao) {
ExportableEntityDao<E> exportableEntityDao = (ExportableEntityDao<E>) dao;
return exportableEntityDao.findByTenantId(tenantId.getId(), pageLink);
}
return new PageData<>();
}
private boolean belongsToTenant(HasId<? extends EntityId> entity, TenantId tenantId) {
return tenantId.equals(((HasTenantId) entity).getTenantId());
}
@ -136,31 +147,31 @@ public class DefaultExportableEntitiesService implements ExportableEntitiesServi
@Transactional(readOnly = true, timeout = 40)
@Override
public List<EntityId> findEntitiesForRequest(TenantId tenantId, ExportRequest request) {
public List<EntityId> findEntitiesByFilter(TenantId tenantId, VersionCreateConfig request) {
switch (request.getType()) {
case SINGLE_ENTITY: {
return List.of(((SingleEntityExportRequest) request).getEntityId());
return List.of(((SingleEntityVersionCreateConfig) request).getEntityId());
}
case ENTITY_LIST: {
return ((EntityListExportRequest) request).getEntitiesIds();
return ((EntityListVersionCreateConfig) request).getEntitiesIds();
}
case ENTITY_TYPE: {
EntityTypeExportRequest exportRequest = (EntityTypeExportRequest) request;
EntityTypeFilter entityTypeFilter = new EntityTypeFilter();
EntityTypeVersionCreateConfig exportRequest = (EntityTypeVersionCreateConfig) request;
org.thingsboard.server.common.data.query.EntityTypeFilter entityTypeFilter = new org.thingsboard.server.common.data.query.EntityTypeFilter();
entityTypeFilter.setEntityType(exportRequest.getEntityType());
CustomerId customerId = new CustomerId(ObjectUtils.defaultIfNull(exportRequest.getCustomerId(), EntityId.NULL_UUID));
return findEntitiesByFilter(tenantId, customerId, entityTypeFilter, exportRequest.getPage(), exportRequest.getPageSize());
return findEntitiesByFilter(tenantId, customerId, entityTypeFilter, 0, Integer.MAX_VALUE);
}
case CUSTOM_ENTITY_FILTER: {
CustomEntityFilterExportRequest exportRequest = (CustomEntityFilterExportRequest) request;
EntitiesByCustomFilterVersionCreateConfig exportRequest = (EntitiesByCustomFilterVersionCreateConfig) request;
EntityFilter filter = exportRequest.getFilter();
CustomerId customerId = new CustomerId(ObjectUtils.defaultIfNull(exportRequest.getCustomerId(), EntityId.NULL_UUID));
return findEntitiesByFilter(tenantId, customerId, filter, exportRequest.getPage(), exportRequest.getPageSize());
return findEntitiesByFilter(tenantId, customerId, filter, 0, Integer.MAX_VALUE);
}
case CUSTOM_ENTITY_QUERY: {
CustomEntityQueryExportRequest exportRequest = (CustomEntityQueryExportRequest) request;
EntitiesByCustomQueryVersionCreateConfig exportRequest = (EntitiesByCustomQueryVersionCreateConfig) request;
EntityDataQuery query = exportRequest.getQuery();
CustomerId customerId = new CustomerId(ObjectUtils.defaultIfNull(exportRequest.getCustomerId(), EntityId.NULL_UUID));
@ -194,6 +205,17 @@ public class DefaultExportableEntitiesService implements ExportableEntitiesServi
}
}
@Override
public <I extends EntityId> void deleteByTenantIdAndId(TenantId tenantId, I id) {
EntityType entityType = id.getEntityType();
Dao<Object> dao = getDao(entityType);
if (dao == null) {
throw new IllegalArgumentException("Unsupported entity type " + entityType);
}
dao.removeById(tenantId, id.getId());
}
@Override
public void checkPermission(SecurityUser user, HasId<? extends EntityId> entity, EntityType entityType, Operation operation) throws ThingsboardException {

6
application/src/main/java/org/thingsboard/server/service/sync/exporting/EntityExportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/EntityExportService.java

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting;
package org.thingsboard.server.service.sync.exportimport.exporting;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
public interface EntityExportService<I extends EntityId, E extends ExportableEntity<I>, D extends EntityExportData<E>> {

12
application/src/main/java/org/thingsboard/server/service/sync/exporting/ExportableEntitiesService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/ExportableEntitiesService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting;
package org.thingsboard.server.service.sync.exportimport.exporting;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
@ -21,9 +21,11 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
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.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.sync.exporting.data.request.ExportRequest;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateConfig;
import java.util.List;
@ -35,7 +37,11 @@ public interface ExportableEntitiesService {
<E extends ExportableEntity<I>, I extends EntityId> E findEntityByTenantIdAndName(TenantId tenantId, EntityType entityType, String name);
List<EntityId> findEntitiesForRequest(TenantId tenantId, ExportRequest request);
<E extends ExportableEntity<I>, I extends EntityId> PageData<E> findEntitiesByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink);
List<EntityId> findEntitiesByFilter(TenantId tenantId, VersionCreateConfig filter); // FIXME [viacheslav]:
<I extends EntityId> void deleteByTenantIdAndId(TenantId tenantId, I id);
void checkPermission(SecurityUser user, HasId<? extends EntityId> entity, EntityType entityType, Operation operation) throws ThingsboardException;

2
application/src/main/java/org/thingsboard/server/service/sync/exporting/data/DeviceExportData.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/DeviceExportData.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.data;
package org.thingsboard.server.service.sync.exportimport.exporting.data;
import lombok.Data;
import lombok.EqualsAndHashCode;

2
application/src/main/java/org/thingsboard/server/service/sync/exporting/data/EntityExportData.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/EntityExportData.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.data;
package org.thingsboard.server.service.sync.exportimport.exporting.data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

2
application/src/main/java/org/thingsboard/server/service/sync/exporting/data/request/EntityExportSettings.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/EntityExportSettings.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.data.request;
package org.thingsboard.server.service.sync.exportimport.exporting.data;
import lombok.AllArgsConstructor;
import lombok.Builder;

2
application/src/main/java/org/thingsboard/server/service/sync/exporting/data/RuleChainExportData.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/data/RuleChainExportData.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.data;
package org.thingsboard.server.service.sync.exportimport.exporting.data;
import lombok.Data;
import lombok.EqualsAndHashCode;

6
application/src/main/java/org/thingsboard/server/service/sync/exporting/impl/BaseEntityExportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/BaseEntityExportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.impl;
package org.thingsboard.server.service.sync.exportimport.exporting.impl;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
@ -21,8 +21,8 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
import java.util.Set;

10
application/src/main/java/org/thingsboard/server/service/sync/exporting/impl/DefaultEntityExportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/DefaultEntityExportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.impl;
package org.thingsboard.server.service.sync.exportimport.exporting.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
@ -28,10 +28,10 @@ import org.thingsboard.server.dao.relation.RelationService;
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.sync.exporting.EntityExportService;
import org.thingsboard.server.service.sync.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.EntityExportService;
import org.thingsboard.server.service.sync.exportimport.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
import java.util.ArrayList;
import java.util.List;

4
application/src/main/java/org/thingsboard/server/service/sync/exporting/impl/DeviceExportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/DeviceExportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.impl;
package org.thingsboard.server.service.sync.exportimport.exporting.impl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.exporting.data.DeviceExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.DeviceExportData;
import java.util.Set;

4
application/src/main/java/org/thingsboard/server/service/sync/exporting/impl/RuleChainExportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/exporting/impl/RuleChainExportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.impl;
package org.thingsboard.server.service.sync.exportimport.exporting.impl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.exporting.data.RuleChainExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.RuleChainExportData;
import java.util.Set;

8
application/src/main/java/org/thingsboard/server/service/sync/importing/EntityImportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/EntityImportService.java

@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing;
package org.thingsboard.server.service.sync.exportimport.importing;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
public interface EntityImportService<I extends EntityId, E extends ExportableEntity<I>, D extends EntityExportData<E>> {

9
application/src/main/java/org/thingsboard/server/service/sync/importing/csv/AbstractBulkImportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/AbstractBulkImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.csv;
package org.thingsboard.server.service.sync.exportimport.importing.csv;
import com.google.common.util.concurrent.FutureCallback;
import com.google.gson.JsonObject;
@ -44,7 +44,6 @@ import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.controller.BaseController;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.sync.importing.csv.BulkImportRequest.ColumnMapping;
import org.thingsboard.server.service.security.AccessValidator;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.AccessControlService;
@ -166,7 +165,7 @@ public abstract class AbstractBulkImportService<E extends HasId<? extends Entity
protected abstract EntityType getEntityType();
private void saveKvs(SecurityUser user, E entity, Map<ColumnMapping, ParsedValue> data) {
private void saveKvs(SecurityUser user, E entity, Map<BulkImportRequest.ColumnMapping, ParsedValue> data) {
Arrays.stream(BulkImportColumnType.values())
.filter(BulkImportColumnType::isKv)
.map(kvType -> {
@ -250,7 +249,7 @@ public abstract class AbstractBulkImportService<E extends HasId<? extends Entity
linesCounter.incrementAndGet();
}
List<ColumnMapping> columnsMappings = request.getMapping().getColumns();
List<BulkImportRequest.ColumnMapping> columnsMappings = request.getMapping().getColumns();
return records.stream()
.map(record -> {
EntityData entityData = new EntityData();
@ -281,7 +280,7 @@ public abstract class AbstractBulkImportService<E extends HasId<? extends Entity
@Data
protected static class EntityData {
private final Map<BulkImportColumnType, String> fields = new LinkedHashMap<>();
private final Map<ColumnMapping, ParsedValue> kvs = new LinkedHashMap<>();
private final Map<BulkImportRequest.ColumnMapping, ParsedValue> kvs = new LinkedHashMap<>();
private int lineNumber;
}

2
application/src/main/java/org/thingsboard/server/service/sync/importing/csv/BulkImportColumnType.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/BulkImportColumnType.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.csv;
package org.thingsboard.server.service.sync.exportimport.importing.csv;
import lombok.Getter;
import org.thingsboard.server.common.data.DataConstants;

2
application/src/main/java/org/thingsboard/server/service/sync/importing/csv/BulkImportRequest.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/BulkImportRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.csv;
package org.thingsboard.server.service.sync.exportimport.importing.csv;
import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/importing/csv/BulkImportResult.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/BulkImportResult.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.csv;
package org.thingsboard.server.service.sync.exportimport.importing.csv;
import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/importing/csv/ImportedEntityInfo.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/csv/ImportedEntityInfo.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.csv;
package org.thingsboard.server.service.sync.exportimport.importing.csv;
import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/importing/data/EntityImportResult.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/data/EntityImportResult.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.data;
package org.thingsboard.server.service.sync.exportimport.importing.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/importing/data/EntityImportSettings.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/data/EntityImportSettings.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.data;
package org.thingsboard.server.service.sync.exportimport.importing.data;
import lombok.AllArgsConstructor;
import lombok.Builder;

4
application/src/main/java/org/thingsboard/server/service/sync/importing/impl/AssetImportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/AssetImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.impl;
package org.thingsboard.server.service.sync.exportimport.importing.impl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
@Service
@TbCoreComponent

12
application/src/main/java/org/thingsboard/server/service/sync/importing/impl/BaseEntityImportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/BaseEntityImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.impl;
package org.thingsboard.server.service.sync.exportimport.importing.impl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
@ -35,11 +35,11 @@ import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.sync.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.importing.EntityImportService;
import org.thingsboard.server.service.sync.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.importing.EntityImportService;
import java.util.ArrayList;
import java.util.List;

4
application/src/main/java/org/thingsboard/server/service/sync/importing/impl/CustomerImportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/CustomerImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.impl;
package org.thingsboard.server.service.sync.exportimport.importing.impl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
@Service
@TbCoreComponent

6
application/src/main/java/org/thingsboard/server/service/sync/importing/impl/DashboardImportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/DashboardImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.impl;
package org.thingsboard.server.service.sync.exportimport.importing.impl;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
@ -30,8 +30,8 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
import org.thingsboard.server.utils.RegexUtils;
import java.util.Collections;

4
application/src/main/java/org/thingsboard/server/service/sync/importing/impl/DeviceImportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/DeviceImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.impl;
package org.thingsboard.server.service.sync.exportimport.importing.impl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -25,7 +25,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exporting.data.DeviceExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.DeviceExportData;
@Service
@TbCoreComponent

4
application/src/main/java/org/thingsboard/server/service/sync/importing/impl/DeviceProfileImportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/DeviceProfileImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.impl;
package org.thingsboard.server.service.sync.exportimport.importing.impl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -28,7 +28,7 @@ import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.ota.OtaPackageStateService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
import java.util.Objects;

6
application/src/main/java/org/thingsboard/server/service/sync/importing/impl/RuleChainImportService.java → application/src/main/java/org/thingsboard/server/service/sync/exportimport/importing/impl/RuleChainImportService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.importing.impl;
package org.thingsboard.server.service.sync.exportimport.importing.impl;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
@ -32,8 +32,8 @@ import org.thingsboard.server.common.data.rule.RuleChainUpdateResult;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.exporting.data.RuleChainExportData;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.exporting.data.RuleChainExportData;
import org.thingsboard.server.utils.RegexUtils;
import java.util.Collections;

32
application/src/main/java/org/thingsboard/server/service/sync/importing/data/request/ImportRequest.java

@ -1,32 +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.
*/
package org.thingsboard.server.service.sync.importing.data.request;
import lombok.Data;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import java.util.List;
@Data
public class ImportRequest {
private List<EntityExportData<?>> exportDataList;
private EntityImportSettings importSettings;
}

463
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java

@ -18,35 +18,62 @@ package org.thingsboard.server.service.sync.vc;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
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.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.JsonDataEntry;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.query.EntityData;
import org.thingsboard.server.common.data.query.EntityDataPageLink;
import org.thingsboard.server.common.data.query.EntityDataQuery;
import org.thingsboard.server.common.data.query.EntityDataSortOrder;
import org.thingsboard.server.common.data.query.EntityKey;
import org.thingsboard.server.common.data.query.EntityKeyType;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.dao.tenant.TenantDao;
import org.thingsboard.server.queue.util.AfterStartUp;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.EntitiesExportImportService;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import org.thingsboard.server.service.sync.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.sync.exportimport.EntitiesExportImportService;
import org.thingsboard.server.service.sync.exportimport.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.vc.data.EntitiesVersionControlSettings;
import org.thingsboard.server.service.sync.vc.data.VersionedEntityInfo;
import org.thingsboard.server.service.sync.vc.data.EntityVersion;
import org.thingsboard.server.service.sync.vc.data.EntityVersionLoadResult;
import org.thingsboard.server.service.sync.vc.data.EntityVersionLoadSettings;
import org.thingsboard.server.service.sync.vc.data.EntityVersionSaveSettings;
import org.thingsboard.server.service.sync.vc.data.VersionCreationResult;
import org.thingsboard.server.service.sync.vc.data.VersionLoadResult;
import org.thingsboard.server.service.sync.vc.data.VersionedEntityInfo;
import org.thingsboard.server.service.sync.vc.data.request.load.VersionLoadRequest;
import org.thingsboard.server.service.sync.vc.data.request.load.VersionLoadSettings;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateRequest;
import org.thingsboard.server.service.sync.vc.data.request.create.EntitiesByCustomFilterVersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.EntitiesByCustomQueryVersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.EntityListVersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.EntityTypeVersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.SingleEntityVersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateConfig;
import org.thingsboard.server.utils.GitRepository;
import java.io.File;
@ -56,16 +83,19 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static org.thingsboard.server.dao.sql.query.EntityKeyMapping.CREATED_TIME;
@Service
@TbCoreComponent
@RequiredArgsConstructor
@ -73,75 +103,152 @@ import java.util.stream.Collectors;
public class DefaultEntitiesVersionControlService implements EntitiesVersionControlService {
private final EntitiesExportImportService exportImportService;
private final ExportableEntitiesService exportableEntitiesService;
private final AttributesService attributesService;
private final EntityService entityService;
private final TenantDao tenantDao;
private GitRepository repository;
private final ReadWriteLock repositoryLock = new ReentrantReadWriteLock();
private ScheduledExecutorService fetchExecutor;
private ScheduledFuture<?> fetchTask;
// TODO [viacheslav]: concurrency
private final Map<TenantId, GitRepository> repositories = new ConcurrentHashMap<>();
@Value("${java.io.tmpdir}")
private String repositoriesFolder;
private final AdminSettingsService adminSettingsService;
private static final String SETTINGS_KEY = "vc";
private final ObjectWriter jsonWriter = new ObjectMapper().writer(SerializationFeature.INDENT_OUTPUT);
@AfterStartUp
public void init() {
EntitiesVersionControlSettings settings = getSettings();
if (settings != null) {
try {
initRepository(settings);
} catch (Exception e) {
log.debug("Failed to init repository", e);
DaoUtil.processInBatches(tenantDao::findTenantsIds, 100, tenantId -> {
EntitiesVersionControlSettings settings = getSettings(tenantId);
if (settings != null) {
try {
initRepository(tenantId, settings);
} catch (Exception e) {
log.warn("Failed to init repository for tenant {}", tenantId, e);
}
}
}
int fetchPeriod = settings == null || settings.getFetchPeriod() == 0 ? 10 : settings.getFetchPeriod();
fetchExecutor = Executors.newSingleThreadScheduledExecutor();
fetchTask = scheduleFetch(fetchPeriod);
});
Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(() -> {
repositories.forEach((tenantId, repository) -> {
try {
repository.fetch();
log.info("Fetching remote repository for tenant {}", tenantId);
} catch (Exception e) {
log.warn("Failed to fetch repository for tenant {}", tenantId, e);
}
});
}, 5, 5, TimeUnit.SECONDS);
}
@Override
public EntityVersion saveEntityVersion(SecurityUser user, EntityId entityId, String branch, String versionName, EntityVersionSaveSettings settings) throws Exception {
return saveEntitiesVersion(user, List.of(entityId), branch, versionName, settings);
}
public VersionCreationResult saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception {
GitRepository repository = checkRepository(user.getTenantId());
repository.getLock().writeLock().lock();
@Override
public EntityVersion saveEntitiesVersion(SecurityUser user, List<EntityId> entitiesIds, String branch, String versionName, EntityVersionSaveSettings settings) throws Exception {
repositoryLock.writeLock().lock();
try {
checkRepository();
checkBranch(user.getTenantId(), branch);
List<EntityExportData<?>> entityDataList = new ArrayList<>();
EntityExportSettings exportSettings = EntityExportSettings.builder()
.exportRelations(settings.isSaveRelations())
.build();
for (EntityId entityId : entitiesIds) {
EntityExportData<ExportableEntity<EntityId>> entityData = exportImportService.exportEntity(user, entityId, exportSettings);
entityDataList.add(entityData);
repository.fetch();
if (repository.listBranches().contains(request.getBranch())) {
repository.checkout(request.getBranch());
repository.merge(request.getBranch());
} else { // FIXME [viacheslav]: rollback orphan branch on failure
repository.createAndCheckoutOrphanBranch(request.getBranch()); // FIXME [viacheslav]: Checkout returned unexpected result NO_CHANGE for master branch
}
fetch();
if (repository.listBranches().contains(branch)) {
repository.checkout(branch);
repository.merge(branch);
} else {
repository.createAndCheckoutOrphanBranch(branch);
for (VersionCreateRequest.Config config : request.getConfigs()) {
EntityExportSettings exportSettings = EntityExportSettings.builder()
.exportRelations(config.isSaveRelations())
.build();
List<EntityExportData<?>> entityDataList = new ArrayList<>();
for (EntityId entityId : findEntities()) {
EntityExportData<ExportableEntity<EntityId>> entityData = exportImportService.exportEntity(user, entityId, exportSettings);
entityDataList.add(entityData);
}
if (config.isRemoveOtherRemoteEntitiesOfType()) {
entityDataList.stream()
.map(EntityExportData::getEntityType)
.distinct()
.forEach(entityType -> {
try {
FileUtils.deleteDirectory(Path.of(repository.getDirectory(), getRelativePath(entityType, null)).toFile());
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
for (EntityExportData<?> entityData : entityDataList) {
String entityDataJson = jsonWriter.writeValueAsString(entityData);
FileUtils.write(Path.of(repository.getDirectory(), getRelativePath(entityData.getEntityType(),
entityData.getEntity().getId().toString())).toFile(), entityDataJson, StandardCharsets.UTF_8);
}
}
// TODO [viacheslav]: find with pagination
for (EntityExportData<?> entityData : entityDataList) {
String entityDataJson = jsonWriter.writeValueAsString(entityData);
FileUtils.write(new File(repository.getDirectory() + "/" + getRelativePath(entityData.getEntityType(),
entityData.getEntity().getId().toString())), entityDataJson, StandardCharsets.UTF_8);
}
repository.add(".");
VersionCreationResult result = new VersionCreationResult();
GitRepository.Status status = repository.status();
result.setAdded(status.getAdded().size());
result.setModified(status.getModified().size());
result.setRemoved(status.getRemoved().size());
GitRepository.Commit commit = repository.commit(versionName, ".");
GitRepository.Commit commit = repository.commit(request.getVersionName());
repository.push();
return toVersion(commit);
result.setVersion(toVersion(commit));
return result;
} finally {
repositoryLock.writeLock().unlock();
repository.getLock().writeLock().unlock();
}
}
private List<EntityId> findEntities(SecurityUser user, VersionCreateConfig entityFilter, int page, int pageSize) {
switch (entityFilter.getType()) {
case SINGLE_ENTITY: {
SingleEntityVersionCreateConfig filter = (SingleEntityVersionCreateConfig) entityFilter;
return List.of(filter.getEntityId());
}
case ENTITY_LIST: {
EntityListVersionCreateConfig filter = (EntityListVersionCreateConfig) entityFilter;
return filter.getEntitiesIds();
}
case ENTITY_TYPE: {
EntityTypeVersionCreateConfig filter = (EntityTypeVersionCreateConfig) entityFilter;
EntitiesByCustomFilterVersionCreateConfig newFilter = new EntitiesByCustomFilterVersionCreateConfig();
org.thingsboard.server.common.data.query.EntityTypeFilter entityTypeFilter = new org.thingsboard.server.common.data.query.EntityTypeFilter();
entityTypeFilter.setEntityType(filter.getEntityType());
newFilter.setFilter(entityTypeFilter);
newFilter.setCustomerId(filter.getCustomerId());
return findEntities(user, newFilter, page, pageSize);
}
case CUSTOM_ENTITY_FILTER: {
EntitiesByCustomFilterVersionCreateConfig filter = (EntitiesByCustomFilterVersionCreateConfig) entityFilter;
EntitiesByCustomQueryVersionCreateConfig newFilter = new EntitiesByCustomQueryVersionCreateConfig();
EntityDataPageLink pageLink = new EntityDataPageLink();
pageLink.setPage(page);
pageLink.setPageSize(pageSize);
EntityKey sortProperty = new EntityKey(EntityKeyType.ENTITY_FIELD, CREATED_TIME);
pageLink.setSortOrder(new EntityDataSortOrder(sortProperty, EntityDataSortOrder.Direction.DESC));
EntityDataQuery query = new EntityDataQuery(filter.getFilter(), pageLink, List.of(sortProperty), Collections.emptyList(), Collections.emptyList());
newFilter.setQuery(query);
newFilter.setCustomerId(filter.getCustomerId());
return findEntities(user, newFilter, page, pageSize);
}
case CUSTOM_ENTITY_QUERY: {
EntitiesByCustomQueryVersionCreateConfig filter = (EntitiesByCustomQueryVersionCreateConfig) entityFilter;
CustomerId customerId = new CustomerId(ObjectUtils.defaultIfNull(filter.getCustomerId(), EntityId.NULL_UUID));
return entityService.findEntityDataByQuery(user.getTenantId(), customerId, filter.getQuery()).getData()
.stream().map(EntityData::getEntityId)
.collect(Collectors.toList());
}
}
}
@ -162,16 +269,14 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
}
private List<EntityVersion> listVersions(TenantId tenantId, String branch, String path) throws Exception {
repositoryLock.readLock().lock();
GitRepository repository = checkRepository(tenantId);
repository.getLock().readLock().lock();
try {
checkRepository();
checkBranch(tenantId, branch);
return repository.listCommits(branch, path, Integer.MAX_VALUE).stream()
.map(this::toVersion)
.collect(Collectors.toList());
} finally {
repositoryLock.readLock().unlock();
repository.getLock().readLock().unlock();
}
}
@ -187,16 +292,14 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
}
private List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, String path) throws Exception {
repositoryLock.readLock().lock();
GitRepository repository = checkRepository(tenantId);
repository.getLock().readLock().lock();
try {
checkRepository();
checkBranch(tenantId, branch);
checkVersion(tenantId, branch, versionId, path);
checkVersion(tenantId, branch, versionId);
return repository.listFilesAtCommit(versionId, path).stream()
.map(filePath -> {
EntityId entityId = fromRelativePath(filePath);
EntityExportData<?> entityData = getEntityDataAtVersion(entityId, versionId);
EntityExportData<?> entityData = getEntityDataAtVersion(tenantId, entityId, versionId);
VersionedEntityInfo info = new VersionedEntityInfo();
info.setExternalId(entityId);
@ -205,171 +308,155 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
})
.collect(Collectors.toList());
} finally {
repositoryLock.readLock().unlock();
repository.getLock().readLock().unlock();
}
}
@Override
public EntityVersionLoadResult loadEntityVersion(SecurityUser user, EntityId externalId, String branch, String versionId, EntityVersionLoadSettings settings) throws Exception {
return loadAtVersion(user, branch, versionId, getRelativePath(externalId.getEntityType(), externalId.getId().toString()), settings).get(0);
}
@Override
public List<EntityVersionLoadResult> loadEntityTypeVersion(SecurityUser user, EntityType entityType, String branch, String versionId, EntityVersionLoadSettings settings) throws Exception {
return loadAtVersion(user, branch, versionId, getRelativePath(entityType, null), settings);
}
@Override
public List<EntityVersionLoadResult> loadAllAtVersion(SecurityUser user, String branch, String versionId, EntityVersionLoadSettings settings) throws Exception {
return loadAtVersion(user, branch, versionId, null, settings);
}
public List<VersionLoadResult> loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception {
GitRepository repository = checkRepository(user.getTenantId());
private List<EntityVersionLoadResult> loadAtVersion(SecurityUser user, String branch, String versionId, String path, EntityVersionLoadSettings settings) throws Exception {
List<EntityExportData<?>> entityDataList = new ArrayList<>();
repositoryLock.readLock().lock();
EntityVersion version;
repository.getLock().readLock().lock();
try {
for (VersionedEntityInfo info : listEntitiesAtVersion(user.getTenantId(), branch, versionId, path)) {
EntityExportData<?> entityData = getEntityDataAtVersion(info.getExternalId(), versionId);
version = checkVersion(user.getTenantId(), request.getBranch(), request.getVersionId());
for (VersionedEntityInfo info : listEntitiesAtVersion(user.getTenantId(), request.getBranch(), request.getVersionId(), path)) {
EntityExportData<?> entityData = getEntityDataAtVersion(user.getTenantId(), info.getExternalId(), versionId);
entityDataList.add(entityData);
}
} finally {
repositoryLock.readLock().unlock();
repository.getLock().readLock().unlock();
}
EntityImportSettings importSettings = EntityImportSettings.builder()
.updateRelations(settings.isLoadRelations())
.findExistingByName(settings.isFindExistingEntityByName())
.build();
// FIXME [viacheslav]: do evrth in transaction
List<EntityImportResult<?>> importResults = exportImportService.importEntities(user, entityDataList, importSettings);
return importResults.stream()
.map(importResult -> EntityVersionLoadResult.builder()
.previousEntityVersion(importResult.getOldEntity())
.newEntityVersion(importResult.getSavedEntity())
.entityType(importResult.getEntityType())
.build())
.collect(Collectors.toList());
Map<EntityType, VersionLoadResult> results = new HashMap<>();
boolean removeNonexistentLocalEntities = false;
if ()
if (request.isRemoveOtherLocalEntitiesOfType()) {
importResults.stream()
.collect(Collectors.groupingBy(EntityImportResult::getEntityType)) // FIXME [viacheslav]: if no entities of entity type - remove all ?
.forEach((entityType, resultsForEntityType) -> {
Set<EntityId> modifiedEntities = resultsForEntityType.stream().map(EntityImportResult::getSavedEntity).map(ExportableEntity::getExternalId).collect(Collectors.toSet());
AtomicInteger deleted = new AtomicInteger();
DaoUtil.processInBatches(pageLink -> {
return exportableEntitiesService.findEntitiesByTenantId(user.getTenantId(), entityType, pageLink);
}, 100, entity -> {
if (entity.getExternalId() == null || !modifiedEntities.contains(entity.getExternalId())) {
try {
exportableEntitiesService.checkPermission(user, entity, entityType, Operation.DELETE);
} catch (ThingsboardException e) {
throw new RuntimeException(e);
}
// need to delete in a specific order?
exportableEntitiesService.deleteByTenantIdAndId(user.getTenantId(), entity.getId());
deleted.getAndIncrement();
}
});
results.put(entityType, VersionLoadResult.builder()
.entityType(entityType)
.created((int) resultsForEntityType.stream().filter(importResult -> importResult.getOldEntity() == null).count())
.updated((int) resultsForEntityType.stream().filter(importResult -> importResult.getOldEntity() != null).count())
.deleted(deleted.get())
.build());
});
}
return new ArrayList<>(results.values());
}
@SneakyThrows
private EntityExportData<?> getEntityDataAtVersion(EntityId externalId, String versionId) {
repositoryLock.readLock().lock();
private EntityExportData<?> getEntityDataAtVersion(TenantId tenantId, EntityId externalId, String versionId) {
GitRepository repository = checkRepository(tenantId);
repository.getLock().readLock().lock();
try {
String entityDataJson = repository.getFileContentAtCommit(getRelativePath(externalId.getEntityType(), externalId.getId().toString()), versionId);
return JacksonUtil.fromString(entityDataJson, EntityExportData.class);
} finally {
repositoryLock.readLock().unlock();
repository.getLock().readLock().unlock();
}
}
private void fetch() throws GitAPIException {
repositoryLock.writeLock().lock();
try {
repository.fetch();
} finally {
repositoryLock.writeLock().unlock();
}
}
private ScheduledFuture<?> scheduleFetch(int fetchPeriod) {
return fetchExecutor.scheduleWithFixedDelay(() -> {
if (repository == null) return;
try {
fetch();
} catch (Exception e) {
log.error("Failed to fetch remote repository", e);
}
}, fetchPeriod, fetchPeriod, TimeUnit.SECONDS);
private void updateEntityVersionInfo(TenantId tenantId, EntityId entityId, EntityVersion version) {
ObjectNode versionInfo = JacksonUtil.newObjectNode();
versionInfo.set("versionName", new TextNode(version.getName()));
versionInfo.set("versionId", new TextNode(version.getId()));
attributesService.save(tenantId, entityId, DataConstants.SERVER_SCOPE,
List.of(new BaseAttributeKvEntry(System.currentTimeMillis(), new JsonDataEntry("entityVersionInfo", versionInfo.toString()))));
}
private void checkVersion(TenantId tenantId, String branch, String versionId, String path) throws Exception {
if (listVersions(tenantId, branch, path).stream().noneMatch(version -> version.getId().equals(versionId))) {
throw new IllegalArgumentException("Version not found");
}
}
@Override
public List<String> listAllowedBranches(TenantId tenantId) {
return Optional.ofNullable(getSettings())
.flatMap(settings -> Optional.ofNullable(settings.getTenantsAllowedBranches()))
.flatMap(tenantsAllowedBranches -> Optional.ofNullable(tenantsAllowedBranches.get(tenantId.getId())))
.orElse(Collections.emptyList());
public List<String> listBranches(TenantId tenantId) throws Exception {
GitRepository repository = checkRepository(tenantId);
return repository.listBranches();
}
private void checkBranch(TenantId tenantId, String branch) {
if (!listAllowedBranches(tenantId).contains(branch)) {
throw new IllegalArgumentException("Tenant does not have access to the branch");
}
}
private EntityVersion checkVersion(TenantId tenantId, String branch, String versionId) throws Exception {
return listVersions(tenantId, branch, null).stream()
.filter(version -> version.getId().equals(versionId))
.findFirst().orElseThrow(() -> new IllegalArgumentException("Version not found"));
}
private void checkRepository() {
if (repository == null) {
throw new IllegalStateException("Repository is not initialized");
}
private GitRepository checkRepository(TenantId tenantId) {
return Optional.ofNullable(repositories.get(tenantId))
.orElseThrow(() -> new IllegalStateException("Repository is not initialized"));
}
private void initRepository(EntitiesVersionControlSettings settings) throws Exception {
repositoryLock.writeLock().lock();
try {
if (Files.exists(Path.of(settings.getRepositoryDirectory()))) {
this.repository = GitRepository.open(settings.getRepositoryDirectory(), settings.getUsername(), settings.getPassword());
} else {
Files.createDirectories(Path.of(settings.getRepositoryDirectory()));
this.repository = GitRepository.clone(settings.getRepositoryUri(), settings.getRepositoryDirectory(),
settings.getUsername(), settings.getPassword());
}
} finally {
repositoryLock.writeLock().unlock();
private void initRepository(TenantId tenantId, EntitiesVersionControlSettings settings) throws Exception {
Path repositoryDirectory = Path.of(repositoriesFolder, tenantId.getId().toString());
GitRepository repository;
if (Files.exists(repositoryDirectory)) {
repository = GitRepository.open(repositoryDirectory.toFile(), settings.getUsername(), settings.getPassword());
} else {
Files.createDirectories(repositoryDirectory);
repository = GitRepository.clone(settings.getRepositoryUri(), settings.getUsername(), settings.getPassword(), repositoryDirectory.toFile());
}
repositories.put(tenantId, repository);
}
private void clearRepository() throws IOException {
repositoryLock.writeLock().lock();
try {
if (repository != null) {
FileUtils.deleteDirectory(new File(repository.getDirectory()));
repository = null;
}
} finally {
repositoryLock.writeLock().unlock();
private void clearRepository(TenantId tenantId) throws IOException {
GitRepository repository = repositories.get(tenantId);
if (repository != null) {
FileUtils.deleteDirectory(new File(repository.getDirectory()));
repositories.remove(tenantId);
}
}
@SneakyThrows
@Override
public void saveSettings(EntitiesVersionControlSettings settings) {
AdminSettings adminSettings = Optional.ofNullable(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "vc"))
.orElseGet(() -> {
AdminSettings newAdminSettings = new AdminSettings();
newAdminSettings.setKey(SETTINGS_KEY);
return newAdminSettings;
});
adminSettings.setJsonValue(JacksonUtil.valueToTree(settings));
adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings);
repositoryLock.writeLock().lock();
try {
clearRepository();
initRepository(settings);
} finally {
repositoryLock.writeLock().unlock();
}
public void saveSettings(TenantId tenantId, EntitiesVersionControlSettings settings) {
attributesService.save(tenantId, tenantId, DataConstants.SERVER_SCOPE, List.of(
new BaseAttributeKvEntry(System.currentTimeMillis(), new JsonDataEntry(SETTINGS_KEY, JacksonUtil.toString(settings)))
)).get();
if (settings.getFetchPeriod() != 0) {
fetchTask.cancel(true);
fetchTask = scheduleFetch(settings.getFetchPeriod());
}
clearRepository(tenantId);
initRepository(tenantId, settings);
}
@SneakyThrows
@Override
public EntitiesVersionControlSettings getSettings() {
return Optional.ofNullable(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "vc"))
.map(adminSettings -> JacksonUtil.treeToValue(adminSettings.getJsonValue(), EntitiesVersionControlSettings.class))
public EntitiesVersionControlSettings getSettings(TenantId tenantId) {
return attributesService.find(tenantId, tenantId, DataConstants.SERVER_SCOPE, SETTINGS_KEY).get()
.flatMap(KvEntry::getJsonValue)
.map(json -> {
try {
return JacksonUtil.fromString(json, EntitiesVersionControlSettings.class);
} catch (IllegalArgumentException e) {
return null;
}
})
.orElse(null);
}
@ -387,7 +474,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
}
private EntityId fromRelativePath(String path) {
EntityType entityType = EntityType.valueOf(StringUtils.substringBefore(path, "/"));
EntityType entityType = EntityType.valueOf(StringUtils.substringBefore(path, "/").toUpperCase());
String entityId = StringUtils.substringBetween(path, "/", ".json");
return EntityIdFactory.getByTypeAndUuid(entityType, entityId);
}

27
application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java

@ -20,19 +20,18 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.vc.data.EntitiesVersionControlSettings;
import org.thingsboard.server.service.sync.vc.data.VersionedEntityInfo;
import org.thingsboard.server.service.sync.vc.data.EntityVersion;
import org.thingsboard.server.service.sync.vc.data.EntityVersionLoadResult;
import org.thingsboard.server.service.sync.vc.data.EntityVersionLoadSettings;
import org.thingsboard.server.service.sync.vc.data.EntityVersionSaveSettings;
import org.thingsboard.server.service.sync.vc.data.VersionCreationResult;
import org.thingsboard.server.service.sync.vc.data.VersionLoadResult;
import org.thingsboard.server.service.sync.vc.data.VersionedEntityInfo;
import org.thingsboard.server.service.sync.vc.data.request.load.VersionLoadRequest;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateRequest;
import java.util.List;
public interface EntitiesVersionControlService {
EntityVersion saveEntityVersion(SecurityUser user, EntityId entityId, String branch, String versionName, EntityVersionSaveSettings settings) throws Exception;
EntityVersion saveEntitiesVersion(SecurityUser user, List<EntityId> entitiesIds, String branch, String versionName, EntityVersionSaveSettings settings) throws Exception;
VersionCreationResult saveEntitiesVersion(SecurityUser user, VersionCreateRequest request) throws Exception;
List<EntityVersion> listEntityVersions(TenantId tenantId, String branch, EntityId externalId) throws Exception;
@ -42,23 +41,19 @@ public interface EntitiesVersionControlService {
List<EntityVersion> listVersions(TenantId tenantId, String branch) throws Exception;
List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, EntityType entityType, String branch, String versionId) throws Exception; // will be good to return entity name also
List<VersionedEntityInfo> listEntitiesAtVersion(TenantId tenantId, EntityType entityType, String branch, String versionId) throws Exception;
List<VersionedEntityInfo> listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception;
EntityVersionLoadResult loadEntityVersion(SecurityUser user, EntityId externalId, String branch, String versionId, EntityVersionLoadSettings settings) throws Exception;
List<EntityVersionLoadResult> loadEntityTypeVersion(SecurityUser user, EntityType entityType, String branch, String versionId, EntityVersionLoadSettings settings) throws Exception;
List<EntityVersionLoadResult> loadAllAtVersion(SecurityUser user, String branch, String versionId, EntityVersionLoadSettings settings) throws Exception;
List<VersionLoadResult> loadEntitiesVersion(SecurityUser user, VersionLoadRequest request) throws Exception;
List<String> listAllowedBranches(TenantId tenantId);
List<String> listBranches(TenantId tenantId) throws Exception;
void saveSettings(EntitiesVersionControlSettings settings);
void saveSettings(TenantId tenantId, EntitiesVersionControlSettings settings);
EntitiesVersionControlSettings getSettings();
EntitiesVersionControlSettings getSettings(TenantId tenantId);
}

10
application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntitiesVersionControlSettings.java

@ -17,18 +17,10 @@ package org.thingsboard.server.service.sync.vc.data;
import lombok.Data;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Data
public class EntitiesVersionControlSettings {
private String repositoryDirectory;
private String repositoryUri;
private String username;
private String password;
private int fetchPeriod;
private Map<UUID, List<String>> tenantsAllowedBranches;
private String defaultBranch;
}

11
application/src/main/java/org/thingsboard/server/service/sync/vc/data/VersionCreationResult.java

@ -0,0 +1,11 @@
package org.thingsboard.server.service.sync.vc.data;
import lombok.Data;
@Data
public class VersionCreationResult {
private EntityVersion version;
private int added;
private int modified;
private int removed;
}

8
application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntityVersionLoadResult.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/VersionLoadResult.java

@ -20,14 +20,14 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class EntityVersionLoadResult {
private ExportableEntity<?> newEntityVersion;
private ExportableEntity<?> previousEntityVersion;
public class VersionLoadResult {
private EntityType entityType;
private int created;
private int updated;
private int deleted;
}

14
application/src/main/java/org/thingsboard/server/service/sync/exporting/data/request/CustomEntityFilterExportRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/EntitiesByCustomFilterVersionCreateConfig.java

@ -13,26 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.data.request;
package org.thingsboard.server.service.sync.vc.data.request.create;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.query.EntityFilter;
import java.util.UUID;
@EqualsAndHashCode(callSuper = true)
@Data
public class CustomEntityFilterExportRequest extends ExportRequest {
public class EntitiesByCustomFilterVersionCreateConfig extends VersionCreateConfig {
private EntityFilter filter;
private int page;
private int pageSize;
private UUID customerId;
private boolean removeOtherRemoteEntitiesOfType;
@Override
public ExportRequestType getType() {
return ExportRequestType.CUSTOM_ENTITY_FILTER;
public VersionCreateConfigType getType() {
return VersionCreateConfigType.CUSTOM_ENTITY_FILTER;
}
}

12
application/src/main/java/org/thingsboard/server/service/sync/exporting/data/request/CustomEntityQueryExportRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/EntitiesByCustomQueryVersionCreateConfig.java

@ -13,24 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.data.request;
package org.thingsboard.server.service.sync.vc.data.request.create;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.query.EntityDataQuery;
import java.util.UUID;
@EqualsAndHashCode(callSuper = true)
@Data
public class CustomEntityQueryExportRequest extends ExportRequest {
public class EntitiesByCustomQueryVersionCreateConfig extends VersionCreateConfig {
private EntityDataQuery query;
private UUID customerId;
private boolean removeOtherRemoteEntitiesOfType;
@Override
public ExportRequestType getType() {
return ExportRequestType.CUSTOM_ENTITY_QUERY;
public VersionCreateConfigType getType() {
return VersionCreateConfigType.CUSTOM_ENTITY_QUERY;
}
}

10
application/src/main/java/org/thingsboard/server/service/sync/exporting/data/request/EntityListExportRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/EntityListVersionCreateConfig.java

@ -13,23 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.data.request;
package org.thingsboard.server.service.sync.vc.data.request.create;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.EntityId;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
public class EntityListExportRequest extends ExportRequest {
public class EntityListVersionCreateConfig extends VersionCreateConfig {
private List<EntityId> entitiesIds;
@Override
public ExportRequestType getType() {
return ExportRequestType.ENTITY_LIST;
public VersionCreateConfigType getType() {
return VersionCreateConfigType.ENTITY_LIST;
}
}

14
application/src/main/java/org/thingsboard/server/service/sync/exporting/data/request/EntityTypeExportRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/EntityTypeVersionCreateConfig.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.data.request;
package org.thingsboard.server.service.sync.vc.data.request.create;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -21,18 +21,18 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@EqualsAndHashCode(callSuper = true)
@Data
public class EntityTypeExportRequest extends ExportRequest {
@EqualsAndHashCode(callSuper = true)
public class EntityTypeVersionCreateConfig extends VersionCreateConfig {
private EntityType entityType;
private int page;
private int pageSize;
private UUID customerId;
private boolean removeOtherRemoteEntitiesOfType;
@Override
public ExportRequestType getType() {
return ExportRequestType.ENTITY_TYPE;
public VersionCreateConfigType getType() {
return VersionCreateConfigType.ENTITY_TYPE;
}
}

10
application/src/main/java/org/thingsboard/server/service/sync/exporting/data/request/SingleEntityExportRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/SingleEntityVersionCreateConfig.java

@ -13,21 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.data.request;
package org.thingsboard.server.service.sync.vc.data.request.create;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.EntityId;
@EqualsAndHashCode(callSuper = true)
@Data
public class SingleEntityExportRequest extends ExportRequest {
@EqualsAndHashCode(callSuper = true)
public class SingleEntityVersionCreateConfig extends VersionCreateConfig {
private EntityId entityId;
@Override
public ExportRequestType getType() {
return ExportRequestType.SINGLE_ENTITY;
public VersionCreateConfigType getType() {
return VersionCreateConfigType.SINGLE_ENTITY;
}
}

18
application/src/main/java/org/thingsboard/server/service/sync/exporting/data/request/ExportRequest.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/VersionCreateConfig.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.data.request;
package org.thingsboard.server.service.sync.vc.data.request.create;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
@ -23,17 +23,17 @@ import lombok.Data;
@JsonTypeInfo(use = Id.NAME, property = "type")
@JsonSubTypes({
@Type(name = "SINGLE_ENTITY", value = SingleEntityExportRequest.class),
@Type(name = "ENTITY_LIST", value = EntityListExportRequest.class),
@Type(name = "ENTITY_TYPE", value = EntityTypeExportRequest.class),
@Type(name = "CUSTOM_ENTITY_FILTER", value = CustomEntityFilterExportRequest.class),
@Type(name = "CUSTOM_ENTITY_QUERY", value = CustomEntityQueryExportRequest.class)
@Type(name = "SINGLE_ENTITY", value = SingleEntityVersionCreateConfig.class),
@Type(name = "ENTITY_LIST", value = EntityListVersionCreateConfig.class),
@Type(name = "ENTITY_TYPE", value = EntityTypeVersionCreateConfig.class),
@Type(name = "CUSTOM_ENTITY_FILTER", value = EntitiesByCustomFilterVersionCreateConfig.class),
@Type(name = "CUSTOM_ENTITY_QUERY", value = EntitiesByCustomQueryVersionCreateConfig.class)
})
@Data
public abstract class ExportRequest {
public abstract class VersionCreateConfig {
private EntityExportSettings exportSettings;
private boolean saveRelations;
public abstract ExportRequestType getType();
public abstract VersionCreateConfigType getType();
}

4
application/src/main/java/org/thingsboard/server/service/sync/exporting/data/request/ExportRequestType.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/VersionCreateConfigType.java

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.exporting.data.request;
package org.thingsboard.server.service.sync.vc.data.request.create;
public enum ExportRequestType {
public enum VersionCreateConfigType {
SINGLE_ENTITY,
ENTITY_LIST,
ENTITY_TYPE,

14
application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntityVersionLoadSettings.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/create/VersionCreateRequest.java

@ -13,12 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc.data;
package org.thingsboard.server.service.sync.vc.data.request.create;
import lombok.Data;
import java.util.List;
@Data
public class EntityVersionLoadSettings {
private boolean loadRelations;
private boolean findExistingEntityByName;
public class VersionCreateRequest {
private String versionName;
private String branch;
private List<VersionCreateConfig> configs;
}

12
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/EntityTypeVersionLoadConfig.java

@ -0,0 +1,12 @@
package org.thingsboard.server.service.sync.vc.data.request.load;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class EntityTypeVersionLoadConfig extends EntityVersionLoadConfig {
private boolean removeNonexistentLocalEntities;
}

20
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/EntityTypeVersionLoadRequest.java

@ -0,0 +1,20 @@
package org.thingsboard.server.service.sync.vc.data.request.load;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.EntityType;
import java.util.Map;
@Data
@EqualsAndHashCode(callSuper = true)
public class EntityTypeVersionLoadRequest extends VersionLoadRequest {
private Map<EntityType, EntityTypeVersionLoadConfig> configs;
@Override
public VersionLoadRequestType getType() {
return VersionLoadRequestType.ENTITY_TYPE;
}
}

11
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/EntityVersionLoadConfig.java

@ -0,0 +1,11 @@
package org.thingsboard.server.service.sync.vc.data.request.load;
import lombok.Data;
@Data
public class EntityVersionLoadConfig {
private boolean loadRelations;
private boolean findExistingEntityByName;
}

20
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/SingleEntityVersionLoadRequest.java

@ -0,0 +1,20 @@
package org.thingsboard.server.service.sync.vc.data.request.load;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.EntityId;
@Data
@EqualsAndHashCode(callSuper = true)
public class SingleEntityVersionLoadRequest extends VersionLoadRequest {
private EntityId externalEntityId;
private EntityVersionLoadConfig config;
@Override
public VersionLoadRequestType getType() {
return VersionLoadRequestType.SINGLE_ENTITY;
}
}

11
application/src/main/java/org/thingsboard/server/service/sync/vc/data/EntityVersionSaveSettings.java → application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/VersionLoadRequest.java

@ -13,11 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.sync.vc.data;
package org.thingsboard.server.service.sync.vc.data.request.load;
import lombok.Data;
@Data
public class EntityVersionSaveSettings {
private boolean saveRelations;
public abstract class VersionLoadRequest {
private String branch;
private String versionId;
public abstract VersionLoadRequestType getType();
}

6
application/src/main/java/org/thingsboard/server/service/sync/vc/data/request/load/VersionLoadRequestType.java

@ -0,0 +1,6 @@
package org.thingsboard.server.service.sync.vc.data.request.load;
public enum VersionLoadRequestType {
SINGLE_ENTITY,
ENTITY_TYPE
}

39
application/src/main/java/org/thingsboard/server/utils/GitRepository.java

@ -24,6 +24,7 @@ import org.eclipse.jgit.api.GitCommand;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.api.LogCommand;
import org.eclipse.jgit.api.RmCommand;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.TransportCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Constants;
@ -33,18 +34,18 @@ import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
public class GitRepository {
@ -54,6 +55,8 @@ public class GitRepository {
@Getter
private final String directory;
@Getter
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private GitRepository(Git git, CredentialsProvider credentialsProvider, String directory) {
this.git = git;
@ -61,21 +64,20 @@ public class GitRepository {
this.directory = directory;
}
public static GitRepository clone(String uri, String directory,
String username, String password) throws GitAPIException {
public static GitRepository clone(String uri, String username, String password, File directory) throws GitAPIException {
CredentialsProvider credentialsProvider = newCredentialsProvider(username, password);
Git git = Git.cloneRepository()
.setURI(uri)
.setDirectory(new java.io.File(directory))
.setDirectory(directory)
.setNoCheckout(true)
.setCredentialsProvider(credentialsProvider)
.call();
return new GitRepository(git, credentialsProvider, directory);
return new GitRepository(git, credentialsProvider, directory.getAbsolutePath());
}
public static GitRepository open(String directory, String username, String password) throws IOException {
Git git = Git.open(new java.io.File(directory));
return new GitRepository(git, newCredentialsProvider(username, password), directory);
public static GitRepository open(File directory, String username, String password) throws IOException {
Git git = Git.open(directory);
return new GitRepository(git, newCredentialsProvider(username, password), directory.getAbsolutePath());
}
@ -180,9 +182,17 @@ public class GitRepository {
execute(git.clean());
}
public Commit commit(String message, String filesPattern) throws GitAPIException {
public void add(String filesPattern) throws GitAPIException { // FIXME [viacheslav]
execute(git.add().setUpdate(true).addFilepattern(filesPattern));
execute(git.add().addFilepattern(filesPattern));
}
public Status status() throws GitAPIException {
org.eclipse.jgit.api.Status status = execute(git.status());
return new Status(status.getAdded(), status.getModified(), status.getRemoved());
}
public Commit commit(String message) throws GitAPIException {
RevCommit revCommit = execute(git.commit()
.setMessage(message)); // TODO [viacheslav]: set configurable author for commit
return toCommit(revCommit);
@ -256,4 +266,11 @@ public class GitRepository {
private final String authorName;
}
@Data
public static class Status {
private final Set<String> added;
private final Set<String> modified;
private final Set<String> removed;
}
}

20
application/src/test/java/org/thingsboard/server/controller/BaseEntitiesExportImportControllerTest.java

@ -64,13 +64,13 @@ import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import org.thingsboard.server.service.sync.exporting.data.request.ExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.SingleEntityExportRequest;
import org.thingsboard.server.service.sync.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.importing.data.request.ImportRequest;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.SingleEntityVersionCreateConfig;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.importing.data.ImportRequest;
import java.nio.ByteBuffer;
import java.util.Arrays;
@ -339,17 +339,17 @@ public abstract class BaseEntitiesExportImportControllerTest extends AbstractCon
protected <E extends ExportableEntity<I>, I extends EntityId> EntityExportData<E> exportSingleEntity(I entityId) throws Exception {
SingleEntityExportRequest exportRequest = new SingleEntityExportRequest();
SingleEntityVersionCreateConfig exportRequest = new SingleEntityVersionCreateConfig();
exportRequest.setEntityId(entityId);
exportRequest.setExportSettings(new EntityExportSettings());
return (EntityExportData<E>) exportEntities(exportRequest).get(0);
}
protected List<EntityExportData<?>> exportEntities(ExportRequest exportRequest) throws Exception {
protected List<EntityExportData<?>> exportEntities(VersionCreateConfig exportRequest) throws Exception {
return getResponse(doPost("/api/entities/export", exportRequest), new TypeReference<List<EntityExportData<?>>>() {});
}
protected List<EntityExportData<?>> exportEntities(List<ExportRequest> exportRequests) throws Exception {
protected List<EntityExportData<?>> exportEntities(List<VersionCreateConfig> exportRequests) throws Exception {
return getResponse(doPost("/api/entities/export?multiple", exportRequests), new TypeReference<List<EntityExportData<?>>>() {});
}

53
application/src/test/java/org/thingsboard/server/controller/sql/EntitiesExportImportControllerSqlTest.java

@ -39,7 +39,6 @@ import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.query.EntityListFilter;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChain;
@ -50,18 +49,18 @@ import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.ota.OtaPackageStateService;
import org.thingsboard.server.service.sync.exporting.data.DeviceExportData;
import org.thingsboard.server.service.sync.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.RuleChainExportData;
import org.thingsboard.server.service.sync.exporting.data.request.CustomEntityFilterExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import org.thingsboard.server.service.sync.exporting.data.request.EntityListExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.EntityTypeExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.ExportRequest;
import org.thingsboard.server.service.sync.exporting.data.request.SingleEntityExportRequest;
import org.thingsboard.server.service.sync.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.importing.data.request.ImportRequest;
import org.thingsboard.server.service.sync.exportimport.exporting.data.DeviceExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportData;
import org.thingsboard.server.service.sync.exportimport.exporting.data.RuleChainExportData;
import org.thingsboard.server.service.sync.vc.data.request.create.EntitiesByCustomFilterVersionCreateConfig;
import org.thingsboard.server.service.sync.exportimport.exporting.data.EntityExportSettings;
import org.thingsboard.server.service.sync.vc.data.request.create.EntityListVersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.EntityTypeVersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.VersionCreateConfig;
import org.thingsboard.server.service.sync.vc.data.request.create.SingleEntityVersionCreateConfig;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportResult;
import org.thingsboard.server.service.sync.exportimport.importing.data.EntityImportSettings;
import org.thingsboard.server.service.sync.exportimport.importing.data.ImportRequest;
import java.util.ArrayList;
import java.util.List;
@ -294,11 +293,11 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
dashboard.setConfiguration(dashboardConfiguration);
dashboard = dashboardService.saveDashboard(dashboard);
EntityTypeExportRequest assetsExportRequest = new EntityTypeExportRequest();
EntityTypeVersionCreateConfig assetsExportRequest = new EntityTypeVersionCreateConfig();
assetsExportRequest.setEntityType(EntityType.ASSET);
assetsExportRequest.setPageSize(10);
assetsExportRequest.setExportSettings(new EntityExportSettings());
EntityTypeExportRequest dashboardsExportRequest = new EntityTypeExportRequest();
EntityTypeVersionCreateConfig dashboardsExportRequest = new EntityTypeVersionCreateConfig();
dashboardsExportRequest.setEntityType(EntityType.DASHBOARD);
dashboardsExportRequest.setPageSize(10);
dashboardsExportRequest.setExportSettings(new EntityExportSettings());
@ -365,7 +364,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
DeviceProfile deviceProfile = createDeviceProfile(tenantId1, ruleChain.getId(), dashboard.getId(), "Device profile 1");
Device device = createDevice(tenantId1, customer.getId(), deviceProfile.getId(), "Customer 1 - Device 1");
EntityListExportRequest exportRequest = new EntityListExportRequest();
EntityListVersionCreateConfig exportRequest = new EntityListVersionCreateConfig();
exportRequest.setExportSettings(new EntityExportSettings());
exportRequest.setEntitiesIds(List.of(customer.getId(), asset.getId(), ruleChain.getId(), deviceProfile.getId(), dashboard.getId()));
List<EntityExportData<?>> exportDataList = exportEntities(exportRequest);
@ -418,7 +417,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
Device device = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation = createRelation(asset.getId(), device.getId());
EntityListExportRequest exportRequest = new EntityListExportRequest();
EntityListVersionCreateConfig exportRequest = new EntityListVersionCreateConfig();
exportRequest.setEntitiesIds(List.of(asset.getId(), device.getId()));
exportRequest.setExportSettings(EntityExportSettings.builder()
.exportRelations(true)
@ -464,7 +463,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
Device device = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation = createRelation(asset.getId(), device.getId());
EntityListExportRequest exportRequest = new EntityListExportRequest();
EntityListVersionCreateConfig exportRequest = new EntityListVersionCreateConfig();
exportRequest.setEntitiesIds(List.of(asset.getId(), device.getId()));
exportRequest.setExportSettings(EntityExportSettings.builder()
.exportRelations(true)
@ -506,7 +505,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
Device device1 = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation1 = createRelation(asset.getId(), device1.getId());
SingleEntityExportRequest exportRequest = new SingleEntityExportRequest();
SingleEntityVersionCreateConfig exportRequest = new SingleEntityVersionCreateConfig();
exportRequest.setEntityId(asset.getId());
exportRequest.setExportSettings(EntityExportSettings.builder()
.exportRelations(true)
@ -538,7 +537,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
Device device = createDevice(tenantId1, null, null, "Device 1");
EntityRelation relation1 = createRelation(asset1.getId(), device.getId());
SingleEntityExportRequest exportRequest = new SingleEntityExportRequest();
SingleEntityVersionCreateConfig exportRequest = new SingleEntityVersionCreateConfig();
exportRequest.setEntityId(device.getId());
exportRequest.setExportSettings(EntityExportSettings.builder()
.exportRelations(true)
@ -568,7 +567,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
logInAsTenantAdmin1();
DeviceProfile defaultDeviceProfile = deviceProfileService.findDefaultDeviceProfile(tenantId1);
EntityListExportRequest exportRequest = new EntityListExportRequest();
EntityListVersionCreateConfig exportRequest = new EntityListVersionCreateConfig();
exportRequest.setEntitiesIds(List.of(defaultDeviceProfile.getId()));
exportRequest.setExportSettings(new EntityExportSettings());
List<EntityExportData<?>> exportDataList = exportEntities(exportRequest);
@ -613,7 +612,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
}
private void testEntityTypeExportRequest(ExportableEntity<?> entity) throws Exception {
EntityTypeExportRequest exportRequest = new EntityTypeExportRequest();
EntityTypeVersionCreateConfig exportRequest = new EntityTypeVersionCreateConfig();
exportRequest.setExportSettings(new EntityExportSettings());
exportRequest.setPageSize(10);
exportRequest.setEntityType(entity.getId().getEntityType());
@ -626,11 +625,11 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
}
private void testCustomEntityFilterExportRequest(ExportableEntity<?> entity) throws Exception {
CustomEntityFilterExportRequest exportRequest = new CustomEntityFilterExportRequest();
EntitiesByCustomFilterVersionCreateConfig exportRequest = new EntitiesByCustomFilterVersionCreateConfig();
exportRequest.setExportSettings(new EntityExportSettings());
exportRequest.setPageSize(10);
EntityListFilter filter = new EntityListFilter();
org.thingsboard.server.common.data.query.EntityListFilter filter = new org.thingsboard.server.common.data.query.EntityListFilter();
filter.setEntityType(entity.getId().getEntityType());
filter.setEntityList(List.of(entity.getId().toString()));
exportRequest.setFilter(filter);
@ -652,10 +651,10 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
Asset tenantAsset = createAsset(tenantId1, null, "A", "Tenant asset 1");
Asset customerAsset = createAsset(tenantId1, customer.getId(), "A", "Customer asset 1");
List<ExportRequest> exportRequests = new ArrayList<>();
List<VersionCreateConfig> exportRequests = new ArrayList<>();
for (EntityType entityType : Set.of(EntityType.DEVICE, EntityType.ASSET)) {
EntityTypeExportRequest exportRequest = new EntityTypeExportRequest();
EntityTypeVersionCreateConfig exportRequest = new EntityTypeVersionCreateConfig();
exportRequest.setExportSettings(new EntityExportSettings());
exportRequest.setPageSize(10);
exportRequest.setEntityType(entityType);
@ -685,7 +684,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
DeviceProfile deviceProfile = createDeviceProfile(tenantId1, ruleChain.getId(), dashboard.getId(), "Device profile 1");
Device device = createDevice(tenantId1, null, deviceProfile.getId(), "Device 1");
EntityListExportRequest exportRequest = new EntityListExportRequest();
EntityListVersionCreateConfig exportRequest = new EntityListVersionCreateConfig();
exportRequest.setEntitiesIds(List.of(customer.getId(), asset.getId(), device.getId(), ruleChain.getId(), dashboard.getId(), deviceProfile.getId()));
exportRequest.setExportSettings(new EntityExportSettings());

20
dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java

@ -32,6 +32,8 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
public abstract class DaoUtil {
@ -51,7 +53,7 @@ public abstract class DaoUtil {
return toPageable(pageLink, Collections.emptyMap());
}
public static Pageable toPageable(PageLink pageLink, Map<String,String> columnMap) {
public static Pageable toPageable(PageLink pageLink, Map<String, String> columnMap) {
return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), pageLink.toSort(pageLink.getSortOrder(), columnMap));
}
@ -59,7 +61,7 @@ public abstract class DaoUtil {
return toPageable(pageLink, Collections.emptyMap(), sortOrders);
}
public static Pageable toPageable(PageLink pageLink, Map<String,String> columnMap, List<SortOrder> sortOrders) {
public static Pageable toPageable(PageLink pageLink, Map<String, String> columnMap, List<SortOrder> sortOrders) {
return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), pageLink.toSort(sortOrders, columnMap));
}
@ -108,4 +110,18 @@ public abstract class DaoUtil {
return ids;
}
public static <T> void processInBatches(Function<PageLink, PageData<T>> finder, int batchSize, Consumer<T> processor) {
PageLink pageLink = new PageLink(batchSize);
PageData<T> batch;
boolean hasNextBatch;
do {
batch = finder.apply(pageLink);
batch.getData().forEach(processor);
hasNextBatch = batch.hasNext();
pageLink = pageLink.nextPageLink();
} while (hasNextBatch);
}
}

4
dao/src/main/java/org/thingsboard/server/dao/ExportableEntityDao.java

@ -16,6 +16,8 @@
package org.thingsboard.server.dao;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import java.util.UUID;
@ -25,4 +27,6 @@ public interface ExportableEntityDao<T extends ExportableEntity<?>> extends Dao<
default T findByTenantIdAndName(UUID tenantId, String name) { throw new UnsupportedOperationException(); }
PageData<T> findByTenantId(UUID tenantId, PageLink pageLink);
}

5
dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java

@ -219,6 +219,11 @@ public class JpaAssetDao extends JpaAbstractSearchTextDao<AssetEntity, Asset> im
return findAssetsByTenantIdAndName(tenantId, name).orElse(null);
}
@Override
public PageData<Asset> findByTenantId(UUID tenantId, PageLink pageLink) {
return findAssetsByTenantId(tenantId, pageLink);
}
@Override
public EntityType getEntityType() {
return EntityType.ASSET;

5
dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java

@ -80,6 +80,11 @@ public class JpaCustomerDao extends JpaAbstractSearchTextDao<CustomerEntity, Cus
return findCustomersByTenantIdAndTitle(tenantId, name).orElse(null);
}
@Override
public PageData<Customer> findByTenantId(UUID tenantId, PageLink pageLink) {
return findCustomersByTenantId(tenantId, pageLink);
}
@Override
public EntityType getEntityType() {
return EntityType.CUSTOMER;

4
dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardRepository.java

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.dao.sql.dashboard;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.thingsboard.server.dao.ExportableEntityRepository;
import org.thingsboard.server.dao.model.sql.DashboardEntity;
@ -31,4 +33,6 @@ public interface DashboardRepository extends JpaRepository<DashboardEntity, UUID
List<DashboardEntity> findByTenantIdAndTitle(UUID tenantId, String title);
Page<DashboardEntity> findByTenantId(UUID tenantId, Pageable pageable);
}

7
dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java

@ -21,6 +21,8 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.EntityType;
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.DaoUtil;
import org.thingsboard.server.dao.dashboard.DashboardDao;
import org.thingsboard.server.dao.model.sql.DashboardEntity;
@ -58,6 +60,11 @@ public class JpaDashboardDao extends JpaAbstractSearchTextDao<DashboardEntity, D
return DaoUtil.getData(dashboardRepository.findByTenantIdAndExternalId(tenantId, externalId));
}
@Override
public PageData<Dashboard> findByTenantId(UUID tenantId, PageLink pageLink) {
return DaoUtil.toPageData(dashboardRepository.findByTenantId(tenantId, DaoUtil.toPageable(pageLink)));
}
@Override
public List<Dashboard> findByTenantIdAndTitle(UUID tenantId, String title) {
return DaoUtil.convertDataList(dashboardRepository.findByTenantIdAndTitle(tenantId, title));

5
dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java

@ -313,6 +313,11 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
return findDeviceByTenantIdAndName(tenantId, name).orElse(null);
}
@Override
public PageData<Device> findByTenantId(UUID tenantId, PageLink pageLink) {
return findDevicesByTenantId(tenantId, pageLink);
}
@Override
public EntityType getEntityType() {
return EntityType.DEVICE;

5
dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java

@ -121,6 +121,11 @@ public class JpaDeviceProfileDao extends JpaAbstractSearchTextDao<DeviceProfileE
return DaoUtil.getData(deviceProfileRepository.findByTenantIdAndName(tenantId, name));
}
@Override
public PageData<DeviceProfile> findByTenantId(UUID tenantId, PageLink pageLink) {
return findDeviceProfiles(TenantId.fromUUID(tenantId), pageLink);
}
@Override
public EntityType getEntityType() {
return EntityType.DEVICE_PROFILE;

5
dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java

@ -114,6 +114,11 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao<RuleChainEntity, R
return DaoUtil.getData(ruleChainRepository.findByTenantIdAndExternalId(tenantId, externalId));
}
@Override
public PageData<RuleChain> findByTenantId(UUID tenantId, PageLink pageLink) {
return findRuleChainsByTenantId(tenantId, pageLink);
}
@Override
public EntityType getEntityType() {
return EntityType.RULE_CHAIN;

Loading…
Cancel
Save