Improvements for relations import

This commit is contained in:
Viacheslav Klimov 2022-04-21 14:34:55 +03:00
parent a5cdbca690
commit 832f32fbe1
5 changed files with 69 additions and 79 deletions

View File

@ -43,7 +43,6 @@ public class EntityExportData<E extends ExportableEntity<? extends EntityId>> {
private E entity; private E entity;
private EntityType entityType; private EntityType entityType;
private List<EntityRelation> inboundRelations; private List<EntityRelation> relations;
private List<EntityRelation> outboundRelations;
} }

View File

@ -33,6 +33,7 @@ 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.EntityExportData;
import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings; import org.thingsboard.server.service.sync.exporting.data.request.EntityExportSettings;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@Service @Service
@ -63,24 +64,25 @@ public class DefaultEntityExportService<I extends EntityId, E extends Exportable
} }
protected void setAdditionalExportData(SecurityUser user, E entity, D exportData, EntityExportSettings exportSettings) throws ThingsboardException { protected void setAdditionalExportData(SecurityUser user, E entity, D exportData, EntityExportSettings exportSettings) throws ThingsboardException {
List<EntityRelation> relations = null;
if (exportSettings.isExportInboundRelations()) { if (exportSettings.isExportInboundRelations()) {
List<EntityRelation> inboundRelations = relationService.findByTo(user.getTenantId(), entity.getId(), RelationTypeGroup.COMMON); List<EntityRelation> inboundRelations = relationService.findByTo(user.getTenantId(), entity.getId(), RelationTypeGroup.COMMON);
if (inboundRelations != null) { for (EntityRelation relation : inboundRelations) {
for (EntityRelation relation : inboundRelations) { exportableEntitiesService.checkPermission(user, relation.getFrom(), Operation.READ);
exportableEntitiesService.checkPermission(user, relation.getFrom(), Operation.READ);
}
} }
exportData.setInboundRelations(inboundRelations); relations = new ArrayList<>(inboundRelations);
} }
if (exportSettings.isExportOutboundRelations()) { if (exportSettings.isExportOutboundRelations()) {
List<EntityRelation> outboundRelations = relationService.findByFrom(user.getTenantId(), entity.getId(), RelationTypeGroup.COMMON); List<EntityRelation> outboundRelations = relationService.findByFrom(user.getTenantId(), entity.getId(), RelationTypeGroup.COMMON);
if (outboundRelations != null) { for (EntityRelation relation : outboundRelations) {
for (EntityRelation relation : outboundRelations) { exportableEntitiesService.checkPermission(user, relation.getTo(), Operation.READ);
exportableEntitiesService.checkPermission(user, relation.getTo(), Operation.READ);
}
} }
exportData.setOutboundRelations(outboundRelations); if (relations == null) {
relations = new ArrayList<>();
}
relations.addAll(outboundRelations);
} }
exportData.setRelations(relations);
} }
protected D newExportData() { protected D newExportData() {

View File

@ -26,8 +26,5 @@ import lombok.NoArgsConstructor;
@Builder @Builder
public class EntityImportSettings { public class EntityImportSettings {
private boolean findExistingByName; private boolean findExistingByName;
private boolean updateRelations;
private boolean importInboundRelations;
private boolean importOutboundRelations;
private boolean removeExistingRelations;
} }

View File

@ -16,7 +16,6 @@
package org.thingsboard.server.service.sync.importing.impl; package org.thingsboard.server.service.sync.importing.impl;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -40,10 +39,9 @@ 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.EntityImportResult;
import org.thingsboard.server.service.sync.importing.data.EntityImportSettings; import org.thingsboard.server.service.sync.importing.data.EntityImportSettings;
import java.util.LinkedList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
public abstract class BaseEntityImportService<I extends EntityId, E extends ExportableEntity<I>, D extends EntityExportData<E>> implements EntityImportService<I, E, D> { public abstract class BaseEntityImportService<I extends EntityId, E extends ExportableEntity<I>, D extends EntityExportData<E>> implements EntityImportService<I, E, D> {
@ -102,47 +100,53 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
}); });
importResult.addSaveReferencesCallback(() -> { importResult.addSaveReferencesCallback(() -> {
List<EntityRelation> newRelations = new LinkedList<>(); List<EntityRelation> relations = exportData.getRelations();
if (relations == null || !importSettings.isUpdateRelations()) {
if (importSettings.isImportInboundRelations() && CollectionUtils.isNotEmpty(exportData.getInboundRelations())) { return;
newRelations.addAll(exportData.getInboundRelations().stream()
.peek(relation -> relation.setTo(savedEntity.getId()))
.collect(Collectors.toList()));
if (importSettings.isRemoveExistingRelations() && oldEntity != null) {
for (EntityRelation existingRelation : relationService.findByTo(user.getTenantId(), savedEntity.getId(), RelationTypeGroup.COMMON)) {
exportableEntitiesService.checkPermission(user, existingRelation.getFrom(), Operation.WRITE);
deleteRelation(user, existingRelation, importResult);
}
}
} }
if (importSettings.isImportOutboundRelations() && CollectionUtils.isNotEmpty(exportData.getOutboundRelations())) { relations = new ArrayList<>(relations);
newRelations.addAll(exportData.getOutboundRelations().stream()
.peek(relation -> relation.setFrom(savedEntity.getId()))
.collect(Collectors.toList()));
if (importSettings.isRemoveExistingRelations() && oldEntity != null) { for (EntityRelation relation : relations) {
for (EntityRelation existingRelation : relationService.findByFrom(user.getTenantId(), savedEntity.getId(), RelationTypeGroup.COMMON)) {
exportableEntitiesService.checkPermission(user, existingRelation.getTo(), Operation.WRITE);
deleteRelation(user, existingRelation, importResult);
}
}
}
for (EntityRelation relation : newRelations) {
HasId<EntityId> otherEntity = null;
if (!relation.getTo().equals(savedEntity.getId())) { if (!relation.getTo().equals(savedEntity.getId())) {
otherEntity = findInternalEntity(user.getTenantId(), relation.getTo()); HasId<EntityId> to = findInternalEntity(user.getTenantId(), relation.getTo());
relation.setTo(otherEntity.getId()); exportableEntitiesService.checkPermission(user, to, to.getId().getEntityType(), Operation.WRITE);
relation.setTo(to.getId());
} }
if (!relation.getFrom().equals(savedEntity.getId())) { if (!relation.getFrom().equals(savedEntity.getId())){
otherEntity = findInternalEntity(user.getTenantId(), relation.getFrom()); HasId<EntityId> from = findInternalEntity(user.getTenantId(), relation.getFrom());
relation.setFrom(otherEntity.getId()); exportableEntitiesService.checkPermission(user, from, from.getId().getEntityType(), Operation.WRITE);
} relation.setFrom(from.getId());
if (otherEntity != null) {
exportableEntitiesService.checkPermission(user, otherEntity, otherEntity.getId().getEntityType(), Operation.WRITE);
} }
}
if (oldEntity != null) {
List<EntityRelation> existingRelations = new ArrayList<>();
existingRelations.addAll(relationService.findByTo(user.getTenantId(), savedEntity.getId(), RelationTypeGroup.COMMON));
existingRelations.addAll(relationService.findByFrom(user.getTenantId(), savedEntity.getId(), RelationTypeGroup.COMMON));
for (EntityRelation existingRelation : existingRelations) {
if (!relations.contains(existingRelation)) {
EntityId otherEntity = null;
if (!existingRelation.getTo().equals(savedEntity.getId())) {
otherEntity = existingRelation.getTo();
} else if (!existingRelation.getFrom().equals(savedEntity.getId())){
otherEntity = existingRelation.getFrom();
}
if (otherEntity != null) {
exportableEntitiesService.checkPermission(user, otherEntity, Operation.WRITE);
}
relationService.deleteRelation(user.getTenantId(), existingRelation);
importResult.addSendEventsCallback(() -> {
entityActionService.logEntityAction(user, existingRelation.getFrom(), null, null,
ActionType.RELATION_DELETED, null, existingRelation);
entityActionService.logEntityAction(user, existingRelation.getTo(), null, null,
ActionType.RELATION_DELETED, null, existingRelation);
});
}
}
}
for (EntityRelation relation : relations) {
relationService.saveRelation(user.getTenantId(), relation); relationService.saveRelation(user.getTenantId(), relation);
importResult.addSendEventsCallback(() -> { importResult.addSendEventsCallback(() -> {
entityActionService.logEntityAction(user, relation.getFrom(), null, null, entityActionService.logEntityAction(user, relation.getFrom(), null, null,
@ -154,17 +158,6 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
}); });
} }
private void deleteRelation(SecurityUser user, EntityRelation relation, EntityImportResult<E> importResult) {
relationService.deleteRelation(user.getTenantId(), relation);
importResult.addSendEventsCallback(() -> {
entityActionService.logEntityAction(user, relation.getFrom(), null, null,
ActionType.RELATION_DELETED, null, relation);
entityActionService.logEntityAction(user, relation.getTo(), null, null,
ActionType.RELATION_DELETED, null, relation);
});
}
protected void onEntitySaved(SecurityUser user, E savedEntity, E oldEntity) throws ThingsboardException { protected void onEntitySaved(SecurityUser user, E savedEntity, E oldEntity) throws ThingsboardException {
entityActionService.logEntityAction(user, savedEntity.getId(), savedEntity, entityActionService.logEntityAction(user, savedEntity.getId(), savedEntity,
savedEntity instanceof HasCustomerId ? ((HasCustomerId) savedEntity).getCustomerId() : user.getCustomerId(), savedEntity instanceof HasCustomerId ? ((HasCustomerId) savedEntity).getCustomerId() : user.getCustomerId(),

View File

@ -311,7 +311,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
Dashboard importedDashboard = (Dashboard) importResults.get(EntityType.DASHBOARD).get(0).getSavedEntity(); Dashboard importedDashboard = (Dashboard) importResults.get(EntityType.DASHBOARD).get(0).getSavedEntity();
Set<String> entityAliasEntitiesIds = Streams.stream(importedDashboard.getConfiguration() Set<String> entityAliasEntitiesIds = Streams.stream(importedDashboard.getConfiguration()
.get("entityAliases").elements().next().get("filter").get("entityList").elements()) .get("entityAliases").elements().next().get("filter").get("entityList").elements())
.map(JsonNode::asText).collect(Collectors.toSet()); .map(JsonNode::asText).collect(Collectors.toSet());
assertThat(entityAliasEntitiesIds).doesNotContain(asset1.getId().toString(), asset2.getId().toString()); assertThat(entityAliasEntitiesIds).doesNotContain(asset1.getId().toString(), asset2.getId().toString());
assertThat(entityAliasEntitiesIds).contains(importedAsset1.getId().toString(), importedAsset2.getId().toString()); assertThat(entityAliasEntitiesIds).contains(importedAsset1.getId().toString(), importedAsset2.getId().toString());
@ -427,8 +427,8 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
List<EntityExportData<?>> exportDataList = exportEntities(exportRequest); List<EntityExportData<?>> exportDataList = exportEntities(exportRequest);
EntityExportData<?> deviceExportData = exportDataList.stream().filter(exportData -> exportData.getEntityType() == EntityType.DEVICE).findFirst().orElse(null); EntityExportData<?> deviceExportData = exportDataList.stream().filter(exportData -> exportData.getEntityType() == EntityType.DEVICE).findFirst().orElse(null);
assertThat(deviceExportData.getInboundRelations()).size().isOne(); assertThat(deviceExportData.getRelations()).size().isOne();
assertThat(deviceExportData.getInboundRelations().get(0)).matches(entityRelation -> { assertThat(deviceExportData.getRelations().get(0)).matches(entityRelation -> {
return entityRelation.getFrom().equals(asset.getId()) && entityRelation.getTo().equals(device.getId()); return entityRelation.getFrom().equals(asset.getId()) && entityRelation.getTo().equals(device.getId());
}); });
((DeviceExportData) deviceExportData).getCredentials().setCredentialsId("ab"); ((DeviceExportData) deviceExportData).getCredentials().setCredentialsId("ab");
@ -439,7 +439,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
ImportRequest importRequest = new ImportRequest(); ImportRequest importRequest = new ImportRequest();
importRequest.setExportDataList(exportDataList); importRequest.setExportDataList(exportDataList);
importRequest.setImportSettings(EntityImportSettings.builder() importRequest.setImportSettings(EntityImportSettings.builder()
.importInboundRelations(true) .updateRelations(true)
.build()); .build());
Map<EntityType, EntityImportResult<?>> importResults = importEntities(importRequest).stream().collect(Collectors.toMap(EntityImportResult::getEntityType, r -> r)); Map<EntityType, EntityImportResult<?>> importResults = importEntities(importRequest).stream().collect(Collectors.toMap(EntityImportResult::getEntityType, r -> r));
@ -473,7 +473,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
.build()); .build());
List<EntityExportData<?>> exportDataList = exportEntities(exportRequest); List<EntityExportData<?>> exportDataList = exportEntities(exportRequest);
assertThat(exportDataList).allMatch(exportData -> exportData.getInboundRelations().size() + exportData.getOutboundRelations().size() == 1); assertThat(exportDataList).allMatch(exportData -> exportData.getRelations().size() == 1);
EntityExportData<?> deviceExportData = exportDataList.stream().filter(exportData -> exportData.getEntityType() == EntityType.DEVICE).findFirst().orElse(null); EntityExportData<?> deviceExportData = exportDataList.stream().filter(exportData -> exportData.getEntityType() == EntityType.DEVICE).findFirst().orElse(null);
((DeviceExportData) deviceExportData).getCredentials().setCredentialsId("ab"); ((DeviceExportData) deviceExportData).getCredentials().setCredentialsId("ab");
@ -484,8 +484,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
ImportRequest importRequest = new ImportRequest(); ImportRequest importRequest = new ImportRequest();
importRequest.setExportDataList(exportDataList); importRequest.setExportDataList(exportDataList);
importRequest.setImportSettings(EntityImportSettings.builder() importRequest.setImportSettings(EntityImportSettings.builder()
.importInboundRelations(true) .updateRelations(true)
.importOutboundRelations(true)
.build()); .build());
Map<EntityType, EntityImportResult<?>> importResults = importEntities(importRequest).stream().collect(Collectors.toMap(EntityImportResult::getEntityType, r -> r)); Map<EntityType, EntityImportResult<?>> importResults = importEntities(importRequest).stream().collect(Collectors.toMap(EntityImportResult::getEntityType, r -> r));
@ -515,7 +514,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
.exportOutboundRelations(true) .exportOutboundRelations(true)
.build()); .build());
EntityExportData<Asset> assetExportData = (EntityExportData<Asset>) exportEntities(exportRequest).get(0); EntityExportData<Asset> assetExportData = (EntityExportData<Asset>) exportEntities(exportRequest).get(0);
assertThat(assetExportData.getOutboundRelations()).size().isOne(); assertThat(assetExportData.getRelations()).size().isOne();
Device device2 = createDevice(tenantId1, null, null, "Device 2"); Device device2 = createDevice(tenantId1, null, null, "Device 2");
EntityRelation relation2 = createRelation(asset.getId(), device2.getId()); EntityRelation relation2 = createRelation(asset.getId(), device2.getId());
@ -523,13 +522,14 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
ImportRequest importRequest = new ImportRequest(); ImportRequest importRequest = new ImportRequest();
importRequest.setExportDataList(List.of(assetExportData)); importRequest.setExportDataList(List.of(assetExportData));
importRequest.setImportSettings(EntityImportSettings.builder() importRequest.setImportSettings(EntityImportSettings.builder()
.importOutboundRelations(true) .updateRelations(true)
.build()); .build());
importEntities(importRequest); importEntities(importRequest);
List<EntityRelation> relations = relationService.findByFrom(TenantId.SYS_TENANT_ID, asset.getId(), RelationTypeGroup.COMMON); List<EntityRelation> relations = relationService.findByFrom(TenantId.SYS_TENANT_ID, asset.getId(), RelationTypeGroup.COMMON);
assertThat(relations).contains(relation1, relation2); assertThat(relations).contains(relation1);
assertThat(relations).doesNotContain(relation2);
} }
@Test @Test
@ -546,7 +546,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
.exportInboundRelations(true) .exportInboundRelations(true)
.build()); .build());
EntityExportData<?> deviceExportData = exportEntities(exportRequest).get(0); EntityExportData<?> deviceExportData = exportEntities(exportRequest).get(0);
assertThat(deviceExportData.getInboundRelations()).size().isOne(); assertThat(deviceExportData.getRelations()).size().isOne();
Asset asset2 = createAsset(tenantId1, null, "A", "Asset 2"); Asset asset2 = createAsset(tenantId1, null, "A", "Asset 2");
EntityRelation relation2 = createRelation(asset2.getId(), device.getId()); EntityRelation relation2 = createRelation(asset2.getId(), device.getId());
@ -554,8 +554,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
ImportRequest importRequest = new ImportRequest(); ImportRequest importRequest = new ImportRequest();
importRequest.setExportDataList(List.of(deviceExportData)); importRequest.setExportDataList(List.of(deviceExportData));
importRequest.setImportSettings(EntityImportSettings.builder() importRequest.setImportSettings(EntityImportSettings.builder()
.importInboundRelations(true) .updateRelations(true)
.removeExistingRelations(true)
.build()); .build());
importEntities(importRequest); importEntities(importRequest);
@ -730,7 +729,7 @@ public class EntitiesExportImportControllerSqlTest extends BaseEntitiesExportImp
verify(clusterService).sendNotificationMsgToEdgeService(any(), any(), eq(importedDeviceProfile.getId()), any(), any(), eq(EdgeEventActionType.ADDED)); verify(clusterService).sendNotificationMsgToEdgeService(any(), any(), eq(importedDeviceProfile.getId()), any(), any(), eq(EdgeEventActionType.ADDED));
verify(otaPackageStateService).update(eq(importedDeviceProfile), eq(false), eq(false)); verify(otaPackageStateService).update(eq(importedDeviceProfile), eq(false), eq(false));
((DeviceExportData)entitiesExportData.get(EntityType.DEVICE)).getCredentials().setCredentialsId("abc"); ((DeviceExportData) entitiesExportData.get(EntityType.DEVICE)).getCredentials().setCredentialsId("abc");
Device importedDevice = (Device) importEntity(entitiesExportData.get(EntityType.DEVICE)).getSavedEntity(); Device importedDevice = (Device) importEntity(entitiesExportData.get(EntityType.DEVICE)).getSavedEntity();
verify(entityActionService).logEntityAction(any(), eq(importedDevice.getId()), eq(importedDevice), verify(entityActionService).logEntityAction(any(), eq(importedDevice.getId()), eq(importedDevice),
any(), eq(ActionType.ADDED), isNull()); any(), eq(ActionType.ADDED), isNull());