From 849513541ecb7cab4e09a1bdf3cf29480bd28ea0 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 16 Mar 2022 17:35:34 +0200 Subject: [PATCH] Entities export/import API refactoring: permission checks and entity lifecycle events --- .../server/controller/AssetController.java | 18 +--- .../server/controller/BaseController.java | 62 ++++++++++++++ .../server/controller/CustomerController.java | 10 +-- .../controller/DashboardController.java | 8 +- .../server/controller/DeviceController.java | 22 +---- .../controller/DeviceProfileController.java | 25 +----- .../EntitiesExportImportController.java | 84 ++++++++++++------- .../controller/RuleChainController.java | 18 +--- .../DefaultEntitiesExportImportService.java | 13 ++- .../expimp/EntitiesExportImportService.java | 5 +- .../expimp/imp/EntityImportResult.java | 26 ++++++ .../expimp/imp/EntityImportService.java | 3 +- .../imp/impl/AbstractEntityImportService.java | 3 +- .../expimp/imp/impl/AssetImportService.java | 8 +- .../imp/impl/CustomerImportService.java | 8 +- .../imp/impl/DashboardImportService.java | 8 +- .../expimp/imp/impl/DeviceImportService.java | 10 ++- .../imp/impl/DeviceProfileImportService.java | 8 +- .../imp/impl/RuleChainImportService.java | 8 +- .../common/data/export/EntityExportData.java | 5 +- .../data/export/impl/AssetExportData.java | 5 ++ .../data/export/impl/CustomerExportData.java | 5 ++ .../data/export/impl/DashboardExportData.java | 5 ++ .../data/export/impl/DeviceExportData.java | 5 ++ .../export/impl/DeviceProfileExportData.java | 5 ++ .../data/export/impl/RuleChainExportData.java | 5 ++ 26 files changed, 240 insertions(+), 142 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/expimp/imp/EntityImportResult.java diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index 7bd9cb065d..94c714e24f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -156,7 +156,7 @@ public class AssetController extends BaseController { Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); - onAssetCreatedOrUpdated(savedAsset, asset.getId() != null, getCurrentUser()); + onEntityUpdatedOrCreated(getCurrentUser(), savedAsset, null, asset.getId() == null); return savedAsset; } catch (Exception e) { @@ -166,20 +166,6 @@ public class AssetController extends BaseController { } } - private void onAssetCreatedOrUpdated(Asset asset, boolean updated, SecurityUser user) { - try { - logEntityAction(user, asset.getId(), asset, - asset.getCustomerId(), - updated ? ActionType.UPDATED : ActionType.ADDED, null); - } catch (ThingsboardException e) { - log.error("Failed to log entity action", e); - } - - if (updated) { - sendEntityNotificationMsg(asset.getTenantId(), asset.getId(), EdgeEventActionType.UPDATED); - } - } - @ApiOperation(value = "Delete asset (deleteAsset)", notes = "Deletes the asset and all the relations (from and to the asset). Referencing non-existing asset Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -681,7 +667,7 @@ public class AssetController extends BaseController { public BulkImportResult processAssetsBulkImport(@RequestBody BulkImportRequest request) throws Exception { SecurityUser user = getCurrentUser(); return assetBulkImportService.processBulkImport(request, user, importedAssetInfo -> { - onAssetCreatedOrUpdated(importedAssetInfo.getEntity(), importedAssetInfo.isUpdated(), user); + onEntityUpdatedOrCreated(user, importedAssetInfo.getEntity(), importedAssetInfo.getOldEntity(), !importedAssetInfo.isUpdated()); }); } diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index f945cc30b7..210a6bea2d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityViewInfo; +import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.OtaPackage; @@ -68,6 +69,7 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.OtaPackageId; import org.thingsboard.server.common.data.id.RpcId; import org.thingsboard.server.common.data.id.RuleChainId; @@ -83,6 +85,7 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.plugin.ComponentDescriptor; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.rpc.Rpc; @@ -141,6 +144,7 @@ import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -919,4 +923,62 @@ public abstract class BaseController { return MediaType.APPLICATION_OCTET_STREAM; } } + + public & HasTenantId, I extends EntityId> void onEntityUpdatedOrCreated(User user, E savedEntity, E oldEntity, boolean isNewEntity) { + boolean notifyEdge = false; + + EntityType entityType = savedEntity.getId().getEntityType(); + switch (entityType) { + case DEVICE: + tbClusterService.onDeviceUpdated((Device) savedEntity, (Device) oldEntity); + break; + case DEVICE_PROFILE: + DeviceProfile deviceProfile = (DeviceProfile) savedEntity; + DeviceProfile oldDeviceProfile = (DeviceProfile) oldEntity; + boolean isFirmwareChanged = false; + boolean isSoftwareChanged = false; + if (!isNewEntity) { + if (!Objects.equals(deviceProfile.getFirmwareId(), oldDeviceProfile.getFirmwareId())) { + isFirmwareChanged = true; + } + if (!Objects.equals(deviceProfile.getSoftwareId(), oldDeviceProfile.getSoftwareId())) { + isSoftwareChanged = true; + } + } + tbClusterService.onDeviceProfileChange(deviceProfile, null); + tbClusterService.broadcastEntityStateChangeEvent(deviceProfile.getTenantId(), deviceProfile.getId(), + isNewEntity ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); + otaPackageStateService.update(deviceProfile, isFirmwareChanged, isSoftwareChanged); + notifyEdge = true; + break; + case RULE_CHAIN: // FIXME: events for rule chain metadata + RuleChainType ruleChainType = ((RuleChain) savedEntity).getType(); + if (RuleChainType.CORE.equals(ruleChainType)) { + tbClusterService.broadcastEntityStateChangeEvent(savedEntity.getTenantId(), savedEntity.getId(), + isNewEntity ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); + } + if (RuleChainType.EDGE.equals(ruleChainType)) { + if (!isNewEntity) { + notifyEdge = true; + } + } + break; + case ASSET: + case CUSTOMER: + case DASHBOARD: + if (!isNewEntity) { + notifyEdge = true; + } + break; + default: + throw new UnsupportedOperationException(); + } + + entityActionService.logEntityAction(user, savedEntity.getId(), savedEntity, savedEntity instanceof HasCustomerId ? ((HasCustomerId) savedEntity).getCustomerId() : null, + isNewEntity ? ActionType.ADDED : ActionType.UPDATED, null); + if (notifyEdge) { + sendEntityNotificationMsg(savedEntity.getTenantId(), savedEntity.getId(), isNewEntity ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); + } + } + } diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java index b419121459..27037f36e7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java @@ -33,7 +33,6 @@ import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.audit.ActionType; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; @@ -151,14 +150,7 @@ public class CustomerController extends BaseController { checkEntity(customer.getId(), customer, Resource.CUSTOMER); Customer savedCustomer = checkNotNull(customerService.saveCustomer(customer)); - - logEntityAction(savedCustomer.getId(), savedCustomer, - savedCustomer.getId(), - customer.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); - - if (customer.getId() != null) { - sendEntityNotificationMsg(savedCustomer.getTenantId(), savedCustomer.getId(), EdgeEventActionType.UPDATED); - } + onEntityUpdatedOrCreated(getCurrentUser(), savedCustomer, null, customer.getId() == null); return savedCustomer; } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 49c33045a5..4ea1ca83c7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -187,13 +187,7 @@ public class DashboardController extends BaseController { Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard)); - logEntityAction(savedDashboard.getId(), savedDashboard, - null, - dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); - - if (dashboard.getId() != null) { - sendEntityNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), EdgeEventActionType.UPDATED); - } + onEntityUpdatedOrCreated(getCurrentUser(), savedDashboard, null, dashboard.getId() == null); return savedDashboard; } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index 85a21e912c..d2ffafa73e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -195,7 +195,7 @@ public class DeviceController extends BaseController { Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); - onDeviceCreatedOrUpdated(savedDevice, oldDevice, !created, getCurrentUser()); + onEntityUpdatedOrCreated(getCurrentUser(), savedDevice, oldDevice, created); return savedDevice; } catch (Exception e) { @@ -224,10 +224,8 @@ public class DeviceController extends BaseController { checkEntity(device.getId(), device, Resource.DEVICE); Device savedDevice = deviceService.saveDeviceWithCredentials(device, credentials); checkNotNull(savedDevice); - tbClusterService.onDeviceUpdated(savedDevice, device); - logEntityAction(savedDevice.getId(), savedDevice, - savedDevice.getCustomerId(), - device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); + + onEntityUpdatedOrCreated(getCurrentUser(), savedDevice, device, device.getId() == null); return savedDevice; } catch (Exception e) { @@ -237,18 +235,6 @@ public class DeviceController extends BaseController { } } - private void onDeviceCreatedOrUpdated(Device savedDevice, Device oldDevice, boolean updated, SecurityUser user) { - tbClusterService.onDeviceUpdated(savedDevice, oldDevice); - - try { - logEntityAction(user, savedDevice.getId(), savedDevice, - savedDevice.getCustomerId(), - updated ? ActionType.UPDATED : ActionType.ADDED, null); - } catch (ThingsboardException e) { - log.error("Failed to log entity action", e); - } - } - @ApiOperation(value = "Delete device (deleteDevice)", notes = "Deletes the device, it's credentials and all the relations (from and to the device). Referencing non-existing device Id will cause an error." + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @@ -1015,7 +1001,7 @@ public class DeviceController extends BaseController { public BulkImportResult processDevicesBulkImport(@RequestBody BulkImportRequest request) throws Exception { SecurityUser user = getCurrentUser(); return deviceBulkImportService.processBulkImport(request, user, importedDeviceInfo -> { - onDeviceCreatedOrUpdated(importedDeviceInfo.getEntity(), importedDeviceInfo.getOldEntity(), importedDeviceInfo.isUpdated(), user); + onEntityUpdatedOrCreated(user, importedDeviceInfo.getEntity(), importedDeviceInfo.getOldEntity(), !importedDeviceInfo.isUpdated()); }); } diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index 25a35e77fa..240e60be2c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -46,7 +46,6 @@ import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; import java.util.List; -import java.util.Objects; import java.util.UUID; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_DATA; @@ -207,32 +206,14 @@ public class DeviceProfileController extends BaseController { checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE); - boolean isFirmwareChanged = false; - boolean isSoftwareChanged = false; - + DeviceProfile oldDeviceProfile = null; if (!created) { - DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(getTenantId(), deviceProfile.getId()); - if (!Objects.equals(deviceProfile.getFirmwareId(), oldDeviceProfile.getFirmwareId())) { - isFirmwareChanged = true; - } - if (!Objects.equals(deviceProfile.getSoftwareId(), oldDeviceProfile.getSoftwareId())) { - isSoftwareChanged = true; - } + oldDeviceProfile = deviceProfileService.findDeviceProfileById(getTenantId(), deviceProfile.getId()); } DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile)); - tbClusterService.onDeviceProfileChange(savedDeviceProfile, null); - tbClusterService.broadcastEntityStateChangeEvent(deviceProfile.getTenantId(), savedDeviceProfile.getId(), - created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); - - logEntityAction(savedDeviceProfile.getId(), savedDeviceProfile, - null, - created ? ActionType.ADDED : ActionType.UPDATED, null); - - otaPackageStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged); + onEntityUpdatedOrCreated(getCurrentUser(), deviceProfile, oldDeviceProfile, created); - sendEntityNotificationMsg(getTenantId(), savedDeviceProfile.getId(), - deviceProfile.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); return savedDeviceProfile; } catch (Exception e) { logEntityAction(emptyId(EntityType.DEVICE_PROFILE), deviceProfile, diff --git a/application/src/main/java/org/thingsboard/server/controller/EntitiesExportImportController.java b/application/src/main/java/org/thingsboard/server/controller/EntitiesExportImportController.java index a11a9189f4..07a033ab03 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntitiesExportImportController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntitiesExportImportController.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.controller; +import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; @@ -23,21 +24,20 @@ 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.HasName; +import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.export.EntitiesExportRequest; -import org.thingsboard.server.common.data.export.EntitiesExportResponse; import org.thingsboard.server.common.data.export.EntityExportData; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.HasId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.expimp.EntitiesExportImportService; +import org.thingsboard.server.service.expimp.imp.EntityImportResult; +import org.thingsboard.server.service.security.model.SecurityUser; +import org.thingsboard.server.service.security.permission.Operation; +import org.thingsboard.server.service.security.permission.Resource; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; import java.util.UUID; @RestController @@ -51,49 +51,69 @@ public class EntitiesExportImportController extends BaseController { @PostMapping("/export/{entityType}/{entityId}") @PreAuthorize("hasAuthority('TENANT_ADMIN')") - public EntityExportData exportEntity(@PathVariable EntityType entityType, + public EntityExportData exportEntity(@ApiParam(allowableValues = "DEVICE, DEVICE_PROFILE, ASSET, RULE_CHAIN, DASHBOARD, CUSTOMER") @PathVariable EntityType entityType, @PathVariable("entityId") UUID entityUuid) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, entityUuid); try { - return exportImportService.exportEntity(getTenantId(), entityId); + return exportEntity(getCurrentUser(), entityId); } catch (Exception e) { throw handleException(e); } } - @PostMapping("/export/batch") - @PreAuthorize("hasAuthority('TENANT_ADMIN')") - public EntitiesExportResponse exportEntities(@RequestBody EntitiesExportRequest exportRequest) throws ThingsboardException { - TenantId tenantId = getTenantId(); - - EntitiesExportResponse exportResponse = new EntitiesExportResponse(); - - Map>>> result = new HashMap<>(); - exportRequest.getEntities().forEach((entityType, entityIds) -> { - List>> exportDataForEntityType = new LinkedList<>(); - entityIds.forEach(entityId -> { - EntityExportData> exportData = exportImportService.exportEntity(tenantId, entityId); - exportDataForEntityType.add(exportData); - }); - result.put(entityType, exportDataForEntityType); - }); - - exportResponse.setExportData(result); - return exportResponse; - } + +// @PostMapping("/export/batch") +// @PreAuthorize("hasAuthority('TENANT_ADMIN')") +// public EntitiesExportResponse exportEntities(@RequestBody EntitiesExportRequest exportRequest) throws ThingsboardException { +// TenantId tenantId = getTenantId(); +// +// EntitiesExportResponse exportResponse = new EntitiesExportResponse(); +// +// Map>>> result = new HashMap<>(); +// exportRequest.getEntities().forEach((entityType, entityIds) -> { +// List>> exportDataForEntityType = new LinkedList<>(); +// entityIds.forEach(entityId -> { +// EntityExportData> exportData = exportImportService.exportEntity(tenantId, entityId); +// exportDataForEntityType.add(exportData); +// }); +// result.put(entityType, exportDataForEntityType); +// }); +// +// exportResponse.setExportData(result); +// return exportResponse; +// } + // TODO: export and import of batches // TODO: api to export and import whole customer, whole tenant @PostMapping("/import") @PreAuthorize("hasAuthority('TENANT_ADMIN')") - public , I extends EntityId, D extends EntityExportData> E importEntity(@RequestBody D exportData) throws ThingsboardException { + public & HasName & HasTenantId, I extends EntityId, D extends EntityExportData> EntityImportResult importEntity(@RequestBody D exportData) throws ThingsboardException { try { - return exportImportService.importEntity(getTenantId(), exportData); + return importEntity(getCurrentUser(), exportData); } catch (Exception e) { throw handleException(e); } } -// public void importEntities(@RequestBody ) + + private , I extends EntityId> EntityExportData> exportEntity(SecurityUser user, I entityId) throws ThingsboardException { + checkEntityId(entityId, Operation.READ); + return exportImportService.exportEntity(getTenantId(), entityId); + } + + private & HasName & HasTenantId, I extends EntityId, D extends EntityExportData> EntityImportResult importEntity(SecurityUser user, D exportData) throws ThingsboardException { + E existingEntity = exportImportService.findEntityByExternalId(user.getTenantId(), exportData.getMainEntity().getId()); + if (existingEntity != null) { + checkEntityId(existingEntity.getId(), Operation.WRITE); // todo maybe need to extract permission check to BaseController and put there permission checks from other controllers + } else { + checkEntity(null, exportData.getMainEntity(), Resource.of(exportData.getEntityType())); + } + + EntityImportResult importResult = exportImportService.importEntity(getTenantId(), exportData); + onEntityUpdatedOrCreated(user, importResult.getSavedEntity(), importResult.getOldEntity(), importResult.getOldEntity() == null); + + return importResult; + } } diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 6479b838b2..aba074ac60 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -78,11 +78,9 @@ import org.thingsboard.server.service.security.permission.Resource; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TreeSet; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -254,20 +252,7 @@ public class RuleChainController extends BaseController { RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain)); - if (RuleChainType.CORE.equals(savedRuleChain.getType())) { - tbClusterService.broadcastEntityStateChangeEvent(ruleChain.getTenantId(), savedRuleChain.getId(), - created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); - } - - logEntityAction(savedRuleChain.getId(), savedRuleChain, - null, - created ? ActionType.ADDED : ActionType.UPDATED, null); - - if (RuleChainType.EDGE.equals(savedRuleChain.getType())) { - if (!created) { - sendEntityNotificationMsg(savedRuleChain.getTenantId(), savedRuleChain.getId(), EdgeEventActionType.UPDATED); - } - } + onEntityUpdatedOrCreated(getCurrentUser(), savedRuleChain, null, created); return savedRuleChain; } catch (Exception e) { @@ -294,6 +279,7 @@ public class RuleChainController extends BaseController { RuleChain savedRuleChain = installScripts.createDefaultRuleChain(getCurrentUser().getTenantId(), request.getName()); + tbClusterService.broadcastEntityStateChangeEvent(savedRuleChain.getTenantId(), savedRuleChain.getId(), ComponentLifecycleEvent.CREATED); logEntityAction(savedRuleChain.getId(), savedRuleChain, null, ActionType.ADDED, null); diff --git a/application/src/main/java/org/thingsboard/server/service/expimp/DefaultEntitiesExportImportService.java b/application/src/main/java/org/thingsboard/server/service/expimp/DefaultEntitiesExportImportService.java index 9b384b34dd..26d983a694 100644 --- a/application/src/main/java/org/thingsboard/server/service/expimp/DefaultEntitiesExportImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/expimp/DefaultEntitiesExportImportService.java @@ -24,7 +24,9 @@ import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.expimp.exp.EntityExportService; +import org.thingsboard.server.service.expimp.imp.EntityImportResult; import org.thingsboard.server.service.expimp.imp.EntityImportService; +import org.thingsboard.server.service.expimp.imp.impl.AbstractEntityImportService; import java.util.Collection; import java.util.EnumMap; @@ -51,16 +53,21 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS } // FIXME: somehow validate export data - // FIXME: validate permissions for create or update - // FIXME: send entity lifecycle event @Override - public , I extends EntityId, D extends EntityExportData> E importEntity(TenantId tenantId, D exportData) { + public , I extends EntityId, D extends EntityExportData> EntityImportResult importEntity(TenantId tenantId, D exportData) { EntityType entityType = exportData.getEntityType(); EntityImportService importService = getImportService(entityType); return importService.importEntity(tenantId, exportData); } + @Override + @SuppressWarnings("unchecked") + public , I extends EntityId> E findEntityByExternalId(TenantId tenantId, I externalId) { + return (E) importServices.values().stream().filter(entityImportService -> entityImportService instanceof AbstractEntityImportService) + .findFirst().map(entityImportService -> (AbstractEntityImportService) importServices).get() + .findByExternalOrInternalId(tenantId, externalId); // FIXME !!! + } @SuppressWarnings("unchecked") private > EntityExportService getExportService(EntityType entityType) { diff --git a/application/src/main/java/org/thingsboard/server/service/expimp/EntitiesExportImportService.java b/application/src/main/java/org/thingsboard/server/service/expimp/EntitiesExportImportService.java index 5d25cb9320..75503d2750 100644 --- a/application/src/main/java/org/thingsboard/server/service/expimp/EntitiesExportImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/expimp/EntitiesExportImportService.java @@ -19,11 +19,14 @@ import org.thingsboard.server.common.data.export.EntityExportData; 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.service.expimp.imp.EntityImportResult; public interface EntitiesExportImportService { , I extends EntityId> EntityExportData exportEntity(TenantId tenantId, I entityId); - , I extends EntityId, D extends EntityExportData> E importEntity(TenantId tenantId, D exportData); + , I extends EntityId, D extends EntityExportData> EntityImportResult importEntity(TenantId tenantId, D exportData); + + , I extends EntityId> E findEntityByExternalId(TenantId tenantId, I externalId); } diff --git a/application/src/main/java/org/thingsboard/server/service/expimp/imp/EntityImportResult.java b/application/src/main/java/org/thingsboard/server/service/expimp/imp/EntityImportResult.java new file mode 100644 index 0000000000..9868670076 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/expimp/imp/EntityImportResult.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.expimp.imp; + +import lombok.Data; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; + +@Data +public class EntityImportResult> { + private E savedEntity; + private E oldEntity; +} diff --git a/application/src/main/java/org/thingsboard/server/service/expimp/imp/EntityImportService.java b/application/src/main/java/org/thingsboard/server/service/expimp/imp/EntityImportService.java index 195ace0b66..e0f469e751 100644 --- a/application/src/main/java/org/thingsboard/server/service/expimp/imp/EntityImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/expimp/imp/EntityImportService.java @@ -23,7 +23,8 @@ import org.thingsboard.server.common.data.id.TenantId; public interface EntityImportService, D extends EntityExportData> { - E importEntity(TenantId tenantId, D exportData); + // FIXME: get rid of boilerplate for import result creation and everything else + EntityImportResult importEntity(TenantId tenantId, D exportData); EntityType getEntityType(); diff --git a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/AbstractEntityImportService.java b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/AbstractEntityImportService.java index 3f33ba04f0..81855ec8dd 100644 --- a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/AbstractEntityImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/AbstractEntityImportService.java @@ -38,7 +38,6 @@ public abstract class AbstractEntityImportService ID getInternalId(TenantId tenantId, ID externalId) { if (externalId == null) { return null; @@ -50,7 +49,7 @@ public abstract class AbstractEntityImportService, ID extends EntityId> T findByExternalOrInternalId(TenantId tenantId, ID externalOrInternalId) { + public final , ID extends EntityId> T findByExternalOrInternalId(TenantId tenantId, ID externalOrInternalId) { ExportableEntityDao dao = getDao(externalOrInternalId.getEntityType()); return Optional.ofNullable(dao.findByTenantIdAndExternalId(tenantId.getId(), externalOrInternalId.getId())) .orElseGet(() -> dao.findByTenantIdAndId(tenantId.getId(), externalOrInternalId.getId())); diff --git a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/AssetImportService.java b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/AssetImportService.java index 5e563762d6..0e3c6f3004 100644 --- a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/AssetImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/AssetImportService.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.id.AssetId; 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.expimp.imp.EntityImportResult; @Service @TbCoreComponent @@ -34,7 +35,7 @@ public class AssetImportService extends AbstractEntityImportService importEntity(TenantId tenantId, AssetExportData exportData) { Asset asset = exportData.getAsset(); Asset existingAsset = findByExternalId(tenantId, asset.getId()); // TODO: extract boiler plate to abstract class ... @@ -51,7 +52,10 @@ public class AssetImportService extends AbstractEntityImportService importResult = new EntityImportResult<>(); + importResult.setSavedEntity(savedAsset); + importResult.setOldEntity(existingAsset); + return importResult; } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/CustomerImportService.java b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/CustomerImportService.java index 9510cc0700..5f98a7fb66 100644 --- a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/CustomerImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/CustomerImportService.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.id.CustomerId; 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.expimp.imp.EntityImportResult; @Service @TbCoreComponent @@ -34,7 +35,7 @@ public class CustomerImportService extends AbstractEntityImportService importEntity(TenantId tenantId, CustomerExportData exportData) { Customer customer = exportData.getCustomer(); Customer existingCustomer = findByExternalId(tenantId, customer.getId()); @@ -49,7 +50,10 @@ public class CustomerImportService extends AbstractEntityImportService importResult = new EntityImportResult<>(); + importResult.setSavedEntity(savedCustomer); + importResult.setOldEntity(existingCustomer); + return importResult; } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DashboardImportService.java b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DashboardImportService.java index eab90bb294..210e7ca841 100644 --- a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DashboardImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DashboardImportService.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.id.DashboardId; 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.expimp.imp.EntityImportResult; @Service @TbCoreComponent @@ -34,7 +35,7 @@ public class DashboardImportService extends AbstractEntityImportService importEntity(TenantId tenantId, DashboardExportData exportData) { Dashboard dashboard = exportData.getDashboard(); Dashboard existingDashboard = findByExternalId(tenantId, dashboard.getId()); @@ -51,7 +52,10 @@ public class DashboardImportService extends AbstractEntityImportService importResult = new EntityImportResult<>(); + importResult.setSavedEntity(savedDashboard); + importResult.setOldEntity(existingDashboard); + return importResult; } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DeviceImportService.java b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DeviceImportService.java index 052fa3e1b3..c72ed48b2f 100644 --- a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DeviceImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DeviceImportService.java @@ -18,7 +18,6 @@ package org.thingsboard.server.service.expimp.imp.impl; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.export.impl.DeviceExportData; @@ -26,7 +25,7 @@ import org.thingsboard.server.common.data.id.DeviceId; 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.action.EntityActionService; +import org.thingsboard.server.service.expimp.imp.EntityImportResult; @Service @TbCoreComponent @@ -38,7 +37,7 @@ public class DeviceImportService extends AbstractEntityImportService importEntity(TenantId tenantId, DeviceExportData exportData) { Device device = exportData.getDevice(); Device existingDevice = findByExternalId(tenantId, device.getId()); // FIXME: !!! // what if exporting and importing back already exported entity ? (save version and then load it back) @@ -70,7 +69,10 @@ public class DeviceImportService extends AbstractEntityImportService importResult = new EntityImportResult<>(); + importResult.setSavedEntity(savedDevice); + importResult.setOldEntity(existingDevice); + return importResult; } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DeviceProfileImportService.java b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DeviceProfileImportService.java index 615f62d389..99efefe812 100644 --- a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DeviceProfileImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/DeviceProfileImportService.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.expimp.imp.EntityImportResult; @Service @TbCoreComponent @@ -34,7 +35,7 @@ public class DeviceProfileImportService extends AbstractEntityImportService importEntity(TenantId tenantId, DeviceProfileExportData exportData) { DeviceProfile deviceProfile = exportData.getDeviceProfile(); DeviceProfile existingDeviceProfile = findByExternalId(tenantId, deviceProfile.getId()); @@ -54,7 +55,10 @@ public class DeviceProfileImportService extends AbstractEntityImportService importResult = new EntityImportResult<>(); + importResult.setSavedEntity(savedDeviceProfile); + importResult.setOldEntity(existingDeviceProfile); + return importResult; } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/RuleChainImportService.java b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/RuleChainImportService.java index eb72f58a7f..92daa19a00 100644 --- a/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/RuleChainImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/expimp/imp/impl/RuleChainImportService.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.expimp.imp.EntityImportResult; @Service @TbCoreComponent @@ -37,7 +38,7 @@ public class RuleChainImportService extends AbstractEntityImportService importEntity(TenantId tenantId, RuleChainExportData exportData) { RuleChain ruleChain = exportData.getRuleChain(); RuleChain existingRuleChain = findByExternalId(tenantId, ruleChain.getId()); @@ -69,7 +70,10 @@ public class RuleChainImportService extends AbstractEntityImportService importResult = new EntityImportResult<>(); + importResult.setSavedEntity(savedRuleChain); + importResult.setOldEntity(existingRuleChain); + return importResult; } @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/export/EntityExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/export/EntityExportData.java index 36d3cb4b0c..4fd1a5c732 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/export/EntityExportData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/export/EntityExportData.java @@ -43,6 +43,9 @@ import org.thingsboard.server.common.data.id.HasId; public interface EntityExportData> { @JsonIgnore - EntityType getEntityType(); // fixme: maybe remove if not needed, as well as generic + E getMainEntity(); + + @JsonIgnore + EntityType getEntityType(); // fixme: maybe remove if not needed } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/AssetExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/AssetExportData.java index c0f417bd76..abb268eeb6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/AssetExportData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/AssetExportData.java @@ -25,6 +25,11 @@ public class AssetExportData implements EntityExportData { private Asset asset; + @Override + public Asset getMainEntity() { + return asset; + } + @Override public EntityType getEntityType() { return EntityType.ASSET; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/CustomerExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/CustomerExportData.java index 31e53db223..02ec9e7efa 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/CustomerExportData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/CustomerExportData.java @@ -25,6 +25,11 @@ public class CustomerExportData implements EntityExportData { private Customer customer; + @Override + public Customer getMainEntity() { + return customer; + } + @Override public EntityType getEntityType() { return EntityType.CUSTOMER; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DashboardExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DashboardExportData.java index 7860c6c553..f75f2479f6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DashboardExportData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DashboardExportData.java @@ -25,6 +25,11 @@ public class DashboardExportData implements EntityExportData { private Dashboard dashboard; + @Override + public Dashboard getMainEntity() { + return dashboard; + } + @Override public EntityType getEntityType() { return EntityType.DASHBOARD; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DeviceExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DeviceExportData.java index 05f3299d02..ff3741dabc 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DeviceExportData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DeviceExportData.java @@ -27,6 +27,11 @@ public class DeviceExportData implements EntityExportData { private Device device; private DeviceCredentials credentials; + @Override + public Device getMainEntity() { + return device; + } + @Override public EntityType getEntityType() { return EntityType.DEVICE; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DeviceProfileExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DeviceProfileExportData.java index c030d0b86e..a5d7872cc6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DeviceProfileExportData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/DeviceProfileExportData.java @@ -25,6 +25,11 @@ public class DeviceProfileExportData implements EntityExportData private DeviceProfile deviceProfile; + @Override + public DeviceProfile getMainEntity() { + return deviceProfile; + } + @Override public EntityType getEntityType() { return EntityType.DEVICE_PROFILE; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/RuleChainExportData.java b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/RuleChainExportData.java index 11fbace911..101f516881 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/RuleChainExportData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/export/impl/RuleChainExportData.java @@ -27,6 +27,11 @@ public class RuleChainExportData implements EntityExportData { private RuleChain ruleChain; private RuleChainMetaData metaData; + @Override + public RuleChain getMainEntity() { + return ruleChain; + } + @Override public EntityType getEntityType() { return EntityType.RULE_CHAIN;