diff --git a/application/pom.xml b/application/pom.xml
index 6d1e009d00..33b21b3243 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 3.4.0-SNAPSHOT
+ 3.4.1-SNAPSHOT
thingsboard
application
diff --git a/application/src/main/conf/logback.xml b/application/src/main/conf/logback.xml
index 6d2c95ee84..284af71953 100644
--- a/application/src/main/conf/logback.xml
+++ b/application/src/main/conf/logback.xml
@@ -37,7 +37,7 @@
-
+
diff --git a/application/src/main/data/upgrade/3.3.4/schema_update.sql b/application/src/main/data/upgrade/3.3.4/schema_update.sql
index 69df2afdc9..c86a4fe1f4 100644
--- a/application/src/main/data/upgrade/3.3.4/schema_update.sql
+++ b/application/src/main/data/upgrade/3.3.4/schema_update.sql
@@ -33,16 +33,7 @@ ALTER TABLE widgets_bundle
ALTER TABLE entity_view
ADD COLUMN IF NOT EXISTS external_id UUID;
-CREATE INDEX IF NOT EXISTS idx_device_external_id ON device(tenant_id, external_id);
-CREATE INDEX IF NOT EXISTS idx_device_profile_external_id ON device_profile(tenant_id, external_id);
-CREATE INDEX IF NOT EXISTS idx_asset_external_id ON asset(tenant_id, external_id);
-CREATE INDEX IF NOT EXISTS idx_rule_chain_external_id ON rule_chain(tenant_id, external_id);
CREATE INDEX IF NOT EXISTS idx_rule_node_external_id ON rule_node(rule_chain_id, external_id);
-CREATE INDEX IF NOT EXISTS idx_dashboard_external_id ON dashboard(tenant_id, external_id);
-CREATE INDEX IF NOT EXISTS idx_customer_external_id ON customer(tenant_id, external_id);
-CREATE INDEX IF NOT EXISTS idx_widgets_bundle_external_id ON widgets_bundle(tenant_id, external_id);
-CREATE INDEX IF NOT EXISTS idx_entity_view_external_id ON entity_view(tenant_id, external_id);
-
CREATE INDEX IF NOT EXISTS idx_rule_node_type ON rule_node(type);
ALTER TABLE admin_settings
@@ -70,3 +61,80 @@ CREATE TABLE IF NOT EXISTS user_auth_settings (
two_fa_settings varchar
);
+CREATE INDEX IF NOT EXISTS idx_api_usage_state_entity_id ON api_usage_state(entity_id);
+
+ALTER TABLE tenant_profile DROP COLUMN IF EXISTS isolated_tb_core;
+
+DO
+$$
+ BEGIN
+ IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'device_external_id_unq_key') THEN
+ ALTER TABLE device ADD CONSTRAINT device_external_id_unq_key UNIQUE (tenant_id, external_id);
+ END IF;
+ END;
+$$;
+
+DO
+$$
+ BEGIN
+ IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'device_profile_external_id_unq_key') THEN
+ ALTER TABLE device_profile ADD CONSTRAINT device_profile_external_id_unq_key UNIQUE (tenant_id, external_id);
+ END IF;
+ END;
+$$;
+
+DO
+$$
+ BEGIN
+ IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'asset_external_id_unq_key') THEN
+ ALTER TABLE asset ADD CONSTRAINT asset_external_id_unq_key UNIQUE (tenant_id, external_id);
+ END IF;
+ END;
+$$;
+
+DO
+$$
+ BEGIN
+ IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'rule_chain_external_id_unq_key') THEN
+ ALTER TABLE rule_chain ADD CONSTRAINT rule_chain_external_id_unq_key UNIQUE (tenant_id, external_id);
+ END IF;
+ END;
+$$;
+
+
+DO
+$$
+ BEGIN
+ IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'dashboard_external_id_unq_key') THEN
+ ALTER TABLE dashboard ADD CONSTRAINT dashboard_external_id_unq_key UNIQUE (tenant_id, external_id);
+ END IF;
+ END;
+$$;
+
+DO
+$$
+ BEGIN
+ IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'customer_external_id_unq_key') THEN
+ ALTER TABLE customer ADD CONSTRAINT customer_external_id_unq_key UNIQUE (tenant_id, external_id);
+ END IF;
+ END;
+$$;
+
+DO
+$$
+ BEGIN
+ IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'widgets_bundle_external_id_unq_key') THEN
+ ALTER TABLE widgets_bundle ADD CONSTRAINT widgets_bundle_external_id_unq_key UNIQUE (tenant_id, external_id);
+ END IF;
+ END;
+$$;
+
+DO
+$$
+ BEGIN
+ IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'entity_view_external_id_unq_key') THEN
+ ALTER TABLE entity_view ADD CONSTRAINT entity_view_external_id_unq_key UNIQUE (tenant_id, external_id);
+ END IF;
+ END;
+$$;
+
diff --git a/application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql b/application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql
deleted file mode 100644
index e0b0cc7f1a..0000000000
--- a/application/src/main/data/upgrade/3.3.4/schema_update_device_profile.sql
+++ /dev/null
@@ -1,49 +0,0 @@
---
--- 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.
---
-
-ALTER TABLE device_profile
- ADD COLUMN IF NOT EXISTS default_queue_id uuid;
-
-DO
-$$
- BEGIN
- IF EXISTS
- (SELECT column_name
- FROM information_schema.columns
- WHERE table_name = 'device_profile'
- AND column_name = 'default_queue_name'
- )
- THEN
- UPDATE device_profile
- SET default_queue_id = q.id
- FROM queue as q
- WHERE default_queue_name = q.name;
- END IF;
- END
-$$;
-
-DO
-$$
- BEGIN
- IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'fk_default_queue_device_profile') THEN
- ALTER TABLE device_profile
- ADD CONSTRAINT fk_default_queue_device_profile FOREIGN KEY (default_queue_id) REFERENCES queue (id);
- END IF;
- END;
-$$;
-
-ALTER TABLE device_profile
- DROP COLUMN IF EXISTS default_queue_name;
diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
index 7e689e58fa..a38de7b839 100644
--- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
+++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
@@ -508,13 +508,8 @@ public class ActorSystemContext {
return partitionService.resolve(serviceType, tenantId, entityId);
}
- public TopicPartitionInfo resolve(ServiceType serviceType, QueueId queueId, TenantId tenantId, EntityId entityId) {
- return partitionService.resolve(serviceType, queueId, tenantId, entityId);
- }
-
- @Deprecated
public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) {
- return partitionService.resolve(serviceType, tenantId, entityId, queueName);
+ return partitionService.resolve(serviceType, queueName, tenantId, entityId);
}
public String getServiceId() {
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
index 3538800d38..d5460689b8 100644
--- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
@@ -162,18 +162,11 @@ class DefaultTbContext implements TbContext {
}
@Override
- @Deprecated
public void enqueue(TbMsg tbMsg, String queueName, Runnable onSuccess, Consumer onFailure) {
TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName);
enqueue(tpi, tbMsg, onFailure, onSuccess);
}
- @Override
- public void enqueue(TbMsg tbMsg, QueueId queueId, Runnable onSuccess, Consumer onFailure) {
- TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId);
- enqueue(tpi, tbMsg, onFailure, onSuccess);
- }
-
private void enqueue(TopicPartitionInfo tpi, TbMsg tbMsg, Consumer onFailure, Runnable onSuccess) {
if (!tbMsg.isValid()) {
log.trace("[{}] Skip invalid message: {}", getTenantId(), tbMsg);
@@ -223,35 +216,30 @@ class DefaultTbContext implements TbContext {
}
@Override
- public void enqueueForTellNext(TbMsg tbMsg, QueueId queueId, String relationType, Runnable onSuccess, Consumer onFailure) {
- TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId);
- enqueueForTellNext(tpi, queueId, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure);
+ public void enqueueForTellNext(TbMsg tbMsg, String queueName, String relationType, Runnable onSuccess, Consumer onFailure) {
+ TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName);
+ enqueueForTellNext(tpi, queueName, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure);
}
@Override
- public void enqueueForTellNext(TbMsg tbMsg, QueueId queueId, Set relationTypes, Runnable onSuccess, Consumer onFailure) {
- TopicPartitionInfo tpi = resolvePartition(tbMsg, queueId);
- enqueueForTellNext(tpi, queueId, tbMsg, relationTypes, null, onSuccess, onFailure);
- }
-
- private TopicPartitionInfo resolvePartition(TbMsg tbMsg, QueueId queueId) {
- return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueId, getTenantId(), tbMsg.getOriginator());
+ public void enqueueForTellNext(TbMsg tbMsg, String queueName, Set relationTypes, Runnable onSuccess, Consumer onFailure) {
+ TopicPartitionInfo tpi = resolvePartition(tbMsg, queueName);
+ enqueueForTellNext(tpi, queueName, tbMsg, relationTypes, null, onSuccess, onFailure);
}
- @Deprecated
private TopicPartitionInfo resolvePartition(TbMsg tbMsg, String queueName) {
return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator());
}
private TopicPartitionInfo resolvePartition(TbMsg tbMsg) {
- return resolvePartition(tbMsg, tbMsg.getQueueId());
+ return resolvePartition(tbMsg, tbMsg.getQueueName());
}
private void enqueueForTellNext(TopicPartitionInfo tpi, TbMsg source, Set relationTypes, String failureMessage, Runnable onSuccess, Consumer onFailure) {
- enqueueForTellNext(tpi, source.getQueueId(), source, relationTypes, failureMessage, onSuccess, onFailure);
+ enqueueForTellNext(tpi, source.getQueueName(), source, relationTypes, failureMessage, onSuccess, onFailure);
}
- private void enqueueForTellNext(TopicPartitionInfo tpi, QueueId queueId, TbMsg source, Set relationTypes, String failureMessage, Runnable onSuccess, Consumer onFailure) {
+ private void enqueueForTellNext(TopicPartitionInfo tpi, String queueName, TbMsg source, Set relationTypes, String failureMessage, Runnable onSuccess, Consumer onFailure) {
if (!source.isValid()) {
log.trace("[{}] Skip invalid message: {}", getTenantId(), source);
if (onFailure != null) {
@@ -261,7 +249,7 @@ class DefaultTbContext implements TbContext {
}
RuleChainId ruleChainId = nodeCtx.getSelf().getRuleChainId();
RuleNodeId ruleNodeId = nodeCtx.getSelf().getId();
- TbMsg tbMsg = TbMsg.newMsg(source, queueId, ruleChainId, ruleNodeId);
+ TbMsg tbMsg = TbMsg.newMsg(source, queueName, ruleChainId, ruleNodeId);
TransportProtos.ToRuleEngineMsg.Builder msg = TransportProtos.ToRuleEngineMsg.newBuilder()
.setTenantIdMSB(getTenantId().getId().getMostSignificantBits())
.setTenantIdLSB(getTenantId().getId().getLeastSignificantBits())
@@ -320,13 +308,13 @@ class DefaultTbContext implements TbContext {
}
@Override
- public TbMsg newMsg(QueueId queueId, String type, EntityId originator, TbMsgMetaData metaData, String data) {
- return newMsg(queueId, type, originator, null, metaData, data);
+ public TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) {
+ return newMsg(queueName, type, originator, null, metaData, data);
}
@Override
- public TbMsg newMsg(QueueId queueId, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
- return TbMsg.newMsg(queueId, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId());
+ public TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
+ return TbMsg.newMsg(queueName, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId());
}
@Override
@@ -340,17 +328,17 @@ class DefaultTbContext implements TbContext {
public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) {
RuleChainId ruleChainId = null;
- QueueId queueId = null;
+ String queueName = null;
if (device.getDeviceProfileId() != null) {
DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().find(device.getDeviceProfileId());
if (deviceProfile == null) {
log.warn("[{}] Device profile is null!", device.getDeviceProfileId());
} else {
ruleChainId = deviceProfile.getDefaultRuleChainId();
- queueId = deviceProfile.getDefaultQueueId();
+ queueName = deviceProfile.getDefaultQueueName();
}
}
- return entityActionMsg(device, device.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, queueId, ruleChainId);
+ return entityActionMsg(device, device.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, queueName, ruleChainId);
}
public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) {
@@ -359,7 +347,7 @@ class DefaultTbContext implements TbContext {
public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action) {
RuleChainId ruleChainId = null;
- QueueId queueId = null;
+ String queueName = null;
if (EntityType.DEVICE.equals(alarm.getOriginator().getEntityType())) {
DeviceId deviceId = new DeviceId(alarm.getOriginator().getId());
DeviceProfile deviceProfile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId);
@@ -367,10 +355,10 @@ class DefaultTbContext implements TbContext {
log.warn("[{}] Device profile is null!", deviceId);
} else {
ruleChainId = deviceProfile.getDefaultRuleChainId();
- queueId = deviceProfile.getDefaultQueueId();
+ queueName = deviceProfile.getDefaultQueueName();
}
}
- return entityActionMsg(alarm, alarm.getId(), ruleNodeId, action, queueId, ruleChainId);
+ return entityActionMsg(alarm, alarm.getId(), ruleNodeId, action, queueName, ruleChainId);
}
@Override
@@ -382,9 +370,9 @@ class DefaultTbContext implements TbContext {
return entityActionMsg(entity, id, ruleNodeId, action, null, null);
}
- public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action, QueueId queueId, RuleChainId ruleChainId) {
+ public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action, String queueName, RuleChainId ruleChainId) {
try {
- return TbMsg.newMsg(queueId, action, id, getActionMetaData(ruleNodeId), mapper.writeValueAsString(mapper.valueToTree(entity)), ruleChainId, null);
+ return TbMsg.newMsg(queueName, action, id, getActionMetaData(ruleNodeId), mapper.writeValueAsString(mapper.valueToTree(entity)), ruleChainId, null);
} catch (JsonProcessingException | IllegalArgumentException e) {
throw new RuntimeException("Failed to process " + id.getEntityType().name().toLowerCase() + " " + action + " msg: " + e);
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
index add500f058..b4911650f3 100644
--- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
@@ -293,7 +293,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor ruleNodeRelations = nodeRoutes.get(originatorNodeId);
if (ruleNodeRelations == null) { // When unchecked, this will cause NullPointerException when rule node doesn't exist anymore
diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
index 5003aac526..d2e11086c7 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
@@ -126,7 +126,9 @@ public class AlarmController extends BaseController {
"\n\nPlatform also deduplicate the alarms based on the entity id of originator and alarm 'type'. " +
"For example, if the user or system component create the alarm with the type 'HighTemperature' for device 'Device A' the new active alarm is created. " +
"If the user tries to create 'HighTemperature' alarm for the same device again, the previous alarm will be updated (the 'end_ts' will be set to current timestamp). " +
- "If the user clears the alarm (see 'Clear Alarm(clearAlarm)'), than new alarm with the same type and same device may be created. " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH
+ "If the user clears the alarm (see 'Clear Alarm(clearAlarm)'), than new alarm with the same type and same device may be created. " +
+ "Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Alarm entity. " +
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH
, produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/alarm", method = RequestMethod.POST)
diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
index f1ff6aa3c6..75e77d4719 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
@@ -139,7 +139,9 @@ public class AssetController extends BaseController {
notes = "Creates or Updates the Asset. When creating asset, platform generates Asset Id as " + UUID_WIKI_LINK +
"The newly created Asset id will be present in the response. " +
"Specify existing Asset id to update the asset. " +
- "Referencing non-existing Asset Id will cause 'Not Found' error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE)
+ "Referencing non-existing Asset Id will cause 'Not Found' error. " +
+ "Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Asset entity. "
+ + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/asset", method = RequestMethod.POST)
@ResponseBody
diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
index a425b0968a..bdf74c9055 100644
--- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
+++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
@@ -112,6 +112,10 @@ public class ControllerConstants {
protected static final String DEVICE_PROFILE_INFO_DESCRIPTION = "Device Profile Info is a lightweight object that includes main information about Device Profile excluding the heavyweight configuration object. ";
protected static final String QUEUE_SERVICE_TYPE_DESCRIPTION = "Service type (implemented only for the TB-RULE-ENGINE)";
protected static final String QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES = "TB-RULE-ENGINE, TB-CORE, TB-TRANSPORT, JS-EXECUTOR";
+ protected static final String QUEUE_QUEUE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the queue name.";
+ protected static final String QUEUE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, topic";
+ protected static final String QUEUE_ID_PARAM_DESCRIPTION = "A string value representing the queue id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
+ protected static final String QUEUE_NAME_PARAM_DESCRIPTION = "A string value representing the queue id. For example, 'Main'";
protected static final String OTA_PACKAGE_INFO_DESCRIPTION = "OTA Package Info is a lightweight object that includes main information about the OTA Package excluding the heavyweight data. ";
protected static final String OTA_PACKAGE_DESCRIPTION = "OTA Package is a heavyweight object that includes main information about the OTA Package and also data. ";
protected static final String OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES = "MD5, SHA256, SHA384, SHA512, CRC32, MURMUR3_32, MURMUR3_128";
diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java
index 2510974991..591eaa1318 100644
--- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java
@@ -138,7 +138,9 @@ public class CustomerController extends BaseController {
notes = "Creates or Updates the Customer. When creating customer, platform generates Customer Id as " + UUID_WIKI_LINK +
"The newly created Customer Id will be present in the response. " +
"Specify existing Customer Id to update the Customer. " +
- "Referencing non-existing Customer Id will cause 'Not Found' error." + TENANT_AUTHORITY_PARAGRAPH)
+ "Referencing non-existing Customer Id will cause 'Not Found' error." +
+ "Remove 'id', 'tenantId' from the request body example (below) to create new Customer entity. " +
+ TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/customer", method = RequestMethod.POST)
@ResponseBody
diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
index 0530f59c97..9ceeb0d14c 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
@@ -172,6 +172,7 @@ public class DashboardController extends BaseController {
"The newly created Dashboard id will be present in the response. " +
"Specify existing Dashboard id to update the dashboard. " +
"Referencing non-existing dashboard Id will cause 'Not Found' error. " +
+ "Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Dashboard entity. " +
TENANT_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
@@ -261,7 +262,7 @@ public class DashboardController extends BaseController {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER);
- Set customerIds = customerIdFromStr(strCustomerIds, dashboard);
+ Set customerIds = customerIdFromStr(strCustomerIds);
return tbDashboardService.updateDashboardCustomers(dashboard, customerIds, getCurrentUser());
}
@@ -281,7 +282,7 @@ public class DashboardController extends BaseController {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER);
- Set customerIds = customerIdFromStr(strCustomerIds, dashboard);
+ Set customerIds = customerIdFromStr(strCustomerIds);
return tbDashboardService.addDashboardCustomers(dashboard, customerIds, getCurrentUser());
}
@@ -301,7 +302,7 @@ public class DashboardController extends BaseController {
checkParameter(DASHBOARD_ID, strDashboardId);
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_CUSTOMER);
- Set customerIds = customerIdFromStr(strCustomerIds, dashboard);
+ Set customerIds = customerIdFromStr(strCustomerIds);
return tbDashboardService.removeDashboardCustomers(dashboard, customerIds, getCurrentUser());
}
@@ -704,14 +705,11 @@ public class DashboardController extends BaseController {
}
}
- private Set customerIdFromStr(String[] strCustomerIds, Dashboard dashboard) {
+ private Set customerIdFromStr(String[] strCustomerIds) {
Set customerIds = new HashSet<>();
if (strCustomerIds != null) {
for (String strCustomerId : strCustomerIds) {
- CustomerId customerId = new CustomerId(UUID.fromString(strCustomerId));
- if (dashboard.isAssignedToCustomer(customerId)) {
- customerIds.add(customerId);
- }
+ customerIds.add(new CustomerId(UUID.fromString(strCustomerId)));
}
}
return customerIds;
diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
index 895e711073..ae1558381f 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
@@ -158,8 +158,9 @@ public class DeviceController extends BaseController {
"The newly created device id will be present in the response. " +
"Specify existing Device id to update the device. " +
"Referencing non-existing device Id will cause 'Not Found' error." +
- "\n\nDevice name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the device names and non-unique 'label' field for user-friendly visualization purposes."
- + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
+ "\n\nDevice name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the device names and non-unique 'label' field for user-friendly visualization purposes." +
+ "Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device entity. " +
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device", method = RequestMethod.POST)
@ResponseBody
@@ -181,6 +182,7 @@ public class DeviceController extends BaseController {
"Requires to provide the Device Credentials object as well. Useful to create device and credentials in one request. " +
"You may find the example of LwM2M device and RPK credentials below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION_MARKDOWN +
+ "Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device entity. " +
TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device-with-credentials", method = RequestMethod.POST)
diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
index 08568a28ce..e45a195a2d 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
@@ -191,6 +191,7 @@ public class DeviceProfileController extends BaseController {
"Specify existing device profile id to update the device profile. " +
"Referencing non-existing device profile Id will cause 'Not Found' error. " + NEW_LINE +
"Device profile name is unique in the scope of tenant. Only one 'default' device profile may exist in scope of tenant." + DEVICE_PROFILE_DATA +
+ "Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device Profile entity. " +
TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json",
consumes = "application/json")
diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
index 5b2c6a6a9d..59c9eb39c1 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
@@ -141,8 +141,9 @@ public class EdgeController extends BaseController {
"The newly created edge id will be present in the response. " +
"Specify existing Edge id to update the edge. " +
"Referencing non-existing Edge Id will cause 'Not Found' error." +
- "\n\nEdge name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the edge names and non-unique 'label' field for user-friendly visualization purposes."
- + TENANT_AUTHORITY_PARAGRAPH,
+ "\n\nEdge name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the edge names and non-unique 'label' field for user-friendly visualization purposes." +
+ "Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Edge entity. " +
+ TENANT_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge", method = RequestMethod.POST)
diff --git a/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java b/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
index 65b5f10407..f2bfbc9478 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
@@ -192,7 +192,7 @@ public class EntitiesVersionControlController extends BaseController {
@GetMapping(value = "/version/{requestId}/status")
public VersionCreationResult getVersionCreateRequestStatus(@ApiParam(value = VC_REQUEST_ID_PARAM_DESCRIPTION, required = true)
@PathVariable UUID requestId) throws Exception {
- accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
+ accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
return versionControlService.getVersionCreateStatus(getCurrentUser(), requestId);
}
@@ -469,7 +469,7 @@ public class EntitiesVersionControlController extends BaseController {
@GetMapping(value = "/entity/{requestId}/status")
public VersionLoadResult getVersionLoadRequestStatus(@ApiParam(value = VC_REQUEST_ID_PARAM_DESCRIPTION, required = true)
@PathVariable UUID requestId) throws Exception {
- accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
+ accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.WRITE);
return versionControlService.getVersionLoadStatus(getCurrentUser(), requestId);
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
index 7d5de91890..0f299fefae 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
@@ -132,7 +132,9 @@ public class EntityViewController extends BaseController {
}
@ApiOperation(value = "Save or update entity view (saveEntityView)",
- notes = ENTITY_VIEW_DESCRIPTION + MODEL_DESCRIPTION,
+ notes = ENTITY_VIEW_DESCRIPTION + MODEL_DESCRIPTION +
+ "Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Entity View entity." +
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/entityView", method = RequestMethod.POST)
diff --git a/application/src/main/java/org/thingsboard/server/controller/QueueController.java b/application/src/main/java/org/thingsboard/server/controller/QueueController.java
index 644bee9ff0..3b37e6727f 100644
--- a/application/src/main/java/org/thingsboard/server/controller/QueueController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/QueueController.java
@@ -15,6 +15,8 @@
*/
package org.thingsboard.server.controller;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
@@ -37,6 +39,22 @@ import org.thingsboard.server.service.security.permission.Resource;
import java.util.UUID;
+import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
+import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.QUEUE_ID_PARAM_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.QUEUE_NAME_PARAM_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.QUEUE_QUEUE_TEXT_SEARCH_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES;
+import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SERVICE_TYPE_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.QUEUE_SORT_PROPERTY_ALLOWABLE_VALUES;
+import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES;
+import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_AUTHORITY_PARAGRAPH;
+import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH;
+import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
+
@RestController
@TbCoreComponent
@RequestMapping("/api")
@@ -45,14 +63,23 @@ public class QueueController extends BaseController {
private final TbQueueService tbQueueService;
+ @ApiOperation(value = "Get Queues (getTenantQueuesByServiceType)",
+ notes = "Returns a page of queues registered in the platform. " +
+ PAGE_DATA_PARAMETERS + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/queues", params = {"serviceType", "pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
- public PageData getTenantQueuesByServiceType(@RequestParam String serviceType,
+ public PageData getTenantQueuesByServiceType(@ApiParam(value = QUEUE_SERVICE_TYPE_DESCRIPTION, allowableValues = QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES, required = true)
+ @RequestParam String serviceType,
+ @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
+ @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
+ @ApiParam(value = QUEUE_QUEUE_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
+ @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = QUEUE_SORT_PROPERTY_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortProperty,
+ @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("serviceType", serviceType);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@@ -65,20 +92,44 @@ public class QueueController extends BaseController {
}
}
+ @ApiOperation(value = "Get Queue (getQueueById)",
+ notes = "Fetch the Queue object based on the provided Queue Id. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/queues/{queueId}", method = RequestMethod.GET)
@ResponseBody
- public Queue getQueueById(@PathVariable("queueId") String queueIdStr) throws ThingsboardException {
+ public Queue getQueueById(@ApiParam(value = QUEUE_ID_PARAM_DESCRIPTION)
+ @PathVariable("queueId") String queueIdStr) throws ThingsboardException {
checkParameter("queueId", queueIdStr);
QueueId queueId = new QueueId(UUID.fromString(queueIdStr));
checkQueueId(queueId, Operation.READ);
return checkNotNull(queueService.findQueueById(getTenantId(), queueId));
}
+ @ApiOperation(value = "Get Queue (getQueueByName)",
+ notes = "Fetch the Queue object based on the provided Queue name. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
+ @RequestMapping(value = "/queues/name/{queueName}", method = RequestMethod.GET)
+ @ResponseBody
+ public Queue getQueueByName(@ApiParam(value = QUEUE_NAME_PARAM_DESCRIPTION)
+ @PathVariable("queueName") String queueName) throws ThingsboardException {
+ checkParameter("queueName", queueName);
+ return checkNotNull(queueService.findQueueByTenantIdAndName(getTenantId(), queueName));
+ }
+
+ @ApiOperation(value = "Create Or Update Queue (saveQueue)",
+ notes = "Create or update the Queue. When creating queue, platform generates Queue Id as " + UUID_WIKI_LINK +
+ "Specify existing Queue id to update the queue. " +
+ "Referencing non-existing Queue Id will cause 'Not Found' error." +
+ "\n\nQueue name is unique in the scope of sysadmin. " +
+ "Remove 'id', 'tenantId' from the request body example (below) to create new Queue entity. " +
+ SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/queues", params = {"serviceType"}, method = RequestMethod.POST)
@ResponseBody
- public Queue saveQueue(@RequestBody Queue queue,
+
+ public Queue saveQueue(@ApiParam(value = "A JSON value representing the queue.")
+ @RequestBody Queue queue,
+ @ApiParam(value = QUEUE_SERVICE_TYPE_DESCRIPTION, allowableValues = QUEUE_SERVICE_TYPE_ALLOWABLE_VALUES, required = true)
@RequestParam String serviceType) throws ThingsboardException {
checkParameter("serviceType", serviceType);
queue.setTenantId(getCurrentUser().getTenantId());
@@ -97,10 +148,12 @@ public class QueueController extends BaseController {
}
}
+ @ApiOperation(value = "Delete Queue (deleteQueue)", notes = "Deletes the Queue. " + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/queues/{queueId}", method = RequestMethod.DELETE)
@ResponseBody
- public void deleteQueue(@PathVariable("queueId") String queueIdStr) throws ThingsboardException {
+ public void deleteQueue(@ApiParam(value = QUEUE_ID_PARAM_DESCRIPTION)
+ @PathVariable("queueId") String queueIdStr) throws ThingsboardException {
checkParameter("queueId", queueIdStr);
QueueId queueId = new QueueId(toUUID(queueIdStr));
checkQueueId(queueId, Operation.DELETE);
diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
index 38e7f5bb7d..faa1711fd9 100644
--- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
@@ -227,7 +227,9 @@ public class RuleChainController extends BaseController {
"The newly created Rule Chain Id will be present in the response. " +
"Specify existing Rule Chain id to update the rule chain. " +
"Referencing non-existing rule chain Id will cause 'Not Found' error." +
- "\n\n" + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
+ "\n\n" + RULE_CHAIN_DESCRIPTION +
+ "Remove 'id', 'tenantId' from the request body example (below) to create new Rule Chain entity." +
+ TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain", method = RequestMethod.POST)
@ResponseBody
diff --git a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java
index 4342a647c5..ec0b530117 100644
--- a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java
@@ -139,7 +139,9 @@ public class TbResourceController extends BaseController {
"The newly created Resource id will be present in the response. " +
"Specify existing Resource id to update the Resource. " +
"Referencing non-existing Resource Id will cause 'Not Found' error. " +
- "\n\nResource combination of the title with the key is unique in the scope of tenant. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
+ "\n\nResource combination of the title with the key is unique in the scope of tenant. " +
+ "Remove 'id', 'tenantId' from the request body example (below) to create new Resource entity." +
+ SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json",
consumes = "application/json")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java
index ef3c141131..b44c5327cd 100644
--- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java
@@ -115,6 +115,7 @@ public class TenantController extends BaseController {
"The newly created Tenant Id will be present in the response. " +
"Specify existing Tenant Id id to update the Tenant. " +
"Referencing non-existing Tenant Id will cause 'Not Found' error." +
+ "Remove 'id', 'tenantId' from the request body example (below) to create new Tenant entity." +
SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenant", method = RequestMethod.POST)
diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java
index dbdc702696..e5a33da948 100644
--- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java
@@ -128,7 +128,6 @@ public class TenantProfileController extends BaseController {
"{\n" +
" \"name\": \"Default\",\n" +
" \"description\": \"Default tenant profile\",\n" +
- " \"isolatedTbCore\": false,\n" +
" \"isolatedTbRuleEngine\": false,\n" +
" \"profileData\": {\n" +
" \"configuration\": {\n" +
@@ -165,6 +164,7 @@ public class TenantProfileController extends BaseController {
" \"default\": true\n" +
"}" +
MARKDOWN_CODE_BLOCK_END +
+ "Remove 'id', from the request body example (below) to create new Tenant Profile entity." +
SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfile", method = RequestMethod.POST)
diff --git a/application/src/main/java/org/thingsboard/server/controller/TwoFaConfigController.java b/application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthConfigController.java
similarity index 99%
rename from application/src/main/java/org/thingsboard/server/controller/TwoFaConfigController.java
rename to application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthConfigController.java
index 4b34b95f59..5aad5c9503 100644
--- a/application/src/main/java/org/thingsboard/server/controller/TwoFaConfigController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/TwoFactorAuthConfigController.java
@@ -50,7 +50,7 @@ import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
@RequestMapping("/api/2fa")
@TbCoreComponent
@RequiredArgsConstructor
-public class TwoFaConfigController extends BaseController {
+public class TwoFactorAuthConfigController extends BaseController {
private final TwoFaConfigManager twoFaConfigManager;
private final TwoFactorAuthService twoFactorAuthService;
diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java
index e9375665bb..e96a73b65c 100644
--- a/application/src/main/java/org/thingsboard/server/controller/UserController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java
@@ -176,7 +176,9 @@ public class UserController extends BaseController {
"The newly created User Id will be present in the response. " +
"Specify existing User Id to update the device. " +
"Referencing non-existing User Id will cause 'Not Found' error." +
- "\n\nDevice email is unique for entire platform setup.")
+ "\n\nDevice email is unique for entire platform setup." +
+ "Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new User entity." +
+ "\n\nAvailable for users with 'SYS_ADMIN', 'TENANT_ADMIN' or 'CUSTOMER_USER' authority.")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/user", method = RequestMethod.POST)
@ResponseBody
diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
index 71ea889c03..725d8ca2b4 100644
--- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
@@ -85,8 +85,9 @@ public class WidgetTypeController extends AutoCommitController {
"Specify existing Widget Type id to update the Widget Type. " +
"Referencing non-existing Widget Type Id will cause 'Not Found' error." +
"\n\nWidget Type alias is unique in the scope of Widget Bundle. " +
- "Special Tenant Id '13814000-1dd2-11b2-8080-808080808080' is automatically used if the create request is sent by user with 'SYS_ADMIN' authority."
- + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
+ "Special Tenant Id '13814000-1dd2-11b2-8080-808080808080' is automatically used if the create request is sent by user with 'SYS_ADMIN' authority." +
+ "Remove 'id', 'tenantId' rom the request body example (below) to create new Widget Type entity." +
+ SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/widgetType", method = RequestMethod.POST)
@ResponseBody
diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
index 2d51c3dee8..23ec498d0e 100644
--- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
@@ -89,8 +89,9 @@ public class WidgetsBundleController extends BaseController {
"Specify existing Widget Bundle id to update the Widget Bundle. " +
"Referencing non-existing Widget Bundle Id will cause 'Not Found' error." +
"\n\nWidget Bundle alias is unique in the scope of tenant. " +
- "Special Tenant Id '13814000-1dd2-11b2-8080-808080808080' is automatically used if the create bundle request is sent by user with 'SYS_ADMIN' authority."
- + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
+ "Special Tenant Id '13814000-1dd2-11b2-8080-808080808080' is automatically used if the create bundle request is sent by user with 'SYS_ADMIN' authority." +
+ "Remove 'id', 'tenantId' from the request body example (below) to create new Widgets Bundle entity." +
+ SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/widgetsBundle", method = RequestMethod.POST)
@ResponseBody
diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java
index b02f85f84a..208fdead93 100644
--- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java
+++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsExpiredResponse.java
@@ -34,7 +34,7 @@ public class ThingsboardCredentialsExpiredResponse extends ThingsboardErrorRespo
return new ThingsboardCredentialsExpiredResponse(message, resetToken);
}
- @ApiModelProperty(position = 5, value = "Password reset token", readOnly = true)
+ @ApiModelProperty(position = 5, value = "Password reset token", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public String getResetToken() {
return resetToken;
}
diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java
index 09fce98985..7cf2ca87f1 100644
--- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java
+++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponse.java
@@ -46,12 +46,12 @@ public class ThingsboardErrorResponse {
return new ThingsboardErrorResponse(message, errorCode, status);
}
- @ApiModelProperty(position = 1, value = "HTTP Response Status Code", example = "401", readOnly = true)
+ @ApiModelProperty(position = 1, value = "HTTP Response Status Code", example = "401", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public Integer getStatus() {
return status.value();
}
- @ApiModelProperty(position = 2, value = "Error message", example = "Authentication failed", readOnly = true)
+ @ApiModelProperty(position = 2, value = "Error message", example = "Authentication failed", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public String getMessage() {
return message;
}
@@ -69,12 +69,12 @@ public class ThingsboardErrorResponse {
"\n\n* `34` - Too many updates (Too many updates over Websocket session)" +
"\n\n* `40` - Subscription violation (HTTP: 403 - Forbidden)",
example = "10", dataType = "integer",
- readOnly = true)
+ accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public ThingsboardErrorCode getErrorCode() {
return errorCode;
}
- @ApiModelProperty(position = 4, value = "Timestamp", readOnly = true)
+ @ApiModelProperty(position = 4, value = "Timestamp", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public Date getTimestamp() {
return timestamp;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java
index 3920e567f9..4e12fa3366 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java
@@ -48,9 +48,8 @@ public class DeviceProfileMsgConstructor {
// builder.setDefaultRuleChainIdMSB(deviceProfile.getDefaultRuleChainId().getId().getMostSignificantBits())
// .setDefaultRuleChainIdLSB(deviceProfile.getDefaultRuleChainId().getId().getLeastSignificantBits());
// }
- if (deviceProfile.getDefaultQueueId() != null) {
- builder.setDefaultQueueIdMSB(deviceProfile.getDefaultQueueId().getId().getMostSignificantBits())
- .setDefaultQueueIdLSB(deviceProfile.getDefaultQueueId().getId().getLeastSignificantBits());
+ if (deviceProfile.getDefaultQueueName() != null) {
+ builder.setDefaultQueueName(deviceProfile.getDefaultQueueName());
}
if (deviceProfile.getDescription() != null) {
builder.setDescription(deviceProfile.getDescription());
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java
index 84cc63d73d..35ac760faa 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java
@@ -15,7 +15,6 @@
*/
package org.thingsboard.server.service.edge.rpc.constructor;
-import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil;
@@ -23,7 +22,6 @@ import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
-import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.EdgeVersion;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg;
@@ -35,11 +33,8 @@ import org.thingsboard.server.service.edge.rpc.constructor.rule.RuleChainMetadat
@Component
@Slf4j
@TbCoreComponent
-@AllArgsConstructor
public class RuleChainMsgConstructor {
- private final QueueService queueService;
-
public RuleChainUpdateMsg constructRuleChainUpdatedMsg(RuleChainId edgeRootRuleChainId, UpdateMsgType msgType, RuleChain ruleChain) {
RuleChainUpdateMsg.Builder builder = RuleChainUpdateMsg.newBuilder()
.setMsgType(msgType)
@@ -61,7 +56,7 @@ public class RuleChainMsgConstructor {
RuleChainMetaData ruleChainMetaData,
EdgeVersion edgeVersion) {
RuleChainMetadataConstructor ruleChainMetadataConstructor
- = RuleChainMetadataConstructorFactory.getByEdgeVersion(edgeVersion, queueService);
+ = RuleChainMetadataConstructorFactory.getByEdgeVersion(edgeVersion);
return ruleChainMetadataConstructor.constructRuleChainMetadataUpdatedMsg(tenantId, msgType, ruleChainMetaData);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java
index a938d42c3b..8fb32926f5 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/AbstractRuleChainMetadataConstructor.java
@@ -16,20 +16,15 @@
package org.thingsboard.server.service.edge.rpc.constructor.rule;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
-import org.thingsboard.rule.engine.flow.TbCheckpointNode;
-import org.thingsboard.server.common.data.id.QueueId;
import org.thingsboard.server.common.data.id.TenantId;
-import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
-import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.NodeConnectionInfoProto;
import org.thingsboard.server.gen.edge.v1.RuleChainConnectionInfoProto;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
@@ -39,16 +34,11 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import java.util.ArrayList;
import java.util.List;
import java.util.NavigableSet;
-import java.util.UUID;
@Slf4j
@AllArgsConstructor
public abstract class AbstractRuleChainMetadataConstructor implements RuleChainMetadataConstructor {
- public static final List nodeTypes = List.of(TbCheckpointNode.class.getName());
-
- private final QueueService queueService;
-
@Override
public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
UpdateMsgType msgType,
@@ -144,24 +134,4 @@ public abstract class AbstractRuleChainMetadataConstructor implements RuleChainM
.setAdditionalInfo(JacksonUtil.OBJECT_MAPPER.writeValueAsString(ruleChainConnectionInfo.getAdditionalInfo()))
.build();
}
-
- protected List updateQueueIdToQueueNameNodeConfiguration(TenantId tenantId, List nodes) {
- List result = new ArrayList<>();
- for (RuleNode node : nodes) {
- if (nodeTypes.contains(node.getType())) {
- ObjectNode configuration = (ObjectNode) node.getConfiguration();
- JsonNode queueIdNode = configuration.remove("queueId");
- if (queueIdNode != null) {
- String queueId = queueIdNode.asText();
- Queue queueById = queueService.findQueueById(tenantId, new QueueId(UUID.fromString(queueId)));
- if (queueById != null) {
- configuration.put("queueName", queueById.getName());
- node.setConfiguration(configuration);
- }
- }
- }
- result.add(node);
- }
- return result;
- }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorFactory.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorFactory.java
index 864a631e96..5fc686f86a 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorFactory.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorFactory.java
@@ -15,21 +15,18 @@
*/
package org.thingsboard.server.service.edge.rpc.constructor.rule;
-import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.EdgeVersion;
public final class RuleChainMetadataConstructorFactory {
- public static RuleChainMetadataConstructor getByEdgeVersion(EdgeVersion edgeVersion,
- QueueService queueService) {
+ public static RuleChainMetadataConstructor getByEdgeVersion(EdgeVersion edgeVersion) {
switch (edgeVersion) {
case V_3_3_0:
- return new RuleChainMetadataConstructorV330(queueService);
+ return new RuleChainMetadataConstructorV330();
case V_3_3_3:
- return new RuleChainMetadataConstructorV333(queueService);
case V_3_4_0:
default:
- return new RuleChainMetadataConstructorV340(queueService);
+ return new RuleChainMetadataConstructorV340();
}
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV330.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV330.java
index 4c29164f5a..3172ee9277 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV330.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV330.java
@@ -27,7 +27,6 @@ import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
-import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import java.util.ArrayList;
@@ -43,16 +42,11 @@ public class RuleChainMetadataConstructorV330 extends AbstractRuleChainMetadataC
private static final String RULE_CHAIN_INPUT_NODE = TbRuleChainInputNode.class.getName();
private static final String TB_RULE_CHAIN_OUTPUT_NODE = TbRuleChainOutputNode.class.getName();
- public RuleChainMetadataConstructorV330(QueueService queueService) {
- super(queueService);
- }
-
@Override
protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
RuleChainMetadataUpdateMsg.Builder builder,
RuleChainMetaData ruleChainMetaData) throws JsonProcessingException {
List supportedNodes = filterNodes(ruleChainMetaData.getNodes());
- supportedNodes = updateQueueIdToQueueNameNodeConfiguration(tenantId, supportedNodes);
NavigableSet removedNodeIndexes = getRemovedNodeIndexes(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections());
List connections = filterConnections(ruleChainMetaData.getNodes(), ruleChainMetaData.getConnections(), removedNodeIndexes);
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV333.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV333.java
deleted file mode 100644
index 3fb346e701..0000000000
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV333.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * 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.edge.rpc.constructor.rule;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import lombok.extern.slf4j.Slf4j;
-import org.thingsboard.server.common.data.id.TenantId;
-import org.thingsboard.server.common.data.rule.RuleChainMetaData;
-import org.thingsboard.server.common.data.rule.RuleNode;
-import org.thingsboard.server.dao.queue.QueueService;
-import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
-
-import java.util.List;
-import java.util.TreeSet;
-
-@Slf4j
-public class RuleChainMetadataConstructorV333 extends AbstractRuleChainMetadataConstructor {
-
- public RuleChainMetadataConstructorV333(QueueService queueService) {
- super(queueService);
- }
-
- @Override
- protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
- RuleChainMetadataUpdateMsg.Builder builder,
- RuleChainMetaData ruleChainMetaData) throws JsonProcessingException {
- List nodes = updateQueueIdToQueueNameNodeConfiguration(tenantId, ruleChainMetaData.getNodes());
- builder.addAllNodes(constructNodes(nodes))
- .addAllConnections(constructConnections(ruleChainMetaData.getConnections()))
- .addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections(), new TreeSet<>()));
- if (ruleChainMetaData.getFirstNodeIndex() != null) {
- builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex());
- } else {
- builder.setFirstNodeIndex(-1);
- }
- }
-}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV340.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV340.java
index edb6260cc5..9acb2ae9f5 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV340.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV340.java
@@ -19,7 +19,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
-import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg;
import java.util.TreeSet;
@@ -27,10 +26,6 @@ import java.util.TreeSet;
@Slf4j
public class RuleChainMetadataConstructorV340 extends AbstractRuleChainMetadataConstructor {
- public RuleChainMetadataConstructorV340(QueueService queueService) {
- super(queueService);
- }
-
@Override
protected void constructRuleChainMetadataUpdatedMsg(TenantId tenantId,
RuleChainMetadataUpdateMsg.Builder builder,
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java
index f30111e1ef..ad6446cb95 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryEdgeProcessor.java
@@ -158,21 +158,21 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
return metaData;
}
- private Pair getDefaultQueueNameAndRuleChainId(TenantId tenantId, EntityId entityId) {
+ private Pair getDefaultQueueNameAndRuleChainId(TenantId tenantId, EntityId entityId) {
if (EntityType.DEVICE.equals(entityId.getEntityType())) {
DeviceProfile deviceProfile = deviceProfileCache.get(tenantId, new DeviceId(entityId.getId()));
RuleChainId ruleChainId;
- QueueId queueId;
+ String queueName;
if (deviceProfile == null) {
log.warn("[{}] Device profile is null!", entityId);
ruleChainId = null;
- queueId = null;
+ queueName = null;
} else {
ruleChainId = deviceProfile.getDefaultRuleChainId();
- queueId = deviceProfile.getDefaultQueueId();
+ queueName = deviceProfile.getDefaultQueueName();
}
- return new ImmutablePair<>(queueId, ruleChainId);
+ return new ImmutablePair<>(queueName, ruleChainId);
} else {
return new ImmutablePair<>(null, null);
}
@@ -183,10 +183,8 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) {
JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
metaData.putValue("ts", tsKv.getTs() + "");
- Pair defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
- QueueId queueId = defaultQueueAndRuleChain.getKey();
- RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
- TbMsg tbMsg = TbMsg.newMsg(queueId, SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
+ var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
+ TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
@@ -206,10 +204,8 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
private ListenableFuture processPostAttributes(TenantId tenantId, CustomerId customerId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) {
SettableFuture futureToSet = SettableFuture.create();
JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
- Pair defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
- QueueId queueId = defaultQueueAndRuleChain.getKey();
- RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
- TbMsg tbMsg = TbMsg.newMsg(queueId, SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
+ var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
+ TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
@@ -233,10 +229,8 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
Futures.addCallback(future, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable List keys) {
- Pair defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
- QueueId queueId = defaultQueueAndRuleChain.getKey();
- RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
- TbMsg tbMsg = TbMsg.newMsg(queueId, DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
+ var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
+ TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null);
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
index 21f3171d3d..e66d7d5595 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
@@ -72,6 +72,7 @@ import org.thingsboard.server.gen.edge.v1.RelationRequestMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.v1.UserCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.v1.WidgetBundleTypesRequestMsg;
+import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.entityview.TbEntityViewService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.state.DefaultDeviceStateService;
@@ -83,6 +84,7 @@ import java.util.Map;
import java.util.UUID;
@Service
+@TbCoreComponent
@Slf4j
public class DefaultEdgeRequestsService implements EdgeRequestsService {
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java
index 741a89749f..5d9b4290f4 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java
@@ -183,11 +183,17 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try {
- if (customerIds.isEmpty()) {
+ Set addedCustomerIds = new HashSet<>();
+ for (CustomerId customerId : customerIds) {
+ if (!dashboard.isAssignedToCustomer(customerId)) {
+ addedCustomerIds.add(customerId);
+ }
+ }
+ if (addedCustomerIds.isEmpty()) {
return dashboard;
} else {
Dashboard savedDashboard = null;
- for (CustomerId customerId : customerIds) {
+ for (CustomerId customerId : addedCustomerIds) {
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId));
ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId);
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard,
@@ -207,11 +213,17 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement
TenantId tenantId = dashboard.getTenantId();
DashboardId dashboardId = dashboard.getId();
try {
- if (customerIds.isEmpty()) {
+ Set removedCustomerIds = new HashSet<>();
+ for (CustomerId customerId : customerIds) {
+ if (dashboard.isAssignedToCustomer(customerId)) {
+ removedCustomerIds.add(customerId);
+ }
+ }
+ if (removedCustomerIds.isEmpty()) {
return dashboard;
} else {
Dashboard savedDashboard = null;
- for (CustomerId customerId : customerIds) {
+ for (CustomerId customerId : removedCustomerIds) {
ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId);
savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, customerId));
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard,
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java
index ad0a91e0eb..4355d998bb 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java
@@ -48,13 +48,11 @@ import java.util.stream.Collectors;
@TbCoreComponent
@AllArgsConstructor
public class DefaultTbQueueService extends AbstractTbEntityService implements TbQueueService {
- private static final String MAIN = "Main";
private static final long DELETE_DELAY = 30;
private final QueueService queueService;
private final TbClusterService tbClusterService;
private final TbQueueAdmin tbQueueAdmin;
- private final DeviceProfileService deviceProfileService;
private final SchedulerComponent scheduler;
@Override
@@ -205,35 +203,7 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
}
tenantIds.forEach(tenantId -> {
- Map> deviceProfileQueues;
-
- if (oldTenantProfile != null && !newTenantProfile.getId().equals(oldTenantProfile.getId()) || !toRemove.isEmpty()) {
- List deviceProfiles = deviceProfileService.findDeviceProfiles(tenantId, new PageLink(Integer.MAX_VALUE)).getData();
- deviceProfileQueues = deviceProfiles.stream()
- .filter(dp -> dp.getDefaultQueueId() != null)
- .collect(Collectors.groupingBy(DeviceProfile::getDefaultQueueId));
- } else {
- deviceProfileQueues = Collections.emptyMap();
- }
-
- Map createdQueues = toCreate.stream()
- .map(key -> saveQueue(new Queue(tenantId, newQueues.get(key))))
- .collect(Collectors.toMap(Queue::getName, Queue::getId));
-
- // assigning created queues to device profiles instead of system queues
- if (oldTenantProfile != null && !oldTenantProfile.isIsolatedTbRuleEngine()) {
- deviceProfileQueues.forEach((queueId, list) -> {
- Queue queue = queueService.findQueueById(TenantId.SYS_TENANT_ID, queueId);
- QueueId queueIdToAssign = createdQueues.get(queue.getName());
- if (queueIdToAssign == null) {
- queueIdToAssign = createdQueues.get(MAIN);
- }
- for (DeviceProfile deviceProfile : list) {
- deviceProfile.setDefaultQueueId(queueIdToAssign);
- saveDeviceProfile(deviceProfile);
- }
- });
- }
+ toCreate.forEach(key -> saveQueue(new Queue(tenantId, newQueues.get(key))));
toUpdate.forEach(key -> {
Queue queueToUpdate = new Queue(tenantId, newQueues.get(key));
@@ -241,9 +211,7 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
queueToUpdate.setId(foundQueue.getId());
queueToUpdate.setCreatedTime(foundQueue.getCreatedTime());
- if (queueToUpdate.equals(foundQueue)) {
- //Queue not changed
- } else {
+ if (!queueToUpdate.equals(foundQueue)) {
saveQueue(queueToUpdate);
}
});
@@ -251,26 +219,9 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb
toRemove.forEach(q -> {
Queue queue = queueService.findQueueByTenantIdAndNameInternal(tenantId, q);
QueueId queueIdForRemove = queue.getId();
- if (deviceProfileQueues.containsKey(queueIdForRemove)) {
- Queue foundQueue = queueService.findQueueByTenantIdAndName(tenantId, q);
- if (foundQueue == null || queue.equals(foundQueue)) {
- foundQueue = queueService.findQueueByTenantIdAndName(tenantId, MAIN);
- }
- QueueId newQueueId = foundQueue.getId();
- deviceProfileQueues.get(queueIdForRemove).stream()
- .peek(dp -> dp.setDefaultQueueId(newQueueId))
- .forEach(this::saveDeviceProfile);
- }
deleteQueue(tenantId, queueIdForRemove);
});
});
}
- //TODO: remove after implementing TbDeviceProfileService
- private void saveDeviceProfile(DeviceProfile deviceProfile) {
- DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
- tbClusterService.onDeviceProfileChange(savedDeviceProfile, null);
- tbClusterService.broadcastEntityStateChangeEvent(deviceProfile.getTenantId(), savedDeviceProfile.getId(), ComponentLifecycleEvent.UPDATED);
- }
-
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java
index e465e70ad7..a41bbb4385 100644
--- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java
@@ -72,7 +72,7 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse
savedUser, user, actionType, true, null);
return savedUser;
} catch (Exception e) {
- notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER), user, actionType, user, e);
+ notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER), tbUser, actionType, user, e);
throw e;
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
index 14e49e056f..78e03ffe1a 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
@@ -195,22 +195,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
public void createDefaultTenantProfiles() throws Exception {
tenantProfileService.findOrCreateDefaultTenantProfile(TenantId.SYS_TENANT_ID);
- TenantProfileData tenantProfileData = new TenantProfileData();
- tenantProfileData.setConfiguration(new DefaultTenantProfileConfiguration());
-
- TenantProfile isolatedTbCoreProfile = new TenantProfile();
- isolatedTbCoreProfile.setDefault(false);
- isolatedTbCoreProfile.setName("Isolated TB Core");
- isolatedTbCoreProfile.setDescription("Isolated TB Core tenant profile");
- isolatedTbCoreProfile.setIsolatedTbCore(true);
- isolatedTbCoreProfile.setIsolatedTbRuleEngine(false);
- isolatedTbCoreProfile.setProfileData(tenantProfileData);
- try {
- tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, isolatedTbCoreProfile);
- } catch (DataValidationException e) {
- log.warn(e.getMessage());
- }
-
TenantProfileData isolatedRuleEngineTenantProfileData = new TenantProfileData();
isolatedRuleEngineTenantProfileData.setConfiguration(new DefaultTenantProfileConfiguration());
@@ -239,7 +223,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
isolatedTbRuleEngineProfile.setDefault(false);
isolatedTbRuleEngineProfile.setName("Isolated TB Rule Engine");
isolatedTbRuleEngineProfile.setDescription("Isolated TB Rule Engine tenant profile");
- isolatedTbRuleEngineProfile.setIsolatedTbCore(false);
isolatedTbRuleEngineProfile.setIsolatedTbRuleEngine(true);
isolatedTbRuleEngineProfile.setProfileData(isolatedRuleEngineTenantProfileData);
@@ -248,20 +231,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
} catch (DataValidationException e) {
log.warn(e.getMessage());
}
-
- TenantProfile isolatedTbCoreAndTbRuleEngineProfile = new TenantProfile();
- isolatedTbCoreAndTbRuleEngineProfile.setDefault(false);
- isolatedTbCoreAndTbRuleEngineProfile.setName("Isolated TB Core and TB Rule Engine");
- isolatedTbCoreAndTbRuleEngineProfile.setDescription("Isolated TB Core and TB Rule Engine tenant profile");
- isolatedTbCoreAndTbRuleEngineProfile.setIsolatedTbCore(true);
- isolatedTbCoreAndTbRuleEngineProfile.setIsolatedTbRuleEngine(true);
- isolatedTbCoreAndTbRuleEngineProfile.setProfileData(isolatedRuleEngineTenantProfileData);
-
- try {
- tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, isolatedTbCoreAndTbRuleEngineProfile);
- } catch (DataValidationException e) {
- log.warn(e.getMessage());
- }
}
@Override
diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
index e428d55d91..d22039683d 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
@@ -589,10 +589,6 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
} catch (Exception e) {
}
- log.info("Updating device profiles...");
- schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.4", "schema_update_device_profile.sql");
- loadSql(schemaUpdateFile, conn);
-
log.info("Updating schema settings...");
conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3004000;");
log.info("Schema updated.");
diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
index 9bfa86b3ba..b90da586fc 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
@@ -156,9 +156,8 @@ public class DefaultDataUpdateService implements DataUpdateService {
break;
case "3.3.4":
log.info("Updating data from version 3.3.4 to 3.4.0 ...");
- rateLimitsUpdater.updateEntities();
tenantsProfileQueueConfigurationUpdater.updateEntities();
- checkPointRuleNodesUpdater.updateEntities();
+ rateLimitsUpdater.updateEntities();
break;
default:
throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion);
@@ -629,47 +628,4 @@ public class DefaultDataUpdateService implements DataUpdateService {
return mainQueueConfiguration;
}
- private final PaginatedUpdater checkPointRuleNodesUpdater =
- new PaginatedUpdater<>() {
-
- @Override
- protected String getName() {
- return "Checkpoint rule nodes updater";
- }
-
- @Override
- protected boolean forceReportTotal() {
- return true;
- }
-
- @Override
- protected PageData findEntities(String id, PageLink pageLink) {
- return ruleChainService.findAllRuleNodesByType("org.thingsboard.rule.engine.flow.TbCheckpointNode", pageLink);
- }
-
- @Override
- protected void updateEntity(RuleNode ruleNode) {
- updateCheckPointRuleNodeConfiguration(ruleNode);
- }
- };
-
- private void updateCheckPointRuleNodeConfiguration(RuleNode node) {
- try {
- ObjectNode configuration = (ObjectNode) node.getConfiguration();
- JsonNode queueNameNode = configuration.remove("queueName");
- if (queueNameNode != null) {
- RuleChain ruleChain = this.ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, node.getRuleChainId());
- TenantId tenantId = ruleChain.getTenantId();
- Map queues =
- queueService.findQueuesByTenantId(tenantId).stream().collect(Collectors.toMap(Queue::getName, Queue::getId));
- String queueName = queueNameNode.asText();
- QueueId queueId = queues.get(queueName);
- configuration.put("queueId", queueId != null ? queueId.toString() : "");
- ruleChainService.saveRuleNode(tenantId, node);
- }
- } catch (Exception e) {
- log.error("Failed to update checkpoint rule node configuration name=["+node.getName()+"], id=["+ node.getId().getId() +"]", e);
- }
- }
-
}
diff --git a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java
index 7e1a3d7fa7..aa8e019317 100644
--- a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java
+++ b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java
@@ -20,7 +20,9 @@ import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.NestedRuntimeException;
@@ -47,13 +49,17 @@ import org.thingsboard.server.queue.usagestats.TbApiUsageClient;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import javax.annotation.PostConstruct;
-import javax.mail.MessagingException;
+import javax.annotation.PreDestroy;
import javax.mail.internet.MimeMessage;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
@Service
@Slf4j
@@ -70,6 +76,8 @@ public class DefaultMailService implements MailService {
private final AdminSettingsService adminSettingsService;
private final TbApiUsageClient apiUsageClient;
+ private static final long DEFAULT_TIMEOUT = 10_000;
+
@Lazy
@Autowired
private TbApiUsageStateService apiUsageStateService;
@@ -77,10 +85,15 @@ public class DefaultMailService implements MailService {
@Autowired
private MailExecutorService mailExecutorService;
+ @Autowired
+ private PasswordResetExecutorService passwordResetExecutorService;
+
private JavaMailSenderImpl mailSender;
private String mailFrom;
+ private long timeout;
+
public DefaultMailService(MessageSource messages, Configuration freemarkerConfig, AdminSettingsService adminSettingsService, TbApiUsageClient apiUsageClient) {
this.messages = messages;
this.freemarkerConfig = freemarkerConfig;
@@ -100,6 +113,7 @@ public class DefaultMailService implements MailService {
JsonNode jsonConfig = settings.getJsonValue();
mailSender = createMailSender(jsonConfig);
mailFrom = jsonConfig.get("mailFrom").asText();
+ timeout = jsonConfig.get("timeout").asLong(DEFAULT_TIMEOUT);
} else {
throw new IncorrectParameterException("Failed to update mail configuration. Settings not found!");
}
@@ -166,7 +180,7 @@ public class DefaultMailService implements MailService {
@Override
public void sendEmail(TenantId tenantId, String email, String subject, String message) throws ThingsboardException {
- sendMail(mailSender, mailFrom, email, subject, message);
+ sendMail(mailSender, mailFrom, email, subject, message, timeout);
}
@Override
@@ -174,13 +188,14 @@ public class DefaultMailService implements MailService {
JavaMailSenderImpl testMailSender = createMailSender(jsonConfig);
String mailFrom = jsonConfig.get("mailFrom").asText();
String subject = messages.getMessage("test.message.subject", null, Locale.US);
+ long timeout = jsonConfig.get("timeout").asLong(DEFAULT_TIMEOUT);
Map model = new HashMap<>();
model.put(TARGET_EMAIL, email);
String message = mergeTemplateIntoString("test.ftl", model);
- sendMail(testMailSender, mailFrom, email, subject, message);
+ sendMail(testMailSender, mailFrom, email, subject, message, timeout);
}
@Override
@@ -194,7 +209,7 @@ public class DefaultMailService implements MailService {
String message = mergeTemplateIntoString("activation.ftl", model);
- sendMail(mailSender, mailFrom, email, subject, message);
+ sendMail(mailSender, mailFrom, email, subject, message, timeout);
}
@Override
@@ -208,7 +223,7 @@ public class DefaultMailService implements MailService {
String message = mergeTemplateIntoString("account.activated.ftl", model);
- sendMail(mailSender, mailFrom, email, subject, message);
+ sendMail(mailSender, mailFrom, email, subject, message, timeout);
}
@Override
@@ -222,12 +237,12 @@ public class DefaultMailService implements MailService {
String message = mergeTemplateIntoString("reset.password.ftl", model);
- sendMail(mailSender, mailFrom, email, subject, message);
+ sendMail(mailSender, mailFrom, email, subject, message, timeout);
}
@Override
public void sendResetPasswordEmailAsync(String passwordResetLink, String email) {
- mailExecutorService.execute(() -> {
+ passwordResetExecutorService.execute(() -> {
try {
this.sendResetPasswordEmail(passwordResetLink, email);
} catch (ThingsboardException e) {
@@ -247,20 +262,20 @@ public class DefaultMailService implements MailService {
String message = mergeTemplateIntoString("password.was.reset.ftl", model);
- sendMail(mailSender, mailFrom, email, subject, message);
+ sendMail(mailSender, mailFrom, email, subject, message, timeout);
}
@Override
public void send(TenantId tenantId, CustomerId customerId, TbEmail tbEmail) throws ThingsboardException {
- sendMail(tenantId, customerId, tbEmail, this.mailSender);
+ sendMail(tenantId, customerId, tbEmail, this.mailSender, timeout);
}
@Override
- public void send(TenantId tenantId, CustomerId customerId, TbEmail tbEmail, JavaMailSender javaMailSender) throws ThingsboardException {
- sendMail(tenantId, customerId, tbEmail, javaMailSender);
+ public void send(TenantId tenantId, CustomerId customerId, TbEmail tbEmail, JavaMailSender javaMailSender, long timeout) throws ThingsboardException {
+ sendMail(tenantId, customerId, tbEmail, javaMailSender, timeout);
}
- private void sendMail(TenantId tenantId, CustomerId customerId, TbEmail tbEmail, JavaMailSender javaMailSender) throws ThingsboardException {
+ private void sendMail(TenantId tenantId, CustomerId customerId, TbEmail tbEmail, JavaMailSender javaMailSender, long timeout) throws ThingsboardException {
if (apiUsageStateService.getApiUsageState(tenantId).isEmailSendEnabled()) {
try {
MimeMessage mailMsg = javaMailSender.createMimeMessage();
@@ -287,7 +302,7 @@ public class DefaultMailService implements MailService {
helper.addInline(imgId, iss, contentType);
}
}
- javaMailSender.send(helper.getMimeMessage());
+ sendMailWithTimeout(javaMailSender, helper.getMimeMessage(), timeout);
apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.EMAIL_EXEC_COUNT, 1);
} catch (Exception e) {
throw handleException(e);
@@ -308,7 +323,7 @@ public class DefaultMailService implements MailService {
String message = mergeTemplateIntoString("account.lockout.ftl", model);
- sendMail(mailSender, mailFrom, email, subject, message);
+ sendMail(mailSender, mailFrom, email, subject, message, timeout);
}
@Override
@@ -320,7 +335,7 @@ public class DefaultMailService implements MailService {
"expirationTimeSeconds", expirationTimeSeconds
));
- sendMail(mailSender, mailFrom, email, subject, message);
+ sendMail(mailSender, mailFrom, email, subject, message, timeout);
}
@Override
@@ -347,7 +362,7 @@ public class DefaultMailService implements MailService {
message = mergeTemplateIntoString("state.disabled.ftl", model);
break;
}
- sendMail(mailSender, mailFrom, email, subject, message);
+ sendMail(mailSender, mailFrom, email, subject, message, timeout);
}
@Override
@@ -447,9 +462,8 @@ public class DefaultMailService implements MailService {
}
}
- private void sendMail(JavaMailSenderImpl mailSender,
- String mailFrom, String email,
- String subject, String message) throws ThingsboardException {
+ private void sendMail(JavaMailSenderImpl mailSender, String mailFrom, String email,
+ String subject, String message, long timeout) throws ThingsboardException {
try {
MimeMessage mimeMsg = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMsg, UTF_8);
@@ -457,12 +471,24 @@ public class DefaultMailService implements MailService {
helper.setTo(email);
helper.setSubject(subject);
helper.setText(message, true);
- mailSender.send(helper.getMimeMessage());
+
+ sendMailWithTimeout(mailSender, helper.getMimeMessage(), timeout);
} catch (Exception e) {
throw handleException(e);
}
}
+ private void sendMailWithTimeout(JavaMailSender mailSender, MimeMessage msg, long timeout) {
+ try {
+ mailExecutorService.submit(() -> mailSender.send(msg)).get(timeout, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ log.debug("Error during mail submission", e);
+ throw new RuntimeException("Timeout!");
+ } catch (Exception e) {
+ throw new RuntimeException(ExceptionUtils.getRootCause(e));
+ }
+ }
+
private String mergeTemplateIntoString(String templateLocation,
Map model) throws ThingsboardException {
try {
diff --git a/msa/js-executor/api/httpServer.js b/application/src/main/java/org/thingsboard/server/service/mail/PasswordResetExecutorService.java
similarity index 53%
rename from msa/js-executor/api/httpServer.js
rename to application/src/main/java/org/thingsboard/server/service/mail/PasswordResetExecutorService.java
index 62bf5807b1..ea761c144d 100644
--- a/msa/js-executor/api/httpServer.js
+++ b/application/src/main/java/org/thingsboard/server/service/mail/PasswordResetExecutorService.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,18 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-const config = require('config'),
- logger = require('../config/logger')._logger('httpServer'),
- express = require('express');
+package org.thingsboard.server.service.mail;
-const httpPort = Number(config.get('http_port'));
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.thingsboard.common.util.AbstractListeningExecutor;
-const app = express();
+@Component
+public class PasswordResetExecutorService extends AbstractListeningExecutor {
-app.get('/livenessProbe', async (req, res) => {
- const date = new Date();
- const message = { now: date.toISOString() };
- res.send(message);
-})
+ @Value("${actors.rule.mail_password_reset_thread_pool_size:10}")
+ private int mailExecutorThreadPoolSize;
-app.listen(httpPort, () => logger.info(`Started http endpoint on port ${httpPort}. Please, use /livenessProbe !`))
\ No newline at end of file
+ @Override
+ protected int getThreadPollSize() {
+ return mailExecutorThreadPoolSize;
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
index 9e60f69620..062e4128d4 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
@@ -181,7 +181,7 @@ public class DefaultTbClusterService implements TbClusterService {
tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId())));
}
}
- TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueId(), tenantId, entityId);
+ TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueName(), tenantId, entityId);
log.trace("PUSHING msg: {} to:{}", tbMsg, tpi);
ToRuleEngineMsg msg = ToRuleEngineMsg.newBuilder()
.setTenantIdMSB(tenantId.getId().getMostSignificantBits())
@@ -194,16 +194,16 @@ public class DefaultTbClusterService implements TbClusterService {
private TbMsg transformMsg(TbMsg tbMsg, DeviceProfile deviceProfile) {
if (deviceProfile != null) {
RuleChainId targetRuleChainId = deviceProfile.getDefaultRuleChainId();
- QueueId targetQueueId = deviceProfile.getDefaultQueueId();
+ String targetQueueName = deviceProfile.getDefaultQueueName();
boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId());
- boolean isQueueTransform = targetQueueId != null && !targetQueueId.equals(tbMsg.getQueueId());
+ boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName());
if (isRuleChainTransform && isQueueTransform) {
- tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueId);
+ tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName);
} else if (isRuleChainTransform) {
tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId);
} else if (isQueueTransform) {
- tbMsg = TbMsg.transformMsg(tbMsg, targetQueueId);
+ tbMsg = TbMsg.transformMsg(tbMsg, targetQueueName);
}
}
return tbMsg;
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
index 92dd4fcf5c..3c7552ff9b 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
@@ -274,7 +274,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
final boolean timeout = !ctx.await(configuration.getPackProcessingTimeout(), TimeUnit.MILLISECONDS);
- TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(configuration.getId(), timeout, ctx);
+ TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(configuration.getName(), timeout, ctx);
if (timeout) {
printFirstOrAll(configuration, ctx, ctx.getPendingMap(), "Timeout");
}
@@ -339,7 +339,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
new TbMsgPackCallback(id, tenantId, ctx);
try {
if (toRuleEngineMsg.getTbMsg() != null && !toRuleEngineMsg.getTbMsg().isEmpty()) {
- forwardToRuleEngineActor(configuration.getId(), tenantId, toRuleEngineMsg, callback);
+ forwardToRuleEngineActor(configuration.getName(), tenantId, toRuleEngineMsg, callback);
} else {
callback.onSuccess();
}
@@ -353,7 +353,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
log.info("{} to process [{}] messages", prefix, map.size());
for (Map.Entry> pending : map.entrySet()) {
ToRuleEngineMsg tmp = pending.getValue().getValue();
- TbMsg tmpMsg = TbMsg.fromBytes(configuration.getId(), tmp.getTbMsg().toByteArray(), TbMsgCallback.EMPTY);
+ TbMsg tmpMsg = TbMsg.fromBytes(configuration.getName(), tmp.getTbMsg().toByteArray(), TbMsgCallback.EMPTY);
RuleNodeInfo ruleNodeInfo = ctx.getLastVisitedRuleNode(pending.getKey());
if (printAll) {
log.trace("[{}] {} to process message: {}, Last Rule Node: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo);
@@ -461,8 +461,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
partitionService.removeQueue(queueDeleteMsg);
}
- private void forwardToRuleEngineActor(QueueId queueId, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) {
- TbMsg tbMsg = TbMsg.fromBytes(queueId, toRuleEngineMsg.getTbMsg().toByteArray(), callback);
+ private void forwardToRuleEngineActor(String queueName, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) {
+ TbMsg tbMsg = TbMsg.fromBytes(queueName, toRuleEngineMsg.getTbMsg().toByteArray(), callback);
QueueToRuleEngineMsg msg;
ProtocolStringList relationTypesList = toRuleEngineMsg.getRelationTypesList();
Set relationTypes = null;
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java
index 75fbd39a95..1ab9686d6f 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java
@@ -45,7 +45,7 @@ public class DefaultTenantRoutingInfoService implements TenantRoutingInfoService
Tenant tenant = tenantService.findTenantById(tenantId);
if (tenant != null) {
TenantProfile tenantProfile = tenantProfileCache.get(tenant.getTenantProfileId());
- return new TenantRoutingInfo(tenantId, tenantProfile.isIsolatedTbCore(), tenantProfile.isIsolatedTbRuleEngine());
+ return new TenantRoutingInfo(tenantId, tenantProfile.isIsolatedTbRuleEngine());
} else {
throw new RuntimeException("Tenant not found!");
}
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingResult.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingResult.java
index 2e3fedb766..001f4a4c2d 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingResult.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingResult.java
@@ -29,7 +29,7 @@ import java.util.concurrent.ConcurrentMap;
public class TbRuleEngineProcessingResult {
@Getter
- private final QueueId queueId;
+ private final String queueName;
@Getter
private final boolean success;
@Getter
@@ -37,8 +37,8 @@ public class TbRuleEngineProcessingResult {
@Getter
private final TbMsgPackProcessingContext ctx;
- public TbRuleEngineProcessingResult(QueueId queueId, boolean timeout, TbMsgPackProcessingContext ctx) {
- this.queueId = queueId;
+ public TbRuleEngineProcessingResult(String queueName, boolean timeout, TbMsgPackProcessingContext ctx) {
+ this.queueName = queueName;
this.timeout = timeout;
this.ctx = ctx;
this.success = !timeout && ctx.getPendingMap().isEmpty() && ctx.getFailedMap().isEmpty();
diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java
index 2191c38017..e50d560d18 100644
--- a/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java
+++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/TbRuleEngineProcessingStrategyFactory.java
@@ -125,7 +125,7 @@ public class TbRuleEngineProcessingStrategyFactory {
}
log.debug("[{}] Going to reprocess {} messages", queueName, toReprocess.size());
if (log.isTraceEnabled()) {
- toReprocess.forEach((id, msg) -> log.trace("Going to reprocess [{}]: {}", id, TbMsg.fromBytes(result.getQueueId(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
+ toReprocess.forEach((id, msg) -> log.trace("Going to reprocess [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
}
if (pauseBetweenRetries > 0) {
try {
@@ -164,10 +164,10 @@ public class TbRuleEngineProcessingStrategyFactory {
log.debug("[{}] Reprocessing skipped for {} failed and {} timeout messages", queueName, result.getFailedMap().size(), result.getPendingMap().size());
}
if (log.isTraceEnabled()) {
- result.getFailedMap().forEach((id, msg) -> log.trace("Failed messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueId(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
+ result.getFailedMap().forEach((id, msg) -> log.trace("Failed messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
}
if (log.isTraceEnabled()) {
- result.getPendingMap().forEach((id, msg) -> log.trace("Timeout messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueId(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
+ result.getPendingMap().forEach((id, msg) -> log.trace("Timeout messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
}
return new TbRuleEngineProcessingDecision(true, null);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java b/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java
index 6aac90b281..d731ef1536 100644
--- a/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java
+++ b/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java
@@ -159,6 +159,8 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer
} else {
return ((Invocable) engine).invokeFunction(functionName, args);
}
+ } catch (ScriptException e) {
+ throw new ExecutionException(e);
} catch (Exception e) {
onScriptExecutionError(scriptId, e, functionName);
throw new ExecutionException(e);
diff --git a/application/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java b/application/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java
index 3bee5ca720..86b364afd4 100644
--- a/application/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java
+++ b/application/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java
@@ -57,6 +57,9 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
@Value("${queue.js.max_requests_timeout}")
private long maxRequestsTimeout;
+ @Value("${queue.js.max_exec_requests_timeout:2000}")
+ private long maxExecRequestsTimeout;
+
@Getter
@Value("${js.remote.max_errors}")
private int maxErrors;
@@ -170,7 +173,7 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
.setScriptIdMSB(scriptId.getMostSignificantBits())
.setScriptIdLSB(scriptId.getLeastSignificantBits())
.setFunctionName(functionName)
- .setTimeout((int) maxRequestsTimeout)
+ .setTimeout((int) maxExecRequestsTimeout)
.setScriptBody(scriptBody);
for (Object arg : args) {
@@ -197,7 +200,6 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
@Override
public void onFailure(Throwable t) {
- onScriptExecutionError(scriptId, t, scriptBody);
if (t instanceof TimeoutException || (t.getCause() != null && t.getCause() instanceof TimeoutException)) {
queueTimeoutMsgs.incrementAndGet();
}
@@ -212,8 +214,14 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
return invokeResult.getResult();
} else {
final RuntimeException e = new RuntimeException(invokeResult.getErrorDetails());
- onScriptExecutionError(scriptId, e, scriptBody);
- log.debug("[{}] Failed to compile script due to [{}]: {}", scriptId, invokeResult.getErrorCode().name(), invokeResult.getErrorDetails());
+ if (JsInvokeProtos.JsInvokeErrorCode.TIMEOUT_ERROR.equals(invokeResult.getErrorCode())) {
+ onScriptExecutionError(scriptId, e, scriptBody);
+ queueTimeoutMsgs.incrementAndGet();
+ } else if (JsInvokeProtos.JsInvokeErrorCode.COMPILATION_ERROR.equals(invokeResult.getErrorCode())) {
+ onScriptExecutionError(scriptId, e, scriptBody);
+ }
+ queueFailedMsgs.incrementAndGet();
+ log.debug("[{}] Failed to invoke function due to [{}]: {}", scriptId, invokeResult.getErrorCode().name(), invokeResult.getErrorDetails());
throw e;
}
}, callbackExecutor);
diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java
index 23ba6fd19e..ff57aec801 100644
--- a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java
+++ b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java
@@ -42,6 +42,7 @@ public class CustomerUserPermissions extends AbstractPermissions {
put(Resource.WIDGET_TYPE, widgetsPermissionChecker);
put(Resource.EDGE, customerEntityPermissionChecker);
put(Resource.RPC, rpcPermissionChecker);
+ put(Resource.DEVICE_PROFILE, deviceProfilePermissionChecker);
}
private static final PermissionChecker customerAlarmPermissionChecker = new PermissionChecker() {
@@ -152,4 +153,19 @@ public class CustomerUserPermissions extends AbstractPermissions {
return user.getTenantId().equals(entity.getTenantId());
}
};
+
+ private static final PermissionChecker deviceProfilePermissionChecker = new PermissionChecker.GenericPermissionChecker(Operation.READ) {
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) {
+ if (!super.hasPermission(user, operation, entityId, entity)) {
+ return false;
+ }
+ if (entity.getTenantId() == null || entity.getTenantId().isNullUid()) {
+ return true;
+ }
+ return user.getTenantId().equals(entity.getTenantId());
+ }
+ };
}
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 dae246ec49..4fdd6cf6ab 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
@@ -308,6 +308,10 @@ public abstract class BaseEntityImportService ID getInternalId(ID externalId, boolean throwExceptionIfNotFound) {
if (externalId == null || externalId.isNullUid()) return null;
+ if (EntityType.TENANT.equals(externalId.getEntityType())) {
+ return (ID) ctx.getTenantId();
+ }
+
EntityId localId = ctx.getInternalId(externalId);
if (localId != null) {
return (ID) localId;
diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java
index 4c0b80b149..72be8e6bf7 100644
--- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java
+++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java
@@ -53,7 +53,6 @@ public class DeviceProfileImportService extends BaseEntityImportService {
cachePut(commit.getTxId(), new VersionCreationResult());
try {
- List> gitFutures = new ArrayList<>();
+ EntitiesExportCtx> theCtx;
switch (request.getType()) {
case SINGLE_ENTITY: {
- handleSingleEntityRequest(new SimpleEntitiesExportCtx(user, commit, (SingleEntityVersionCreateRequest) request));
+ var ctx = new SimpleEntitiesExportCtx(user, commit, (SingleEntityVersionCreateRequest) request);
+ handleSingleEntityRequest(ctx);
+ theCtx = ctx;
break;
}
case COMPLEX: {
- handleComplexRequest(new ComplexEntitiesExportCtx(user, commit, (ComplexVersionCreateRequest) request));
+ var ctx = new ComplexEntitiesExportCtx(user, commit, (ComplexVersionCreateRequest) request);
+ handleComplexRequest(ctx);
+ theCtx = ctx;
break;
}
+ default:
+ throw new RuntimeException("Unsupported request type: " + request.getType());
}
- var resultFuture = Futures.transformAsync(Futures.allAsList(gitFutures), f -> gitServiceQueue.push(commit), executor);
+ var resultFuture = Futures.transformAsync(Futures.allAsList(theCtx.getFutures()), f -> gitServiceQueue.push(commit), executor);
DonAsynchron.withCallback(resultFuture, result -> cachePut(commit.getTxId(), result), e -> processCommitError(user, request, commit, e), executor);
} catch (Exception e) {
processCommitError(user, request, commit, e);
diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java
index 0c098d8281..413980d119 100644
--- a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java
+++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java
@@ -76,11 +76,13 @@ import org.thingsboard.server.service.sync.vc.data.VoidGitRequest;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@@ -102,7 +104,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
private final SchedulerComponent scheduler;
private final Map> pendingRequestMap = new HashMap<>();
- private final Map> chunkedMsgs = new ConcurrentHashMap<>();
+ private final Map> chunkedMsgs = new ConcurrentHashMap<>();
@Value("${queue.vc.request-timeout:60000}")
private int requestTimeout;
@@ -286,7 +288,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
@SuppressWarnings("rawtypes")
public ListenableFuture getEntity(TenantId tenantId, String versionId, EntityId entityId) {
EntityContentGitRequest request = new EntityContentGitRequest(tenantId, versionId, entityId);
- chunkedMsgs.put(request.getRequestId(), new LinkedHashMap<>());
+ chunkedMsgs.put(request.getRequestId(), new HashMap<>());
registerAndSend(request, builder -> builder.setEntityContentRequest(EntityContentRequestMsg.newBuilder()
.setVersionId(versionId)
.setEntityType(entityId.getEntityType().name())
@@ -328,7 +330,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
@SuppressWarnings("rawtypes")
public ListenableFuture> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit) {
EntitiesContentGitRequest request = new EntitiesContentGitRequest(tenantId, versionId, entityType);
- chunkedMsgs.put(request.getRequestId(), new LinkedHashMap<>());
+ chunkedMsgs.put(request.getRequestId(), new HashMap<>());
registerAndSend(request, builder -> builder.setEntitiesContentRequest(EntitiesContentRequestMsg.newBuilder()
.setVersionId(versionId)
.setEntityType(entityType.name())
@@ -412,10 +414,10 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
((ListVersionsGitRequest) request).getFuture().set(toPageData(listVersionsResponse));
} else if (vcResponseMsg.hasEntityContentResponse()) {
TransportProtos.EntityContentResponseMsg responseMsg = vcResponseMsg.getEntityContentResponse();
- log.trace("[{}] received chunk {} for 'getEntity'", responseMsg.getChunkedMsgId(), responseMsg.getChunkIndex());
- var joined = joinChunks(requestId, responseMsg, 1);
+ log.trace("Received chunk {} for 'getEntity'", responseMsg.getChunkIndex());
+ var joined = joinChunks(requestId, responseMsg, 0, 1);
if (joined.isPresent()) {
- log.trace("[{}] collected all chunks for 'getEntity'", responseMsg.getChunkedMsgId());
+ log.trace("Collected all chunks for 'getEntity'");
((EntityContentGitRequest) request).getFuture().set(joined.get().get(0));
} else {
completed = false;
@@ -424,7 +426,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
TransportProtos.EntitiesContentResponseMsg responseMsg = vcResponseMsg.getEntitiesContentResponse();
TransportProtos.EntityContentResponseMsg item = responseMsg.getItem();
if (responseMsg.getItemsCount() > 0) {
- var joined = joinChunks(requestId, item, responseMsg.getItemsCount());
+ var joined = joinChunks(requestId, item, responseMsg.getItemIdx(), responseMsg.getItemsCount());
if (joined.isPresent()) {
((EntitiesContentGitRequest) request).getFuture().set(joined.get());
} else {
@@ -459,16 +461,17 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
}
@SuppressWarnings("rawtypes")
- private Optional> joinChunks(UUID requestId, TransportProtos.EntityContentResponseMsg responseMsg, int expectedMsgCount) {
+ private Optional> joinChunks(UUID requestId, TransportProtos.EntityContentResponseMsg responseMsg, int itemIdx, int expectedMsgCount) {
var chunksMap = chunkedMsgs.get(requestId);
if (chunksMap == null) {
return Optional.empty();
}
- String[] msgChunks = chunksMap.computeIfAbsent(responseMsg.getChunkedMsgId(), id -> new String[responseMsg.getChunksCount()]);
+ String[] msgChunks = chunksMap.computeIfAbsent(itemIdx, id -> new String[responseMsg.getChunksCount()]);
msgChunks[responseMsg.getChunkIndex()] = responseMsg.getData();
if (chunksMap.size() == expectedMsgCount && chunksMap.values().stream()
.allMatch(chunks -> CollectionsUtil.countNonNull(chunks) == chunks.length)) {
- return Optional.of(chunksMap.values().stream()
+ return Optional.of(chunksMap.entrySet().stream()
+ .sorted(Comparator.comparingInt(Map.Entry::getKey)).map(Map.Entry::getValue)
.map(chunks -> String.join("", chunks))
.map(this::toData)
.collect(Collectors.toList()));
diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/AttributeData.java b/application/src/main/java/org/thingsboard/server/service/telemetry/AttributeData.java
index 9b67628aa3..5eb258c2a6 100644
--- a/application/src/main/java/org/thingsboard/server/service/telemetry/AttributeData.java
+++ b/application/src/main/java/org/thingsboard/server/service/telemetry/AttributeData.java
@@ -32,17 +32,17 @@ public class AttributeData implements Comparable{
this.value = value;
}
- @ApiModelProperty(position = 1, value = "Timestamp last updated attribute, in milliseconds", example = "1609459200000", readOnly = true)
+ @ApiModelProperty(position = 1, value = "Timestamp last updated attribute, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public long getLastUpdateTs() {
return lastUpdateTs;
}
- @ApiModelProperty(position = 2, value = "String representing attribute key", example = "active", readOnly = true)
+ @ApiModelProperty(position = 2, value = "String representing attribute key", example = "active", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public String getKey() {
return key;
}
- @ApiModelProperty(position = 3, value = "Object representing value of attribute key", example = "false", readOnly = true)
+ @ApiModelProperty(position = 3, value = "Object representing value of attribute key", example = "false", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public Object getValue() {
return value;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/TsData.java b/application/src/main/java/org/thingsboard/server/service/telemetry/TsData.java
index e48561a965..56d1785d45 100644
--- a/application/src/main/java/org/thingsboard/server/service/telemetry/TsData.java
+++ b/application/src/main/java/org/thingsboard/server/service/telemetry/TsData.java
@@ -30,12 +30,12 @@ public class TsData implements Comparable{
this.value = value;
}
- @ApiModelProperty(position = 1, value = "Timestamp last updated timeseries, in milliseconds", example = "1609459200000", readOnly = true)
+ @ApiModelProperty(position = 1, value = "Timestamp last updated timeseries, in milliseconds", example = "1609459200000", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public long getTs() {
return ts;
}
- @ApiModelProperty(position = 2, value = "Object representing value of timeseries key", example = "20", readOnly = true)
+ @ApiModelProperty(position = 2, value = "Object representing value of timeseries key", example = "20", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
public Object getValue() {
return value;
}
diff --git a/application/src/main/resources/logback.xml b/application/src/main/resources/logback.xml
index 4784ad2d43..941bd7d278 100644
--- a/application/src/main/resources/logback.xml
+++ b/application/src/main/resources/logback.xml
@@ -27,7 +27,7 @@
-
+
diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index 9b458734f7..17b996934e 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -148,7 +148,7 @@ ui:
# Help parameters
help:
# Base url for UI help assets
- base-url: "${UI_HELP_BASE_URL:https://raw.githubusercontent.com/thingsboard/thingsboard-ui-help/release-3.3.4}"
+ base-url: "${UI_HELP_BASE_URL:https://raw.githubusercontent.com/thingsboard/thingsboard-ui-help/release-3.4}"
database:
ts_max_intervals: "${DATABASE_TS_MAX_INTERVALS:700}" # Max number of DB queries generated by single API call to fetch telemetry records
@@ -326,7 +326,9 @@ actors:
# Specify thread pool size for javascript executor service
js_thread_pool_size: "${ACTORS_RULE_JS_THREAD_POOL_SIZE:50}"
# Specify thread pool size for mail sender executor service
- mail_thread_pool_size: "${ACTORS_RULE_MAIL_THREAD_POOL_SIZE:50}"
+ mail_thread_pool_size: "${ACTORS_RULE_MAIL_THREAD_POOL_SIZE:40}"
+ # Specify thread pool size for password reset emails
+ mail_password_reset_thread_pool_size: "${ACTORS_RULE_MAIL_PASSWORD_RESET_THREAD_POOL_SIZE:10}"
# Specify thread pool size for sms sender executor service
sms_thread_pool_size: "${ACTORS_RULE_SMS_THREAD_POOL_SIZE:50}"
# Whether to allow usage of system mail service for rules
@@ -545,10 +547,6 @@ spring:
audit-log:
# Enable/disable audit log functionality.
enabled: "${AUDIT_LOG_ENABLED:true}"
- # Specify partitioning size for audit log by tenant id storage. Example MINUTES, HOURS, DAYS, MONTHS
- by_tenant_partitioning: "${AUDIT_LOG_BY_TENANT_PARTITIONING:MONTHS}"
- # Number of days as history period if startTime and endTime are not specified
- default_query_period: "${AUDIT_LOG_DEFAULT_QUERY_PERIOD:30}"
# Logging levels per each entity type.
# Allowed values: OFF (disable), W (log write operations), RW (log read and write operations)
logging-level:
@@ -945,10 +943,11 @@ queue:
topic-properties:
rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
- transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
+ transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}"
notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100;min.insync.replicas:1}"
ota-updates: "${TB_QUEUE_KAFKA_OTA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}"
+ version-control: "${TB_QUEUE_KAFKA_VC_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}"
consumer-stats:
enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}"
print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}"
@@ -965,6 +964,8 @@ queue:
transport-api: "${TB_QUEUE_AWS_SQS_TA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}"
notifications: "${TB_QUEUE_AWS_SQS_NOTIFICATIONS_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}"
js-executor: "${TB_QUEUE_AWS_SQS_JE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}"
+ ota-updates: "${TB_QUEUE_AWS_SQS_OTA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}"
+ version-control: "${TB_QUEUE_AWS_SQS_VC_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}"
# VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds
pubsub:
project_id: "${TB_QUEUE_PUBSUB_PROJECT_ID:YOUR_PROJECT_ID}"
@@ -977,6 +978,7 @@ queue:
transport-api: "${TB_QUEUE_PUBSUB_TA_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}"
notifications: "${TB_QUEUE_PUBSUB_NOTIFICATIONS_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}"
js-executor: "${TB_QUEUE_PUBSUB_JE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}"
+ version-control: "${TB_QUEUE_PUBSUB_VC_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}"
service_bus:
namespace_name: "${TB_QUEUE_SERVICE_BUS_NAMESPACE_NAME:YOUR_NAMESPACE_NAME}"
sas_key_name: "${TB_QUEUE_SERVICE_BUS_SAS_KEY_NAME:YOUR_SAS_KEY_NAME}"
@@ -988,6 +990,7 @@ queue:
transport-api: "${TB_QUEUE_SERVICE_BUS_TA_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}"
notifications: "${TB_QUEUE_SERVICE_BUS_NOTIFICATIONS_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}"
js-executor: "${TB_QUEUE_SERVICE_BUS_JE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}"
+ version-control: "${TB_QUEUE_SERVICE_BUS_VC_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}"
rabbitmq:
exchange_name: "${TB_QUEUE_RABBIT_MQ_EXCHANGE_NAME:}"
host: "${TB_QUEUE_RABBIT_MQ_HOST:localhost}"
@@ -1004,6 +1007,7 @@ queue:
transport-api: "${TB_QUEUE_RABBIT_MQ_TA_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}"
notifications: "${TB_QUEUE_RABBIT_MQ_NOTIFICATIONS_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}"
js-executor: "${TB_QUEUE_RABBIT_MQ_JE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}"
+ version-control: "${TB_QUEUE_RABBIT_MQ_VC_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}"
partitions:
hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256
transport_api:
@@ -1045,6 +1049,8 @@ queue:
max_eval_requests_timeout: "${REMOTE_JS_MAX_EVAL_REQUEST_TIMEOUT:60000}"
# JS max request timeout
max_requests_timeout: "${REMOTE_JS_MAX_REQUEST_TIMEOUT:10000}"
+ # JS execution max request timeout
+ max_exec_requests_timeout: "${REMOTE_JS_MAX_EXEC_REQUEST_TIMEOUT:2000}"
# JS response poll interval
response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}"
rule-engine:
diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java
index a5af165699..d204750e32 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java
@@ -20,9 +20,10 @@ import org.mockito.ArgumentMatcher;
import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.SpyBean;
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.HasName;
+import org.thingsboard.server.common.data.HasTenantId;
+import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
@@ -37,7 +38,6 @@ import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg;
import org.thingsboard.server.dao.audit.AuditLogService;
import org.thingsboard.server.dao.model.ModelConstants;
-import org.thingsboard.server.service.gateway_device.GatewayNotificationsService;
import java.util.ArrayList;
import java.util.List;
@@ -58,21 +58,19 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
@SpyBean
protected AuditLogService auditLogService;
- @SpyBean
- protected GatewayNotificationsService gatewayNotificationsService;
-
protected final String msgErrorPermission = "You don't have permission to perform this operation!";
protected final String msgErrorShouldBeSpecified = "should be specified";
+ protected final String msgErrorNotFound = "Requested item wasn't found!";
protected void testNotifyEntityAllOneTime(HasName entity, EntityId entityId, EntityId originatorId,
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, Object... additionalInfo) {
int cntTime = 1;
- testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
+ testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId);
- testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime);
Mockito.reset(tbClusterService, auditLogService);
}
@@ -85,27 +83,35 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.eq(edgeTypeByActionType(actionType)));
ArgumentMatcher matcherOriginatorId = argument -> argument.equals(relation.getTo());
ArgumentMatcher matcherEntityClassEquals = Objects::isNull;
- testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime,
+ ArgumentMatcher matcherCustomerId = customerId == null ?
+ argument -> argument.getClass().equals(CustomerId.class) : argument -> argument.equals(customerId);
+ ArgumentMatcher matcherUserId = userId == null ?
+ argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId);
+ testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime,
extractMatcherAdditionalInfo(additionalInfo));
testPushMsgToRuleEngineNever(relation.getTo());
matcherOriginatorId = argument -> argument.equals(relation.getFrom());
- testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime,
+ testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime,
extractMatcherAdditionalInfo(additionalInfo));
testPushMsgToRuleEngineNever(relation.getFrom());
Mockito.reset(tbClusterService, auditLogService);
}
protected void testNotifyEntityAllManyRelation(EntityRelation relation,
- TenantId tenantId, CustomerId customerId, UserId userId, String userName,
- ActionType actionType, int cntTime) {
+ TenantId tenantId, CustomerId customerId, UserId userId, String userName,
+ ActionType actionType, int cntTime) {
Mockito.verify(tbClusterService, times(cntTime)).sendNotificationMsgToEdge(Mockito.eq(tenantId),
Mockito.isNull(), Mockito.isNull(), Mockito.any(), Mockito.eq(EdgeEventType.RELATION),
Mockito.eq(edgeTypeByActionType(actionType)));
ArgumentMatcher matcherOriginatorId = argument -> argument.getClass().equals(relation.getFrom().getClass());
ArgumentMatcher matcherEntityClassEquals = Objects::isNull;
- testLogEntityActionAdditionalInfoAny(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId,
+ ArgumentMatcher matcherCustomerId = customerId == null ?
+ argument -> argument.getClass().equals(CustomerId.class) : argument -> argument.equals(customerId);
+ ArgumentMatcher matcherUserId = userId == null ?
+ argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId);
+ testLogEntityActionAdditionalInfoAny(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId,
userName, actionType, cntTime * 2, 1);
- testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, new Tenant(), cntTime);
Mockito.reset(tbClusterService, auditLogService);
}
@@ -113,16 +119,16 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, Object... additionalInfo) {
int cntTime = 1;
- testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
+ testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
testLogEntityActionEntityEqClass(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId);
- testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime);
Mockito.reset(tbClusterService, auditLogService);
}
protected void testNotifyEntityNeverMsgToEdgeServiceOneTime(HasName entity, EntityId entityId, TenantId tenantId,
ActionType actionType) {
- testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, 1);
+ testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, 1);
testLogEntityActionNever(entityId, entity);
testPushMsgToRuleEngineNever(entityId);
Mockito.reset(tbClusterService, auditLogService);
@@ -132,13 +138,13 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
TenantId tenantId, CustomerId customerId, UserId userId,
String userName, ActionType actionType, Object... additionalInfo) {
int cntTime = 1;
- testNotificationMsgToEdgeServiceNever(entityId);
+ testNotificationMsgToEdgeServiceNeverWithActionType(entityId, actionType);
testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId);
if (ActionType.RELATIONS_DELETED.equals(actionType)) {
testPushMsgToRuleEngineNever(originatorId);
} else {
- testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime);
}
Mockito.reset(tbClusterService, auditLogService);
}
@@ -148,12 +154,16 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
ActionType actionType, int cntTime, Object... additionalInfo) {
EntityId entityId = createEntityId_NULL_UUID(entity);
EntityId originatorId = createEntityId_NULL_UUID(originator);
- testNotificationMsgToEdgeServiceNever(entityId);
+ testNotificationMsgToEdgeServiceNeverWithActionType(entityId, actionType);
ArgumentMatcher matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass());
- testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime,
+ ArgumentMatcher matcherCustomerId = customerId == null ?
+ argument -> argument.getClass().equals(CustomerId.class) : argument -> argument.equals(customerId);
+ ArgumentMatcher matcherUserId = userId == null ?
+ argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId);
+ testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime,
extractMatcherAdditionalInfo(additionalInfo));
- testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime);
Mockito.reset(tbClusterService, auditLogService);
}
@@ -165,10 +175,13 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
testSendNotificationMsgToEdgeServiceTimeEntityEqAny(tenantId, actionTypeEdge, cntTimeEdge);
ArgumentMatcher matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass());
- testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime,
+ ArgumentMatcher matcherCustomerId = customerId == null ?
+ argument -> argument.getClass().equals(CustomerId.class) : argument -> argument.equals(customerId);
+ ArgumentMatcher matcherUserId = userId == null ?
+ argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId);
+ testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime,
extractMatcherAdditionalInfoClass(additionalInfo));
- testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTimeRuleEngine);
- Mockito.reset(tbClusterService, auditLogService);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTimeRuleEngine);
}
protected void testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(HasName entity, HasName originator,
@@ -178,9 +191,13 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
testSendNotificationMsgToEdgeServiceTimeEntityEqAny(tenantId, actionTypeEdge, cntTimeEdge);
ArgumentMatcher matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass());
- testLogEntityActionAdditionalInfoAny(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime,
+ ArgumentMatcher matcherCustomerId = customerId == null ?
+ argument -> argument.getClass().equals(CustomerId.class) : argument -> argument.equals(customerId);
+ ArgumentMatcher matcherUserId = userId == null ?
+ argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId);
+ testLogEntityActionAdditionalInfoAny(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime,
cntAdditionalInfo);
- testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTimeEdge);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTimeEdge);
Mockito.reset(tbClusterService, auditLogService);
}
@@ -189,12 +206,16 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
ActionType actionType, int cntTime, int cntAdditionalInfo) {
EntityId entityId = createEntityId_NULL_UUID(entity);
EntityId originatorId = createEntityId_NULL_UUID(originator);
- testNotificationMsgToEdgeServiceNever(entityId);
+ testNotificationMsgToEdgeServiceNeverWithActionType(entityId, actionType);
ArgumentMatcher matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass());
- testLogEntityActionAdditionalInfoAny(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime,
+ ArgumentMatcher matcherCustomerId = customerId == null ?
+ argument -> argument.getClass().equals(CustomerId.class) : argument -> argument.equals(customerId);
+ ArgumentMatcher matcherUserId = userId == null ?
+ argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId);
+ testLogEntityActionAdditionalInfoAny(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime,
cntAdditionalInfo);
- testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime);
Mockito.reset(tbClusterService, auditLogService);
}
@@ -202,10 +223,10 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, Object... additionalInfo) {
int cntTime = 1;
- testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
+ testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId);
- testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime);
testBroadcastEntityStateChangeEventTime(entityId, tenantId, cntTime);
Mockito.reset(tbClusterService, auditLogService);
}
@@ -214,34 +235,40 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, Object... additionalInfo) {
int cntTime = 1;
- testNotificationMsgToEdgeServiceNever(entityId);
+ testNotificationMsgToEdgeServiceNeverWithActionType(entityId, actionType);
testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId);
- testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime);
testBroadcastEntityStateChangeEventTime(entityId, tenantId, cntTime);
Mockito.reset(tbClusterService, auditLogService);
}
- protected void testNotifyEntityBroadcastEntityStateChangeEventManyMsgToEdgeServiceNever(HasName entity, HasName originator,
- TenantId tenantId, CustomerId customerId, UserId userId, String userName,
- ActionType actionType, int cntTime, int cntAdditionalInfo) {
+ protected void testNotifyEntityBroadcastEntityStateChangeEventMany(HasName entity, HasName originator,
+ TenantId tenantId, CustomerId customerId,
+ UserId userId, String userName, ActionType actionType,
+ ActionType actionTypeEdge,
+ int cntTime, int cntTimeEdge, int cntTimeRuleEngine,
+ int cntAdditionalInfo) {
EntityId entityId = createEntityId_NULL_UUID(entity);
EntityId originatorId = createEntityId_NULL_UUID(originator);
- testNotificationMsgToEdgeServiceNever(entityId);
+ testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionTypeEdge, cntTimeEdge);
ArgumentMatcher matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass());
- testLogEntityActionAdditionalInfoAny(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime,
+ ArgumentMatcher matcherCustomerId = customerId == null ?
+ argument -> argument.getClass().equals(CustomerId.class) : argument -> argument.equals(customerId);
+ ArgumentMatcher matcherUserId = userId == null ?
+ argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId);
+ testLogEntityActionAdditionalInfoAny(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime,
cntAdditionalInfo);
- testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
+ testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTimeRuleEngine);
testBroadcastEntityStateChangeEventTime(entityId, tenantId, cntTime);
- Mockito.reset(tbClusterService, auditLogService);
}
protected void testNotifyEntityMsgToEdgePushMsgToCoreOneTime(HasName entity, EntityId entityId, EntityId originatorId,
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, Object... additionalInfo) {
int cntTime = 1;
- testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
+ testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
tesPushMsgToCoreTime(cntTime);
Mockito.reset(tbClusterService, auditLogService);
@@ -252,7 +279,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Object... additionalInfo) {
CustomerId customer_NULL_UUID = (CustomerId) EntityIdFactory.getByTypeAndUuid(EntityType.CUSTOMER, ModelConstants.NULL_UUID);
EntityId entity_originator_NULL_UUID = createEntityId_NULL_UUID(entity);
- testNotificationMsgToEdgeServiceNever(entity_originator_NULL_UUID);
+ testNotificationMsgToEdgeServiceNeverWithActionType(entity_originator_NULL_UUID, actionType);
ArgumentMatcher matcherEntityEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher matcherError = argument -> argument.getMessage().contains(exp.getMessage())
& argument.getClass().equals(exp.getClass());
@@ -266,7 +293,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Object... additionalInfo) {
CustomerId customer_NULL_UUID = (CustomerId) EntityIdFactory.getByTypeAndUuid(EntityType.CUSTOMER, ModelConstants.NULL_UUID);
EntityId entity_originator_NULL_UUID = createEntityId_NULL_UUID(entity);
- testNotificationMsgToEdgeServiceNever(entity_originator_NULL_UUID);
+ testNotificationMsgToEdgeServiceNeverWithActionType(entity_originator_NULL_UUID, actionType);
ArgumentMatcher matcherEntityIsNull = Objects::isNull;
ArgumentMatcher matcherError = argument -> argument.getMessage().contains(exp.getMessage()) &
argument.getClass().equals(exp.getClass());
@@ -283,20 +310,11 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.reset(tbClusterService, auditLogService);
}
- protected void testNotificationUpdateGatewayOneTime(Device device, Device oldDevice) {
- Mockito.verify(gatewayNotificationsService, times(1)).onDeviceUpdated(Mockito.eq(device), Mockito.eq(oldDevice));
- }
-
- protected void testNotificationUpdateGatewayNever() {
- Mockito.verify(gatewayNotificationsService, never()).onDeviceUpdated(Mockito.any(Device.class), Mockito.any(Device.class));
- }
-
- protected void testNotificationDeleteGatewayOneTime(Device device) {
- Mockito.verify(gatewayNotificationsService, times(1)).onDeviceDeleted(device);
- }
-
- protected void testNotificationDeleteGatewayNever() {
- Mockito.verify(gatewayNotificationsService, never()).onDeviceDeleted(Mockito.any(Device.class));
+ private void testNotificationMsgToEdgeServiceNeverWithActionType(EntityId entityId, ActionType actionType) {
+ EdgeEventActionType edgeEventActionType = ActionType.CREDENTIALS_UPDATED.equals(actionType) ?
+ EdgeEventActionType.CREDENTIALS_UPDATED : edgeTypeByActionType(actionType);
+ Mockito.verify(tbClusterService, never()).sendNotificationMsgToEdge(Mockito.any(),
+ Mockito.any(), Mockito.any(entityId.getClass()), Mockito.any(), Mockito.any(), Mockito.eq(edgeEventActionType));
}
private void testNotificationMsgToEdgeServiceNever(EntityId entityId) {
@@ -317,16 +335,24 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.any(entityId.getClass()), Mockito.any(), Mockito.any());
}
- private void testPushMsgToRuleEngineTime(ArgumentMatcher matcherOriginatorId, TenantId tenantId, int cntTime) {
+ protected void testBroadcastEntityStateChangeEventNever(EntityId entityId) {
+ Mockito.verify(tbClusterService, never()).broadcastEntityStateChangeEvent(Mockito.any(),
+ Mockito.any(entityId.getClass()), Mockito.any(ComponentLifecycleEvent.class));
+ }
+
+ private void testPushMsgToRuleEngineTime(ArgumentMatcher matcherOriginatorId, TenantId tenantId, HasName entity, int cntTime) {
+ tenantId = tenantId.isNullUid() && ((HasTenantId) entity).getTenantId() != null ? ((HasTenantId) entity).getTenantId() : tenantId;
Mockito.verify(tbClusterService, times(cntTime)).pushMsgToRuleEngine(Mockito.eq(tenantId),
Mockito.argThat(matcherOriginatorId), Mockito.any(TbMsg.class), Mockito.isNull());
}
- private void testSendNotificationMsgToEdgeServiceTime(EntityId entityId, TenantId tenantId, ActionType actionType, int cntTime) {
+ private void testNotificationMsgToEdgeServiceTime(EntityId entityId, TenantId tenantId, ActionType actionType, int cntTime) {
EdgeEventActionType edgeEventActionType = ActionType.CREDENTIALS_UPDATED.equals(actionType) ?
EdgeEventActionType.CREDENTIALS_UPDATED : edgeTypeByActionType(actionType);
+ ArgumentMatcher matcherEntityId = cntTime == 1 ? argument -> argument.equals(entityId) :
+ argument -> argument.getClass().equals(entityId.getClass());
Mockito.verify(tbClusterService, times(cntTime)).sendNotificationMsgToEdge(Mockito.eq(tenantId),
- Mockito.any(), Mockito.eq(entityId), Mockito.any(), Mockito.isNull(),
+ Mockito.any(), Mockito.argThat(matcherEntityId), Mockito.any(), Mockito.isNull(),
Mockito.eq(edgeEventActionType));
}
@@ -336,8 +362,10 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.eq(edgeTypeByActionType(actionType)));
}
- private void testBroadcastEntityStateChangeEventTime(EntityId entityId, TenantId tenantId, int cntTime) {
- Mockito.verify(tbClusterService, times(cntTime)).broadcastEntityStateChangeEvent(Mockito.eq(tenantId),
+ protected void testBroadcastEntityStateChangeEventTime(EntityId entityId, TenantId tenantId, int cntTime) {
+ ArgumentMatcher matcherTenantIdId = cntTime > 1 || tenantId == null ? argument -> argument.getClass().equals(TenantId.class) :
+ argument -> argument.equals(tenantId) ;
+ Mockito.verify(tbClusterService, times(cntTime)).broadcastEntityStateChangeEvent(Mockito.argThat(matcherTenantIdId),
Mockito.any(entityId.getClass()), Mockito.any(ComponentLifecycleEvent.class));
}
@@ -348,9 +376,13 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
private void testLogEntityAction(HasName entity, EntityId originatorId, TenantId tenantId,
CustomerId customerId, UserId userId, String userName,
ActionType actionType, int cntTime, Object... additionalInfo) {
- ArgumentMatcher matcherEntityEquals = entity == null ? Objects::isNull : argument -> argument.equals(entity);
+ ArgumentMatcher matcherEntityEquals = entity == null ? Objects::isNull : argument -> argument.toString().equals(entity.toString());
ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId);
- testLogEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, customerId, userId, userName,
+ ArgumentMatcher matcherCustomerId = customerId == null ?
+ argument -> argument.getClass().equals(CustomerId.class) : argument -> argument.equals(customerId);
+ ArgumentMatcher matcherUserId = userId == null ?
+ argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId);
+ testLogEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName,
actionType, cntTime, extractMatcherAdditionalInfo(additionalInfo));
}
@@ -359,19 +391,24 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
ActionType actionType, int cntTime, Object... additionalInfo) {
ArgumentMatcher matcherEntityEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId);
- testLogEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, customerId, userId, userName,
+ ArgumentMatcher matcherCustomerId = customerId == null ?
+ argument -> argument.getClass().equals(CustomerId.class) : argument -> argument.equals(customerId);
+ ArgumentMatcher matcherUserId = userId == null ?
+ argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId);
+ testLogEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName,
actionType, cntTime, extractMatcherAdditionalInfo(additionalInfo));
}
private void testLogEntityActionAdditionalInfo(ArgumentMatcher matcherEntity, ArgumentMatcher matcherOriginatorId,
- TenantId tenantId, CustomerId customerId, UserId userId, String userName,
- ActionType actionType, int cntTime, List> matcherAdditionalInfos) {
+ TenantId tenantId, ArgumentMatcher matcherCustomerId,
+ ArgumentMatcher matcherUserId, String userName, ActionType actionType,
+ int cntTime, List> matcherAdditionalInfos) {
switch (matcherAdditionalInfos.size()) {
case 1:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
- Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherCustomerId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
@@ -382,8 +419,8 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
case 2:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
- Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherCustomerId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
@@ -395,8 +432,8 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
case 3:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
- Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherCustomerId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
@@ -409,8 +446,8 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
default:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
- Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherCustomerId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
@@ -420,14 +457,15 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
}
private void testLogEntityActionAdditionalInfoAny(ArgumentMatcher matcherEntity, ArgumentMatcher matcherOriginatorId,
- TenantId tenantId, CustomerId customerId, UserId userId, String userName,
+ TenantId tenantId, ArgumentMatcher matcherCustomerId,
+ ArgumentMatcher matcherUserId, String userName,
ActionType actionType, int cntTime, int cntAdditionalInfo) {
switch (cntAdditionalInfo) {
case 1:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
- Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherCustomerId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
@@ -438,8 +476,8 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
case 2:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
- Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherCustomerId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
@@ -451,8 +489,8 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
case 3:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
- Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherCustomerId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
@@ -465,8 +503,8 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
default:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
- Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherCustomerId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
@@ -479,12 +517,14 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
CustomerId customerId, UserId userId, String userName, ActionType actionType,
int cntTime, ArgumentMatcher matcherError,
List> matcherAdditionalInfos) {
+ ArgumentMatcher matcherUserId = userId == null ? argument -> argument.getClass().equals(UserId.class) :
+ argument -> argument.equals(userId);
switch (matcherAdditionalInfos.size()) {
case 1:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.eq(originatorId),
Mockito.argThat(matcherEntity),
@@ -496,7 +536,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.eq(originatorId),
Mockito.argThat(matcherEntity),
@@ -508,7 +548,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.eq(originatorId),
Mockito.argThat(matcherEntity),
@@ -522,7 +562,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
Mockito.eq(customerId),
- Mockito.eq(userId),
+ Mockito.argThat(matcherUserId),
Mockito.eq(userName),
Mockito.eq(originatorId),
Mockito.argThat(matcherEntity),
@@ -558,7 +598,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
return result;
}
- private EntityId createEntityId_NULL_UUID(HasName entity) {
+ protected EntityId createEntityId_NULL_UUID(HasName entity) {
return EntityIdFactory.getByTypeAndUuid(entityClassToEntityTypeName(entity), ModelConstants.NULL_UUID);
}
@@ -571,6 +611,12 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
}
private String entityClassToEntityTypeName(HasName entity) {
+ String entityType = entityClassToString(entity);
+ return "SAVE_OTA_PACKAGE_INFO_REQUEST".equals(entityType) || "OTA_PACKAGE_INFO".equals(entityType)?
+ EntityType.OTA_PACKAGE.name().toUpperCase(Locale.ENGLISH) : entityType;
+ }
+
+ private String entityClassToString(HasName entity) {
String className = entity.getClass().toString()
.substring(entity.getClass().toString().lastIndexOf(".") + 1);
List str = className.chars()
diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
index 329bad55a5..75d3a0aa97 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
@@ -285,7 +285,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
protected void loginDifferentTenant() throws Exception {
if (savedDifferentTenant != null) {
- login(savedDifferentTenant.getEmail(), TENANT_ADMIN_PASSWORD);
+ login(DIFFERENT_TENANT_ADMIN_EMAIL, DIFFERENT_TENANT_ADMIN_PASSWORD);
} else {
loginSysAdmin();
@@ -422,12 +422,6 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
}
protected DeviceProfile createDeviceProfile(String name, DeviceProfileTransportConfiguration deviceProfileTransportConfiguration) {
- return createDeviceProfile(name, deviceProfileTransportConfiguration, null);
- }
-
- protected DeviceProfile createDeviceProfile(String name,
- DeviceProfileTransportConfiguration deviceProfileTransportConfiguration,
- QueueId defaultQueueId) {
DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setName(name);
deviceProfile.setType(DeviceProfileType.DEFAULT);
@@ -445,7 +439,6 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
deviceProfile.setProfileData(deviceProfileData);
deviceProfile.setDefault(false);
deviceProfile.setDefaultRuleChainId(null);
- deviceProfile.setDefaultQueueId(defaultQueueId);
return deviceProfile;
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAdminControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAdminControllerTest.java
index b89133f29a..81ecce8300 100644
--- a/application/src/test/java/org/thingsboard/server/controller/BaseAdminControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/BaseAdminControllerTest.java
@@ -18,14 +18,29 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.Test;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.thingsboard.common.util.JacksonUtil;
+import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.AdminSettings;
+import org.thingsboard.server.service.mail.DefaultMailService;
-import static org.hamcrest.Matchers.*;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class BaseAdminControllerTest extends AbstractControllerTest {
+ @Autowired
+ MailService mailService;
+
+ @Autowired
+ DefaultMailService defaultMailService;
+
@Test
public void testFindAdminSettingsByKey() throws Exception {
loginSysAdmin();
@@ -100,5 +115,28 @@ public abstract class BaseAdminControllerTest extends AbstractControllerTest {
doPost("/api/admin/settings/testMail", adminSettings)
.andExpect(status().isOk());
}
-
+
+ @Test
+ public void testSendTestMailTimeout() throws Exception {
+ loginSysAdmin();
+ AdminSettings adminSettings = doGet("/api/admin/settings/mail", AdminSettings.class);
+ ObjectNode objectNode = JacksonUtil.fromString(adminSettings.getJsonValue().toString(), ObjectNode.class);
+
+ objectNode.put("smtpHost", "mail.gandi.net");
+ objectNode.put("timeout", 1_000);
+ objectNode.put("username", "username");
+ objectNode.put("password", "password");
+
+ adminSettings.setJsonValue(objectNode);
+
+ Mockito.doAnswer((invocations) -> {
+ var jsonConfig = (JsonNode) invocations.getArgument(0);
+ var email = (String) invocations.getArgument(1);
+
+ defaultMailService.sendTestMail(jsonConfig, email);
+ return null;
+ }).when(mailService).sendTestMail(Mockito.any(), Mockito.anyString());
+ doPost("/api/admin/settings/testMail", adminSettings).andExpect(status().is5xxServerError());
+ Mockito.doNothing().when(mailService).sendTestMail(Mockito.any(), Mockito.any());
+ }
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java
index cfb9489f69..66fc1a5178 100644
--- a/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java
@@ -283,6 +283,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
doDelete("/api/tenant/" + savedTenant2.getId().getId().toString())
.andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
+
testNotifyEntityNever(savedDashboard.getId(), savedDashboard);
loginSysAdmin();
diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
index dc5f9efa23..ee4d005233 100644
--- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
@@ -27,10 +27,14 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
+import org.springframework.boot.test.mock.mockito.SpyBean;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntitySubtype;
+import org.thingsboard.server.common.data.OtaPackageInfo;
+import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
@@ -49,6 +53,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
import org.thingsboard.server.dao.model.ModelConstants;
+import org.thingsboard.server.service.gateway_device.GatewayNotificationsService;
import java.util.ArrayList;
import java.util.List;
@@ -56,12 +61,15 @@ import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
+import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
- static final TypeReference> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() {
- };
+ static final TypeReference> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() {};
ListeningExecutorService executor;
@@ -71,6 +79,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
private Tenant savedTenant;
private User tenantAdmin;
+ @SpyBean
+ private GatewayNotificationsService gatewayNotificationsService;
+
@Before
public void beforeTest() throws Exception {
executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
@@ -113,6 +124,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Device savedDevice = doPost("/api/device", device, Device.class);
Device oldDevice = new Device(savedDevice);
+
testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED);
@@ -203,7 +215,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
String savedDeviceIdStr = savedDevice.getId().getId().toString();
doPost("/api/device", savedDevice)
- .andExpect( status().isNotFound())
+ .andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Device", savedDeviceIdStr))));
testNotifyEntityNever(savedDevice.getId(), savedDevice);
@@ -221,6 +233,66 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
deleteDifferentTenant();
}
+ @Test
+ public void testSaveDeviceWithProfileFromDifferentTenant() throws Exception {
+ loginDifferentTenant();
+ DeviceProfile differentProfile = createDeviceProfile("Different profile");
+ differentProfile = doPost("/api/deviceProfile", differentProfile, DeviceProfile.class);
+
+ loginTenantAdmin();
+ Device device = new Device();
+ device.setName("My device");
+ device.setDeviceProfileId(differentProfile.getId());
+ doPost("/api/device", device).andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Device can`t be referencing to device profile from different tenant!")));
+ }
+
+ @Test
+ public void testSaveDeviceWithFirmwareFromDifferentTenant() throws Exception {
+ loginDifferentTenant();
+ DeviceProfile differentProfile = createDeviceProfile("Different profile");
+ differentProfile = doPost("/api/deviceProfile", differentProfile, DeviceProfile.class);
+ SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest();
+ firmwareInfo.setDeviceProfileId(differentProfile.getId());
+ firmwareInfo.setType(FIRMWARE);
+ firmwareInfo.setTitle("title");
+ firmwareInfo.setVersion("1.0");
+ firmwareInfo.setUrl("test.url");
+ firmwareInfo.setUsesUrl(true);
+ OtaPackageInfo savedFw = doPost("/api/otaPackage", firmwareInfo, OtaPackageInfo.class);
+
+ loginTenantAdmin();
+ Device device = new Device();
+ device.setName("My device");
+ device.setType("default");
+ device.setFirmwareId(savedFw.getId());
+ doPost("/api/device", device).andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Can't assign firmware from different tenant!")));
+ }
+
+ @Test
+ public void testSaveDeviceWithSoftwareFromDifferentTenant() throws Exception {
+ loginDifferentTenant();
+ DeviceProfile differentProfile = createDeviceProfile("Different profile");
+ differentProfile = doPost("/api/deviceProfile", differentProfile, DeviceProfile.class);
+ SaveOtaPackageInfoRequest softwareInfo = new SaveOtaPackageInfoRequest();
+ softwareInfo.setDeviceProfileId(differentProfile.getId());
+ softwareInfo.setType(SOFTWARE);
+ softwareInfo.setTitle("title");
+ softwareInfo.setVersion("1.0");
+ softwareInfo.setUrl("test.url");
+ softwareInfo.setUsesUrl(true);
+ OtaPackageInfo savedSw = doPost("/api/otaPackage", softwareInfo, OtaPackageInfo.class);
+
+ loginTenantAdmin();
+ Device device = new Device();
+ device.setName("My device");
+ device.setType("default");
+ device.setSoftwareId(savedSw.getId());
+ doPost("/api/device", device).andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Can't assign software from different tenant!")));
+ }
+
@Test
public void testFindDeviceById() throws Exception {
Device device = new Device();
@@ -248,8 +320,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
}
testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Device(), new Device(),
- savedTenant.getId(),
- tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
+ savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED, cntEntity);
testNotificationUpdateGatewayNever();
@@ -813,7 +884,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Device(), new Device(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, cntEntity * 2);
+ Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
testNotificationUpdateGatewayNever();
+ Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
List loadedDevices = new ArrayList<>(cntEntity);
PageLink pageLink = new PageLink(23);
@@ -828,8 +901,6 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
assertThat(devices).containsExactlyInAnyOrderElementsOf(loadedDevices);
- Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
-
deleteEntitiesAsync("/api/customer/device/", loadedDevices, executor).get(TIMEOUT, TimeUnit.SECONDS);
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new Device(), new Device(),
@@ -1116,4 +1187,20 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals(0, pageData.getData().size());
}
+
+ protected void testNotificationUpdateGatewayOneTime(Device device, Device oldDevice) {
+ Mockito.verify(gatewayNotificationsService, times(1)).onDeviceUpdated(Mockito.eq(device), Mockito.eq(oldDevice));
+ }
+
+ protected void testNotificationUpdateGatewayNever() {
+ Mockito.verify(gatewayNotificationsService, never()).onDeviceUpdated(Mockito.any(Device.class), Mockito.any(Device.class));
+ }
+
+ protected void testNotificationDeleteGatewayOneTime(Device device) {
+ Mockito.verify(gatewayNotificationsService, times(1)).onDeviceDeleted(device);
+ }
+
+ protected void testNotificationDeleteGatewayNever() {
+ Mockito.verify(gatewayNotificationsService, never()).onDeviceDeleted(Mockito.any(Device.class));
+ }
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java
index 80266563ef..4f782b15b3 100644
--- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java
@@ -28,12 +28,16 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
+import org.thingsboard.server.common.data.Customer;
+import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType;
+import org.thingsboard.server.common.data.OtaPackageInfo;
+import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
@@ -44,6 +48,7 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
+import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.exception.DataValidationException;
@@ -58,6 +63,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
+import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE;
public abstract class BaseDeviceProfileControllerTest extends AbstractControllerTest {
@@ -170,6 +177,25 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
Assert.assertEquals(savedDeviceProfile.getId(), foundDeviceProfileInfo.getId());
Assert.assertEquals(savedDeviceProfile.getName(), foundDeviceProfileInfo.getName());
Assert.assertEquals(savedDeviceProfile.getType(), foundDeviceProfileInfo.getType());
+
+ Customer customer = new Customer();
+ customer.setTitle("Customer");
+ customer.setTenantId(savedTenant.getId());
+ Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
+
+ User customerUser = new User();
+ customerUser.setAuthority(Authority.CUSTOMER_USER);
+ customerUser.setTenantId(savedTenant.getId());
+ customerUser.setCustomerId(savedCustomer.getId());
+ customerUser.setEmail("customer2@thingsboard.org");
+
+ createUserAndLogin(customerUser, "customer");
+
+ foundDeviceProfileInfo = doGet("/api/deviceProfileInfo/" + savedDeviceProfile.getId().getId().toString(), DeviceProfileInfo.class);
+ Assert.assertNotNull(foundDeviceProfileInfo);
+ Assert.assertEquals(savedDeviceProfile.getId(), foundDeviceProfileInfo.getId());
+ Assert.assertEquals(savedDeviceProfile.getName(), foundDeviceProfileInfo.getName());
+ Assert.assertEquals(savedDeviceProfile.getType(), foundDeviceProfileInfo.getType());
}
@Test
@@ -325,6 +351,80 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
testNotifyEntityNever(savedDeviceProfile.getId(), savedDeviceProfile);
}
+ @Test
+ public void testSaveDeviceProfileWithRuleChainFromDifferentTenant() throws Exception {
+ loginDifferentTenant();
+ RuleChain ruleChain = new RuleChain();
+ ruleChain.setName("Different rule chain");
+ RuleChain savedRuleChain = doPost("/api/ruleChain", ruleChain, RuleChain.class);
+
+ loginTenantAdmin();
+
+ DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
+ deviceProfile.setDefaultRuleChainId(savedRuleChain.getId());
+ doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Can't assign rule chain from different tenant!")));
+ }
+
+ @Test
+ public void testSaveDeviceProfileWithDashboardFromDifferentTenant() throws Exception {
+ loginDifferentTenant();
+ Dashboard dashboard = new Dashboard();
+ dashboard.setTitle("Different dashboard");
+ Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
+
+ loginTenantAdmin();
+
+ DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
+ deviceProfile.setDefaultDashboardId(savedDashboard.getId());
+ doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Can't assign dashboard from different tenant!")));
+ }
+
+ @Test
+ public void testSaveDeviceProfileWithFirmwareFromDifferentTenant() throws Exception {
+ loginDifferentTenant();
+ DeviceProfile differentProfile = createDeviceProfile("Different profile");
+ differentProfile = doPost("/api/deviceProfile", differentProfile, DeviceProfile.class);
+ SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest();
+ firmwareInfo.setDeviceProfileId(differentProfile.getId());
+ firmwareInfo.setType(FIRMWARE);
+ firmwareInfo.setTitle("title");
+ firmwareInfo.setVersion("1.0");
+ firmwareInfo.setUrl("test.url");
+ firmwareInfo.setUsesUrl(true);
+ OtaPackageInfo savedFw = doPost("/api/otaPackage", firmwareInfo, OtaPackageInfo.class);
+
+ loginTenantAdmin();
+
+ DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
+ deviceProfile.setFirmwareId(savedFw.getId());
+ doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Can't assign firmware from different tenant!")));
+ }
+
+ @Test
+ public void testSaveDeviceProfileWithSoftwareFromDifferentTenant() throws Exception {
+ loginDifferentTenant();
+ DeviceProfile differentProfile = createDeviceProfile("Different profile");
+ differentProfile = doPost("/api/deviceProfile", differentProfile, DeviceProfile.class);
+ SaveOtaPackageInfoRequest softwareInfo = new SaveOtaPackageInfoRequest();
+ softwareInfo.setDeviceProfileId(differentProfile.getId());
+ softwareInfo.setType(SOFTWARE);
+ softwareInfo.setTitle("title");
+ softwareInfo.setVersion("1.0");
+ softwareInfo.setUrl("test.url");
+ softwareInfo.setUsesUrl(true);
+ OtaPackageInfo savedSw = doPost("/api/otaPackage", softwareInfo, OtaPackageInfo.class);
+
+ loginTenantAdmin();
+
+ DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
+ deviceProfile.setSoftwareId(savedSw.getId());
+ doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Can't assign software from different tenant!")));
+ }
+
@Test
public void testDeleteDeviceProfile() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
@@ -367,6 +467,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new DeviceProfile(), new DeviceProfile(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED, ActionType.ADDED, cntEntity, cntEntity, cntEntity);
+ Mockito.reset(tbClusterService, auditLogService);
List loadedDeviceProfiles = new ArrayList<>();
pageLink = new PageLink(17);
@@ -988,7 +1089,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(errorMsg)));
- testNotifyEntityEqualsOneTimeServiceNeverError(deviceProfile,savedTenant.getId(),
+ testNotifyEntityEqualsOneTimeServiceNeverError(deviceProfile, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(errorMsg));
}
@@ -1003,7 +1104,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(errorMsg)));
- testNotifyEntityEqualsOneTimeServiceNeverError(deviceProfile,savedTenant.getId(),
+ testNotifyEntityEqualsOneTimeServiceNeverError(deviceProfile, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(errorMsg));
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityRelationControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityRelationControllerTest.java
index 08a157484f..2d28e32906 100644
--- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityRelationControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityRelationControllerTest.java
@@ -354,10 +354,9 @@ public abstract class BaseEntityRelationControllerTest extends AbstractControlle
doDelete(url)
.andExpect(status().isNotFound())
- .andExpect(statusReason(containsString("Requested item wasn't found!")));
+ .andExpect(statusReason(containsString(msgErrorNotFound)));
testNotifyEntityNever(mainDevice.getId(), null);
-
}
@Test
@@ -377,7 +376,7 @@ public abstract class BaseEntityRelationControllerTest extends AbstractControlle
doDelete(url)
.andExpect(status().isNotFound())
- .andExpect(statusReason(containsString("Requested item wasn't found!")));
+ .andExpect(statusReason(containsString(msgErrorNotFound)));
testNotifyEntityNever(mainDevice.getId(), null);
}
@@ -570,7 +569,6 @@ public abstract class BaseEntityRelationControllerTest extends AbstractControlle
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Device", relation.getFrom().getId().toString()))));
-
deleteDifferentTenant();
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java
index 615914c6d7..f1121dfb14 100644
--- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java
@@ -32,6 +32,7 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mockito;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.ResultActions;
import org.thingsboard.common.util.ThingsBoardExecutors;
@@ -41,6 +42,7 @@ import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EntityViewInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.objects.AttributesEntityView;
@@ -52,6 +54,7 @@ import org.thingsboard.server.common.data.query.EntityKey;
import org.thingsboard.server.common.data.query.EntityKeyType;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.DeviceCredentials;
+import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.model.ModelConstants;
import java.util.ArrayList;
@@ -92,7 +95,6 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
@Before
public void beforeTest() throws Exception {
- log.debug("beforeTest");
executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
loginTenantAdmin();
@@ -126,6 +128,9 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
@Test
public void testSaveEntityView() throws Exception {
String name = "Test entity view";
+
+ Mockito.reset(tbClusterService, auditLogService);
+
EntityView savedView = getNewSavedEntityView(name);
Assert.assertNotNull(savedView);
@@ -140,6 +145,12 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
assertEquals(savedView, foundEntityView);
+ testBroadcastEntityStateChangeEventTime(foundEntityView.getId(), tenantId, 1);
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundEntityView, foundEntityView,
+ tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.ADDED, ActionType.ADDED, 1, 0, 1);
+ Mockito.reset(tbClusterService, auditLogService);
+
savedView.setName("New test entity view");
doPost("/api/entityView", savedView, EntityView.class);
@@ -147,23 +158,57 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
assertEquals(savedView, foundEntityView);
- doGet("/api/tenant/entityViews?entityViewName=" + name, EntityView.class, status().isNotFound());
+ testBroadcastEntityStateChangeEventTime(foundEntityView.getId(), tenantId, 1);
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundEntityView, foundEntityView,
+ tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.UPDATED, ActionType.UPDATED, 1, 1, 5);
+
+ doGet("/api/tenant/entityViews?entityViewName=" + name)
+ .andExpect(status().isNotFound())
+ .andExpect(statusReason(containsString(msgErrorNotFound)));
}
@Test
public void testSaveEntityViewWithViolationOfValidation() throws Exception {
EntityView entityView = createEntityView(RandomStringUtils.randomAlphabetic(300), 0, 0);
- doPost("/api/entityView", entityView).andExpect(statusReason(containsString("length of name must be equal or less than 255")));
+
+ Mockito.reset(tbClusterService, auditLogService);
+
+ String msgError = msgErrorFieldLength("name");
+ doPost("/api/entityView", entityView)
+ .andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString(msgError)));
+
+ testNotifyEntityEqualsOneTimeServiceNeverError(entityView,
+ tenantId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.ADDED, new DataValidationException(msgError));
+ Mockito.reset(tbClusterService, auditLogService);
+
entityView.setName("Normal name");
+ msgError = msgErrorFieldLength("type");
entityView.setType(RandomStringUtils.randomAlphabetic(300));
- doPost("/api/entityView", entityView).andExpect(statusReason(containsString("length of type must be equal or less than 255")));
+ doPost("/api/entityView", entityView)
+ .andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString(msgError)));
+
+ testNotifyEntityEqualsOneTimeServiceNeverError(entityView,
+ tenantId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.ADDED, new DataValidationException(msgError));
}
@Test
public void testUpdateEntityViewFromDifferentTenant() throws Exception {
EntityView savedView = getNewSavedEntityView("Test entity view");
loginDifferentTenant();
- doPost("/api/entityView", savedView, EntityView.class, status().isForbidden());
+
+ Mockito.reset(tbClusterService, auditLogService);
+
+ doPost("/api/entityView", savedView)
+ .andExpect(status().isForbidden())
+ .andExpect(statusReason(containsString(msgErrorPermission)));
+
+ testNotifyEntityNever(savedView.getId(), savedView);
+
deleteDifferentTenant();
}
@@ -174,20 +219,36 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
view.setCustomerId(customer.getId());
EntityView savedView = doPost("/api/entityView", view, EntityView.class);
- doDelete("/api/entityView/" + savedView.getId().getId().toString())
+ Mockito.reset(tbClusterService, auditLogService);
+
+ String entityIdStr = savedView.getId().getId().toString();
+ doDelete("/api/entityView/" + entityIdStr)
.andExpect(status().isOk());
- doGet("/api/entityView/" + savedView.getId().getId().toString())
- .andExpect(status().isNotFound());
+ testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedView, savedView.getId(), savedView.getId(),
+ tenantId, view.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.DELETED, entityIdStr);
+
+ doGet("/api/entityView/" + entityIdStr)
+ .andExpect(status().isNotFound())
+ .andExpect(statusReason(containsString(msgErrorNoFound("Entity view",entityIdStr))));
}
@Test
public void testSaveEntityViewWithEmptyName() throws Exception {
EntityView entityView = new EntityView();
entityView.setType("default");
+
+ Mockito.reset(tbClusterService, auditLogService);
+
+ String msgError = "Entity view name " + msgErrorShouldBeSpecified;
doPost("/api/entityView", entityView)
.andExpect(status().isBadRequest())
- .andExpect(statusReason(containsString("Entity view name should be specified!")));
+ .andExpect(statusReason(containsString(msgError)));
+
+ testNotifyEntityEqualsOneTimeServiceNeverError(entityView,
+ tenantId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.ADDED, new DataValidationException(msgError));
}
@Test
@@ -195,8 +256,17 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
EntityView view = getNewSavedEntityView("Test entity view");
Customer savedCustomer = doPost("/api/customer", getNewCustomer("My customer"), Customer.class);
view.setCustomerId(savedCustomer.getId());
+
+ Mockito.reset(tbClusterService, auditLogService);
+
EntityView savedView = doPost("/api/entityView", view, EntityView.class);
+ testBroadcastEntityStateChangeEventTime(savedView.getId(), tenantId, 1);
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(savedView, savedView,
+ tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.UPDATED, ActionType.UPDATED, 1, 1, 5);
+ Mockito.reset(tbClusterService, auditLogService);
+
EntityView assignedView = doPost(
"/api/customer/" + savedCustomer.getId().getId().toString() + "/entityView/" + savedView.getId().getId().toString(),
EntityView.class);
@@ -205,18 +275,38 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
EntityView foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class);
assertEquals(savedCustomer.getId(), foundView.getCustomerId());
+ testBroadcastEntityStateChangeEventNever(foundView.getId());
+ testNotifyEntityAllOneTime(foundView, foundView.getId(), foundView.getId(),
+ tenantId, foundView.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.ASSIGNED_TO_CUSTOMER,
+ foundView.getId().getId().toString(), foundView.getCustomerId().getId().toString(), savedCustomer.getTitle());
+
EntityView unAssignedView = doDelete("/api/customer/entityView/" + savedView.getId().getId().toString(), EntityView.class);
assertEquals(ModelConstants.NULL_UUID, unAssignedView.getCustomerId().getId());
foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class);
assertEquals(ModelConstants.NULL_UUID, foundView.getCustomerId().getId());
+
+ testBroadcastEntityStateChangeEventNever(foundView.getId());
+ testNotifyEntityAllOneTime(unAssignedView, savedView.getId(), savedView.getId(),
+ tenantId, savedView.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.UNASSIGNED_FROM_CUSTOMER,
+ savedView.getCustomerId().getId().toString(), savedCustomer.getTitle());
}
@Test
public void testAssignEntityViewToNonExistentCustomer() throws Exception {
EntityView savedView = getNewSavedEntityView("Test entity view");
- doPost("/api/customer/" + Uuids.timeBased().toString() + "/device/" + savedView.getId().getId().toString())
- .andExpect(status().isNotFound());
+
+ Mockito.reset(tbClusterService, auditLogService);
+
+ String customerIdStr = Uuids.timeBased().toString();
+ String msgError = msgErrorNoFound("Customer", customerIdStr);
+ doPost("/api/customer/" + customerIdStr + "/device/" + savedView.getId().getId().toString())
+ .andExpect(status().isNotFound())
+ .andExpect(statusReason(containsString(msgError)));
+
+ testNotifyEntityNever(savedView.getId(), savedView);
}
@Test
@@ -242,8 +332,13 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
EntityView savedView = getNewSavedEntityView("Test entity view");
+ Mockito.reset(tbClusterService, auditLogService);
+
doPost("/api/customer/" + savedCustomer.getId().getId().toString() + "/entityView/" + savedView.getId().getId().toString())
- .andExpect(status().isForbidden());
+ .andExpect(status().isForbidden())
+ .andExpect(statusReason(containsString(msgErrorPermission)));
+
+ testNotifyEntityNever(savedView.getId(), savedView);
loginSysAdmin();
@@ -257,8 +352,11 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
CustomerId customerId = customer.getId();
String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViewInfos?";
- List> viewFutures = new ArrayList<>(128);
- for (int i = 0; i < 128; i++) {
+ Mockito.reset(tbClusterService, auditLogService);
+
+ int cntEntity = 128;
+ List> viewFutures = new ArrayList<>(cntEntity);
+ for (int i = 0; i < cntEntity; i++) {
String entityName = "Test entity view " + i;
viewFutures.add(executor.submit(() ->
new EntityViewInfo(doPost("/api/customer/" + customerId.getId().toString() + "/entityView/"
@@ -269,6 +367,15 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
List loadedViews = loadListOfInfo(new PageLink(23), urlTemplate);
assertThat(entityViewInfos).containsExactlyInAnyOrderElementsOf(loadedViews);
+
+ testNotifyEntityBroadcastEntityStateChangeEventMany(new EntityView(), new EntityView(),
+ tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.ADDED, ActionType.ADDED, cntEntity, 0, cntEntity*2, 0);
+
+ testNotifyEntityBroadcastEntityStateChangeEventMany(new EntityView(), new EntityView(),
+ tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.ASSIGNED_TO_CUSTOMER, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity,
+ cntEntity*2, 3);
}
@Test
@@ -289,12 +396,21 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
assertThat(namesOfView2).as(name2).containsExactlyInAnyOrderElementsOf(loadedNamesOfView2);
deleteFutures.clear();
+
+ Mockito.reset(tbClusterService, auditLogService);
+
+ int cntEntity = loadedNamesOfView1.size();
for (EntityView view : loadedNamesOfView1) {
deleteFutures.add(executor.submit(() ->
doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk())));
}
Futures.allAsList(deleteFutures).get(TIMEOUT, SECONDS);
+ testBroadcastEntityStateChangeEventNever(loadedNamesOfView1.get(0).getId());
+ testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new EntityView(), new EntityView(),
+ tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL,
+ ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UNASSIGNED_FROM_CUSTOMER, cntEntity, cntEntity, 2);
+
PageData pageData = doGetTypedWithPageLink(urlTemplate, PAGE_DATA_ENTITY_VIEW_TYPE_REF,
new PageLink(4, 0, name1));
Assert.assertFalse(pageData.hasNext());
@@ -370,10 +486,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
Set expectedActualAttributesSet = Set.of("caKey1", "caKey2", "caKey3", "caKey4");
Set actualAttributesSet =
putAttributesAndWait("{\"caKey1\":\"value1\", \"caKey2\":true, \"caKey3\":42.0, \"caKey4\":73}", expectedActualAttributesSet);
- log.debug("got correct actualAttributesSet, saving new entity view...");
EntityView savedView = getNewSavedEntityView("Test entity view");
- log.debug("fetching entity view telemetry...");
List