added logic update to the rule nodes upgrade script
This commit is contained in:
parent
5831876b8e
commit
21e5a1a130
@ -258,6 +258,7 @@ public class ThingsboardInstallService {
|
||||
installScripts.loadSystemLwm2mResources();
|
||||
case "3.5.0":
|
||||
log.info("Upgrading ThingsBoard from version 3.5.0 to 3.5.1 ...");
|
||||
databaseEntitiesUpgradeService.upgradeDatabase("3.5.0");
|
||||
dataUpdateService.updateData("3.5.0");
|
||||
log.info("Updating system data...");
|
||||
systemDataLoaderService.updateSystemWidgets();
|
||||
|
||||
@ -713,6 +713,25 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
|
||||
log.error("Failed updating schema!!!", e);
|
||||
}
|
||||
break;
|
||||
case "3.5.0":
|
||||
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
|
||||
log.info("Updating schema ...");
|
||||
if (isOldSchema(conn, 3005000)) {
|
||||
try {
|
||||
conn.createStatement().execute("ALTER TABLE rule_node ADD COLUMN IF NOT EXISTS configuration_version int DEFAULT 0;");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
conn.createStatement().execute("CREATE INDEX IF NOT EXISTS idx_rule_node_type_configuration_version ON rule_node(type, configuration_version);");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3005001;");
|
||||
}
|
||||
log.info("Schema updated.");
|
||||
} catch (Exception e) {
|
||||
log.error("Failed updating schema!!!", e);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
|
||||
}
|
||||
|
||||
@ -22,22 +22,19 @@ import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.TbNode;
|
||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.VersionedNode;
|
||||
import org.thingsboard.rule.engine.flow.TbRuleChainInputNode;
|
||||
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration;
|
||||
import org.thingsboard.rule.engine.metadata.TbFetchDeviceCredentialsNode;
|
||||
import org.thingsboard.rule.engine.metadata.TbGetAttributesNode;
|
||||
import org.thingsboard.rule.engine.metadata.TbGetCustomerAttributeNode;
|
||||
import org.thingsboard.rule.engine.metadata.TbGetCustomerDetailsNode;
|
||||
import org.thingsboard.rule.engine.metadata.TbGetDeviceAttrNode;
|
||||
import org.thingsboard.rule.engine.metadata.TbGetOriginatorFieldsNode;
|
||||
import org.thingsboard.rule.engine.metadata.TbGetRelatedAttributeNode;
|
||||
import org.thingsboard.rule.engine.metadata.TbGetTenantAttributeNode;
|
||||
import org.thingsboard.rule.engine.metadata.TbGetTenantDetailsNode;
|
||||
import org.thingsboard.rule.engine.profile.TbDeviceProfileNode;
|
||||
import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration;
|
||||
import org.thingsboard.server.common.data.DataConstants;
|
||||
@ -73,6 +70,7 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData;
|
||||
import org.thingsboard.server.common.data.rule.RuleChainType;
|
||||
import org.thingsboard.server.common.data.rule.RuleNode;
|
||||
import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
import org.thingsboard.server.dao.DaoUtil;
|
||||
import org.thingsboard.server.dao.alarm.AlarmDao;
|
||||
import org.thingsboard.server.dao.audit.AuditLogDao;
|
||||
@ -92,10 +90,13 @@ import org.thingsboard.server.service.install.InstallScripts;
|
||||
import org.thingsboard.server.service.install.SystemDataLoaderService;
|
||||
import org.thingsboard.server.service.install.TbRuleEngineQueueConfigService;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.stream.Collectors;
|
||||
@ -107,6 +108,9 @@ import static org.thingsboard.server.common.data.StringUtils.isBlank;
|
||||
@Slf4j
|
||||
public class DefaultDataUpdateService implements DataUpdateService {
|
||||
|
||||
@Value("${plugins.scan_packages}")
|
||||
private String[] scanPackages;
|
||||
|
||||
@Autowired
|
||||
private TenantService tenantService;
|
||||
|
||||
@ -217,55 +221,96 @@ public class DefaultDataUpdateService implements DataUpdateService {
|
||||
break;
|
||||
case "3.5.0":
|
||||
log.info("Updating data from version 3.5.0 to 3.5.1 ...");
|
||||
log.info("Starting enrichment rule nodes update ...");
|
||||
upgradeEnrichmentRuleNodesWithFetchTo();
|
||||
log.info("Finished enrichment rule nodes update!");
|
||||
upgradeRuleNodes();
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion);
|
||||
}
|
||||
}
|
||||
|
||||
private void upgradeEnrichmentRuleNodesWithFetchTo() {
|
||||
private void upgradeRuleNodes() {
|
||||
var ruleChainIdToTenantIdMap = new HashMap<RuleChainId, TenantId>();
|
||||
try {
|
||||
var ruleChainIdToTenantId = new HashMap<RuleChainId, TenantId>();
|
||||
upgradeRuleNode(ruleChainIdToTenantId, new TbGetOriginatorFieldsNode());
|
||||
upgradeRuleNode(ruleChainIdToTenantId, new TbGetRelatedAttributeNode());
|
||||
upgradeRuleNode(ruleChainIdToTenantId, new TbGetTenantAttributeNode());
|
||||
upgradeRuleNode(ruleChainIdToTenantId, new TbGetCustomerAttributeNode());
|
||||
upgradeRuleNode(ruleChainIdToTenantId, new TbGetAttributesNode());
|
||||
upgradeRuleNode(ruleChainIdToTenantId, new TbGetDeviceAttrNode());
|
||||
upgradeRuleNode(ruleChainIdToTenantId, new TbGetCustomerDetailsNode());
|
||||
upgradeRuleNode(ruleChainIdToTenantId, new TbGetTenantDetailsNode());
|
||||
upgradeRuleNode(ruleChainIdToTenantId, new TbFetchDeviceCredentialsNode());
|
||||
} catch (Exception e) {
|
||||
log.error("Unexpected error during enrichment rule nodes updating!", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void upgradeRuleNode(HashMap<RuleChainId, TenantId> ruleChainIdToTenantId, VersionedNode versionedNode) {
|
||||
var ruleNodes = new PageDataIterable<>(
|
||||
pageLink -> ruleChainService.findAllRuleNodesByType(versionedNode.getClass().getName(), pageLink), 1024
|
||||
log.info("Starting rule nodes upgrade ...");
|
||||
var ruleNodeDefinitions = getBeanDefinitions(
|
||||
org.thingsboard.rule.engine.api.RuleNode.class
|
||||
);
|
||||
ruleNodes.forEach(ruleNode -> {
|
||||
var upgradeRuleNodeConfigurationResult = versionedNode.upgrade(ruleNode.getId(), ruleNode.getConfiguration());
|
||||
for (BeanDefinition def : ruleNodeDefinitions) {
|
||||
String clazzName = def.getBeanClassName();
|
||||
Class<?> clazz = Class.forName(clazzName);
|
||||
TbNode tbNode = (TbNode) clazz.getDeclaredConstructor().newInstance();
|
||||
if (tbNode instanceof VersionedNode) {
|
||||
var versionedNode = (VersionedNode) tbNode;
|
||||
var ruleNodeName = versionedNode.getClass().getName();
|
||||
int currentVersion = versionedNode.getCurrentVersion();
|
||||
var ruleNodesToUpdate = new PageDataIterable<>(
|
||||
pageLink ->
|
||||
ruleChainService.findAllRuleNodesByTypeAndVersionLessThan(ruleNodeName, currentVersion, pageLink),
|
||||
1024
|
||||
);
|
||||
for (RuleNode ruleNode : ruleNodesToUpdate) {
|
||||
RuleNodeId ruleNodeId = ruleNode.getId();
|
||||
var oldConfiguration = ruleNode.getConfiguration();
|
||||
int fromVersion = ruleNode.getConfigurationVersion();
|
||||
log.info("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
|
||||
ruleNodeId,
|
||||
clazzName,
|
||||
fromVersion,
|
||||
currentVersion);
|
||||
try {
|
||||
TbPair<Boolean, JsonNode> upgradeRuleNodeConfigurationResult = versionedNode.upgrade(ruleNodeId, fromVersion, oldConfiguration);
|
||||
if (upgradeRuleNodeConfigurationResult.getFirst()) {
|
||||
ruleNode.setConfiguration(upgradeRuleNodeConfigurationResult.getSecond());
|
||||
var ruleChainId = ruleNode.getRuleChainId();
|
||||
var tenantId = ruleChainIdToTenantId.computeIfAbsent(ruleChainId,
|
||||
var tenantId = getTenantId(ruleChainIdToTenantIdMap, ruleNodeId, ruleChainId);
|
||||
if (tenantId == null) {
|
||||
log.warn("Failed to find tenant id for rule chain with id: {}", ruleChainId);
|
||||
continue;
|
||||
}
|
||||
ruleChainService.saveRuleNode(tenantId, ruleNode);
|
||||
log.info("Successfully upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
|
||||
ruleNodeId,
|
||||
clazzName,
|
||||
fromVersion,
|
||||
currentVersion);
|
||||
}
|
||||
} catch (TbNodeException e) {
|
||||
log.warn("Failed to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {} due to: ",
|
||||
ruleNodeId,
|
||||
clazzName,
|
||||
fromVersion,
|
||||
currentVersion,
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("Finished rule nodes upgrade!");
|
||||
} catch (Exception e) {
|
||||
log.error("Unexpected error during rule nodes upgrade: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
private TenantId getTenantId(HashMap<RuleChainId, TenantId> ruleChainIdToTenantId, RuleNodeId ruleNodeId, RuleChainId ruleChainId) {
|
||||
return ruleChainIdToTenantId.computeIfAbsent(ruleChainId,
|
||||
id -> {
|
||||
RuleChain ruleChain = ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, id);
|
||||
if (ruleChain == null) {
|
||||
log.error("Failed to find rule chain by id: [{}], ruleNodeId: [{}]", ruleChainId, ruleNode.getId());
|
||||
log.warn("Failed to find rule chain by id: {} ruleNodeId: {}", ruleChainId, ruleNodeId);
|
||||
return null;
|
||||
}
|
||||
return ruleChain.getTenantId();
|
||||
});
|
||||
if (tenantId != null) {
|
||||
ruleChainService.saveRuleNode(tenantId, ruleNode);
|
||||
}
|
||||
|
||||
private Set<BeanDefinition> getBeanDefinitions(Class<? extends Annotation> componentType) {
|
||||
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
|
||||
scanner.addIncludeFilter(new AnnotationTypeFilter(componentType));
|
||||
Set<BeanDefinition> defs = new HashSet<>();
|
||||
for (String scanPackage : scanPackages) {
|
||||
defs.addAll(scanner.findCandidateComponents(scanPackage));
|
||||
}
|
||||
});
|
||||
return defs;
|
||||
}
|
||||
|
||||
private final PaginatedUpdater<String, DeviceProfileEntity> deviceProfileEntityDynamicConditionsUpdater =
|
||||
|
||||
@ -99,6 +99,8 @@ public interface RuleChainService extends EntityDaoService {
|
||||
|
||||
PageData<RuleNode> findAllRuleNodesByType(String type, PageLink pageLink);
|
||||
|
||||
PageData<RuleNode> findAllRuleNodesByTypeAndVersionLessThan(String type, int version, PageLink pageLink);
|
||||
|
||||
RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode);
|
||||
|
||||
void deleteRuleNodes(TenantId tenantId, RuleChainId ruleChainId);
|
||||
|
||||
@ -50,7 +50,9 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl
|
||||
private boolean debugMode;
|
||||
@ApiModelProperty(position = 7, value = "Enable/disable singleton mode. ", example = "false")
|
||||
private boolean singletonMode;
|
||||
@ApiModelProperty(position = 8, value = "JSON with the rule node configuration. Structure depends on the rule node implementation.", dataType = "com.fasterxml.jackson.databind.JsonNode")
|
||||
@ApiModelProperty(position = 8, value = "Version of rule node configuration. ", example = "0")
|
||||
private int configurationVersion;
|
||||
@ApiModelProperty(position = 9, value = "JSON with the rule node configuration. Structure depends on the rule node implementation.", dataType = "com.fasterxml.jackson.databind.JsonNode")
|
||||
private transient JsonNode configuration;
|
||||
@JsonIgnore
|
||||
private byte[] configurationBytes;
|
||||
@ -109,7 +111,7 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl
|
||||
return super.getCreatedTime();
|
||||
}
|
||||
|
||||
@ApiModelProperty(position = 8, value = "Additional parameters of the rule node. Contains 'layoutX' and 'layoutY' properties for visualization.", dataType = "com.fasterxml.jackson.databind.JsonNode")
|
||||
@ApiModelProperty(position = 10, value = "Additional parameters of the rule node. Contains 'layoutX' and 'layoutY' properties for visualization.", dataType = "com.fasterxml.jackson.databind.JsonNode")
|
||||
@Override
|
||||
public JsonNode getAdditionalInfo() {
|
||||
return super.getAdditionalInfo();
|
||||
|
||||
@ -477,6 +477,7 @@ public class ModelConstants {
|
||||
public static final String RULE_NODE_CHAIN_ID_PROPERTY = "rule_chain_id";
|
||||
public static final String RULE_NODE_TYPE_PROPERTY = "type";
|
||||
public static final String RULE_NODE_NAME_PROPERTY = "name";
|
||||
public static final String RULE_NODE_VERSION_PROPERTY = "configuration_version";
|
||||
public static final String RULE_NODE_CONFIGURATION_PROPERTY = "configuration";
|
||||
|
||||
/**
|
||||
|
||||
@ -53,6 +53,9 @@ public class RuleNodeEntity extends BaseSqlEntity<RuleNode> implements SearchTex
|
||||
@Column(name = ModelConstants.SEARCH_TEXT_PROPERTY)
|
||||
private String searchText;
|
||||
|
||||
@Column(name = ModelConstants.RULE_NODE_VERSION_PROPERTY)
|
||||
private int configurationVersion;
|
||||
|
||||
@Type(type = "json")
|
||||
@Column(name = ModelConstants.RULE_NODE_CONFIGURATION_PROPERTY)
|
||||
private JsonNode configuration;
|
||||
@ -86,6 +89,7 @@ public class RuleNodeEntity extends BaseSqlEntity<RuleNode> implements SearchTex
|
||||
this.debugMode = ruleNode.isDebugMode();
|
||||
this.singletonMode = ruleNode.isSingletonMode();
|
||||
this.searchText = ruleNode.getName();
|
||||
this.configurationVersion = ruleNode.getConfigurationVersion();
|
||||
this.configuration = ruleNode.getConfiguration();
|
||||
this.additionalInfo = ruleNode.getAdditionalInfo();
|
||||
if (ruleNode.getExternalId() != null) {
|
||||
@ -114,6 +118,7 @@ public class RuleNodeEntity extends BaseSqlEntity<RuleNode> implements SearchTex
|
||||
ruleNode.setName(name);
|
||||
ruleNode.setDebugMode(debugMode);
|
||||
ruleNode.setSingletonMode(singletonMode);
|
||||
ruleNode.setConfigurationVersion(configurationVersion);
|
||||
ruleNode.setConfiguration(configuration);
|
||||
ruleNode.setAdditionalInfo(additionalInfo);
|
||||
if (externalId != null) {
|
||||
|
||||
@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.VersionedNode;
|
||||
import org.thingsboard.server.common.data.BaseData;
|
||||
import org.thingsboard.server.common.data.EntityType;
|
||||
@ -77,6 +78,7 @@ import java.util.stream.Collectors;
|
||||
import static org.thingsboard.server.common.data.DataConstants.TENANT;
|
||||
import static org.thingsboard.server.dao.service.Validator.validateId;
|
||||
import static org.thingsboard.server.dao.service.Validator.validatePageLink;
|
||||
import static org.thingsboard.server.dao.service.Validator.validatePositiveNumber;
|
||||
import static org.thingsboard.server.dao.service.Validator.validateString;
|
||||
|
||||
/**
|
||||
@ -189,11 +191,11 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
|
||||
RuleNode savedNode = ruleNodeDao.save(tenantId, node);
|
||||
relations.add(new EntityRelation(ruleChainMetaData.getRuleChainId(), savedNode.getId(),
|
||||
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
|
||||
TbPair<Boolean, JsonNode> upgradeResult = upgradeRuleNode(savedNode);
|
||||
if (upgradeResult.getFirst()) {
|
||||
savedNode.setConfiguration(upgradeResult.getSecond());
|
||||
savedNode = ruleNodeDao.save(tenantId, savedNode);
|
||||
}
|
||||
// TbPair<Boolean, JsonNode> upgradeResult = upgradeRuleNode(savedNode);
|
||||
// if (upgradeResult.getFirst()) {
|
||||
// savedNode.setConfiguration(upgradeResult.getSecond());
|
||||
// savedNode = ruleNodeDao.save(tenantId, savedNode);
|
||||
// }
|
||||
int index = nodes.indexOf(node);
|
||||
nodes.set(index, savedNode);
|
||||
ruleNodeIndexMap.put(savedNode.getId(), index);
|
||||
@ -263,24 +265,38 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
|
||||
return RuleChainUpdateResult.successful(updatedRuleNodes);
|
||||
}
|
||||
|
||||
private TbPair<Boolean, JsonNode> upgradeRuleNode(RuleNode node) {
|
||||
var configuration = node.getConfiguration();
|
||||
String ruleNodeClassName = node.getType();
|
||||
private TbPair<Boolean, JsonNode> upgradeRuleNode(RuleNode ruleNode) {
|
||||
RuleNodeId ruleNodeId = ruleNode.getId();
|
||||
String ruleNodeType = ruleNode.getType();
|
||||
int fromVersion = ruleNode.getConfigurationVersion();
|
||||
try {
|
||||
var ruleNodeClass = Class.forName(ruleNodeClassName).getConstructor().newInstance();
|
||||
var ruleNodeClass = Class.forName(ruleNodeType).getDeclaredConstructor().newInstance();
|
||||
if (ruleNodeClass instanceof VersionedNode) {
|
||||
VersionedNode versionedNode = (VersionedNode) ruleNodeClass;
|
||||
return versionedNode.upgrade(node.getId(), configuration);
|
||||
int toVersion = versionedNode.getCurrentVersion();
|
||||
log.info("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}",
|
||||
ruleNodeId,
|
||||
ruleNodeType,
|
||||
fromVersion,
|
||||
toVersion);
|
||||
try {
|
||||
return versionedNode.upgrade(ruleNodeId, fromVersion, ruleNode.getConfiguration());
|
||||
} catch (TbNodeException e) {
|
||||
log.warn("Failed to upgrade rule node with id: {} fromVersion: {} toVersion: {} due to: ",
|
||||
ruleNodeId,
|
||||
fromVersion,
|
||||
toVersion,
|
||||
e);
|
||||
}
|
||||
} catch (InstantiationException |
|
||||
IllegalAccessException |
|
||||
}
|
||||
} catch (ClassNotFoundException |
|
||||
InvocationTargetException |
|
||||
NoSuchMethodException |
|
||||
ClassNotFoundException e
|
||||
) {
|
||||
log.warn("Failed to upgrade rule node due to: ", e);
|
||||
InstantiationException |
|
||||
IllegalAccessException |
|
||||
NoSuchMethodException e) {
|
||||
log.warn("Failed to create instance of rule node with id: {} and type: {}", ruleNodeId, ruleNodeType);
|
||||
}
|
||||
return new TbPair<>(false, node.getConfiguration());
|
||||
return new TbPair<>(false, ruleNode.getConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -728,6 +744,15 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
|
||||
return ruleNodeDao.findAllRuleNodesByType(type, pageLink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageData<RuleNode> findAllRuleNodesByTypeAndVersionLessThan(String type, int version, PageLink pageLink) {
|
||||
log.trace("Executing findAllRuleNodesByTypeAndVersionLessThan, type {}, pageLink {}, version {}", type, pageLink, version);
|
||||
validateString(type, "Incorrect type of the rule node");
|
||||
validatePositiveNumber(version, "Incorrect version to compare with. Version should be greater than 0!");
|
||||
validatePageLink(pageLink);
|
||||
return ruleNodeDao.findAllRuleNodesByTypeAndVersionLessThan(type, version, pageLink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode) {
|
||||
return ruleNodeDao.save(tenantId, ruleNode);
|
||||
|
||||
@ -34,6 +34,8 @@ public interface RuleNodeDao extends Dao<RuleNode> {
|
||||
|
||||
PageData<RuleNode> findAllRuleNodesByType(String type, PageLink pageLink);
|
||||
|
||||
PageData<RuleNode> findAllRuleNodesByTypeAndVersionLessThan(String type, int version, PageLink pageLink);
|
||||
|
||||
List<RuleNode> findByExternalIds(RuleChainId ruleChainId, List<RuleNodeId> externalIds);
|
||||
|
||||
void deleteByIdIn(List<RuleNodeId> ruleNodeIds);
|
||||
|
||||
@ -61,7 +61,7 @@ public class Validator {
|
||||
|
||||
|
||||
/**
|
||||
* This method validate <code>String</code> string. If string is invalid than throw
|
||||
* This method validate <code>long</code> value. If value isn't possitive than throw
|
||||
* <code>IncorrectParameterException</code> exception
|
||||
*
|
||||
* @param val the val
|
||||
|
||||
@ -69,6 +69,16 @@ public class JpaRuleNodeDao extends JpaAbstractSearchTextDao<RuleNodeEntity, Rul
|
||||
DaoUtil.toPageable(pageLink)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageData<RuleNode> findAllRuleNodesByTypeAndVersionLessThan(String type, int version, PageLink pageLink) {
|
||||
return DaoUtil.toPageData(ruleNodeRepository
|
||||
.findAllRuleNodesByTypeAndVersionLessThan(
|
||||
type,
|
||||
version,
|
||||
Objects.toString(pageLink.getTextSearch(), ""),
|
||||
DaoUtil.toPageable(pageLink)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RuleNode> findByExternalIds(RuleChainId ruleChainId, List<RuleNodeId> externalIds) {
|
||||
return DaoUtil.convertDataList(ruleNodeRepository.findRuleNodesByRuleChainIdAndExternalIdIn(ruleChainId.getId(),
|
||||
|
||||
@ -41,6 +41,12 @@ public interface RuleNodeRepository extends JpaRepository<RuleNodeEntity, UUID>
|
||||
@Param("searchText") String searchText,
|
||||
Pageable pageable);
|
||||
|
||||
@Query("SELECT r FROM RuleNodeEntity r WHERE r.type = :ruleType AND r.configurationVersion < :version AND LOWER(r.configuration) LIKE LOWER(CONCAT('%', :searchText, '%')) ")
|
||||
Page<RuleNodeEntity> findAllRuleNodesByTypeAndVersionLessThan(@Param("ruleType") String ruleType,
|
||||
@Param("version") int version,
|
||||
@Param("searchText") String searchText,
|
||||
Pageable pageable);
|
||||
|
||||
List<RuleNodeEntity> findRuleNodesByRuleChainIdAndExternalIdIn(UUID ruleChainId, List<UUID> externalIds);
|
||||
|
||||
@Transactional
|
||||
|
||||
@ -89,6 +89,8 @@ CREATE INDEX IF NOT EXISTS idx_rule_node_external_id ON rule_node(rule_chain_id,
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rule_node_type ON rule_node(type);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rule_node_type_configuration_version ON rule_node(type, configuration_version);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_api_usage_state_entity_id ON api_usage_state(entity_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_alarm_comment_alarm_id ON alarm_comment(alarm_id);
|
||||
|
||||
@ -184,6 +184,7 @@ CREATE TABLE IF NOT EXISTS rule_node (
|
||||
created_time bigint NOT NULL,
|
||||
rule_chain_id uuid,
|
||||
additional_info varchar,
|
||||
configuration_version int DEFAULT 0,
|
||||
configuration varchar(10000000),
|
||||
type varchar(255),
|
||||
name varchar(255),
|
||||
|
||||
@ -19,25 +19,10 @@ import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.util.TbPair;
|
||||
|
||||
public interface VersionedNode {
|
||||
public interface VersionedNode extends TbNode {
|
||||
|
||||
String VERSION_PROPERTY_NAME = "version";
|
||||
TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException;
|
||||
|
||||
TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, JsonNode oldConfiguration);
|
||||
|
||||
default int getVersionOrElseThrowTbNodeException(RuleNodeId ruleNodeId, JsonNode oldConfiguration) throws TbNodeException {
|
||||
if (oldConfiguration == null) {
|
||||
throw new TbNodeException("Rule node: [" + this.getClass().getName() + "] " +
|
||||
"with id: [" + ruleNodeId + "] has null configuration!");
|
||||
} else if (!oldConfiguration.isObject()) {
|
||||
throw new TbNodeException("Rule node: [" + this.getClass().getName() + "] " +
|
||||
"with id: [" + ruleNodeId + "] has non json object configuration!");
|
||||
|
||||
}
|
||||
if (!oldConfiguration.has(VERSION_PROPERTY_NAME)) {
|
||||
return 0;
|
||||
}
|
||||
return oldConfiguration.get(VERSION_PROPERTY_NAME).asInt();
|
||||
}
|
||||
int getCurrentVersion();
|
||||
|
||||
}
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2023 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.rule.engine.api;
|
||||
|
||||
public interface VersionedNodeConfiguration {
|
||||
|
||||
int getVersion();
|
||||
|
||||
}
|
||||
@ -16,12 +16,10 @@
|
||||
package org.thingsboard.rule.engine.metadata;
|
||||
|
||||
import lombok.Data;
|
||||
import org.thingsboard.rule.engine.api.VersionedNodeConfiguration;
|
||||
|
||||
@Data
|
||||
public abstract class TbAbstractFetchToNodeConfiguration implements VersionedNodeConfiguration {
|
||||
public abstract class TbAbstractFetchToNodeConfiguration {
|
||||
|
||||
private FetchTo fetchTo;
|
||||
private int version = 1;
|
||||
|
||||
}
|
||||
|
||||
@ -149,11 +149,10 @@ public abstract class TbAbstractGetEntityAttrNode<T extends EntityId> extends Tb
|
||||
ctx.tellSuccess(transformMessage(msg, msgData, msgMetaData));
|
||||
}
|
||||
|
||||
protected TbPair<Boolean, JsonNode> upgradeToUseFetchToAndDataToFetch(RuleNodeId ruleNodeId, JsonNode oldConfiguration) throws TbNodeException {
|
||||
protected TbPair<Boolean, JsonNode> upgradeToUseFetchToAndDataToFetch(JsonNode oldConfiguration) throws TbNodeException {
|
||||
var newConfigObjectNode = (ObjectNode) oldConfiguration;
|
||||
if (!newConfigObjectNode.has(OLD_PROPERTY_NAME)) {
|
||||
throw new TbNodeException("Rule node: [" + this.getClass().getName() + "] " +
|
||||
"with id: [" + ruleNodeId + "] doesn't have property: [" + OLD_PROPERTY_NAME + "]");
|
||||
throw new TbNodeException("property to update: '" + OLD_PROPERTY_NAME + "' doesn't exists in configuration!");
|
||||
}
|
||||
var value = newConfigObjectNode.get(OLD_PROPERTY_NAME).asText();
|
||||
if ("true".equals(value)) {
|
||||
@ -163,12 +162,9 @@ public abstract class TbAbstractGetEntityAttrNode<T extends EntityId> extends Tb
|
||||
newConfigObjectNode.remove(OLD_PROPERTY_NAME);
|
||||
newConfigObjectNode.put(DATA_TO_FETCH_PROPERTY_NAME, DataToFetch.ATTRIBUTES.name());
|
||||
} else {
|
||||
throw new TbNodeException("Rule node: [" + this.getClass().getName() + "] " +
|
||||
"with id: [" + ruleNodeId + "] has property: [" + OLD_PROPERTY_NAME + "] " +
|
||||
"with unexpected value: [" + value + "] Allowed values: true or false!");
|
||||
throw new TbNodeException("property to update: '" + OLD_PROPERTY_NAME + "' has unexpected value: " + value + ". Allowed values: true or false!");
|
||||
}
|
||||
newConfigObjectNode.put(FETCH_TO_PROPERTY_NAME, FetchTo.METADATA.name());
|
||||
newConfigObjectNode.put(VERSION_PROPERTY_NAME, 1);
|
||||
return new TbPair<>(true, newConfigObjectNode);
|
||||
}
|
||||
|
||||
|
||||
@ -36,13 +36,18 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@Slf4j
|
||||
public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeConfiguration> implements TbNode, VersionedNode {
|
||||
public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeConfiguration> implements VersionedNode {
|
||||
|
||||
protected final static String FETCH_TO_PROPERTY_NAME = "fetchTo";
|
||||
|
||||
protected C config;
|
||||
protected FetchTo fetchTo;
|
||||
|
||||
@Override
|
||||
public int getCurrentVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
||||
config = loadNodeConfiguration(configuration);
|
||||
@ -93,7 +98,6 @@ public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeC
|
||||
}
|
||||
|
||||
protected TbPair<Boolean, JsonNode> upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
RuleNodeId ruleNodeId,
|
||||
JsonNode oldConfiguration,
|
||||
String oldProperty,
|
||||
String ifTrue,
|
||||
@ -101,24 +105,19 @@ public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeC
|
||||
) throws TbNodeException {
|
||||
var newConfigObjectNode = (ObjectNode) oldConfiguration;
|
||||
if (!newConfigObjectNode.has(oldProperty)) {
|
||||
throw new TbNodeException("Rule node: [" + this.getClass().getName() + "] " +
|
||||
"with id: [" + ruleNodeId + "] doesn't have property: [" + oldProperty + "]");
|
||||
throw new TbNodeException("property to update: '" + oldProperty + "' doesn't exists in configuration!");
|
||||
}
|
||||
var value = newConfigObjectNode.get(oldProperty).asText();
|
||||
if ("true".equals(value)) {
|
||||
newConfigObjectNode.remove(oldProperty);
|
||||
newConfigObjectNode.put(FETCH_TO_PROPERTY_NAME, ifTrue);
|
||||
newConfigObjectNode.put(VERSION_PROPERTY_NAME, 1);
|
||||
return new TbPair<>(true, newConfigObjectNode);
|
||||
} else if ("false".equals(value)) {
|
||||
newConfigObjectNode.remove(oldProperty);
|
||||
newConfigObjectNode.put(FETCH_TO_PROPERTY_NAME, ifFalse);
|
||||
newConfigObjectNode.put(VERSION_PROPERTY_NAME, 1);
|
||||
return new TbPair<>(true, newConfigObjectNode);
|
||||
} else {
|
||||
throw new TbNodeException("Rule node: [" + this.getClass().getName() + "] " +
|
||||
"with id: [" + ruleNodeId + "] has property: [" + oldProperty + "] " +
|
||||
"with unexpected value: [" + value + "] Allowed values: true or false!");
|
||||
throw new TbNodeException("property to update: '" + oldProperty + "' has unexpected value: " + value + ". Allowed values: true or false!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -89,22 +89,14 @@ public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo<TbFe
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, JsonNode oldConfiguration) {
|
||||
try {
|
||||
int oldVersion = getVersionOrElseThrowTbNodeException(ruleNodeId, oldConfiguration);
|
||||
if (oldVersion == 0) {
|
||||
return upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
ruleNodeId,
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
oldConfiguration,
|
||||
"fetchToMetadata",
|
||||
FetchTo.METADATA.name(),
|
||||
FetchTo.DATA.name()
|
||||
);
|
||||
}
|
||||
} catch (TbNodeException e) {
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
return new TbPair<>(false, oldConfiguration);
|
||||
FetchTo.DATA.name()) :
|
||||
new TbPair<>(false, oldConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -57,22 +57,14 @@ public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttrib
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, JsonNode oldConfiguration) {
|
||||
try {
|
||||
int oldVersion = getVersionOrElseThrowTbNodeException(ruleNodeId, oldConfiguration);
|
||||
if (oldVersion == 0) {
|
||||
return upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
ruleNodeId,
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
oldConfiguration,
|
||||
"fetchToData",
|
||||
FetchTo.DATA.name(),
|
||||
FetchTo.METADATA.name()
|
||||
);
|
||||
}
|
||||
} catch (TbNodeException e) {
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
return new TbPair<>(false, oldConfiguration);
|
||||
FetchTo.METADATA.name()) :
|
||||
new TbPair<>(false, oldConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -72,16 +72,10 @@ public class TbGetCustomerAttributeNode extends TbAbstractGetEntityAttrNode<Cust
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, JsonNode oldConfiguration) {
|
||||
try {
|
||||
int oldVersion = getVersionOrElseThrowTbNodeException(ruleNodeId, oldConfiguration);
|
||||
if (oldVersion == 0) {
|
||||
return upgradeToUseFetchToAndDataToFetch(ruleNodeId, oldConfiguration);
|
||||
}
|
||||
} catch (TbNodeException e) {
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
return new TbPair<>(false, oldConfiguration);
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeToUseFetchToAndDataToFetch(oldConfiguration) :
|
||||
new TbPair<>(false, oldConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -107,22 +107,14 @@ public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode<TbG
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, JsonNode oldConfiguration) {
|
||||
try {
|
||||
int oldVersion = getVersionOrElseThrowTbNodeException(ruleNodeId, oldConfiguration);
|
||||
if (oldVersion == 0) {
|
||||
return upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
ruleNodeId,
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
oldConfiguration,
|
||||
"addToMetadata",
|
||||
FetchTo.METADATA.name(),
|
||||
FetchTo.DATA.name()
|
||||
);
|
||||
}
|
||||
} catch (TbNodeException e) {
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
return new TbPair<>(false, oldConfiguration);
|
||||
FetchTo.DATA.name()) :
|
||||
new TbPair<>(false, oldConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -60,22 +60,14 @@ public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode<TbGetDevice
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, JsonNode oldConfiguration) {
|
||||
try {
|
||||
int oldVersion = getVersionOrElseThrowTbNodeException(ruleNodeId, oldConfiguration);
|
||||
if (oldVersion == 0) {
|
||||
return upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
ruleNodeId,
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
oldConfiguration,
|
||||
"fetchToData",
|
||||
FetchTo.DATA.name(),
|
||||
FetchTo.METADATA.name()
|
||||
);
|
||||
}
|
||||
} catch (TbNodeException e) {
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
return new TbPair<>(false, oldConfiguration);
|
||||
FetchTo.METADATA.name()) :
|
||||
new TbPair<>(false, oldConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -102,18 +102,12 @@ public class TbGetOriginatorFieldsNode extends TbAbstractNodeWithFetchTo<TbGetOr
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, JsonNode oldConfiguration) {
|
||||
try {
|
||||
int oldVersion = getVersionOrElseThrowTbNodeException(ruleNodeId, oldConfiguration);
|
||||
if (oldVersion == 0) {
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) {
|
||||
if (fromVersion == 0) {
|
||||
var newConfigObjectNode = (ObjectNode) oldConfiguration;
|
||||
newConfigObjectNode.put(FETCH_TO_PROPERTY_NAME, FetchTo.METADATA.name());
|
||||
newConfigObjectNode.put(VERSION_PROPERTY_NAME, 1);
|
||||
return new TbPair<>(true, newConfigObjectNode);
|
||||
}
|
||||
} catch (TbNodeException e) {
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
return new TbPair<>(false, oldConfiguration);
|
||||
}
|
||||
|
||||
|
||||
@ -75,16 +75,8 @@ public class TbGetRelatedAttributeNode extends TbAbstractGetEntityAttrNode<Entit
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, JsonNode oldConfiguration) {
|
||||
try {
|
||||
int oldVersion = getVersionOrElseThrowTbNodeException(ruleNodeId, oldConfiguration);
|
||||
if (oldVersion == 0) {
|
||||
return upgradeToUseFetchToAndDataToFetch(ruleNodeId, oldConfiguration);
|
||||
}
|
||||
} catch (TbNodeException e) {
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
return new TbPair<>(false, oldConfiguration);
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ? upgradeToUseFetchToAndDataToFetch(oldConfiguration) : new TbPair<>(false, oldConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -66,16 +66,8 @@ public class TbGetTenantAttributeNode extends TbAbstractGetEntityAttrNode<Tenant
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, JsonNode oldConfiguration) {
|
||||
try {
|
||||
int oldVersion = getVersionOrElseThrowTbNodeException(ruleNodeId, oldConfiguration);
|
||||
if (oldVersion == 0) {
|
||||
return upgradeToUseFetchToAndDataToFetch(ruleNodeId, oldConfiguration);
|
||||
}
|
||||
} catch (TbNodeException e) {
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
return new TbPair<>(false, oldConfiguration);
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ? upgradeToUseFetchToAndDataToFetch(oldConfiguration) : new TbPair<>(false, oldConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -62,22 +62,14 @@ public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode<TbGet
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, JsonNode oldConfiguration) {
|
||||
try {
|
||||
int oldVersion = getVersionOrElseThrowTbNodeException(ruleNodeId, oldConfiguration);
|
||||
if (oldVersion == 0) {
|
||||
return upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
ruleNodeId,
|
||||
public TbPair<Boolean, JsonNode> upgrade(RuleNodeId ruleNodeId, int fromVersion, JsonNode oldConfiguration) throws TbNodeException {
|
||||
return fromVersion == 0 ?
|
||||
upgradeRuleNodesWithOldPropertyToUseFetchTo(
|
||||
oldConfiguration,
|
||||
"addToMetadata",
|
||||
FetchTo.METADATA.name(),
|
||||
FetchTo.DATA.name()
|
||||
);
|
||||
}
|
||||
} catch (TbNodeException e) {
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
return new TbPair<>(false, oldConfiguration);
|
||||
FetchTo.DATA.name()) :
|
||||
new TbPair<>(false, oldConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user