Fix import/export of rule chains and dashboard with external id references

This commit is contained in:
Andrii Shvaika 2022-06-20 12:00:21 +03:00
parent 5cad77910f
commit bdd8432049
6 changed files with 27 additions and 40 deletions

View File

@ -45,10 +45,8 @@ public class DashboardExportService extends BaseEntityExportService<DashboardId,
customerInfo.setCustomerId(getExternalIdOrElseInternal(ctx, customerInfo.getCustomerId()));
});
}
if (dashboard.getEntityAliasesConfig() != null) {
for (JsonNode entityAlias : dashboard.getEntityAliasesConfig()) {
replaceUuidsRecursively(ctx, entityAlias, Collections.singleton("id"));
}
replaceUuidsRecursively(ctx, entityAlias, Collections.emptySet());
}
for (JsonNode widgetConfig : dashboard.getWidgetsConfig()) {
replaceUuidsRecursively(ctx, JacksonUtil.getSafely(widgetConfig, "config", "actions"), Collections.singleton("id"));

View File

@ -51,12 +51,7 @@ public class RuleChainExportService extends BaseEntityExportService<RuleChainId,
ruleNode.setId(ctx.getExternalId(ruleNode.getId()));
ruleNode.setCreatedTime(0);
ruleNode.setExternalId(null);
JsonNode ruleNodeConfig = ruleNode.getConfiguration();
String newRuleNodeConfigJson = RegexUtils.replace(JacksonUtil.toString(ruleNodeConfig), RegexUtils.UUID_PATTERN, uuid -> {
return getExternalIdOrElseInternalByUuid(ctx, UUID.fromString(uuid)).toString();
});
ruleNodeConfig = JacksonUtil.toJsonNode(newRuleNodeConfigJson);
ruleNode.setConfiguration(ruleNodeConfig);
replaceUuidsRecursively(ctx, ruleNode.getConfiguration(), Collections.emptySet());
});
Optional.ofNullable(metaData.getRuleChainConnections()).orElse(Collections.emptyList())
.forEach(ruleChainConnectionInfo -> {

View File

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.service.sync.ie.importing.impl;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.api.client.util.Objects;
import com.google.common.util.concurrent.FutureCallback;
import lombok.RequiredArgsConstructor;
@ -23,6 +24,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
@ -53,11 +55,13 @@ import org.thingsboard.server.service.entitiy.TbNotificationEntityService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
import org.thingsboard.server.service.sync.ie.importing.EntityImportService;
import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@ -386,4 +390,9 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
return oldEntity == null ? null : getter.apply(oldEntity);
}
protected void replaceIdsRecursively(EntitiesImportCtx ctx, IdProvider idProvider, JsonNode entityAlias, Set<String> skipFieldsSet, LinkedHashSet<EntityType> hints) {
JacksonUtil.replaceUuidsRecursively(entityAlias, skipFieldsSet,
uuid -> idProvider.getInternalIdByUuid(uuid, ctx.isFinalImportAttempt(), hints).map(EntityId::getId).orElse(uuid));
}
}

View File

@ -28,6 +28,7 @@ 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.DashboardId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.dao.dashboard.DashboardService;
@ -72,21 +73,11 @@ public class DashboardImportService extends BaseEntityImportService<DashboardId,
@Override
protected Dashboard prepare(EntitiesImportCtx ctx, Dashboard dashboard, Dashboard old, EntityExportData<Dashboard> exportData, IdProvider idProvider) {
JsonNode configuration = dashboard.getConfiguration();
JsonNode entityAliases = configuration.get("entityAliases");
if (entityAliases != null && entityAliases.isObject()) {
for (JsonNode entityAlias : entityAliases) {
ArrayList<String> fields = Lists.newArrayList(entityAlias.fieldNames());
for (String field : fields) {
if (field.equals("id")) continue;
JsonNode oldFieldValue = entityAlias.get(field);
JsonNode newFieldValue = JacksonUtil.toJsonNode(RegexUtils.replace(oldFieldValue.toString(), RegexUtils.UUID_PATTERN, uuid -> {
return idProvider.getInternalIdByUuid(UUID.fromString(uuid), ctx.isFinalImportAttempt(), HINTS)
.map(entityId -> entityId.getId().toString()).orElse(uuid);
}));
((ObjectNode) entityAlias).set(field, newFieldValue);
}
for (JsonNode entityAlias : dashboard.getEntityAliasesConfig()) {
replaceIdsRecursively(ctx, idProvider, entityAlias, Collections.emptySet(), HINTS);
}
for (JsonNode widgetConfig : dashboard.getWidgetsConfig()) {
replaceIdsRecursively(ctx, idProvider, JacksonUtil.getSafely(widgetConfig, "config", "actions"), Collections.singleton("id"), HINTS);
}
return dashboard;
}

View File

@ -93,16 +93,7 @@ public class RuleChainImportService extends BaseEntityImportService<RuleChainId,
});
}
ruleNodes.forEach(ruleNode -> {
JsonNode ruleNodeConfig = ruleNode.getConfiguration();
String newRuleNodeConfigJson = RegexUtils.replace(JacksonUtil.toString(ruleNodeConfig), RegexUtils.UUID_PATTERN, uuid -> {
return idProvider.getInternalIdByUuid(UUID.fromString(uuid), ctx.isFinalImportAttempt(), HINTS)
.map(entityId -> entityId.getId().toString())
.orElse(uuid);
});
ruleNodeConfig = JacksonUtil.toJsonNode(newRuleNodeConfigJson);
ruleNode.setConfiguration(ruleNodeConfig);
});
ruleNodes.forEach(ruleNode -> replaceIdsRecursively(ctx, idProvider, ruleNode.getConfiguration(), Collections.emptySet(), HINTS));
Optional.ofNullable(metaData.getRuleChainConnections()).orElse(Collections.emptyList())
.forEach(ruleChainConnectionInfo -> {
ruleChainConnectionInfo.setTargetRuleChainId(idProvider.getInternalId(ruleChainConnectionInfo.getTargetRuleChainId(), false));

View File

@ -73,16 +73,19 @@ public class Dashboard extends DashboardInfo implements ExportableEntity<Dashboa
}
@JsonIgnore
public ObjectNode getEntityAliasesConfig() {
return (ObjectNode) Optional.ofNullable(configuration)
.map(config -> config.get("entityAliases"))
.filter(JsonNode::isObject).orElse(null);
public List<ObjectNode> getEntityAliasesConfig() {
return getChildObjects("entityAliases");
}
@JsonIgnore
public List<ObjectNode> getWidgetsConfig() {
return getChildObjects("widgets");
}
@JsonIgnore
private List<ObjectNode> getChildObjects(String propertyName) {
return Optional.ofNullable(configuration)
.map(config -> config.get("widgets"))
.map(config -> config.get(propertyName))
.filter(node -> !node.isEmpty())
.map(node -> (ObjectNode) node)
.map(object -> {