diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/DefaultExportableEntitiesService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/DefaultExportableEntitiesService.java index 49314e62fd..9779fad66a 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/DefaultExportableEntitiesService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/DefaultExportableEntitiesService.java @@ -108,34 +108,40 @@ public class DefaultExportableEntitiesService implements ExportableEntitiesServi return entity; } + @Override + public , I extends EntityId> E findDefaultEntityByTenantId(TenantId tenantId, EntityType entityType) { + ExportableEntityDao dao = getExportableEntityDao(entityType); + if (dao == null) { + return null; + } + return dao.findDefaultEntityByTenantId(tenantId.getId()); + } + @Override public , I extends EntityId> PageData findEntitiesByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink) { ExportableEntityDao dao = getExportableEntityDao(entityType); - if (dao != null) { - return dao.findByTenantId(tenantId.getId(), pageLink); - } else { - return new PageData<>(); + if (dao == null) { + return PageData.emptyPageData(); } + return dao.findByTenantId(tenantId.getId(), pageLink); } @Override public PageData findEntitiesIdsByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink) { ExportableEntityDao dao = getExportableEntityDao(entityType); - if (dao != null) { - return dao.findIdsByTenantId(tenantId.getId(), pageLink); - } else { - return new PageData<>(); + if (dao == null) { + return PageData.emptyPageData(); } + return dao.findIdsByTenantId(tenantId.getId(), pageLink); } @Override public I getExternalIdByInternal(I internalId) { ExportableEntityDao dao = getExportableEntityDao(internalId.getEntityType()); - if (dao != null) { - return dao.getExternalIdByInternal(internalId); - } else { + if (dao == null) { return null; } + return dao.getExternalIdByInternal(internalId); } private boolean belongsToTenant(HasId entity, TenantId tenantId) { diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/ExportableEntitiesService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/ExportableEntitiesService.java index 5eadec9410..4d726ec44a 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/ExportableEntitiesService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/ExportableEntitiesService.java @@ -33,6 +33,8 @@ public interface ExportableEntitiesService { , I extends EntityId> E findEntityByTenantIdAndName(TenantId tenantId, EntityType entityType, String name); + , I extends EntityId> E findDefaultEntityByTenantId(TenantId tenantId, EntityType entityType); + , I extends EntityId> PageData findEntitiesByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink); PageData findEntitiesIdsByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink); diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java index cf05a35f33..e144fed6c6 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java @@ -27,6 +27,7 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ExportableEntity; +import org.thingsboard.server.common.data.HasDefaultOption; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; @@ -73,7 +74,7 @@ public abstract class BaseEntityImportService Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndId(ctx.getTenantId(), entity.getId()))) + return (E) Optional.ofNullable(entitiesService.findEntityByTenantIdAndExternalId(ctx.getTenantId(), entity.getId())) + .or(() -> Optional.ofNullable(entitiesService.findEntityByTenantIdAndId(ctx.getTenantId(), entity.getId()))) .or(() -> { if (ctx.isFindExistingByName()) { - return Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndName(ctx.getTenantId(), getEntityType(), entity.getName())); + return Optional.ofNullable(entitiesService.findEntityByTenantIdAndName(ctx.getTenantId(), getEntityType(), entity.getName())); } else { return Optional.empty(); } }) + .or(() -> { + if (entity instanceof HasDefaultOption hasDefaultOption) { + if (hasDefaultOption.isDefault()) { + return Optional.ofNullable(entitiesService.findDefaultEntityByTenantId(ctx.getTenantId(), getEntityType())); + } + } + return Optional.empty(); + }) .orElse(null); } @SuppressWarnings("unchecked") private HasId findInternalEntity(TenantId tenantId, ID externalId) { - return (HasId) Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndExternalId(tenantId, externalId)) - .or(() -> Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndId(tenantId, externalId))) + return (HasId) Optional.ofNullable(entitiesService.findEntityByTenantIdAndExternalId(tenantId, externalId)) + .or(() -> Optional.ofNullable(entitiesService.findEntityByTenantIdAndId(tenantId, externalId))) .orElseThrow(() -> new MissingEntityException(externalId)); } diff --git a/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java b/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java index b07fe34089..f20f1d5370 100644 --- a/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java @@ -532,20 +532,19 @@ public class ExportImportServiceSqlTest extends BaseExportImportServiceTest { @Test - public void testExportImportDeviceProfile_betweenTenants_findExistingByName() throws Exception { + public void testExportImportDefaultDeviceProfile_betweenTenants_findExisting() throws Exception { DeviceProfile defaultDeviceProfile = deviceProfileService.findDefaultDeviceProfile(tenantId1); + defaultDeviceProfile.setName("non-default-name"); + deviceProfileService.saveDeviceProfile(defaultDeviceProfile); EntityExportData deviceProfileExportData = exportEntity(tenantAdmin1, defaultDeviceProfile.getId()); - assertThatThrownBy(() -> { - importEntity(tenantAdmin2, deviceProfileExportData, EntityImportSettings.builder() - .findExistingByName(false) - .build()); - }).hasMessageContaining("default device profile is present"); - importEntity(tenantAdmin2, deviceProfileExportData, EntityImportSettings.builder() - .findExistingByName(true) + .findExistingByName(false) .build()); - checkImportedEntity(tenantId1, defaultDeviceProfile, tenantId2, deviceProfileService.findDefaultDeviceProfile(tenantId2)); + DeviceProfile importedDeviceProfile = deviceProfileService.findDefaultDeviceProfile(tenantId2); + assertThat(importedDeviceProfile.isDefault()).isTrue(); + assertThat(importedDeviceProfile.getName()).isEqualTo(defaultDeviceProfile.getName()); + checkImportedEntity(tenantId1, defaultDeviceProfile, tenantId2, importedDeviceProfile); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index 264dd0a29e..6791a460ed 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -18,6 +18,7 @@ package org.thingsboard.server.common.data; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.JsonProcessingException; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -33,7 +34,6 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; -import jakarta.validation.Valid; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -42,7 +42,7 @@ import java.io.IOException; @ToString(exclude = {"image", "profileDataBytes"}) @EqualsAndHashCode(callSuper = true) @Slf4j -public class DeviceProfile extends BaseData implements HasName, HasTenantId, HasOtaPackage, HasRuleEngineProfile, ExportableEntity, HasImage { +public class DeviceProfile extends BaseData implements HasName, HasTenantId, HasOtaPackage, HasRuleEngineProfile, ExportableEntity, HasImage, HasDefaultOption { private static final long serialVersionUID = 6998485460273302018L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/HasDefaultOption.java b/common/data/src/main/java/org/thingsboard/server/common/data/HasDefaultOption.java new file mode 100644 index 0000000000..6eeae38d6c --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HasDefaultOption.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2024 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.common.data; + +public interface HasDefaultOption { + + boolean isDefault(); + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfile.java index 2eb98a604a..91563c0f2d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfile.java @@ -22,6 +22,7 @@ import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.ExportableEntity; +import org.thingsboard.server.common.data.HasDefaultOption; import org.thingsboard.server.common.data.HasImage; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasRuleEngineProfile; @@ -38,7 +39,7 @@ import org.thingsboard.server.common.data.validation.NoXss; @ToString(exclude = {"image"}) @EqualsAndHashCode(callSuper = true) @Slf4j -public class AssetProfile extends BaseData implements HasName, HasTenantId, HasRuleEngineProfile, ExportableEntity, HasImage { +public class AssetProfile extends BaseData implements HasName, HasTenantId, HasRuleEngineProfile, ExportableEntity, HasImage, HasDefaultOption { private static final long serialVersionUID = 6998485460273302018L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java index c293e6f570..5448fcd259 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java @@ -23,6 +23,7 @@ import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.BaseDataWithAdditionalInfo; import org.thingsboard.server.common.data.ExportableEntity; +import org.thingsboard.server.common.data.HasDefaultOption; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.RuleChainId; @@ -35,7 +36,7 @@ import org.thingsboard.server.common.data.validation.NoXss; @Data @EqualsAndHashCode(callSuper = true) @Slf4j -public class RuleChain extends BaseDataWithAdditionalInfo implements HasName, HasTenantId, ExportableEntity { +public class RuleChain extends BaseDataWithAdditionalInfo implements HasName, HasTenantId, ExportableEntity, HasDefaultOption { private static final long serialVersionUID = -5656679015121935465L; @@ -108,4 +109,10 @@ public class RuleChain extends BaseDataWithAdditionalInfo implement setJson(data, json -> this.configuration = json, bytes -> this.configurationBytes = bytes); } + @JsonIgnore + @Override + public boolean isDefault() { + return root && type == RuleChainType.CORE; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityDao.java b/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityDao.java index c800f5a0e3..7830024546 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ExportableEntityDao.java @@ -36,4 +36,6 @@ public interface ExportableEntityDao findByTenantAndImageLink(TenantId tenantId, String imageLink, int limit) { return assetProfileRepository.findByTenantAndImageLink(tenantId.getId(), imageLink, PageRequest.of(0, limit)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java index 2bf326a455..0f597756eb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceProfileDao.java @@ -150,6 +150,11 @@ public class JpaDeviceProfileDao extends JpaAbstractDao findByTenantAndImageLink(TenantId tenantId, String imageLink, int limit) { return deviceProfileRepository.findByTenantAndImageLink(tenantId.getId(), imageLink, PageRequest.of(0, limit)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java index a59b722695..46232c5bbb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java @@ -129,6 +129,11 @@ public class JpaRuleChainDao extends JpaAbstractDao .map(RuleChainId::new).orElse(null); } + @Override + public RuleChain findDefaultEntityByTenantId(UUID tenantId) { + return findRootRuleChainByTenantIdAndType(tenantId, RuleChainType.CORE); + } + @Override public EntityType getEntityType() { return EntityType.RULE_CHAIN;