Entities export/import API refactoring: permission checks and entity lifecycle events

This commit is contained in:
Viacheslav Klimov 2022-03-16 17:35:34 +02:00
parent 4062dc70fb
commit 849513541e
26 changed files with 239 additions and 141 deletions

View File

@ -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<Asset> 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());
});
}

View File

@ -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 <E extends HasName & HasId<I> & 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);
}
}
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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<Device> 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());
});
}

View File

@ -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);
onEntityUpdatedOrCreated(getCurrentUser(), deviceProfile, oldDeviceProfile, created);
logEntityAction(savedDeviceProfile.getId(), savedDeviceProfile,
null,
created ? ActionType.ADDED : ActionType.UPDATED, null);
otaPackageStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged);
sendEntityNotificationMsg(getTenantId(), savedDeviceProfile.getId(),
deviceProfile.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
return savedDeviceProfile;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.DEVICE_PROFILE), deviceProfile,

View File

@ -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<EntityType, List<EntityExportData<HasId<EntityId>>>> result = new HashMap<>();
exportRequest.getEntities().forEach((entityType, entityIds) -> {
List<EntityExportData<HasId<EntityId>>> exportDataForEntityType = new LinkedList<>();
entityIds.forEach(entityId -> {
EntityExportData<HasId<EntityId>> 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<EntityType, List<EntityExportData<HasId<EntityId>>>> result = new HashMap<>();
// exportRequest.getEntities().forEach((entityType, entityIds) -> {
// List<EntityExportData<HasId<EntityId>>> exportDataForEntityType = new LinkedList<>();
// entityIds.forEach(entityId -> {
// EntityExportData<HasId<EntityId>> 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 <E extends HasId<I>, I extends EntityId, D extends EntityExportData<E>> E importEntity(@RequestBody D exportData) throws ThingsboardException {
public <E extends HasId<I> & HasName & HasTenantId, I extends EntityId, D extends EntityExportData<E>> EntityImportResult<E> 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 <E extends HasId<I>, I extends EntityId> EntityExportData<HasId<EntityId>> exportEntity(SecurityUser user, I entityId) throws ThingsboardException {
checkEntityId(entityId, Operation.READ);
return exportImportService.exportEntity(getTenantId(), entityId);
}
private <E extends HasId<I> & HasName & HasTenantId, I extends EntityId, D extends EntityExportData<E>> EntityImportResult<E> 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<E> importResult = exportImportService.importEntity(getTenantId(), exportData);
onEntityUpdatedOrCreated(user, importResult.getSavedEntity(), importResult.getOldEntity(), importResult.getOldEntity() == null);
return importResult;
}
}

View File

@ -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);

View File

@ -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 <E extends HasId<I>, I extends EntityId, D extends EntityExportData<E>> E importEntity(TenantId tenantId, D exportData) {
public <E extends HasId<I>, I extends EntityId, D extends EntityExportData<E>> EntityImportResult<E> importEntity(TenantId tenantId, D exportData) {
EntityType entityType = exportData.getEntityType();
EntityImportService<I, E, D> importService = getImportService(entityType);
return importService.importEntity(tenantId, exportData);
}
@Override
@SuppressWarnings("unchecked")
public <E extends HasId<I>, 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 <I extends EntityId, E extends HasId<I>> EntityExportService<I, E> getExportService(EntityType entityType) {

View File

@ -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 {
<E extends HasId<I>, I extends EntityId> EntityExportData<E> exportEntity(TenantId tenantId, I entityId);
<E extends HasId<I>, I extends EntityId, D extends EntityExportData<E>> E importEntity(TenantId tenantId, D exportData);
<E extends HasId<I>, I extends EntityId, D extends EntityExportData<E>> EntityImportResult<E> importEntity(TenantId tenantId, D exportData);
<E extends HasId<I>, I extends EntityId> E findEntityByExternalId(TenantId tenantId, I externalId);
}

View File

@ -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<E extends HasId<? extends EntityId>> {
private E savedEntity;
private E oldEntity;
}

View File

@ -23,7 +23,8 @@ import org.thingsboard.server.common.data.id.TenantId;
public interface EntityImportService<I extends EntityId, E extends HasId<I>, D extends EntityExportData<E>> {
E importEntity(TenantId tenantId, D exportData);
// FIXME: get rid of boilerplate for import result creation and everything else
EntityImportResult<E> importEntity(TenantId tenantId, D exportData);
EntityType getEntityType();

View File

@ -38,7 +38,6 @@ public abstract class AbstractEntityImportService<I extends EntityId, E extends
return findByExternalOrInternalId(tenantId, externalId);
}
protected final <ID extends EntityId> ID getInternalId(TenantId tenantId, ID externalId) {
if (externalId == null) {
return null;
@ -50,7 +49,7 @@ public abstract class AbstractEntityImportService<I extends EntityId, E extends
return entity.getId();
}
private <T extends HasId<ID>, ID extends EntityId> T findByExternalOrInternalId(TenantId tenantId, ID externalOrInternalId) {
public final <T extends HasId<ID>, ID extends EntityId> T findByExternalOrInternalId(TenantId tenantId, ID externalOrInternalId) {
ExportableEntityDao<T> dao = getDao(externalOrInternalId.getEntityType());
return Optional.ofNullable(dao.findByTenantIdAndExternalId(tenantId.getId(), externalOrInternalId.getId()))
.orElseGet(() -> dao.findByTenantIdAndId(tenantId.getId(), externalOrInternalId.getId()));

View File

@ -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<AssetId, Ass
@Override
public Asset importEntity(TenantId tenantId, AssetExportData exportData) {
public EntityImportResult<Asset> 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<AssetId, Ass
Asset savedAsset = assetService.saveAsset(asset);
return savedAsset;
EntityImportResult<Asset> importResult = new EntityImportResult<>();
importResult.setSavedEntity(savedAsset);
importResult.setOldEntity(existingAsset);
return importResult;
}
@Override

View File

@ -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<CustomerI
@Override
public Customer importEntity(TenantId tenantId, CustomerExportData exportData) {
public EntityImportResult<Customer> importEntity(TenantId tenantId, CustomerExportData exportData) {
Customer customer = exportData.getCustomer();
Customer existingCustomer = findByExternalId(tenantId, customer.getId());
@ -49,7 +50,10 @@ public class CustomerImportService extends AbstractEntityImportService<CustomerI
Customer savedCustomer = customerService.saveCustomer(customer);
return savedCustomer;
EntityImportResult<Customer> importResult = new EntityImportResult<>();
importResult.setSavedEntity(savedCustomer);
importResult.setOldEntity(existingCustomer);
return importResult;
}
@Override

View File

@ -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<Dashboar
@Override
public Dashboard importEntity(TenantId tenantId, DashboardExportData exportData) {
public EntityImportResult<Dashboard> importEntity(TenantId tenantId, DashboardExportData exportData) {
Dashboard dashboard = exportData.getDashboard();
Dashboard existingDashboard = findByExternalId(tenantId, dashboard.getId());
@ -51,7 +52,10 @@ public class DashboardImportService extends AbstractEntityImportService<Dashboar
Dashboard savedDashboard = dashboardService.saveDashboard(dashboard);
return savedDashboard;
EntityImportResult<Dashboard> importResult = new EntityImportResult<>();
importResult.setSavedEntity(savedDashboard);
importResult.setOldEntity(existingDashboard);
return importResult;
}
@Override

View File

@ -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<DeviceId, D
@Transactional
@Override
public Device importEntity(TenantId tenantId, DeviceExportData exportData) {
public EntityImportResult<Device> 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<DeviceId, D
Device savedDevice = deviceService.saveDeviceWithCredentials(device, exportData.getCredentials());
return savedDevice;
EntityImportResult<Device> importResult = new EntityImportResult<>();
importResult.setSavedEntity(savedDevice);
importResult.setOldEntity(existingDevice);
return importResult;
}
@Override

View File

@ -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<Devi
@Override
public DeviceProfile importEntity(TenantId tenantId, DeviceProfileExportData exportData) {
public EntityImportResult<DeviceProfile> importEntity(TenantId tenantId, DeviceProfileExportData exportData) {
DeviceProfile deviceProfile = exportData.getDeviceProfile();
DeviceProfile existingDeviceProfile = findByExternalId(tenantId, deviceProfile.getId());
@ -54,7 +55,10 @@ public class DeviceProfileImportService extends AbstractEntityImportService<Devi
DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
return savedDeviceProfile;
EntityImportResult<DeviceProfile> importResult = new EntityImportResult<>();
importResult.setSavedEntity(savedDeviceProfile);
importResult.setOldEntity(existingDeviceProfile);
return importResult;
}
@Override

View File

@ -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<RuleChai
@Transactional
@Override
public RuleChain importEntity(TenantId tenantId, RuleChainExportData exportData) {
public EntityImportResult<RuleChain> importEntity(TenantId tenantId, RuleChainExportData exportData) {
RuleChain ruleChain = exportData.getRuleChain();
RuleChain existingRuleChain = findByExternalId(tenantId, ruleChain.getId());
@ -69,7 +70,10 @@ public class RuleChainImportService extends AbstractEntityImportService<RuleChai
});
ruleChainService.saveRuleChainMetaData(tenantId, metaData);
return savedRuleChain;
EntityImportResult<RuleChain> importResult = new EntityImportResult<>();
importResult.setSavedEntity(savedRuleChain);
importResult.setOldEntity(existingRuleChain);
return importResult;
}
@Override

View File

@ -43,6 +43,9 @@ import org.thingsboard.server.common.data.id.HasId;
public interface EntityExportData<E extends HasId<? extends EntityId>> {
@JsonIgnore
EntityType getEntityType(); // fixme: maybe remove if not needed, as well as generic
E getMainEntity();
@JsonIgnore
EntityType getEntityType(); // fixme: maybe remove if not needed
}

View File

@ -25,6 +25,11 @@ public class AssetExportData implements EntityExportData<Asset> {
private Asset asset;
@Override
public Asset getMainEntity() {
return asset;
}
@Override
public EntityType getEntityType() {
return EntityType.ASSET;

View File

@ -25,6 +25,11 @@ public class CustomerExportData implements EntityExportData<Customer> {
private Customer customer;
@Override
public Customer getMainEntity() {
return customer;
}
@Override
public EntityType getEntityType() {
return EntityType.CUSTOMER;

View File

@ -25,6 +25,11 @@ public class DashboardExportData implements EntityExportData<Dashboard> {
private Dashboard dashboard;
@Override
public Dashboard getMainEntity() {
return dashboard;
}
@Override
public EntityType getEntityType() {
return EntityType.DASHBOARD;

View File

@ -27,6 +27,11 @@ public class DeviceExportData implements EntityExportData<Device> {
private Device device;
private DeviceCredentials credentials;
@Override
public Device getMainEntity() {
return device;
}
@Override
public EntityType getEntityType() {
return EntityType.DEVICE;

View File

@ -25,6 +25,11 @@ public class DeviceProfileExportData implements EntityExportData<DeviceProfile>
private DeviceProfile deviceProfile;
@Override
public DeviceProfile getMainEntity() {
return deviceProfile;
}
@Override
public EntityType getEntityType() {
return EntityType.DEVICE_PROFILE;

View File

@ -27,6 +27,11 @@ public class RuleChainExportData implements EntityExportData<RuleChain> {
private RuleChain ruleChain;
private RuleChainMetaData metaData;
@Override
public RuleChain getMainEntity() {
return ruleChain;
}
@Override
public EntityType getEntityType() {
return EntityType.RULE_CHAIN;