Browse Source

Merge pull request #1236 from thingsboard/feature/tenant_level_rate_limits

tenant level rate limits
pull/1240/head
Igor Kulikov 8 years ago
committed by GitHub
parent
commit
8cc1e9f72b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
  2. 10
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
  3. 4
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
  4. 2
      application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java
  5. 5
      application/src/main/java/org/thingsboard/server/controller/AdminController.java
  6. 8
      application/src/main/java/org/thingsboard/server/controller/AlarmController.java
  7. 10
      application/src/main/java/org/thingsboard/server/controller/AssetController.java
  8. 25
      application/src/main/java/org/thingsboard/server/controller/AuthController.java
  9. 29
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  10. 2
      application/src/main/java/org/thingsboard/server/controller/CustomerController.java
  11. 18
      application/src/main/java/org/thingsboard/server/controller/DashboardController.java
  12. 14
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  13. 24
      application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
  14. 12
      application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
  15. 12
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  16. 67
      application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
  17. 16
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  18. 2
      application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
  19. 6
      application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
  20. 9
      application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java
  21. 4
      application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java
  22. 14
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  23. 5
      application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java
  24. 4
      application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java
  25. 30
      application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java
  26. 9
      application/src/main/java/org/thingsboard/server/service/security/auth/jwt/RefreshTokenAuthenticationProvider.java
  27. 7
      application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestAuthenticationProvider.java
  28. 10
      application/src/main/java/org/thingsboard/server/service/security/device/DefaultDeviceAuthService.java
  29. 3
      application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java
  30. 10
      application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java
  31. 39
      application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java
  32. 56
      application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java
  33. 1
      application/src/main/java/org/thingsboard/server/service/telemetry/TelemetrySubscriptionService.java
  34. 2
      application/src/main/java/org/thingsboard/server/service/telemetry/sub/SubscriptionState.java
  35. 7
      application/src/main/java/org/thingsboard/server/service/transport/LocalTransportApiService.java
  36. 11
      application/src/main/proto/cluster.proto
  37. 3
      application/src/main/resources/thingsboard.yml
  38. 8
      application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java
  39. 2
      application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java
  40. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java
  41. 4
      common/message/pom.xml
  42. 8
      common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimits.java
  43. 4
      common/transport/transport-api/pom.xml
  44. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/DeviceAuthService.java
  45. 13
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/AbstractTransportService.java
  46. 11
      dao/src/main/java/org/thingsboard/server/dao/Dao.java
  47. 6
      dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java
  48. 12
      dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
  49. 92
      dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
  50. 16
      dao/src/main/java/org/thingsboard/server/dao/alarm/CassandraAlarmDao.java
  51. 3
      dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java
  52. 12
      dao/src/main/java/org/thingsboard/server/dao/asset/AssetService.java
  53. 88
      dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
  54. 23
      dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java
  55. 11
      dao/src/main/java/org/thingsboard/server/dao/attributes/AttributesDao.java
  56. 11
      dao/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java
  57. 21
      dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java
  58. 25
      dao/src/main/java/org/thingsboard/server/dao/attributes/CassandraBaseAttributesDao.java
  59. 6
      dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java
  60. 25
      dao/src/main/java/org/thingsboard/server/dao/audit/CassandraAuditLogDao.java
  61. 6
      dao/src/main/java/org/thingsboard/server/dao/cache/PreviousDeviceCredentialsIdKeyGenerator.java
  62. 34
      dao/src/main/java/org/thingsboard/server/dao/component/BaseComponentDescriptorService.java
  63. 37
      dao/src/main/java/org/thingsboard/server/dao/component/CassandraBaseComponentDescriptorDao.java
  64. 15
      dao/src/main/java/org/thingsboard/server/dao/component/ComponentDescriptorDao.java
  65. 15
      dao/src/main/java/org/thingsboard/server/dao/component/ComponentDescriptorService.java
  66. 8
      dao/src/main/java/org/thingsboard/server/dao/customer/CassandraCustomerDao.java
  67. 3
      dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java
  68. 6
      dao/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java
  69. 42
      dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
  70. 7
      dao/src/main/java/org/thingsboard/server/dao/dashboard/CassandraDashboardInfoDao.java
  71. 3
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java
  72. 18
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java
  73. 78
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
  74. 9
      dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceCredentialsDao.java
  75. 23
      dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java
  76. 8
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsDao.java
  77. 9
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java
  78. 46
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java
  79. 3
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java
  80. 12
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceService.java
  81. 93
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
  82. 5
      dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java
  83. 24
      dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java
  84. 5
      dao/src/main/java/org/thingsboard/server/dao/entity/EntityService.java
  85. 21
      dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java
  86. 3
      dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java
  87. 13
      dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
  88. 85
      dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java
  89. 10
      dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java
  90. 22
      dao/src/main/java/org/thingsboard/server/dao/event/CassandraBaseEventDao.java
  91. 3
      dao/src/main/java/org/thingsboard/server/dao/event/EventDao.java
  92. 25
      dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java
  93. 54
      dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractModelDao.java
  94. 15
      dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractSearchTextDao.java
  95. 21
      dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractSearchTimeDao.java
  96. 15
      dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateExecutor.java
  97. 2
      dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraStatementTask.java
  98. 77
      dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationDao.java
  99. 132
      dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java
  100. 31
      dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java

6
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java

@ -123,7 +123,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
}
private void initAttributes() {
Device device = systemContext.getDeviceService().findDeviceById(deviceId);
Device device = systemContext.getDeviceService().findDeviceById(tenantId, deviceId);
this.deviceName = device.getName();
this.deviceType = device.getType();
this.defaultMetaData = new TbMsgMetaData();
@ -290,9 +290,9 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
private ListenableFuture<List<AttributeKvEntry>> getAttributeKvEntries(DeviceId deviceId, String scope, Optional<Set<String>> names) {
if (names.isPresent()) {
if (!names.get().isEmpty()) {
return systemContext.getAttributesService().find(deviceId, scope, names.get());
return systemContext.getAttributesService().find(tenantId, deviceId, scope, names.get());
} else {
return systemContext.getAttributesService().findAll(deviceId, scope);
return systemContext.getAttributesService().findAll(tenantId, deviceId, scope);
}
} else {
return Futures.immediateFuture(Collections.emptyList());

10
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java

@ -90,9 +90,9 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
@Override
public void start(ActorContext context) {
if (!started) {
RuleChain ruleChain = service.findRuleChainById(entityId);
RuleChain ruleChain = service.findRuleChainById(tenantId, entityId);
ruleChainName = ruleChain.getName();
List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId);
List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId);
log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size());
// Creating and starting the actors;
for (RuleNode ruleNode : ruleNodeList) {
@ -109,9 +109,9 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
@Override
public void onUpdate(ActorContext context) {
RuleChain ruleChain = service.findRuleChainById(entityId);
RuleChain ruleChain = service.findRuleChainById(tenantId, entityId);
ruleChainName = ruleChain.getName();
List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId);
List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId);
log.trace("[{}][{}] Updating rule chain with {} nodes", tenantId, entityId, ruleNodeList.size());
for (RuleNode ruleNode : ruleNodeList) {
RuleNodeCtx existing = nodeActors.get(ruleNode.getId());
@ -164,7 +164,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
nodeRoutes.clear();
// Populating the routes map;
for (RuleNode ruleNode : ruleNodeList) {
List<EntityRelation> relations = service.getRuleNodeRelations(ruleNode.getId());
List<EntityRelation> relations = service.getRuleNodeRelations(TenantId.SYS_TENANT_ID, ruleNode.getId());
log.trace("[{}][{}][{}] Processing rule node relations [{}]", tenantId, entityId, ruleNode.getId(), relations.size());
if (relations.size() == 0) {
nodeRoutes.put(ruleNode.getId(), Collections.emptyList());

4
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java

@ -49,7 +49,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
this.parent = parent;
this.self = self;
this.service = systemContext.getRuleChainService();
this.ruleNode = systemContext.getRuleChainService().findRuleNodeById(entityId);
this.ruleNode = systemContext.getRuleChainService().findRuleNodeById(tenantId, entityId);
this.defaultCtx = new DefaultTbContext(systemContext, new RuleNodeCtx(tenantId, parent, self, ruleNode));
}
@ -61,7 +61,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
@Override
public void onUpdate(ActorContext context) throws Exception {
RuleNode newRuleNode = systemContext.getRuleChainService().findRuleNodeById(entityId);
RuleNode newRuleNode = systemContext.getRuleChainService().findRuleNodeById(tenantId, entityId);
boolean restartRequired = !(ruleNode.getType().equals(newRuleNode.getType())
&& ruleNode.getConfiguration().equals(newRuleNode.getConfiguration()));
this.ruleNode = newRuleNode;

2
application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java

@ -143,7 +143,7 @@ public class TenantActor extends RuleChainManagerActor {
if (target != null) {
if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) {
RuleChain ruleChain = systemContext.getRuleChainService().
findRuleChainById(new RuleChainId(msg.getEntityId().getId()));
findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId()));
ruleChainManager.visit(ruleChain, target);
}
target.tell(msg, ActorRef.noSender());

5
application/src/main/java/org/thingsboard/server/controller/AdminController.java

@ -26,6 +26,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.service.update.UpdateService;
import org.thingsboard.server.service.update.model.UpdateMessage;
@ -48,7 +49,7 @@ public class AdminController extends BaseController {
@ResponseBody
public AdminSettings getAdminSettings(@PathVariable("key") String key) throws ThingsboardException {
try {
return checkNotNull(adminSettingsService.findAdminSettingsByKey(key));
return checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key));
} catch (Exception e) {
throw handleException(e);
}
@ -59,7 +60,7 @@ public class AdminController extends BaseController {
@ResponseBody
public AdminSettings saveAdminSettings(@RequestBody AdminSettings adminSettings) throws ThingsboardException {
try {
adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(adminSettings));
adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings));
if (adminSettings.getKey().equals("mail")) {
mailService.updateMailConfiguration();
}

8
application/src/main/java/org/thingsboard/server/controller/AlarmController.java

@ -100,7 +100,7 @@ public class AlarmController extends BaseController {
try {
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId);
alarmService.ackAlarm(alarmId, System.currentTimeMillis()).get();
alarmService.ackAlarm(getCurrentUser().getTenantId(), alarmId, System.currentTimeMillis()).get();
logEntityAction(alarmId, alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_ACK, null);
} catch (Exception e) {
throw handleException(e);
@ -115,7 +115,7 @@ public class AlarmController extends BaseController {
try {
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId);
alarmService.clearAlarm(alarmId, null, System.currentTimeMillis()).get();
alarmService.clearAlarm(getCurrentUser().getTenantId(), alarmId, null, System.currentTimeMillis()).get();
logEntityAction(alarmId, alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_CLEAR, null);
} catch (Exception e) {
throw handleException(e);
@ -149,7 +149,7 @@ public class AlarmController extends BaseController {
checkEntityId(entityId);
try {
TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
return checkNotNull(alarmService.findAlarms(new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get());
return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get());
} catch (Exception e) {
throw handleException(e);
}
@ -175,7 +175,7 @@ public class AlarmController extends BaseController {
}
checkEntityId(entityId);
try {
return alarmService.findHighestAlarmSeverity(entityId, alarmSearchStatus, alarmStatus);
return alarmService.findHighestAlarmSeverity(getCurrentUser().getTenantId(), entityId, alarmSearchStatus, alarmStatus);
} catch (Exception e) {
throw handleException(e);
}

10
application/src/main/java/org/thingsboard/server/controller/AssetController.java

@ -104,7 +104,7 @@ public class AssetController extends BaseController {
try {
AssetId assetId = new AssetId(toUUID(strAssetId));
Asset asset = checkAssetId(assetId);
assetService.deleteAsset(assetId);
assetService.deleteAsset(getTenantId(), assetId);
logEntityAction(assetId, asset,
asset.getCustomerId(),
@ -133,7 +133,7 @@ public class AssetController extends BaseController {
AssetId assetId = new AssetId(toUUID(strAssetId));
checkAssetId(assetId);
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(assetId, customerId));
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(getTenantId(), assetId, customerId));
logEntityAction(assetId, savedAsset,
savedAsset.getCustomerId(),
@ -164,7 +164,7 @@ public class AssetController extends BaseController {
Customer customer = checkCustomerId(asset.getCustomerId());
Asset savedAsset = checkNotNull(assetService.unassignAssetFromCustomer(assetId));
Asset savedAsset = checkNotNull(assetService.unassignAssetFromCustomer(getTenantId(), assetId));
logEntityAction(assetId, asset,
asset.getCustomerId(),
@ -190,7 +190,7 @@ public class AssetController extends BaseController {
AssetId assetId = new AssetId(toUUID(strAssetId));
Asset asset = checkAssetId(assetId);
Customer publicCustomer = customerService.findOrCreatePublicCustomer(asset.getTenantId());
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(assetId, publicCustomer.getId()));
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(getTenantId(), assetId, publicCustomer.getId()));
logEntityAction(assetId, savedAsset,
savedAsset.getCustomerId(),
@ -303,7 +303,7 @@ public class AssetController extends BaseController {
checkNotNull(query.getAssetTypes());
checkEntityId(query.getParameters().getEntityId());
try {
List<Asset> assets = checkNotNull(assetService.findAssetsByQuery(query).get());
List<Asset> assets = checkNotNull(assetService.findAssetsByQuery(getTenantId(), query).get());
assets = assets.stream().filter(asset -> {
try {
checkAsset(asset);

25
application/src/main/java/org/thingsboard/server/controller/AuthController.java

@ -36,6 +36,7 @@ import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
import org.thingsboard.server.service.security.model.SecurityUser;
@ -52,8 +53,6 @@ import java.net.URISyntaxException;
@Slf4j
public class AuthController extends BaseController {
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@ -71,7 +70,7 @@ public class AuthController extends BaseController {
public @ResponseBody User getUser() throws ThingsboardException {
try {
SecurityUser securityUser = getCurrentUser();
return userService.findUserById(securityUser.getId());
return userService.findUserById(securityUser.getTenantId(), securityUser.getId());
} catch (Exception e) {
throw handleException(e);
}
@ -86,12 +85,12 @@ public class AuthController extends BaseController {
String currentPassword = changePasswordRequest.get("currentPassword").asText();
String newPassword = changePasswordRequest.get("newPassword").asText();
SecurityUser securityUser = getCurrentUser();
UserCredentials userCredentials = userService.findUserCredentialsByUserId(securityUser.getId());
UserCredentials userCredentials = userService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, securityUser.getId());
if (!passwordEncoder.matches(currentPassword, userCredentials.getPassword())) {
throw new ThingsboardException("Current password doesn't match!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
userCredentials.setPassword(passwordEncoder.encode(newPassword));
userService.saveUserCredentials(userCredentials);
userService.saveUserCredentials(securityUser.getTenantId(), userCredentials);
} catch (Exception e) {
throw handleException(e);
}
@ -102,7 +101,7 @@ public class AuthController extends BaseController {
@RequestParam(value = "activateToken") String activateToken) {
HttpHeaders headers = new HttpHeaders();
HttpStatus responseStatus;
UserCredentials userCredentials = userService.findUserCredentialsByActivateToken(activateToken);
UserCredentials userCredentials = userService.findUserCredentialsByActivateToken(TenantId.SYS_TENANT_ID, activateToken);
if (userCredentials != null) {
String createURI = "/login/createPassword";
try {
@ -126,7 +125,7 @@ public class AuthController extends BaseController {
HttpServletRequest request) throws ThingsboardException {
try {
String email = resetPasswordByEmailRequest.get("email").asText();
UserCredentials userCredentials = userService.requestPasswordReset(email);
UserCredentials userCredentials = userService.requestPasswordReset(TenantId.SYS_TENANT_ID, email);
String baseUrl = constructBaseUrl(request);
String resetUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl,
userCredentials.getResetToken());
@ -143,7 +142,7 @@ public class AuthController extends BaseController {
HttpHeaders headers = new HttpHeaders();
HttpStatus responseStatus;
String resetURI = "/login/resetPassword";
UserCredentials userCredentials = userService.findUserCredentialsByResetToken(resetToken);
UserCredentials userCredentials = userService.findUserCredentialsByResetToken(TenantId.SYS_TENANT_ID, resetToken);
if (userCredentials != null) {
try {
URI location = new URI(resetURI + "?resetToken=" + resetToken);
@ -169,8 +168,8 @@ public class AuthController extends BaseController {
String activateToken = activateRequest.get("activateToken").asText();
String password = activateRequest.get("password").asText();
String encodedPassword = passwordEncoder.encode(password);
UserCredentials credentials = userService.activateUserCredentials(activateToken, encodedPassword);
User user = userService.findUserById(credentials.getUserId());
UserCredentials credentials = userService.activateUserCredentials(TenantId.SYS_TENANT_ID, activateToken, encodedPassword);
User user = userService.findUserById(TenantId.SYS_TENANT_ID, credentials.getUserId());
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
String baseUrl = constructBaseUrl(request);
@ -205,13 +204,13 @@ public class AuthController extends BaseController {
try {
String resetToken = resetPasswordRequest.get("resetToken").asText();
String password = resetPasswordRequest.get("password").asText();
UserCredentials userCredentials = userService.findUserCredentialsByResetToken(resetToken);
UserCredentials userCredentials = userService.findUserCredentialsByResetToken(TenantId.SYS_TENANT_ID, resetToken);
if (userCredentials != null) {
String encodedPassword = passwordEncoder.encode(password);
userCredentials.setPassword(encodedPassword);
userCredentials.setResetToken(null);
userCredentials = userService.saveUserCredentials(userCredentials);
User user = userService.findUserById(userCredentials.getUserId());
userCredentials = userService.saveUserCredentials(TenantId.SYS_TENANT_ID, userCredentials);
User user = userService.findUserById(TenantId.SYS_TENANT_ID, userCredentials.getUserId());
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled(), principal);
String baseUrl = constructBaseUrl(request);

29
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -275,7 +275,7 @@ public abstract class BaseController {
ThingsboardErrorCode.PERMISSION_DENIED);
}
if (customerId != null && !customerId.isNullUid()) {
Customer customer = customerService.findCustomerById(customerId);
Customer customer = customerService.findCustomerById(authUser.getTenantId(), customerId);
checkCustomer(customer);
return customer;
} else {
@ -294,7 +294,7 @@ public abstract class BaseController {
User checkUserId(UserId userId) throws ThingsboardException {
try {
validateId(userId, "Incorrect userId " + userId);
User user = userService.findUserById(userId);
User user = userService.findUserById(getCurrentUser().getTenantId(), userId);
checkUser(user);
return user;
} catch (Exception e) {
@ -314,9 +314,10 @@ public abstract class BaseController {
try {
checkNotNull(entityId);
validateId(entityId.getId(), "Incorrect entityId " + entityId);
SecurityUser authUser = getCurrentUser();
switch (entityId.getEntityType()) {
case DEVICE:
checkDevice(deviceService.findDeviceById(new DeviceId(entityId.getId())));
checkDevice(deviceService.findDeviceById(authUser.getTenantId(), new DeviceId(entityId.getId())));
return;
case CUSTOMER:
checkCustomerId(new CustomerId(entityId.getId()));
@ -328,7 +329,7 @@ public abstract class BaseController {
checkRuleChain(new RuleChainId(entityId.getId()));
return;
case ASSET:
checkAsset(assetService.findAssetById(new AssetId(entityId.getId())));
checkAsset(assetService.findAssetById(authUser.getTenantId(), new AssetId(entityId.getId())));
return;
case DASHBOARD:
checkDashboardId(new DashboardId(entityId.getId()));
@ -350,7 +351,7 @@ public abstract class BaseController {
Device checkDeviceId(DeviceId deviceId) throws ThingsboardException {
try {
validateId(deviceId, "Incorrect deviceId " + deviceId);
Device device = deviceService.findDeviceById(deviceId);
Device device = deviceService.findDeviceById(getCurrentUser().getTenantId(), deviceId);
checkDevice(device);
return device;
} catch (Exception e) {
@ -367,7 +368,7 @@ public abstract class BaseController {
protected EntityView checkEntityViewId(EntityViewId entityViewId) throws ThingsboardException {
try {
validateId(entityViewId, "Incorrect entityViewId " + entityViewId);
EntityView entityView = entityViewService.findEntityViewById(entityViewId);
EntityView entityView = entityViewService.findEntityViewById(getCurrentUser().getTenantId(), entityViewId);
checkEntityView(entityView);
return entityView;
} catch (Exception e) {
@ -384,7 +385,7 @@ public abstract class BaseController {
Asset checkAssetId(AssetId assetId) throws ThingsboardException {
try {
validateId(assetId, "Incorrect assetId " + assetId);
Asset asset = assetService.findAssetById(assetId);
Asset asset = assetService.findAssetById(getCurrentUser().getTenantId(), assetId);
checkAsset(asset);
return asset;
} catch (Exception e) {
@ -401,7 +402,7 @@ public abstract class BaseController {
Alarm checkAlarmId(AlarmId alarmId) throws ThingsboardException {
try {
validateId(alarmId, "Incorrect alarmId " + alarmId);
Alarm alarm = alarmService.findAlarmByIdAsync(alarmId).get();
Alarm alarm = alarmService.findAlarmByIdAsync(getCurrentUser().getTenantId(), alarmId).get();
checkAlarm(alarm);
return alarm;
} catch (Exception e) {
@ -412,7 +413,7 @@ public abstract class BaseController {
AlarmInfo checkAlarmInfoId(AlarmId alarmId) throws ThingsboardException {
try {
validateId(alarmId, "Incorrect alarmId " + alarmId);
AlarmInfo alarmInfo = alarmService.findAlarmInfoByIdAsync(alarmId).get();
AlarmInfo alarmInfo = alarmService.findAlarmInfoByIdAsync(getCurrentUser().getTenantId(), alarmId).get();
checkAlarm(alarmInfo);
return alarmInfo;
} catch (Exception e) {
@ -428,7 +429,7 @@ public abstract class BaseController {
WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, boolean modify) throws ThingsboardException {
try {
validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId);
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(widgetsBundleId);
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(getCurrentUser().getTenantId(), widgetsBundleId);
checkWidgetsBundle(widgetsBundle, modify);
return widgetsBundle;
} catch (Exception e) {
@ -449,7 +450,7 @@ public abstract class BaseController {
WidgetType checkWidgetTypeId(WidgetTypeId widgetTypeId, boolean modify) throws ThingsboardException {
try {
validateId(widgetTypeId, "Incorrect widgetTypeId " + widgetTypeId);
WidgetType widgetType = widgetTypeService.findWidgetTypeById(widgetTypeId);
WidgetType widgetType = widgetTypeService.findWidgetTypeById(getCurrentUser().getTenantId(), widgetTypeId);
checkWidgetType(widgetType, modify);
return widgetType;
} catch (Exception e) {
@ -470,7 +471,7 @@ public abstract class BaseController {
Dashboard checkDashboardId(DashboardId dashboardId) throws ThingsboardException {
try {
validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
Dashboard dashboard = dashboardService.findDashboardById(dashboardId);
Dashboard dashboard = dashboardService.findDashboardById(getCurrentUser().getTenantId(), dashboardId);
checkDashboard(dashboard);
return dashboard;
} catch (Exception e) {
@ -481,7 +482,7 @@ public abstract class BaseController {
DashboardInfo checkDashboardInfoId(DashboardId dashboardId) throws ThingsboardException {
try {
validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
DashboardInfo dashboardInfo = dashboardService.findDashboardInfoById(dashboardId);
DashboardInfo dashboardInfo = dashboardService.findDashboardInfoById(getCurrentUser().getTenantId(), dashboardId);
checkDashboard(dashboardInfo);
return dashboardInfo;
} catch (Exception e) {
@ -530,7 +531,7 @@ public abstract class BaseController {
protected RuleChain checkRuleChain(RuleChainId ruleChainId) throws ThingsboardException {
checkNotNull(ruleChainId);
return checkRuleChain(ruleChainService.findRuleChainById(ruleChainId));
return checkRuleChain(ruleChainService.findRuleChainById(getCurrentUser().getTenantId(), ruleChainId));
}
protected RuleChain checkRuleChain(RuleChain ruleChain) throws ThingsboardException {

2
application/src/main/java/org/thingsboard/server/controller/CustomerController.java

@ -119,7 +119,7 @@ public class CustomerController extends BaseController {
try {
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
Customer customer = checkCustomerId(customerId);
customerService.deleteCustomer(customerId);
customerService.deleteCustomer(getTenantId(), customerId);
logEntityAction(customerId, customer,
customer.getId(),

18
application/src/main/java/org/thingsboard/server/controller/DashboardController.java

@ -124,7 +124,7 @@ public class DashboardController extends BaseController {
try {
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId);
dashboardService.deleteDashboard(dashboardId);
dashboardService.deleteDashboard(getCurrentUser().getTenantId(), dashboardId);
logEntityAction(dashboardId, dashboard,
null,
@ -155,7 +155,7 @@ public class DashboardController extends BaseController {
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
checkDashboardId(dashboardId);
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(dashboardId, customerId));
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(getCurrentUser().getTenantId(), dashboardId, customerId));
logEntityAction(dashboardId, savedDashboard,
customerId,
@ -186,7 +186,7 @@ public class DashboardController extends BaseController {
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId);
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(dashboardId, customerId));
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(getCurrentUser().getTenantId(), dashboardId, customerId));
logEntityAction(dashboardId, dashboard,
customerId,
@ -242,7 +242,7 @@ public class DashboardController extends BaseController {
} else {
Dashboard savedDashboard = null;
for (CustomerId customerId : addedCustomerIds) {
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(dashboardId, customerId));
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(getCurrentUser().getTenantId(), dashboardId, customerId));
ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId);
logEntityAction(dashboardId, savedDashboard,
customerId,
@ -250,7 +250,7 @@ public class DashboardController extends BaseController {
}
for (CustomerId customerId : removedCustomerIds) {
ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId);
savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(dashboardId, customerId));
savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(getCurrentUser().getTenantId(), dashboardId, customerId));
logEntityAction(dashboardId, dashboard,
customerId,
ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle());
@ -293,7 +293,7 @@ public class DashboardController extends BaseController {
} else {
Dashboard savedDashboard = null;
for (CustomerId customerId : customerIds) {
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(dashboardId, customerId));
savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(getCurrentUser().getTenantId(), dashboardId, customerId));
ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId);
logEntityAction(dashboardId, savedDashboard,
customerId,
@ -337,7 +337,7 @@ public class DashboardController extends BaseController {
Dashboard savedDashboard = null;
for (CustomerId customerId : customerIds) {
ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId);
savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(dashboardId, customerId));
savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(getCurrentUser().getTenantId(), dashboardId, customerId));
logEntityAction(dashboardId, dashboard,
customerId,
ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle());
@ -364,7 +364,7 @@ public class DashboardController extends BaseController {
DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
Dashboard dashboard = checkDashboardId(dashboardId);
Customer publicCustomer = customerService.findOrCreatePublicCustomer(dashboard.getTenantId());
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(dashboardId, publicCustomer.getId()));
Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(getCurrentUser().getTenantId(), dashboardId, publicCustomer.getId()));
logEntityAction(dashboardId, savedDashboard,
publicCustomer.getId(),
@ -391,7 +391,7 @@ public class DashboardController extends BaseController {
Dashboard dashboard = checkDashboardId(dashboardId);
Customer publicCustomer = customerService.findOrCreatePublicCustomer(dashboard.getTenantId());
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(dashboardId, publicCustomer.getId()));
Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(getCurrentUser().getTenantId(), dashboardId, publicCustomer.getId()));
logEntityAction(dashboardId, dashboard,
publicCustomer.getId(),

14
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -117,7 +117,7 @@ public class DeviceController extends BaseController {
try {
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
Device device = checkDeviceId(deviceId);
deviceService.deleteDevice(deviceId);
deviceService.deleteDevice(getCurrentUser().getTenantId(), deviceId);
logEntityAction(deviceId, device,
device.getCustomerId(),
@ -147,7 +147,7 @@ public class DeviceController extends BaseController {
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
checkDeviceId(deviceId);
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(deviceId, customerId));
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(getCurrentUser().getTenantId(), deviceId, customerId));
logEntityAction(deviceId, savedDevice,
savedDevice.getCustomerId(),
@ -175,7 +175,7 @@ public class DeviceController extends BaseController {
}
Customer customer = checkCustomerId(device.getCustomerId());
Device savedDevice = checkNotNull(deviceService.unassignDeviceFromCustomer(deviceId));
Device savedDevice = checkNotNull(deviceService.unassignDeviceFromCustomer(getCurrentUser().getTenantId(), deviceId));
logEntityAction(deviceId, device,
device.getCustomerId(),
@ -199,7 +199,7 @@ public class DeviceController extends BaseController {
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
Device device = checkDeviceId(deviceId);
Customer publicCustomer = customerService.findOrCreatePublicCustomer(device.getTenantId());
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(deviceId, publicCustomer.getId()));
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(getCurrentUser().getTenantId(), deviceId, publicCustomer.getId()));
logEntityAction(deviceId, savedDevice,
savedDevice.getCustomerId(),
@ -222,7 +222,7 @@ public class DeviceController extends BaseController {
try {
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
Device device = checkDeviceId(deviceId);
DeviceCredentials deviceCredentials = checkNotNull(deviceCredentialsService.findDeviceCredentialsByDeviceId(deviceId));
DeviceCredentials deviceCredentials = checkNotNull(deviceCredentialsService.findDeviceCredentialsByDeviceId(getCurrentUser().getTenantId(), deviceId));
logEntityAction(deviceId, device,
device.getCustomerId(),
ActionType.CREDENTIALS_READ, null, strDeviceId);
@ -242,7 +242,7 @@ public class DeviceController extends BaseController {
checkNotNull(deviceCredentials);
try {
Device device = checkDeviceId(deviceCredentials.getDeviceId());
DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(deviceCredentials));
DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(getCurrentUser().getTenantId(), deviceCredentials));
actorService.onCredentialsUpdate(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId());
logEntityAction(device.getId(), device,
device.getCustomerId(),
@ -352,7 +352,7 @@ public class DeviceController extends BaseController {
checkNotNull(query.getDeviceTypes());
checkEntityId(query.getParameters().getEntityId());
try {
List<Device> devices = checkNotNull(deviceService.findDevicesByQuery(query).get());
List<Device> devices = checkNotNull(deviceService.findDevicesByQuery(getCurrentUser().getTenantId(), query).get());
devices = devices.stream().filter(device -> {
try {
checkDevice(device);

24
application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java

@ -60,7 +60,7 @@ public class EntityRelationController extends BaseController {
if (relation.getTypeGroup() == null) {
relation.setTypeGroup(RelationTypeGroup.COMMON);
}
relationService.saveRelation(relation);
relationService.saveRelation(getTenantId(), relation);
logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(),
ActionType.RELATION_ADD_OR_UPDATE, null, relation);
logEntityAction(relation.getTo(), null, getCurrentUser().getCustomerId(),
@ -94,7 +94,7 @@ public class EntityRelationController extends BaseController {
RelationTypeGroup relationTypeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
EntityRelation relation = new EntityRelation(fromId, toId, strRelationType, relationTypeGroup);
try {
Boolean found = relationService.deleteRelation(fromId, toId, strRelationType, relationTypeGroup);
Boolean found = relationService.deleteRelation(getTenantId(), fromId, toId, strRelationType, relationTypeGroup);
if (!found) {
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
}
@ -121,7 +121,7 @@ public class EntityRelationController extends BaseController {
EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId);
checkEntityId(entityId);
try {
relationService.deleteEntityRelations(entityId);
relationService.deleteEntityRelations(getTenantId(), entityId);
logEntityAction(entityId, null, getCurrentUser().getCustomerId(), ActionType.RELATIONS_DELETED, null);
} catch (Exception e) {
logEntityAction(entityId, null, getCurrentUser().getCustomerId(), ActionType.RELATIONS_DELETED, e);
@ -148,7 +148,7 @@ public class EntityRelationController extends BaseController {
checkEntityId(fromId);
checkEntityId(toId);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
return checkNotNull(relationService.getRelation(fromId, toId, strRelationType, typeGroup));
return checkNotNull(relationService.getRelation(getTenantId(), fromId, toId, strRelationType, typeGroup));
} catch (Exception e) {
throw handleException(e);
}
@ -166,7 +166,7 @@ public class EntityRelationController extends BaseController {
checkEntityId(entityId);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(relationService.findByFrom(entityId, typeGroup));
return checkNotNull(relationService.findByFrom(getTenantId(), entityId, typeGroup));
} catch (Exception e) {
throw handleException(e);
}
@ -184,7 +184,7 @@ public class EntityRelationController extends BaseController {
checkEntityId(entityId);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(relationService.findInfoByFrom(entityId, typeGroup).get());
return checkNotNull(relationService.findInfoByFrom(getTenantId(), entityId, typeGroup).get());
} catch (Exception e) {
throw handleException(e);
}
@ -204,7 +204,7 @@ public class EntityRelationController extends BaseController {
checkEntityId(entityId);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(relationService.findByFromAndType(entityId, strRelationType, typeGroup));
return checkNotNull(relationService.findByFromAndType(getTenantId(), entityId, strRelationType, typeGroup));
} catch (Exception e) {
throw handleException(e);
}
@ -222,7 +222,7 @@ public class EntityRelationController extends BaseController {
checkEntityId(entityId);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(relationService.findByTo(entityId, typeGroup));
return checkNotNull(relationService.findByTo(getTenantId(), entityId, typeGroup));
} catch (Exception e) {
throw handleException(e);
}
@ -240,7 +240,7 @@ public class EntityRelationController extends BaseController {
checkEntityId(entityId);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(relationService.findInfoByTo(entityId, typeGroup).get());
return checkNotNull(relationService.findInfoByTo(getTenantId(), entityId, typeGroup).get());
} catch (Exception e) {
throw handleException(e);
}
@ -260,7 +260,7 @@ public class EntityRelationController extends BaseController {
checkEntityId(entityId);
RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
return checkNotNull(relationService.findByToAndType(entityId, strRelationType, typeGroup));
return checkNotNull(relationService.findByToAndType(getTenantId(), entityId, strRelationType, typeGroup));
} catch (Exception e) {
throw handleException(e);
}
@ -275,7 +275,7 @@ public class EntityRelationController extends BaseController {
checkNotNull(query.getFilters());
checkEntityId(query.getParameters().getEntityId());
try {
return checkNotNull(relationService.findByQuery(query).get());
return checkNotNull(relationService.findByQuery(getTenantId(), query).get());
} catch (Exception e) {
throw handleException(e);
}
@ -290,7 +290,7 @@ public class EntityRelationController extends BaseController {
checkNotNull(query.getFilters());
checkEntityId(query.getParameters().getEntityId());
try {
return checkNotNull(relationService.findInfoByQuery(query).get());
return checkNotNull(relationService.findInfoByQuery(getTenantId(), query).get());
} catch (Exception e) {
throw handleException(e);
}

12
application/src/main/java/org/thingsboard/server/controller/EntityViewController.java

@ -114,7 +114,7 @@ public class EntityViewController extends BaseController {
private ListenableFuture<List<Void>> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection<String> keys, SecurityUser user) throws ThingsboardException {
EntityViewId entityId = entityView.getId();
if (keys != null && !keys.isEmpty()) {
ListenableFuture<List<AttributeKvEntry>> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys);
ListenableFuture<List<AttributeKvEntry>> getAttrFuture = attributesService.find(getTenantId(), entityView.getEntityId(), scope, keys);
return Futures.transform(getAttrFuture, attributeKvEntries -> {
List<AttributeKvEntry> attributes;
if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) {
@ -129,7 +129,7 @@ public class EntityViewController extends BaseController {
(startTime == 0 && endTime > lastUpdateTs)
? true : startTime < lastUpdateTs && endTime > lastUpdateTs;
}).collect(Collectors.toList());
tsSubService.saveAndNotify(entityId, scope, attributes, new FutureCallback<Void>() {
tsSubService.saveAndNotify(entityView.getTenantId(), entityId, scope, attributes, new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void tmp) {
try {
@ -169,7 +169,7 @@ public class EntityViewController extends BaseController {
try {
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
EntityView entityView = checkEntityViewId(entityViewId);
entityViewService.deleteEntityView(entityViewId);
entityViewService.deleteEntityView(getTenantId(), entityViewId);
logEntityAction(entityViewId, entityView, entityView.getCustomerId(),
ActionType.DELETED, null, strEntityViewId);
} catch (Exception e) {
@ -208,7 +208,7 @@ public class EntityViewController extends BaseController {
EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
checkEntityViewId(entityViewId);
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(entityViewId, customerId));
EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(getTenantId(), entityViewId, customerId));
logEntityAction(entityViewId, savedEntityView,
savedEntityView.getCustomerId(),
ActionType.ASSIGNED_TO_CUSTOMER, null, strEntityViewId, strCustomerId, customer.getName());
@ -233,7 +233,7 @@ public class EntityViewController extends BaseController {
throw new IncorrectParameterException("Entity View isn't assigned to any customer!");
}
Customer customer = checkCustomerId(entityView.getCustomerId());
EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(entityViewId));
EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(getTenantId(), entityViewId));
logEntityAction(entityViewId, entityView,
entityView.getCustomerId(),
ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEntityViewId, customer.getId().toString(), customer.getName());
@ -305,7 +305,7 @@ public class EntityViewController extends BaseController {
checkNotNull(query.getEntityViewTypes());
checkEntityId(query.getParameters().getEntityId());
try {
List<EntityView> entityViews = checkNotNull(entityViewService.findEntityViewsByQuery(query).get());
List<EntityView> entityViews = checkNotNull(entityViewService.findEntityViewsByQuery(getTenantId(), query).get());
entityViews = entityViews.stream().filter(entityView -> {
try {
checkEntityView(entityView);

12
application/src/main/java/org/thingsboard/server/controller/RuleChainController.java

@ -94,7 +94,7 @@ public class RuleChainController extends BaseController {
try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
checkRuleChain(ruleChainId);
return ruleChainService.loadRuleChainMetaData(ruleChainId);
return ruleChainService.loadRuleChainMetaData(getTenantId(), ruleChainId);
} catch (Exception e) {
throw handleException(e);
}
@ -137,9 +137,9 @@ public class RuleChainController extends BaseController {
RuleChain ruleChain = checkRuleChain(ruleChainId);
TenantId tenantId = getCurrentUser().getTenantId();
RuleChain previousRootRuleChain = ruleChainService.getRootTenantRuleChain(tenantId);
if (ruleChainService.setRootRuleChain(ruleChainId)) {
if (ruleChainService.setRootRuleChain(getTenantId(), ruleChainId)) {
previousRootRuleChain = ruleChainService.findRuleChainById(previousRootRuleChain.getId());
previousRootRuleChain = ruleChainService.findRuleChainById(getTenantId(), previousRootRuleChain.getId());
actorService.onEntityStateChange(previousRootRuleChain.getTenantId(), previousRootRuleChain.getId(),
ComponentLifecycleEvent.UPDATED);
@ -147,7 +147,7 @@ public class RuleChainController extends BaseController {
logEntityAction(previousRootRuleChain.getId(), previousRootRuleChain,
null, ActionType.UPDATED, null);
ruleChain = ruleChainService.findRuleChainById(ruleChainId);
ruleChain = ruleChainService.findRuleChainById(getTenantId(), ruleChainId);
actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(),
ComponentLifecycleEvent.UPDATED);
@ -172,7 +172,7 @@ public class RuleChainController extends BaseController {
public RuleChainMetaData saveRuleChainMetaData(@RequestBody RuleChainMetaData ruleChainMetaData) throws ThingsboardException {
try {
RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId());
RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(ruleChainMetaData));
RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(getTenantId(), ruleChainMetaData));
actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED);
@ -216,7 +216,7 @@ public class RuleChainController extends BaseController {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId);
ruleChainService.deleteRuleChainById(ruleChainId);
ruleChainService.deleteRuleChainById(getTenantId(), ruleChainId);
actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED);

67
application/src/main/java/org/thingsboard/server/controller/TelemetryController.java

@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.kv.Aggregation;
import org.thingsboard.server.common.data.kv.AttributeKey;
@ -127,7 +128,7 @@ public class TelemetryController extends BaseController {
@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr
, @PathVariable("scope") String scope) throws ThingsboardException {
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
(result, entityId) -> getAttributeKeysCallback(result, entityId, scope));
(result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope));
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@ -138,7 +139,7 @@ public class TelemetryController extends BaseController {
@RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
(result, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr));
(result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr));
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@ -150,7 +151,7 @@ public class TelemetryController extends BaseController {
@RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
(result, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr));
(result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr));
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@ -159,9 +160,7 @@ public class TelemetryController extends BaseController {
public DeferredResult<ResponseEntity> getTimeseriesKeys(
@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException {
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
(result, entityId) -> {
Futures.addCallback(tsService.findAllLatest(entityId), getTsKeysToResponseCallback(result));
});
(result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result)));
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@ -173,7 +172,7 @@ public class TelemetryController extends BaseController {
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
(result, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr));
(result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr));
}
@ -190,13 +189,13 @@ public class TelemetryController extends BaseController {
@RequestParam(name = "agg", defaultValue = "NONE") String aggStr
) throws ThingsboardException {
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
(result, entityId) -> {
(result, tenantId, entityId) -> {
// If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted
Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr);
List<ReadTsKvQuery> queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg))
.collect(Collectors.toList());
Futures.addCallback(tsService.findAll(entityId, queries), getTsKvListCallback(result));
Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result));
});
}
@ -206,7 +205,7 @@ public class TelemetryController extends BaseController {
public DeferredResult<ResponseEntity> saveDeviceAttributes(@PathVariable("deviceId") String deviceIdStr, @PathVariable("scope") String scope,
@RequestBody JsonNode request) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
return saveAttributes(entityId, scope, request);
return saveAttributes(getTenantId(), entityId, scope, request);
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@ -216,7 +215,7 @@ public class TelemetryController extends BaseController {
@PathVariable("scope") String scope,
@RequestBody JsonNode request) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveAttributes(entityId, scope, request);
return saveAttributes(getTenantId(), entityId, scope, request);
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@ -226,7 +225,7 @@ public class TelemetryController extends BaseController {
@PathVariable("scope") String scope,
@RequestBody JsonNode request) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveAttributes(entityId, scope, request);
return saveAttributes(getTenantId(), entityId, scope, request);
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@ -236,7 +235,7 @@ public class TelemetryController extends BaseController {
@PathVariable("scope") String scope,
@RequestBody String requestBody) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveTelemetry(entityId, requestBody, 0L);
return saveTelemetry(getTenantId(), entityId, requestBody, 0L);
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@ -246,7 +245,7 @@ public class TelemetryController extends BaseController {
@PathVariable("scope") String scope, @PathVariable("ttl") Long ttl,
@RequestBody String requestBody) throws ThingsboardException {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
return saveTelemetry(entityId, requestBody, ttl);
return saveTelemetry(getTenantId(), entityId, requestBody, ttl);
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@ -280,13 +279,13 @@ public class TelemetryController extends BaseController {
deleteToTs = endTs;
}
return accessValidator.validateEntityAndCallback(user, entityIdStr, (result, entityId) -> {
return accessValidator.validateEntityAndCallback(user, entityIdStr, (result, tenantId, entityId) -> {
List<DeleteTsKvQuery> deleteTsKvQueries = new ArrayList<>();
for (String key : keys) {
deleteTsKvQueries.add(new BaseDeleteTsKvQuery(key, deleteFromTs, deleteToTs, rewriteLatestIfDeleted));
}
ListenableFuture<List<Void>> future = tsService.remove(entityId, deleteTsKvQueries);
ListenableFuture<List<Void>> future = tsService.remove(user.getTenantId(), entityId, deleteTsKvQueries);
Futures.addCallback(future, new FutureCallback<List<Void>>() {
@Override
public void onSuccess(@Nullable List<Void> tmp) {
@ -333,8 +332,8 @@ public class TelemetryController extends BaseController {
if (DataConstants.SERVER_SCOPE.equals(scope) ||
DataConstants.SHARED_SCOPE.equals(scope) ||
DataConstants.CLIENT_SCOPE.equals(scope)) {
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityIdStr, (result, entityId) -> {
ListenableFuture<List<Void>> future = attributesService.removeAll(entityId, scope, keys);
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityIdStr, (result, tenantId, entityId) -> {
ListenableFuture<List<Void>> future = attributesService.removeAll(user.getTenantId(), entityId, scope, keys);
Futures.addCallback(future, new FutureCallback<List<Void>>() {
@Override
public void onSuccess(@Nullable List<Void> tmp) {
@ -362,7 +361,7 @@ public class TelemetryController extends BaseController {
}
}
private DeferredResult<ResponseEntity> saveAttributes(EntityId entityIdSrc, String scope, JsonNode json) throws ThingsboardException {
private DeferredResult<ResponseEntity> saveAttributes(TenantId srcTenantId, EntityId entityIdSrc, String scope, JsonNode json) throws ThingsboardException {
if (!DataConstants.SERVER_SCOPE.equals(scope) && !DataConstants.SHARED_SCOPE.equals(scope)) {
return getImmediateDeferredResult("Invalid scope: " + scope, HttpStatus.BAD_REQUEST);
}
@ -372,8 +371,8 @@ public class TelemetryController extends BaseController {
return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST);
}
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityIdSrc, (result, entityId) -> {
tsSubService.saveAndNotify(entityId, scope, attributes, new FutureCallback<Void>() {
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityIdSrc, (result, tenantId, entityId) -> {
tsSubService.saveAndNotify(tenantId, entityId, scope, attributes, new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void tmp) {
logAttributesUpdated(user, entityId, scope, attributes, null);
@ -398,7 +397,7 @@ public class TelemetryController extends BaseController {
}
}
private DeferredResult<ResponseEntity> saveTelemetry(EntityId entityIdSrc, String requestBody, long ttl) throws ThingsboardException {
private DeferredResult<ResponseEntity> saveTelemetry(TenantId curTenantId, EntityId entityIdSrc, String requestBody, long ttl) throws ThingsboardException {
Map<Long, List<KvEntry>> telemetryRequest;
JsonElement telemetryJson;
try {
@ -421,8 +420,8 @@ public class TelemetryController extends BaseController {
return getImmediateDeferredResult("No timeseries data found in request body!", HttpStatus.BAD_REQUEST);
}
SecurityUser user = getCurrentUser();
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityIdSrc, (result, entityId) -> {
tsSubService.saveAndNotify(entityId, entries, ttl, new FutureCallback<Void>() {
return accessValidator.validateEntityAndCallback(getCurrentUser(), entityIdSrc, (result, tenantId, entityId) -> {
tsSubService.saveAndNotify(tenantId, entityId, entries, ttl, new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void tmp) {
result.setResult(new ResponseEntity(HttpStatus.OK));
@ -439,9 +438,9 @@ public class TelemetryController extends BaseController {
private void getLatestTimeseriesValuesCallback(@Nullable DeferredResult<ResponseEntity> result, SecurityUser user, EntityId entityId, String keys) {
ListenableFuture<List<TsKvEntry>> future;
if (StringUtils.isEmpty(keys)) {
future = tsService.findAllLatest(entityId);
future = tsService.findAllLatest(user.getTenantId(), entityId);
} else {
future = tsService.findLatest(entityId, toKeysList(keys));
future = tsService.findLatest(user.getTenantId(), entityId, toKeysList(keys));
}
Futures.addCallback(future, getTsKvListCallback(result));
}
@ -451,17 +450,17 @@ public class TelemetryController extends BaseController {
FutureCallback<List<AttributeKvEntry>> callback = getAttributeValuesToResponseCallback(result, user, scope, entityId, keyList);
if (!StringUtils.isEmpty(scope)) {
if (keyList != null && !keyList.isEmpty()) {
Futures.addCallback(attributesService.find(entityId, scope, keyList), callback);
Futures.addCallback(attributesService.find(user.getTenantId(), entityId, scope, keyList), callback);
} else {
Futures.addCallback(attributesService.findAll(entityId, scope), callback);
Futures.addCallback(attributesService.findAll(user.getTenantId(), entityId, scope), callback);
}
} else {
List<ListenableFuture<List<AttributeKvEntry>>> futures = new ArrayList<>();
for (String tmpScope : DataConstants.allScopes()) {
if (keyList != null && !keyList.isEmpty()) {
futures.add(attributesService.find(entityId, tmpScope, keyList));
futures.add(attributesService.find(user.getTenantId(), entityId, tmpScope, keyList));
} else {
futures.add(attributesService.findAll(entityId, tmpScope));
futures.add(attributesService.findAll(user.getTenantId(), entityId, tmpScope));
}
}
@ -471,14 +470,14 @@ public class TelemetryController extends BaseController {
}
}
private void getAttributeKeysCallback(@Nullable DeferredResult<ResponseEntity> result, EntityId entityId, String scope) {
Futures.addCallback(attributesService.findAll(entityId, scope), getAttributeKeysToResponseCallback(result));
private void getAttributeKeysCallback(@Nullable DeferredResult<ResponseEntity> result, TenantId tenantId, EntityId entityId, String scope) {
Futures.addCallback(attributesService.findAll(tenantId, entityId, scope), getAttributeKeysToResponseCallback(result));
}
private void getAttributeKeysCallback(@Nullable DeferredResult<ResponseEntity> result, EntityId entityId) {
private void getAttributeKeysCallback(@Nullable DeferredResult<ResponseEntity> result, TenantId tenantId, EntityId entityId) {
List<ListenableFuture<List<AttributeKvEntry>>> futures = new ArrayList<>();
for (String scope : DataConstants.allScopes()) {
futures.add(attributesService.findAll(entityId, scope));
futures.add(attributesService.findAll(tenantId, entityId, scope));
}
ListenableFuture<List<AttributeKvEntry>> future = mergeAllAttributesFutures(futures);

16
application/src/main/java/org/thingsboard/server/controller/UserController.java

@ -107,14 +107,14 @@ public class UserController extends BaseController {
try {
UserId userId = new UserId(toUUID(strUserId));
SecurityUser authUser = getCurrentUser();
User user = userService.findUserById(userId);
User user = userService.findUserById(authUser.getTenantId(), userId);
if (!userTokenAccessEnabled || (authUser.getAuthority() == Authority.SYS_ADMIN && user.getAuthority() != Authority.TENANT_ADMIN)
|| (authUser.getAuthority() == Authority.TENANT_ADMIN && !authUser.getTenantId().equals(user.getTenantId()))) {
throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
ThingsboardErrorCode.PERMISSION_DENIED);
}
UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
UserCredentials credentials = userService.findUserCredentialsByUserId(userId);
UserCredentials credentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), userId);
SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser);
JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser);
@ -146,7 +146,7 @@ public class UserController extends BaseController {
}
User savedUser = checkNotNull(userService.saveUser(user));
if (sendEmail) {
UserCredentials userCredentials = userService.findUserCredentialsByUserId(savedUser.getId());
UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), savedUser.getId());
String baseUrl = constructBaseUrl(request);
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
userCredentials.getActivateToken());
@ -154,7 +154,7 @@ public class UserController extends BaseController {
try {
mailService.sendActivationEmail(activateUrl, email);
} catch (ThingsboardException e) {
userService.deleteUser(savedUser.getId());
userService.deleteUser(authUser.getTenantId(), savedUser.getId());
throw e;
}
}
@ -180,8 +180,8 @@ public class UserController extends BaseController {
@RequestParam(value = "email") String email,
HttpServletRequest request) throws ThingsboardException {
try {
User user = checkNotNull(userService.findUserByEmail(email));
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getId());
User user = checkNotNull(userService.findUserByEmail(getCurrentUser().getTenantId(), email));
UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId());
if (!userCredentials.isEnabled()) {
String baseUrl = constructBaseUrl(request);
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
@ -210,7 +210,7 @@ public class UserController extends BaseController {
ThingsboardErrorCode.PERMISSION_DENIED);
}
User user = checkUserId(userId);
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getId());
UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId());
if (!userCredentials.isEnabled()) {
String baseUrl = constructBaseUrl(request);
String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
@ -232,7 +232,7 @@ public class UserController extends BaseController {
try {
UserId userId = new UserId(toUUID(strUserId));
User user = checkUserId(userId);
userService.deleteUser(userId);
userService.deleteUser(getCurrentUser().getTenantId(), userId);
logEntityAction(userId, user,
user.getCustomerId(),

2
application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java

@ -75,7 +75,7 @@ public class WidgetTypeController extends BaseController {
try {
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
checkWidgetTypeId(widgetTypeId, true);
widgetTypeService.deleteWidgetType(widgetTypeId);
widgetTypeService.deleteWidgetType(getCurrentUser().getTenantId(), widgetTypeId);
} catch (Exception e) {
throw handleException(e);
}

6
application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java

@ -77,7 +77,7 @@ public class WidgetsBundleController extends BaseController {
try {
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId));
checkWidgetsBundleId(widgetsBundleId, true);
widgetsBundleService.deleteWidgetsBundle(widgetsBundleId);
widgetsBundleService.deleteWidgetsBundle(getTenantId(), widgetsBundleId);
} catch (Exception e) {
throw handleException(e);
}
@ -94,7 +94,7 @@ public class WidgetsBundleController extends BaseController {
try {
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) {
return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(pageLink));
return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(getTenantId(), pageLink));
} else {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink));
@ -110,7 +110,7 @@ public class WidgetsBundleController extends BaseController {
public List<WidgetsBundle> getWidgetsBundles() throws ThingsboardException {
try {
if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) {
return checkNotNull(widgetsBundleService.findSystemWidgetsBundles());
return checkNotNull(widgetsBundleService.findSystemWidgetsBundles(getTenantId()));
} else {
TenantId tenantId = getCurrentUser().getTenantId();
return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(tenantId));

9
application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java

@ -30,6 +30,7 @@ import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.rule.engine.api.NodeDefinition;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.dao.component.ComponentDescriptorService;
@ -159,18 +160,18 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
log.error("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e);
throw new RuntimeException(e);
}
ComponentDescriptor persistedComponent = componentDescriptorService.findByClazz(clazzName);
ComponentDescriptor persistedComponent = componentDescriptorService.findByClazz(TenantId.SYS_TENANT_ID, clazzName);
if (persistedComponent == null) {
log.info("Persisting new component: {}", scannedComponent);
scannedComponent = componentDescriptorService.saveComponent(scannedComponent);
scannedComponent = componentDescriptorService.saveComponent(TenantId.SYS_TENANT_ID, scannedComponent);
} else if (scannedComponent.equals(persistedComponent)) {
log.info("Component is already persisted: {}", persistedComponent);
scannedComponent = persistedComponent;
} else {
log.info("Component {} will be updated to {}", persistedComponent, scannedComponent);
componentDescriptorService.deleteByClazz(persistedComponent.getClazz());
componentDescriptorService.deleteByClazz(TenantId.SYS_TENANT_ID, persistedComponent.getClazz());
scannedComponent.setId(persistedComponent.getId());
scannedComponent = componentDescriptorService.saveComponent(scannedComponent);
scannedComponent = componentDescriptorService.saveComponent(TenantId.SYS_TENANT_ID, scannedComponent);
}
return scannedComponent;
}

4
application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java

@ -25,6 +25,8 @@ import org.thingsboard.server.common.data.ShortCustomerInfo;
import org.thingsboard.server.common.data.UUIDConverter;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.dashboard.DashboardService;
import java.io.IOException;
@ -96,7 +98,7 @@ public class DatabaseHelper {
}
}
for (CustomerId customerId : customerIds) {
dashboardService.assignDashboardToCustomer(dashboardId, customerId);
dashboardService.assignDashboardToCustomer(new TenantId(EntityId.NULL_UUID), dashboardId, customerId);
}
});
}

14
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -96,7 +96,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
ObjectNode node = objectMapper.createObjectNode();
node.put("baseUrl", "http://localhost:8080");
generalSettings.setJsonValue(node);
adminSettingsService.saveAdminSettings(generalSettings);
adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, generalSettings);
AdminSettings mailSettings = new AdminSettings();
mailSettings.setKey("mail");
@ -110,7 +110,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
node.put("username", "");
node.put("password", ""); //NOSONAR, key used to identify password field (not password value itself)
mailSettings.setJsonValue(node);
adminSettingsService.saveAdminSettings(mailSettings);
adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, mailSettings);
}
@Override
@ -158,7 +158,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
public void deleteSystemWidgetBundle(String bundleAlias) throws Exception {
WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(new TenantId(ModelConstants.NULL_UUID), bundleAlias);
if (widgetsBundle != null) {
widgetsBundleService.deleteWidgetsBundle(widgetsBundle.getId());
widgetsBundleService.deleteWidgetsBundle(TenantId.SYS_TENANT_ID, widgetsBundle.getId());
}
}
@ -178,11 +178,11 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
user.setTenantId(tenantId);
user.setCustomerId(customerId);
user = userService.saveUser(user);
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getId());
UserCredentials userCredentials = userService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, user.getId());
userCredentials.setPassword(passwordEncoder.encode(password));
userCredentials.setEnabled(true);
userCredentials.setActivateToken(null);
userService.saveUserCredentials(userCredentials);
userService.saveUserCredentials(TenantId.SYS_TENANT_ID, userCredentials);
return user;
}
@ -203,9 +203,9 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
device.setAdditionalInfo(additionalInfo);
}
device = deviceService.saveDevice(device);
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getId());
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(TenantId.SYS_TENANT_ID, device.getId());
deviceCredentials.setCredentialsId(accessToken);
deviceCredentialsService.updateDeviceCredentials(deviceCredentials);
deviceCredentialsService.updateDeviceCredentials(TenantId.SYS_TENANT_ID, deviceCredentials);
return device;
}

5
application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java

@ -23,6 +23,7 @@ import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
@ -116,7 +117,7 @@ public class InstallScripts {
ruleChain = ruleChainService.saveRuleChain(ruleChain);
ruleChainMetaData.setRuleChainId(ruleChain.getId());
ruleChainService.saveRuleChainMetaData(ruleChainMetaData);
ruleChainService.saveRuleChainMetaData(new TenantId(EntityId.NULL_UUID), ruleChainMetaData);
} catch (Exception e) {
log.error("Unable to load rule chain from json: [{}]", path.toString());
throw new RuntimeException("Unable to load rule chain from json", e);
@ -169,7 +170,7 @@ public class InstallScripts {
dashboard.setTenantId(tenantId);
Dashboard savedDashboard = dashboardService.saveDashboard(dashboard);
if (customerId != null && !customerId.isNullUid()) {
dashboardService.assignDashboardToCustomer(savedDashboard.getId(), customerId);
dashboardService.assignDashboardToCustomer(new TenantId(EntityId.NULL_UUID), savedDashboard.getId(), customerId);
}
} catch (Exception e) {
log.error("Unable to load dashboard from json: [{}]", path.toString());

4
application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java

@ -31,6 +31,8 @@ import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.settings.AdminSettingsService;
@ -70,7 +72,7 @@ public class DefaultMailService implements MailService {
@Override
public void updateMailConfiguration() {
AdminSettings settings = adminSettingsService.findAdminSettingsByKey("mail");
AdminSettings settings = adminSettingsService.findAdminSettingsByKey(new TenantId(EntityId.NULL_UUID), "mail");
if (settings != null) {
JsonNode jsonConfig = settings.getJsonValue();
mailSender = createMailSender(jsonConfig);

30
application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java

@ -110,24 +110,24 @@ public class AccessValidator {
}
public DeferredResult<ResponseEntity> validateEntityAndCallback(SecurityUser currentUser, String entityType, String entityIdStr,
BiConsumer<DeferredResult<ResponseEntity>, EntityId> onSuccess) throws ThingsboardException {
ThreeConsumer<DeferredResult<ResponseEntity>, TenantId, EntityId> onSuccess) throws ThingsboardException {
return validateEntityAndCallback(currentUser, entityType, entityIdStr, onSuccess, (result, t) -> handleError(t, result, HttpStatus.INTERNAL_SERVER_ERROR));
}
public DeferredResult<ResponseEntity> validateEntityAndCallback(SecurityUser currentUser, String entityType, String entityIdStr,
BiConsumer<DeferredResult<ResponseEntity>, EntityId> onSuccess,
ThreeConsumer<DeferredResult<ResponseEntity>, TenantId, EntityId> onSuccess,
BiConsumer<DeferredResult<ResponseEntity>, Throwable> onFailure) throws ThingsboardException {
return validateEntityAndCallback(currentUser, EntityIdFactory.getByTypeAndId(entityType, entityIdStr),
onSuccess, onFailure);
}
public DeferredResult<ResponseEntity> validateEntityAndCallback(SecurityUser currentUser, EntityId entityId,
BiConsumer<DeferredResult<ResponseEntity>, EntityId> onSuccess) throws ThingsboardException {
ThreeConsumer<DeferredResult<ResponseEntity>, TenantId, EntityId> onSuccess) throws ThingsboardException {
return validateEntityAndCallback(currentUser, entityId, onSuccess, (result, t) -> handleError(t, result, HttpStatus.INTERNAL_SERVER_ERROR));
}
public DeferredResult<ResponseEntity> validateEntityAndCallback(SecurityUser currentUser, EntityId entityId,
BiConsumer<DeferredResult<ResponseEntity>, EntityId> onSuccess,
ThreeConsumer<DeferredResult<ResponseEntity>, TenantId, EntityId> onSuccess,
BiConsumer<DeferredResult<ResponseEntity>, Throwable> onFailure) throws ThingsboardException {
final DeferredResult<ResponseEntity> response = new DeferredResult<>();
@ -136,7 +136,7 @@ public class AccessValidator {
new FutureCallback<DeferredResult<ResponseEntity>>() {
@Override
public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) {
onSuccess.accept(response, entityId);
onSuccess.accept(response, currentUser.getTenantId(), entityId);
}
@Override
@ -178,7 +178,7 @@ public class AccessValidator {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
ListenableFuture<Device> deviceFuture = deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId()));
ListenableFuture<Device> deviceFuture = deviceService.findDeviceByIdAsync(currentUser.getTenantId(), new DeviceId(entityId.getId()));
Futures.addCallback(deviceFuture, getCallback(callback, device -> {
if (device == null) {
return ValidationResult.entityNotFound(DEVICE_WITH_REQUESTED_ID_NOT_FOUND);
@ -199,7 +199,7 @@ public class AccessValidator {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
ListenableFuture<Asset> assetFuture = assetService.findAssetByIdAsync(new AssetId(entityId.getId()));
ListenableFuture<Asset> assetFuture = assetService.findAssetByIdAsync(currentUser.getTenantId(), new AssetId(entityId.getId()));
Futures.addCallback(assetFuture, getCallback(callback, asset -> {
if (asset == null) {
return ValidationResult.entityNotFound("Asset with requested id wasn't found!");
@ -220,7 +220,7 @@ public class AccessValidator {
if (currentUser.isCustomerUser()) {
callback.onSuccess(ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
ListenableFuture<RuleChain> ruleChainFuture = ruleChainService.findRuleChainByIdAsync(new RuleChainId(entityId.getId()));
ListenableFuture<RuleChain> ruleChainFuture = ruleChainService.findRuleChainByIdAsync(currentUser.getTenantId(), new RuleChainId(entityId.getId()));
Futures.addCallback(ruleChainFuture, getCallback(callback, ruleChain -> {
if (ruleChain == null) {
return ValidationResult.entityNotFound("Rule chain with requested id wasn't found!");
@ -241,7 +241,7 @@ public class AccessValidator {
if (currentUser.isCustomerUser()) {
callback.onSuccess(ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
ListenableFuture<RuleNode> ruleNodeFuture = ruleChainService.findRuleNodeByIdAsync(new RuleNodeId(entityId.getId()));
ListenableFuture<RuleNode> ruleNodeFuture = ruleChainService.findRuleNodeByIdAsync(currentUser.getTenantId(), new RuleNodeId(entityId.getId()));
Futures.addCallback(ruleNodeFuture, getCallback(callback, ruleNodeTmp -> {
RuleNode ruleNode = ruleNodeTmp;
if (ruleNode == null) {
@ -250,7 +250,7 @@ public class AccessValidator {
return ValidationResult.entityNotFound("Rule chain with requested node id wasn't found!");
} else {
//TODO: make async
RuleChain ruleChain = ruleChainService.findRuleChainById(ruleNode.getRuleChainId());
RuleChain ruleChain = ruleChainService.findRuleChainById(currentUser.getTenantId(), ruleNode.getRuleChainId());
if (currentUser.isTenantAdmin() && !ruleChain.getTenantId().equals(currentUser.getTenantId())) {
return ValidationResult.accessDenied("Rule chain doesn't belong to the current Tenant!");
} else if (currentUser.isSystemAdmin() && !ruleChain.getTenantId().isNullUid()) {
@ -267,7 +267,7 @@ public class AccessValidator {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
ListenableFuture<Customer> customerFuture = customerService.findCustomerByIdAsync(new CustomerId(entityId.getId()));
ListenableFuture<Customer> customerFuture = customerService.findCustomerByIdAsync(currentUser.getTenantId(), new CustomerId(entityId.getId()));
Futures.addCallback(customerFuture, getCallback(callback, customer -> {
if (customer == null) {
return ValidationResult.entityNotFound("Customer with requested id wasn't found!");
@ -290,7 +290,7 @@ public class AccessValidator {
} else if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.ok(null));
} else {
ListenableFuture<Tenant> tenantFuture = tenantService.findTenantByIdAsync(new TenantId(entityId.getId()));
ListenableFuture<Tenant> tenantFuture = tenantService.findTenantByIdAsync(currentUser.getTenantId(), new TenantId(entityId.getId()));
Futures.addCallback(tenantFuture, getCallback(callback, tenant -> {
if (tenant == null) {
return ValidationResult.entityNotFound("Tenant with requested id wasn't found!");
@ -307,7 +307,7 @@ public class AccessValidator {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
ListenableFuture<EntityView> entityViewFuture = entityViewService.findEntityViewByIdAsync(new EntityViewId(entityId.getId()));
ListenableFuture<EntityView> entityViewFuture = entityViewService.findEntityViewByIdAsync(currentUser.getTenantId(), new EntityViewId(entityId.getId()));
Futures.addCallback(entityViewFuture, getCallback(callback, entityView -> {
if (entityView == null) {
return ValidationResult.entityNotFound(ENTITY_VIEW_WITH_REQUESTED_ID_NOT_FOUND);
@ -349,4 +349,8 @@ public class AccessValidator {
}
response.setResult(responseEntity);
}
public interface ThreeConsumer<A, B, C> {
void accept(A a, B b, C c);
}
}

9
application/src/main/java/org/thingsboard/server/service/security/auth/jwt/RefreshTokenAuthenticationProvider.java

@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.UserCredentials;
@ -72,12 +73,13 @@ public class RefreshTokenAuthenticationProvider implements AuthenticationProvide
}
private SecurityUser authenticateByUserId(UserId userId) {
User user = userService.findUserById(userId);
TenantId systemId = new TenantId(EntityId.NULL_UUID);
User user = userService.findUserById(systemId, userId);
if (user == null) {
throw new UsernameNotFoundException("User not found by refresh token");
}
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getId());
UserCredentials userCredentials = userService.findUserCredentialsByUserId(systemId, user.getId());
if (userCredentials == null) {
throw new UsernameNotFoundException("User credentials not found");
}
@ -96,13 +98,14 @@ public class RefreshTokenAuthenticationProvider implements AuthenticationProvide
}
private SecurityUser authenticateByPublicId(String publicId) {
TenantId systemId = new TenantId(EntityId.NULL_UUID);
CustomerId customerId;
try {
customerId = new CustomerId(UUID.fromString(publicId));
} catch (Exception e) {
throw new BadCredentialsException("Refresh token is not valid");
}
Customer publicCustomer = customerService.findCustomerById(customerId);
Customer publicCustomer = customerService.findCustomerById(systemId, customerId);
if (publicCustomer == null) {
throw new UsernameNotFoundException("Public entity not found by refresh token");
}

7
application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestAuthenticationProvider.java

@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.UserCredentials;
@ -76,12 +77,12 @@ public class RestAuthenticationProvider implements AuthenticationProvider {
}
private Authentication authenticateByUsernameAndPassword(UserPrincipal userPrincipal, String username, String password) {
User user = userService.findUserByEmail(username);
User user = userService.findUserByEmail(TenantId.SYS_TENANT_ID, username);
if (user == null) {
throw new UsernameNotFoundException("User not found: " + username);
}
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getId());
UserCredentials userCredentials = userService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, user.getId());
if (userCredentials == null) {
throw new UsernameNotFoundException("User credentials not found");
}
@ -108,7 +109,7 @@ public class RestAuthenticationProvider implements AuthenticationProvider {
} catch (Exception e) {
throw new BadCredentialsException("Authentication Failed. Public Id is not valid.");
}
Customer publicCustomer = customerService.findCustomerById(customerId);
Customer publicCustomer = customerService.findCustomerById(TenantId.SYS_TENANT_ID, customerId);
if (publicCustomer == null) {
throw new UsernameNotFoundException("Public entity not found: " + publicId);
}

10
application/src/main/java/org/thingsboard/server/service/security/device/DefaultDeviceAuthService.java

@ -18,8 +18,6 @@ package org.thingsboard.server.service.security.device;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsFilter;
import org.thingsboard.server.common.transport.auth.DeviceAuthResult;
@ -27,8 +25,6 @@ import org.thingsboard.server.common.transport.auth.DeviceAuthService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService;
import java.util.Optional;
@Service
@Slf4j
public class DefaultDeviceAuthService implements DeviceAuthService {
@ -65,8 +61,4 @@ public class DefaultDeviceAuthService implements DeviceAuthService {
}
}
@Override
public Optional<Device> findDeviceById(DeviceId deviceId) {
return Optional.ofNullable(deviceService.findDeviceById(deviceId));
}
}
}

3
application/src/main/java/org/thingsboard/server/service/security/model/token/JwtTokenFactory.java

@ -21,6 +21,7 @@ import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
@ -69,7 +70,7 @@ public class JwtTokenFactory {
UserPrincipal principal = securityUser.getUserPrincipal();
String subject = principal.getValue();
Claims claims = Jwts.claims().setSubject(subject);
claims.put(SCOPES, securityUser.getAuthorities().stream().map(s -> s.getAuthority()).collect(Collectors.toList()));
claims.put(SCOPES, securityUser.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()));
claims.put(USER_ID, securityUser.getId().getId().toString());
claims.put(FIRST_NAME, securityUser.getFirstName());
claims.put(LAST_NAME, securityUser.getLastName());

10
application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java

@ -207,7 +207,7 @@ public class DefaultDeviceStateService implements DeviceStateService {
if (proto.getDeleted()) {
queueExecutor.submit(() -> onDeviceDeleted(tenantId, deviceId));
} else {
Device device = deviceService.findDeviceById(deviceId);
Device device = deviceService.findDeviceById(TenantId.SYS_TENANT_ID, deviceId);
if (device != null) {
if (proto.getAdded()) {
onDeviceAdded(device);
@ -320,7 +320,7 @@ public class DefaultDeviceStateService implements DeviceStateService {
DeviceStateData deviceStateData = deviceStates.get(deviceId);
if (deviceStateData == null) {
if (!routingService.resolveById(deviceId).isPresent()) {
Device device = deviceService.findDeviceById(deviceId);
Device device = deviceService.findDeviceById(TenantId.SYS_TENANT_ID, deviceId);
if (device != null) {
try {
deviceStateData = fetchDeviceState(device).get();
@ -414,7 +414,7 @@ public class DefaultDeviceStateService implements DeviceStateService {
}
private ListenableFuture<DeviceStateData> fetchDeviceState(Device device) {
ListenableFuture<List<AttributeKvEntry>> attributes = attributesService.find(device.getId(), DataConstants.SERVER_SCOPE, PERSISTENT_ATTRIBUTES);
ListenableFuture<List<AttributeKvEntry>> attributes = attributesService.find(TenantId.SYS_TENANT_ID, device.getId(), DataConstants.SERVER_SCOPE, PERSISTENT_ATTRIBUTES);
return Futures.transform(attributes, new Function<List<AttributeKvEntry>, DeviceStateData>() {
@Nullable
@Override
@ -465,11 +465,11 @@ public class DefaultDeviceStateService implements DeviceStateService {
}
private void saveAttribute(DeviceId deviceId, String key, long value) {
tsSubService.saveAttrAndNotify(deviceId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(deviceId, key, value));
tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(deviceId, key, value));
}
private void saveAttribute(DeviceId deviceId, String key, boolean value) {
tsSubService.saveAttrAndNotify(deviceId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(deviceId, key, value));
tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(deviceId, key, value));
}
private class AttributeSaveCallback implements FutureCallback<Void> {

39
application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java

@ -63,6 +63,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -131,7 +132,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
long startTime = 0L;
long endTime = 0L;
if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW) && TelemetryFeature.TIMESERIES.equals(sub.getType())) {
EntityView entityView = entityViewService.findEntityViewById(new EntityViewId(entityId.getId()));
EntityView entityView = entityViewService.findEntityViewById(TenantId.SYS_TENANT_ID, new EntityViewId(entityId.getId()));
entityId = entityView.getEntityId();
startTime = entityView.getStartTimeMs();
endTime = entityView.getEndTimeMs();
@ -160,7 +161,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
.stream().filter(entry -> entityView.getKeys().getTimeseries().contains(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
return new SubscriptionState(sub.getWsSessionId(), sub.getSubscriptionId(), entityId, sub.getType(), false, keyStates, sub.getScope());
return new SubscriptionState(sub.getWsSessionId(), sub.getSubscriptionId(), sub.getTenantId(), entityId, sub.getType(), false, keyStates, sub.getScope());
}
@Override
@ -185,45 +186,45 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
}
@Override
public void saveAndNotify(EntityId entityId, List<TsKvEntry> ts, FutureCallback<Void> callback) {
saveAndNotify(entityId, ts, 0L, callback);
public void saveAndNotify(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, FutureCallback<Void> callback) {
saveAndNotify(tenantId, entityId, ts, 0L, callback);
}
@Override
public void saveAndNotify(EntityId entityId, List<TsKvEntry> ts, long ttl, FutureCallback<Void> callback) {
ListenableFuture<List<Void>> saveFuture = tsService.save(entityId, ts, ttl);
public void saveAndNotify(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, long ttl, FutureCallback<Void> callback) {
ListenableFuture<List<Void>> saveFuture = tsService.save(tenantId, entityId, ts, ttl);
addMainCallback(saveFuture, callback);
addWsCallback(saveFuture, success -> onTimeseriesUpdate(entityId, ts));
}
@Override
public void saveAndNotify(EntityId entityId, String scope, List<AttributeKvEntry> attributes, FutureCallback<Void> callback) {
ListenableFuture<List<Void>> saveFuture = attrService.save(entityId, scope, attributes);
public void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes, FutureCallback<Void> callback) {
ListenableFuture<List<Void>> saveFuture = attrService.save(tenantId, entityId, scope, attributes);
addMainCallback(saveFuture, callback);
addWsCallback(saveFuture, success -> onAttributesUpdate(entityId, scope, attributes));
}
@Override
public void saveAttrAndNotify(EntityId entityId, String scope, String key, long value, FutureCallback<Void> callback) {
saveAndNotify(entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry(key, value)
public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value, FutureCallback<Void> callback) {
saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry(key, value)
, System.currentTimeMillis())), callback);
}
@Override
public void saveAttrAndNotify(EntityId entityId, String scope, String key, String value, FutureCallback<Void> callback) {
saveAndNotify(entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry(key, value)
public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, String value, FutureCallback<Void> callback) {
saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry(key, value)
, System.currentTimeMillis())), callback);
}
@Override
public void saveAttrAndNotify(EntityId entityId, String scope, String key, double value, FutureCallback<Void> callback) {
saveAndNotify(entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new DoubleDataEntry(key, value)
public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, double value, FutureCallback<Void> callback) {
saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new DoubleDataEntry(key, value)
, System.currentTimeMillis())), callback);
}
@Override
public void saveAttrAndNotify(EntityId entityId, String scope, String key, boolean value, FutureCallback<Void> callback) {
saveAndNotify(entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new BooleanDataEntry(key, value)
public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, boolean value, FutureCallback<Void> callback) {
saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new BooleanDataEntry(key, value)
, System.currentTimeMillis())), callback);
}
@ -246,6 +247,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
Collectors.toMap(ClusterAPIProtos.SubscriptionKetStateProto::getKey, ClusterAPIProtos.SubscriptionKetStateProto::getTs));
Subscription subscription = new Subscription(
new SubscriptionState(proto.getSessionId(), proto.getSubscriptionId(),
new TenantId(UUID.fromString(proto.getTenantId())),
EntityIdFactory.getByTypeAndId(proto.getEntityType(), proto.getEntityId()),
TelemetryFeature.valueOf(proto.getType()), proto.getAllKeys(), statesMap, proto.getScope()),
false, new ServerAddress(serverAddress.getHost(), serverAddress.getPort(), serverAddress.getServerType()));
@ -372,7 +374,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
registerSubscription(sessionId, entityId, subscription);
if (subscription.getType() == TelemetryFeature.ATTRIBUTES) {
final Map<String, Long> keyStates = subscription.getKeyStates();
DonAsynchron.withCallback(attrService.find(entityId, DataConstants.CLIENT_SCOPE, keyStates.keySet()), values -> {
DonAsynchron.withCallback(attrService.find(subscription.getSub().getTenantId(), entityId, DataConstants.CLIENT_SCOPE, keyStates.keySet()), values -> {
List<TsKvEntry> missedUpdates = new ArrayList<>();
values.forEach(latestEntry -> {
if (latestEntry.getLastUpdateTs() > keyStates.get(latestEntry.getKey())) {
@ -395,7 +397,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
}
});
if (!queries.isEmpty()) {
DonAsynchron.withCallback(tsService.findAll(entityId, queries),
DonAsynchron.withCallback(tsService.findAll(subscription.getSub().getTenantId(), entityId, queries),
missedUpdates -> {
if (missedUpdates != null && !missedUpdates.isEmpty()) {
tellRemoteSubUpdate(address, sessionId, new SubscriptionUpdate(subscription.getSubscriptionId(), missedUpdates));
@ -606,6 +608,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
ClusterAPIProtos.SubscriptionProto.Builder builder = ClusterAPIProtos.SubscriptionProto.newBuilder();
builder.setSessionId(sessionId);
builder.setSubscriptionId(sub.getSubscriptionId());
builder.setTenantId(sub.getSub().getTenantId().getId().toString());
builder.setEntityType(sub.getEntityId().getEntityType().name());
builder.setEntityId(sub.getEntityId().getId().toString());
builder.setType(sub.getType().name());

56
application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java

@ -1,12 +1,12 @@
/**
* Copyright © 2016-2018 The Thingsboard Authors
*
* <p>
* 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
*
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
@ -28,6 +28,7 @@ import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.Aggregation;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
@ -36,6 +37,7 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.dao.util.TenantRateLimitException;
import org.thingsboard.server.service.security.AccessValidator;
import org.thingsboard.server.service.security.ValidationCallback;
import org.thingsboard.server.service.security.ValidationResult;
@ -206,7 +208,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
keys.forEach(key -> subState.put(key, 0L));
attributesData.forEach(v -> subState.put(v.getKey(), v.getTs()));
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, TelemetryFeature.ATTRIBUTES, false, subState, cmd.getScope());
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), sessionRef.getSecurityCtx().getTenantId(), entityId, TelemetryFeature.ATTRIBUTES, false, subState, cmd.getScope());
subscriptionManager.addLocalWsSubscription(sessionId, entityId, sub);
}
@ -226,9 +228,9 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
};
if (StringUtils.isEmpty(cmd.getScope())) {
accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(entityId, keys, callback));
accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, keys, callback));
} else {
accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(entityId, cmd.getScope(), keys, callback));
accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, cmd.getScope(), keys, callback));
}
}
@ -279,7 +281,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
}
};
accessValidator.validate(sessionRef.getSecurityCtx(), entityId,
on(r -> Futures.addCallback(tsService.findAll(entityId, queries), callback, executor), callback::onFailure));
on(r -> Futures.addCallback(tsService.findAll(sessionRef.getSecurityCtx().getTenantId(), entityId, queries), callback, executor), callback::onFailure));
}
private void handleWsAttributesSubscription(TelemetryWebSocketSessionRef sessionRef,
@ -293,7 +295,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
Map<String, Long> subState = new HashMap<>(attributesData.size());
attributesData.forEach(v -> subState.put(v.getKey(), v.getTs()));
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, TelemetryFeature.ATTRIBUTES, true, subState, cmd.getScope());
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), sessionRef.getSecurityCtx().getTenantId(), entityId, TelemetryFeature.ATTRIBUTES, true, subState, cmd.getScope());
subscriptionManager.addLocalWsSubscription(sessionId, entityId, sub);
}
@ -308,9 +310,9 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
if (StringUtils.isEmpty(cmd.getScope())) {
accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(entityId, callback));
accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, callback));
} else {
accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(entityId, cmd.getScope(), callback));
accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, cmd.getScope(), callback));
}
}
@ -347,14 +349,14 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
final FutureCallback<List<TsKvEntry>> callback = getSubscriptionCallback(sessionRef, cmd, sessionId, entityId, startTs, keys);
accessValidator.validate(sessionRef.getSecurityCtx(), entityId,
on(r -> Futures.addCallback(tsService.findAll(entityId, queries), callback, executor), callback::onFailure));
on(r -> Futures.addCallback(tsService.findAll(sessionRef.getSecurityCtx().getTenantId(), entityId, queries), callback, executor), callback::onFailure));
} else {
List<String> keys = new ArrayList<>(getKeys(cmd).orElse(Collections.emptySet()));
startTs = System.currentTimeMillis();
log.debug("[{}] fetching latest timeseries data for keys: ({}) for device : {}", sessionId, cmd.getKeys(), entityId);
final FutureCallback<List<TsKvEntry>> callback = getSubscriptionCallback(sessionRef, cmd, sessionId, entityId, startTs, keys);
accessValidator.validate(sessionRef.getSecurityCtx(), entityId,
on(r -> Futures.addCallback(tsService.findLatest(entityId, keys), callback, executor), callback::onFailure));
on(r -> Futures.addCallback(tsService.findLatest(sessionRef.getSecurityCtx().getTenantId(), entityId, keys), callback, executor), callback::onFailure));
}
}
@ -366,7 +368,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
sendWsMsg(sessionRef, new SubscriptionUpdate(cmd.getCmdId(), data));
Map<String, Long> subState = new HashMap<>(data.size());
data.forEach(v -> subState.put(v.getKey(), v.getTs()));
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, TelemetryFeature.TIMESERIES, true, subState, cmd.getScope());
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), sessionRef.getSecurityCtx().getTenantId(), entityId, TelemetryFeature.TIMESERIES, true, subState, cmd.getScope());
subscriptionManager.addLocalWsSubscription(sessionId, entityId, sub);
}
@ -384,7 +386,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
}
};
accessValidator.validate(sessionRef.getSecurityCtx(), entityId,
on(r -> Futures.addCallback(tsService.findAllLatest(entityId), callback, executor), callback::onFailure));
on(r -> Futures.addCallback(tsService.findAllLatest(sessionRef.getSecurityCtx().getTenantId(), entityId), callback, executor), callback::onFailure));
}
private FutureCallback<List<TsKvEntry>> getSubscriptionCallback(final TelemetryWebSocketSessionRef sessionRef, final TimeseriesSubscriptionCmd cmd, final String sessionId, final EntityId entityId, final long startTs, final List<String> keys) {
@ -396,13 +398,17 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
Map<String, Long> subState = new HashMap<>(keys.size());
keys.forEach(key -> subState.put(key, startTs));
data.forEach(v -> subState.put(v.getKey(), v.getTs()));
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), entityId, TelemetryFeature.TIMESERIES, false, subState, cmd.getScope());
SubscriptionState sub = new SubscriptionState(sessionId, cmd.getCmdId(), sessionRef.getSecurityCtx().getTenantId(), entityId, TelemetryFeature.TIMESERIES, false, subState, cmd.getScope());
subscriptionManager.addLocalWsSubscription(sessionId, entityId, sub);
}
@Override
public void onFailure(Throwable e) {
log.error(FAILED_TO_FETCH_DATA, e);
if (e instanceof TenantRateLimitException || e.getCause() instanceof TenantRateLimitException) {
log.trace("[{}] Tenant rate limit detected for subscription: [{}]:{}", sessionRef.getSecurityCtx().getTenantId(), entityId, cmd);
} else {
log.info(FAILED_TO_FETCH_DATA, e);
}
SubscriptionUpdate update = new SubscriptionUpdate(cmd.getCmdId(), SubscriptionErrorCode.INTERNAL_ERROR,
FAILED_TO_FETCH_DATA);
sendWsMsg(sessionRef, update);
@ -472,13 +478,13 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
}, executor);
}
private <T> FutureCallback<ValidationResult> getAttributesFetchCallback(final EntityId entityId, final List<String> keys, final FutureCallback<List<AttributeKvEntry>> callback) {
private <T> FutureCallback<ValidationResult> getAttributesFetchCallback(final TenantId tenantId, final EntityId entityId, final List<String> keys, final FutureCallback<List<AttributeKvEntry>> callback) {
return new FutureCallback<ValidationResult>() {
@Override
public void onSuccess(@Nullable ValidationResult result) {
List<ListenableFuture<List<AttributeKvEntry>>> futures = new ArrayList<>();
for (String scope : DataConstants.allScopes()) {
futures.add(attributesService.find(entityId, scope, keys));
futures.add(attributesService.find(tenantId, entityId, scope, keys));
}
ListenableFuture<List<AttributeKvEntry>> future = mergeAllAttributesFutures(futures);
@ -492,11 +498,11 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
};
}
private <T> FutureCallback<ValidationResult> getAttributesFetchCallback(final EntityId entityId, final String scope, final List<String> keys, final FutureCallback<List<AttributeKvEntry>> callback) {
private <T> FutureCallback<ValidationResult> getAttributesFetchCallback(final TenantId tenantId, final EntityId entityId, final String scope, final List<String> keys, final FutureCallback<List<AttributeKvEntry>> callback) {
return new FutureCallback<ValidationResult>() {
@Override
public void onSuccess(@Nullable ValidationResult result) {
Futures.addCallback(attributesService.find(entityId, scope, keys), callback);
Futures.addCallback(attributesService.find(tenantId, entityId, scope, keys), callback);
}
@Override
@ -506,13 +512,13 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
};
}
private <T> FutureCallback<ValidationResult> getAttributesFetchCallback(final EntityId entityId, final FutureCallback<List<AttributeKvEntry>> callback) {
private <T> FutureCallback<ValidationResult> getAttributesFetchCallback(final TenantId tenantId, final EntityId entityId, final FutureCallback<List<AttributeKvEntry>> callback) {
return new FutureCallback<ValidationResult>() {
@Override
public void onSuccess(@Nullable ValidationResult result) {
List<ListenableFuture<List<AttributeKvEntry>>> futures = new ArrayList<>();
for (String scope : DataConstants.allScopes()) {
futures.add(attributesService.findAll(entityId, scope));
futures.add(attributesService.findAll(tenantId, entityId, scope));
}
ListenableFuture<List<AttributeKvEntry>> future = mergeAllAttributesFutures(futures);
@ -526,11 +532,11 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
};
}
private <T> FutureCallback<ValidationResult> getAttributesFetchCallback(final EntityId entityId, final String scope, final FutureCallback<List<AttributeKvEntry>> callback) {
private <T> FutureCallback<ValidationResult> getAttributesFetchCallback(final TenantId tenantId, final EntityId entityId, final String scope, final FutureCallback<List<AttributeKvEntry>> callback) {
return new FutureCallback<ValidationResult>() {
@Override
public void onSuccess(@Nullable ValidationResult result) {
Futures.addCallback(attributesService.findAll(entityId, scope), callback);
Futures.addCallback(attributesService.findAll(tenantId, entityId, scope), callback);
}
@Override

1
application/src/main/java/org/thingsboard/server/service/telemetry/TelemetrySubscriptionService.java

@ -17,6 +17,7 @@ package org.thingsboard.server.service.telemetry;
import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.service.telemetry.sub.SubscriptionState;

2
application/src/main/java/org/thingsboard/server/service/telemetry/sub/SubscriptionState.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.telemetry.sub;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.service.telemetry.TelemetryFeature;
import java.util.Map;
@ -30,6 +31,7 @@ public class SubscriptionState {
@Getter private final String wsSessionId;
@Getter private final int subscriptionId;
@Getter private final TenantId tenantId;
@Getter private final EntityId entityId;
@Getter private final TelemetryFeature type;
@Getter private final boolean allKeys;

7
application/src/main/java/org/thingsboard/server/service/transport/LocalTransportApiService.java

@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
@ -107,7 +108,7 @@ public class LocalTransportApiService implements TransportApiService {
private ListenableFuture<TransportApiResponseMsg> handle(GetOrCreateDeviceFromGatewayRequestMsg requestMsg) {
DeviceId gatewayId = new DeviceId(new UUID(requestMsg.getGatewayIdMSB(), requestMsg.getGatewayIdLSB()));
ListenableFuture<Device> gatewayFuture = deviceService.findDeviceByIdAsync(gatewayId);
ListenableFuture<Device> gatewayFuture = deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, gatewayId);
return Futures.transform(gatewayFuture, gateway -> {
deviceCreationLock.lock();
try {
@ -119,7 +120,7 @@ public class LocalTransportApiService implements TransportApiService {
device.setType(requestMsg.getDeviceType());
device.setCustomerId(gateway.getCustomerId());
device = deviceService.saveDevice(device);
relationService.saveRelationAsync(new EntityRelation(gateway.getId(), device.getId(), "Created"));
relationService.saveRelationAsync(TenantId.SYS_TENANT_ID, new EntityRelation(gateway.getId(), device.getId(), "Created"));
deviceStateService.onDeviceAdded(device);
}
return TransportApiResponseMsg.newBuilder()
@ -135,7 +136,7 @@ public class LocalTransportApiService implements TransportApiService {
private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId) {
return Futures.transform(deviceService.findDeviceByIdAsync(deviceId), device -> {
return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, deviceId), device -> {
if (device == null) {
log.trace("[{}] Failed to lookup device by id", deviceId);
return getEmptyTransportApiResponse();

11
application/src/main/proto/cluster.proto

@ -67,11 +67,12 @@ message SubscriptionProto {
string sessionId = 1;
int32 subscriptionId = 2;
string entityType = 3;
string entityId = 4;
string type = 5;
bool allKeys = 6;
repeated SubscriptionKetStateProto keyStates = 7;
string scope = 8;
string tenantId = 4;
string entityId = 5;
string type = 6;
bool allKeys = 7;
repeated SubscriptionKetStateProto keyStates = 8;
string scope = 9;
}
message SubscriptionUpdateProto {

3
application/src/main/resources/thingsboard.yml

@ -143,6 +143,9 @@ cassandra:
concurrent_limit: "${CASSANDRA_QUERY_CONCURRENT_LIMIT:1000}"
permit_max_wait_time: "${PERMIT_MAX_WAIT_TIME:120000}"
rate_limit_print_interval_ms: "${CASSANDRA_QUERY_RATE_LIMIT_PRINT_MS:10000}"
tenant_rate_limits:
enabled: "${CASSANDRA_QUERY_TENANT_RATE_LIMITS_ENABLED:false}"
configuration: "${CASSANDRA_QUERY_TENANT_RATE_LIMITS_VALUE:1000:1,30000:60}"
# SQL configuration parameters
sql:

8
application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java

@ -142,9 +142,9 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
device.setType("default");
device = doPost("/api/device", device, Device.class);
attributesService.save(device.getId(), DataConstants.SERVER_SCOPE,
attributesService.save(device.getTenantId(), device.getId(), DataConstants.SERVER_SCOPE,
Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey1", "serverAttributeValue1"), System.currentTimeMillis())));
attributesService.save(device.getId(), DataConstants.SERVER_SCOPE,
attributesService.save(device.getTenantId(), device.getId(), DataConstants.SERVER_SCOPE,
Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey2", "serverAttributeValue2"), System.currentTimeMillis())));
@ -257,9 +257,9 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
device.setType("default");
device = doPost("/api/device", device, Device.class);
attributesService.save(device.getId(), DataConstants.SERVER_SCOPE,
attributesService.save(device.getTenantId(), device.getId(), DataConstants.SERVER_SCOPE,
Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey1", "serverAttributeValue1"), System.currentTimeMillis())));
attributesService.save(device.getId(), DataConstants.SERVER_SCOPE,
attributesService.save(device.getTenantId(), device.getId(), DataConstants.SERVER_SCOPE,
Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey2", "serverAttributeValue2"), System.currentTimeMillis())));

2
application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java

@ -131,7 +131,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
device.setType("default");
device = doPost("/api/device", device, Device.class);
attributesService.save(device.getId(), DataConstants.SERVER_SCOPE,
attributesService.save(device.getTenantId(), device.getId(), DataConstants.SERVER_SCOPE,
Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey", "serverAttributeValue"), System.currentTimeMillis())));
Thread.sleep(1000);

3
common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java

@ -24,6 +24,9 @@ import org.thingsboard.server.common.data.EntityType;
public final class TenantId extends UUIDBased implements EntityId {
@JsonIgnore
public static final TenantId SYS_TENANT_ID = new TenantId(EntityId.NULL_UUID);
private static final long serialVersionUID = 1L;
@JsonCreator

4
common/message/pom.xml

@ -60,6 +60,10 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-core</artifactId>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>

8
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TbTransportRateLimits.java → common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimits.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.transport.service;
package org.thingsboard.server.common.msg.tools;
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket4j;
@ -25,10 +25,10 @@ import java.time.Duration;
/**
* Created by ashvayka on 22.10.18.
*/
class TbTransportRateLimits {
public class TbRateLimits {
private final LocalBucket bucket;
public TbTransportRateLimits(String limitsConfiguration) {
public TbRateLimits(String limitsConfiguration) {
LocalBucketBuilder builder = Bucket4j.builder();
boolean initialized = false;
for (String limitSrc : limitsConfiguration.split(",")) {
@ -46,7 +46,7 @@ class TbTransportRateLimits {
}
boolean tryConsume() {
public boolean tryConsume() {
return bucket.tryConsume(1);
}

4
common/transport/transport-api/pom.xml

@ -99,10 +99,6 @@
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</dependency>
<dependency>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-core</artifactId>
</dependency>
</dependencies>
<build>

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/DeviceAuthService.java

@ -25,6 +25,4 @@ public interface DeviceAuthService {
DeviceAuthResult process(DeviceCredentialsFilter credentials);
Optional<Device> findDeviceById(DeviceId deviceId);
}

13
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/AbstractTransportService.java

@ -20,6 +20,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.tools.TbRateLimits;
import org.thingsboard.server.common.transport.SessionMsgListener;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback;
@ -58,8 +59,8 @@ public abstract class AbstractTransportService implements TransportService {
private ConcurrentMap<UUID, SessionMetaData> sessions = new ConcurrentHashMap<>();
//TODO: Implement cleanup of this maps.
private ConcurrentMap<TenantId, TbTransportRateLimits> perTenantLimits = new ConcurrentHashMap<>();
private ConcurrentMap<DeviceId, TbTransportRateLimits> perDeviceLimits = new ConcurrentHashMap<>();
private ConcurrentMap<TenantId, TbRateLimits> perTenantLimits = new ConcurrentHashMap<>();
private ConcurrentMap<DeviceId, TbRateLimits> perDeviceLimits = new ConcurrentHashMap<>();
@Override
public void registerAsyncSession(TransportProtos.SessionInfoProto sessionInfo, SessionMsgListener listener) {
@ -204,7 +205,7 @@ public abstract class AbstractTransportService implements TransportService {
return true;
}
TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB()));
TbTransportRateLimits rateLimits = perTenantLimits.computeIfAbsent(tenantId, id -> new TbTransportRateLimits(perTenantLimitsConf));
TbRateLimits rateLimits = perTenantLimits.computeIfAbsent(tenantId, id -> new TbRateLimits(perTenantLimitsConf));
if (!rateLimits.tryConsume()) {
if (callback != null) {
callback.onError(new TbRateLimitsException(EntityType.TENANT));
@ -215,7 +216,7 @@ public abstract class AbstractTransportService implements TransportService {
return false;
}
DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()));
rateLimits = perDeviceLimits.computeIfAbsent(deviceId, id -> new TbTransportRateLimits(perDevicesLimitsConf));
rateLimits = perDeviceLimits.computeIfAbsent(deviceId, id -> new TbRateLimits(perDevicesLimitsConf));
if (!rateLimits.tryConsume()) {
if (callback != null) {
callback.onError(new TbRateLimitsException(EntityType.DEVICE));
@ -271,8 +272,8 @@ public abstract class AbstractTransportService implements TransportService {
public void init() {
if (rateLimitEnabled) {
//Just checking the configuration parameters
new TbTransportRateLimits(perTenantLimitsConf);
new TbTransportRateLimits(perDevicesLimitsConf);
new TbRateLimits(perTenantLimitsConf);
new TbRateLimits(perDevicesLimitsConf);
}
this.schedulerExecutor = Executors.newSingleThreadScheduledExecutor();
this.transportCallbackExecutor = new ThreadPoolExecutor(0, 20, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());

11
dao/src/main/java/org/thingsboard/server/dao/Dao.java

@ -16,20 +16,21 @@
package org.thingsboard.server.dao;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.id.TenantId;
import java.util.List;
import java.util.UUID;
public interface Dao<T> {
List<T> find();
List<T> find(TenantId tenantId);
T findById(UUID id);
T findById(TenantId tenantId, UUID id);
ListenableFuture<T> findByIdAsync(UUID id);
ListenableFuture<T> findByIdAsync(TenantId tenantId, UUID id);
T save(T t);
T save(TenantId tenantId, T t);
boolean removeById(UUID id);
boolean removeById(TenantId tenantId, UUID id);
}

6
dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java

@ -33,9 +33,9 @@ public interface AlarmDao extends Dao<Alarm> {
ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type);
ListenableFuture<Alarm> findAlarmByIdAsync(UUID key);
ListenableFuture<Alarm> findAlarmByIdAsync(TenantId tenantId, UUID key);
Alarm save(Alarm alarm);
Alarm save(TenantId tenantId, Alarm alarm);
ListenableFuture<List<AlarmInfo>> findAlarms(AlarmQuery query);
ListenableFuture<List<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query);
}

12
dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java

@ -35,17 +35,17 @@ public interface AlarmService {
Alarm createOrUpdateAlarm(Alarm alarm);
ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTs);
ListenableFuture<Boolean> ackAlarm(TenantId tenantId, AlarmId alarmId, long ackTs);
ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, JsonNode details, long ackTs);
ListenableFuture<Boolean> clearAlarm(TenantId tenantId, AlarmId alarmId, JsonNode details, long ackTs);
ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId);
ListenableFuture<Alarm> findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId);
ListenableFuture<AlarmInfo> findAlarmInfoByIdAsync(AlarmId alarmId);
ListenableFuture<AlarmInfo> findAlarmInfoByIdAsync(TenantId tenantId, AlarmId alarmId);
ListenableFuture<TimePageData<AlarmInfo>> findAlarms(AlarmQuery query);
ListenableFuture<TimePageData<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query);
AlarmSeverity findHighestAlarmSeverity(EntityId entityId, AlarmSearchStatus alarmSearchStatus,
AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus,
AlarmStatus alarmStatus);
ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type);

92
dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java

@ -91,7 +91,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
@Override
public Alarm createOrUpdateAlarm(Alarm alarm) {
alarmDataValidator.validate(alarm);
alarmDataValidator.validate(alarm, Alarm::getTenantId);
try {
if (alarm.getStartTs() == 0L) {
alarm.setStartTs(System.currentTimeMillis());
@ -120,7 +120,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
private Alarm createAlarm(Alarm alarm) throws InterruptedException, ExecutionException {
log.debug("New Alarm : {}", alarm);
Alarm saved = alarmDao.save(alarm);
Alarm saved = alarmDao.save(alarm.getTenantId(), alarm);
createAlarmRelations(saved);
return saved;
}
@ -129,17 +129,17 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
if (alarm.isPropagate()) {
EntityRelationsQuery query = new EntityRelationsQuery();
query.setParameters(new RelationsSearchParameters(alarm.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE));
List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList());
List<EntityId> parentEntities = relationService.findByQuery(alarm.getTenantId(), query).get().stream().map(EntityRelation::getFrom).collect(Collectors.toList());
for (EntityId parentId : parentEntities) {
createAlarmRelation(parentId, alarm.getId(), alarm.getStatus(), true);
createAlarmRelation(alarm.getTenantId(), parentId, alarm.getId(), alarm.getStatus(), true);
}
}
createAlarmRelation(alarm.getOriginator(), alarm.getId(), alarm.getStatus(), true);
createAlarmRelation(alarm.getTenantId(), alarm.getOriginator(), alarm.getId(), alarm.getStatus(), true);
}
private ListenableFuture<Alarm> updateAlarm(Alarm update) {
alarmDataValidator.validate(update);
return getAndUpdate(update.getId(), new Function<Alarm, Alarm>() {
alarmDataValidator.validate(update, Alarm::getTenantId);
return getAndUpdate(update.getTenantId(), update.getId(), new Function<Alarm, Alarm>() {
@Nullable
@Override
public Alarm apply(@Nullable Alarm alarm) {
@ -157,7 +157,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
AlarmStatus newStatus = newAlarm.getStatus();
boolean oldPropagate = oldAlarm.isPropagate();
boolean newPropagate = newAlarm.isPropagate();
Alarm result = alarmDao.save(merge(oldAlarm, newAlarm));
Alarm result = alarmDao.save(newAlarm.getTenantId(), merge(oldAlarm, newAlarm));
if (!oldPropagate && newPropagate) {
try {
createAlarmRelations(result);
@ -172,8 +172,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
}
@Override
public ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTime) {
return getAndUpdate(alarmId, new Function<Alarm, Boolean>() {
public ListenableFuture<Boolean> ackAlarm(TenantId tenantId, AlarmId alarmId, long ackTime) {
return getAndUpdate(tenantId, alarmId, new Function<Alarm, Boolean>() {
@Nullable
@Override
public Boolean apply(@Nullable Alarm alarm) {
@ -184,7 +184,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
AlarmStatus newStatus = oldStatus.isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK;
alarm.setStatus(newStatus);
alarm.setAckTs(ackTime);
alarmDao.save(alarm);
alarmDao.save(alarm.getTenantId(), alarm);
updateRelations(alarm, oldStatus, newStatus);
return true;
}
@ -193,8 +193,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
}
@Override
public ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, JsonNode details, long clearTime) {
return getAndUpdate(alarmId, new Function<Alarm, Boolean>() {
public ListenableFuture<Boolean> clearAlarm(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTime) {
return getAndUpdate(tenantId, alarmId, new Function<Alarm, Boolean>() {
@Nullable
@Override
public Boolean apply(@Nullable Alarm alarm) {
@ -208,7 +208,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
if (details != null) {
alarm.setDetails(details);
}
alarmDao.save(alarm);
alarmDao.save(alarm.getTenantId(), alarm);
updateRelations(alarm, oldStatus, newStatus);
return true;
}
@ -217,21 +217,21 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
}
@Override
public ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId) {
public ListenableFuture<Alarm> findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId) {
log.trace("Executing findAlarmById [{}]", alarmId);
validateId(alarmId, "Incorrect alarmId " + alarmId);
return alarmDao.findAlarmByIdAsync(alarmId.getId());
return alarmDao.findAlarmByIdAsync(tenantId, alarmId.getId());
}
@Override
public ListenableFuture<AlarmInfo> findAlarmInfoByIdAsync(AlarmId alarmId) {
public ListenableFuture<AlarmInfo> findAlarmInfoByIdAsync(TenantId tenantId, AlarmId alarmId) {
log.trace("Executing findAlarmInfoByIdAsync [{}]", alarmId);
validateId(alarmId, "Incorrect alarmId " + alarmId);
return Futures.transformAsync(alarmDao.findAlarmByIdAsync(alarmId.getId()),
return Futures.transformAsync(alarmDao.findAlarmByIdAsync(tenantId, alarmId.getId()),
a -> {
AlarmInfo alarmInfo = new AlarmInfo(a);
return Futures.transform(
entityService.fetchEntityNameAsync(alarmInfo.getOriginator()), originatorName -> {
entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> {
alarmInfo.setOriginatorName(originatorName);
return alarmInfo;
}
@ -240,14 +240,14 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
}
@Override
public ListenableFuture<TimePageData<AlarmInfo>> findAlarms(AlarmQuery query) {
ListenableFuture<List<AlarmInfo>> alarms = alarmDao.findAlarms(query);
public ListenableFuture<TimePageData<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query) {
ListenableFuture<List<AlarmInfo>> alarms = alarmDao.findAlarms(tenantId, query);
if (query.getFetchOriginator() != null && query.getFetchOriginator().booleanValue()) {
alarms = Futures.transformAsync(alarms, input -> {
List<ListenableFuture<AlarmInfo>> alarmFutures = new ArrayList<>(input.size());
for (AlarmInfo alarmInfo : input) {
alarmFutures.add(Futures.transform(
entityService.fetchEntityNameAsync(alarmInfo.getOriginator()), originatorName -> {
entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> {
if (originatorName == null) {
originatorName = "Deleted";
}
@ -269,7 +269,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
}
@Override
public AlarmSeverity findHighestAlarmSeverity(EntityId entityId, AlarmSearchStatus alarmSearchStatus,
public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus,
AlarmStatus alarmStatus) {
TimePageLink nextPageLink = new TimePageLink(100);
boolean hasNext = true;
@ -279,7 +279,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
query = new AlarmQuery(entityId, nextPageLink, alarmSearchStatus, alarmStatus, false);
List<AlarmInfo> alarms;
try {
alarms = alarmDao.findAlarms(query).get();
alarms = alarmDao.findAlarms(tenantId, query).get();
} catch (ExecutionException | InterruptedException e) {
log.warn("Failed to find highest alarm severity. EntityId: [{}], AlarmSearchStatus: [{}], AlarmStatus: [{}]",
entityId, alarmSearchStatus, alarmStatus);
@ -312,14 +312,14 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
}
}
private void deleteRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException {
private void deleteRelation(TenantId tenantId, EntityRelation alarmRelation) throws ExecutionException, InterruptedException {
log.debug("Deleting Alarm relation: {}", alarmRelation);
relationService.deleteRelationAsync(alarmRelation).get();
relationService.deleteRelationAsync(tenantId, alarmRelation).get();
}
private void createRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException {
private void createRelation(TenantId tenantId, EntityRelation alarmRelation) throws ExecutionException, InterruptedException {
log.debug("Creating Alarm relation: {}", alarmRelation);
relationService.saveRelationAsync(alarmRelation).get();
relationService.saveRelationAsync(tenantId, alarmRelation).get();
}
private Alarm merge(Alarm existing, Alarm alarm) {
@ -344,10 +344,10 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
private void updateRelations(Alarm alarm, AlarmStatus oldStatus, AlarmStatus newStatus) {
try {
List<EntityRelation> relations = relationService.findByToAsync(alarm.getId(), RelationTypeGroup.ALARM).get();
List<EntityRelation> relations = relationService.findByToAsync(alarm.getTenantId(), alarm.getId(), RelationTypeGroup.ALARM).get();
Set<EntityId> parents = relations.stream().map(EntityRelation::getFrom).collect(Collectors.toSet());
for (EntityId parentId : parents) {
updateAlarmRelation(parentId, alarm.getId(), oldStatus, newStatus);
updateAlarmRelation(alarm.getTenantId(), parentId, alarm.getId(), oldStatus, newStatus);
}
} catch (ExecutionException | InterruptedException e) {
log.warn("[{}] Failed to update relations. Old status: [{}], New status: [{}]", alarm.getId(), oldStatus, newStatus);
@ -355,39 +355,39 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
}
}
private void createAlarmRelation(EntityId entityId, EntityId alarmId, AlarmStatus status, boolean createAnyRelation) {
private void createAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status, boolean createAnyRelation) {
try {
if (createAnyRelation) {
createRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + AlarmSearchStatus.ANY.name(), RelationTypeGroup.ALARM));
createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + AlarmSearchStatus.ANY.name(), RelationTypeGroup.ALARM));
}
createRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.name(), RelationTypeGroup.ALARM));
createRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getClearSearchStatus().name(), RelationTypeGroup.ALARM));
createRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM));
createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.name(), RelationTypeGroup.ALARM));
createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getClearSearchStatus().name(), RelationTypeGroup.ALARM));
createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM));
} catch (ExecutionException | InterruptedException e) {
log.warn("[{}] Failed to create relation. Status: [{}]", alarmId, status);
throw new RuntimeException(e);
}
}
private void deleteAlarmRelation(EntityId entityId, EntityId alarmId, AlarmStatus status) {
private void deleteAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status) {
try {
deleteRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.name(), RelationTypeGroup.ALARM));
deleteRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getClearSearchStatus().name(), RelationTypeGroup.ALARM));
deleteRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM));
deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.name(), RelationTypeGroup.ALARM));
deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getClearSearchStatus().name(), RelationTypeGroup.ALARM));
deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM));
} catch (ExecutionException | InterruptedException e) {
log.warn("[{}] Failed to delete relation. Status: [{}]", alarmId, status);
throw new RuntimeException(e);
}
}
private void updateAlarmRelation(EntityId entityId, EntityId alarmId, AlarmStatus oldStatus, AlarmStatus newStatus) {
deleteAlarmRelation(entityId, alarmId, oldStatus);
createAlarmRelation(entityId, alarmId, newStatus, false);
private void updateAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus oldStatus, AlarmStatus newStatus) {
deleteAlarmRelation(tenantId, entityId, alarmId, oldStatus);
createAlarmRelation(tenantId, entityId, alarmId, newStatus, false);
}
private <T> ListenableFuture<T> getAndUpdate(AlarmId alarmId, Function<Alarm, T> function) {
private <T> ListenableFuture<T> getAndUpdate(TenantId tenantId, AlarmId alarmId, Function<Alarm, T> function) {
validateId(alarmId, "Alarm id should be specified!");
ListenableFuture<Alarm> entity = alarmDao.findAlarmByIdAsync(alarmId.getId());
ListenableFuture<Alarm> entity = alarmDao.findAlarmByIdAsync(tenantId, alarmId.getId());
return Futures.transform(entity, function, readResultsProcessingExecutor);
}
@ -395,7 +395,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
new DataValidator<Alarm>() {
@Override
protected void validateDataImpl(Alarm alarm) {
protected void validateDataImpl(TenantId tenantId, Alarm alarm) {
if (StringUtils.isEmpty(alarm.getType())) {
throw new DataValidationException("Alarm type should be specified!");
}
@ -411,7 +411,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
if (alarm.getTenantId() == null) {
throw new DataValidationException("Alarm should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(alarm.getTenantId().getId());
Tenant tenant = tenantDao.findById(alarm.getTenantId(), alarm.getTenantId().getId());
if (tenant == null) {
throw new DataValidationException("Alarm is referencing to non-existent tenant!");
}

16
dao/src/main/java/org/thingsboard/server/dao/alarm/CassandraAlarmDao.java

@ -73,9 +73,9 @@ public class CassandraAlarmDao extends CassandraAbstractModelDao<AlarmEntity, Al
}
@Override
public Alarm save(Alarm alarm) {
public Alarm save(TenantId tenantId, Alarm alarm) {
log.debug("Save asset [{}] ", alarm);
return super.save(alarm);
return super.save(tenantId, alarm);
}
@Override
@ -88,11 +88,11 @@ public class CassandraAlarmDao extends CassandraAbstractModelDao<AlarmEntity, Al
query.and(eq(ALARM_TYPE_PROPERTY, type));
query.limit(1);
query.orderBy(QueryBuilder.asc(ModelConstants.ALARM_TYPE_PROPERTY), QueryBuilder.desc(ModelConstants.ID_PROPERTY));
return findOneByStatementAsync(query);
return findOneByStatementAsync(tenantId, query);
}
@Override
public ListenableFuture<List<AlarmInfo>> findAlarms(AlarmQuery query) {
public ListenableFuture<List<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query) {
log.trace("Try to find alarms by entity [{}], searchStatus [{}], status [{}] and pageLink [{}]", query.getAffectedEntityId(), query.getSearchStatus(), query.getStatus(), query.getPageLink());
EntityId affectedEntity = query.getAffectedEntityId();
String searchStatusName;
@ -104,12 +104,12 @@ public class CassandraAlarmDao extends CassandraAbstractModelDao<AlarmEntity, Al
searchStatusName = query.getStatus().name();
}
String relationType = BaseAlarmService.ALARM_RELATION_PREFIX + searchStatusName;
ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(affectedEntity, relationType, RelationTypeGroup.ALARM, EntityType.ALARM, query.getPageLink());
ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(tenantId, affectedEntity, relationType, RelationTypeGroup.ALARM, EntityType.ALARM, query.getPageLink());
return Futures.transformAsync(relations, input -> {
List<ListenableFuture<AlarmInfo>> alarmFutures = new ArrayList<>(input.size());
for (EntityRelation relation : input) {
alarmFutures.add(Futures.transform(
findAlarmByIdAsync(relation.getTo().getId()),
findAlarmByIdAsync(tenantId, relation.getTo().getId()),
AlarmInfo::new));
}
return Futures.successfulAsList(alarmFutures);
@ -117,11 +117,11 @@ public class CassandraAlarmDao extends CassandraAbstractModelDao<AlarmEntity, Al
}
@Override
public ListenableFuture<Alarm> findAlarmByIdAsync(UUID key) {
public ListenableFuture<Alarm> findAlarmByIdAsync(TenantId tenantId, UUID key) {
log.debug("Get alarm by id {}", key);
Select.Where query = select().from(ALARM_BY_ID_VIEW_NAME).where(eq(ModelConstants.ID_PROPERTY, key));
query.limit(1);
log.trace("Execute query {}", query);
return findOneByStatementAsync(query);
return findOneByStatementAsync(tenantId, query);
}
}

3
dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java

@ -18,6 +18,7 @@ package org.thingsboard.server.dao.asset;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.Dao;
@ -37,7 +38,7 @@ public interface AssetDao extends Dao<Asset> {
* @param asset the asset object
* @return saved asset object
*/
Asset save(Asset asset);
Asset save(TenantId tenantId, Asset asset);
/**
* Find assets by tenantId and page link.

12
dao/src/main/java/org/thingsboard/server/dao/asset/AssetService.java

@ -30,19 +30,19 @@ import java.util.Optional;
public interface AssetService {
Asset findAssetById(AssetId assetId);
Asset findAssetById(TenantId tenantId, AssetId assetId);
ListenableFuture<Asset> findAssetByIdAsync(AssetId assetId);
ListenableFuture<Asset> findAssetByIdAsync(TenantId tenantId, AssetId assetId);
Asset findAssetByTenantIdAndName(TenantId tenantId, String name);
Asset saveAsset(Asset asset);
Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId);
Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, CustomerId customerId);
Asset unassignAssetFromCustomer(AssetId assetId);
Asset unassignAssetFromCustomer(TenantId tenantId, AssetId assetId);
void deleteAsset(AssetId assetId);
void deleteAsset(TenantId tenantId, AssetId assetId);
TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink);
@ -60,7 +60,7 @@ public interface AssetService {
void unassignCustomerAssets(TenantId tenantId, CustomerId customerId);
ListenableFuture<List<Asset>> findAssetsByQuery(AssetSearchQuery query);
ListenableFuture<List<Asset>> findAssetsByQuery(TenantId tenantId, AssetSearchQuery query);
ListenableFuture<List<EntitySubtype>> findAssetTypesByTenantId(TenantId tenantId);
}

88
dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java

@ -86,17 +86,17 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
private CacheManager cacheManager;
@Override
public Asset findAssetById(AssetId assetId) {
public Asset findAssetById(TenantId tenantId, AssetId assetId) {
log.trace("Executing findAssetById [{}]", assetId);
validateId(assetId, INCORRECT_ASSET_ID + assetId);
return assetDao.findById(assetId.getId());
return assetDao.findById(tenantId, assetId.getId());
}
@Override
public ListenableFuture<Asset> findAssetByIdAsync(AssetId assetId) {
public ListenableFuture<Asset> findAssetByIdAsync(TenantId tenantId, AssetId assetId) {
log.trace("Executing findAssetById [{}]", assetId);
validateId(assetId, INCORRECT_ASSET_ID + assetId);
return assetDao.findByIdAsync(assetId.getId());
return assetDao.findByIdAsync(tenantId, assetId.getId());
}
@Cacheable(cacheNames = ASSET_CACHE, key = "{#tenantId, #name}")
@ -112,31 +112,31 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
@Override
public Asset saveAsset(Asset asset) {
log.trace("Executing saveAsset [{}]", asset);
assetValidator.validate(asset);
return assetDao.save(asset);
assetValidator.validate(asset, Asset::getTenantId);
return assetDao.save(asset.getTenantId(), asset);
}
@Override
public Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId) {
Asset asset = findAssetById(assetId);
public Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, CustomerId customerId) {
Asset asset = findAssetById(tenantId, assetId);
asset.setCustomerId(customerId);
return saveAsset(asset);
}
@Override
public Asset unassignAssetFromCustomer(AssetId assetId) {
Asset asset = findAssetById(assetId);
public Asset unassignAssetFromCustomer(TenantId tenantId, AssetId assetId) {
Asset asset = findAssetById(tenantId, assetId);
asset.setCustomerId(null);
return saveAsset(asset);
}
@Override
public void deleteAsset(AssetId assetId) {
public void deleteAsset(TenantId tenantId, AssetId assetId) {
log.trace("Executing deleteAsset [{}]", assetId);
validateId(assetId, INCORRECT_ASSET_ID + assetId);
deleteEntityRelations(assetId);
deleteEntityRelations(tenantId, assetId);
Asset asset = assetDao.findById(assetId.getId());
Asset asset = assetDao.findById(tenantId, assetId.getId());
try {
List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(asset.getTenantId(), assetId).get();
if (entityViews != null && !entityViews.isEmpty()) {
@ -153,7 +153,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
Cache cache = cacheManager.getCache(ASSET_CACHE);
cache.evict(list);
assetDao.removeById(assetId.getId());
assetDao.removeById(tenantId, assetId.getId());
}
@Override
@ -187,7 +187,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
public void deleteAssetsByTenantId(TenantId tenantId) {
log.trace("Executing deleteAssetsByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
tenantAssetsRemover.removeEntities(tenantId);
tenantAssetsRemover.removeEntities(tenantId, tenantId);
}
@Override
@ -225,24 +225,24 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
log.trace("Executing unassignCustomerAssets, tenantId [{}], customerId [{}]", tenantId, customerId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
new CustomerAssetsUnassigner(tenantId).removeEntities(customerId);
customerAssetsUnasigner.removeEntities(tenantId, customerId);
}
@Override
public ListenableFuture<List<Asset>> findAssetsByQuery(AssetSearchQuery query) {
ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(query.toEntitySearchQuery());
public ListenableFuture<List<Asset>> findAssetsByQuery(TenantId tenantId, AssetSearchQuery query) {
ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(tenantId, query.toEntitySearchQuery());
ListenableFuture<List<Asset>> assets = Futures.transformAsync(relations, r -> {
EntitySearchDirection direction = query.toEntitySearchQuery().getParameters().getDirection();
List<ListenableFuture<Asset>> futures = new ArrayList<>();
for (EntityRelation relation : r) {
EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom();
if (entityId.getEntityType() == EntityType.ASSET) {
futures.add(findAssetByIdAsync(new AssetId(entityId.getId())));
futures.add(findAssetByIdAsync(tenantId, new AssetId(entityId.getId())));
}
}
return Futures.successfulAsList(futures);
});
assets = Futures.transform(assets, (Function<List<Asset>, List<Asset>>)assetList ->
assets = Futures.transform(assets, assetList ->
assetList == null ? Collections.emptyList() : assetList.stream().filter(asset -> query.getAssetTypes().contains(asset.getType())).collect(Collectors.toList())
);
return assets;
@ -254,7 +254,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
ListenableFuture<List<EntitySubtype>> tenantAssetTypes = assetDao.findTenantAssetTypesAsync(tenantId.getId());
return Futures.transform(tenantAssetTypes,
(Function<List<EntitySubtype>, List<EntitySubtype>>) assetTypes -> {
assetTypes -> {
assetTypes.sort(Comparator.comparing(EntitySubtype::getType));
return assetTypes;
});
@ -264,7 +264,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
new DataValidator<Asset>() {
@Override
protected void validateCreate(Asset asset) {
protected void validateCreate(TenantId tenantId, Asset asset) {
assetDao.findAssetsByTenantIdAndName(asset.getTenantId().getId(), asset.getName()).ifPresent(
d -> {
throw new DataValidationException("Asset with such name already exists!");
@ -273,7 +273,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
}
@Override
protected void validateUpdate(Asset asset) {
protected void validateUpdate(TenantId tenantId, Asset asset) {
assetDao.findAssetsByTenantIdAndName(asset.getTenantId().getId(), asset.getName()).ifPresent(
d -> {
if (!d.getId().equals(asset.getId())) {
@ -284,7 +284,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
}
@Override
protected void validateDataImpl(Asset asset) {
protected void validateDataImpl(TenantId tenantId, Asset asset) {
if (StringUtils.isEmpty(asset.getType())) {
throw new DataValidationException("Asset type should be specified!");
}
@ -294,7 +294,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
if (asset.getTenantId() == null) {
throw new DataValidationException("Asset should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(asset.getTenantId().getId());
Tenant tenant = tenantDao.findById(tenantId, asset.getTenantId().getId());
if (tenant == null) {
throw new DataValidationException("Asset is referencing to non-existent tenant!");
}
@ -302,7 +302,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
if (asset.getCustomerId() == null) {
asset.setCustomerId(new CustomerId(NULL_UUID));
} else if (!asset.getCustomerId().getId().equals(NULL_UUID)) {
Customer customer = customerDao.findById(asset.getCustomerId().getId());
Customer customer = customerDao.findById(tenantId, asset.getCustomerId().getId());
if (customer == null) {
throw new DataValidationException("Can't assign asset to non-existent customer!");
}
@ -314,35 +314,29 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
};
private PaginatedRemover<TenantId, Asset> tenantAssetsRemover =
new PaginatedRemover<TenantId, Asset>() {
new PaginatedRemover<TenantId, Asset>() {
@Override
protected List<Asset> findEntities(TenantId id, TextPageLink pageLink) {
return assetDao.findAssetsByTenantId(id.getId(), pageLink);
}
@Override
protected void removeEntity(Asset entity) {
deleteAsset(new AssetId(entity.getId().getId()));
}
};
@Override
protected List<Asset> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) {
return assetDao.findAssetsByTenantId(id.getId(), pageLink);
}
class CustomerAssetsUnassigner extends PaginatedRemover<CustomerId, Asset> {
@Override
protected void removeEntity(TenantId tenantId, Asset entity) {
deleteAsset(tenantId, new AssetId(entity.getId().getId()));
}
};
private TenantId tenantId;
CustomerAssetsUnassigner(TenantId tenantId) {
this.tenantId = tenantId;
}
private PaginatedRemover<CustomerId, Asset> customerAssetsUnasigner = new PaginatedRemover<CustomerId, Asset>() {
@Override
protected List<Asset> findEntities(CustomerId id, TextPageLink pageLink) {
protected List<Asset> findEntities(TenantId tenantId, CustomerId id, TextPageLink pageLink) {
return assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink);
}
@Override
protected void removeEntity(Asset entity) {
unassignAssetFromCustomer(new AssetId(entity.getId().getId()));
protected void removeEntity(TenantId tenantId, Asset entity) {
unassignAssetFromCustomer(tenantId, new AssetId(entity.getId().getId()));
}
}
};
}

23
dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java

@ -28,6 +28,7 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.EntitySubtypeEntity;
@ -77,19 +78,19 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao<AssetEntit
}
@Override
public Asset save(Asset domain) {
Asset savedAsset = super.save(domain);
public Asset save(TenantId tenantId, Asset domain) {
Asset savedAsset = super.save(tenantId, domain);
EntitySubtype entitySubtype = new EntitySubtype(savedAsset.getTenantId(), EntityType.ASSET, savedAsset.getType());
EntitySubtypeEntity entitySubtypeEntity = new EntitySubtypeEntity(entitySubtype);
Statement saveStatement = cluster.getMapper(EntitySubtypeEntity.class).saveQuery(entitySubtypeEntity);
executeWrite(saveStatement);
executeWrite(tenantId, saveStatement);
return savedAsset;
}
@Override
public List<Asset> findAssetsByTenantId(UUID tenantId, TextPageLink pageLink) {
log.debug("Try to find assets by tenantId [{}] and pageLink [{}]", tenantId, pageLink);
List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<AssetEntity> assetEntities = findPageWithTextSearch(new TenantId(tenantId), ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Collections.singletonList(eq(ASSET_TENANT_ID_PROPERTY, tenantId)), pageLink);
log.trace("Found assets [{}] by tenantId [{}] and pageLink [{}]", assetEntities, tenantId, pageLink);
@ -99,7 +100,7 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao<AssetEntit
@Override
public List<Asset> findAssetsByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
log.debug("Try to find assets by tenantId [{}], type [{}] and pageLink [{}]", tenantId, type, pageLink);
List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<AssetEntity> assetEntities = findPageWithTextSearch(new TenantId(tenantId), ASSET_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Arrays.asList(eq(ASSET_TYPE_PROPERTY, type),
eq(ASSET_TENANT_ID_PROPERTY, tenantId)), pageLink);
log.trace("Found assets [{}] by tenantId [{}], type [{}] and pageLink [{}]", assetEntities, tenantId, type, pageLink);
@ -112,13 +113,13 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao<AssetEntit
Select.Where query = select.where();
query.and(eq(ASSET_TENANT_ID_PROPERTY, tenantId));
query.and(in(ID_PROPERTY, assetIds));
return findListByStatementAsync(query);
return findListByStatementAsync(new TenantId(tenantId), query);
}
@Override
public List<Asset> findAssetsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) {
log.debug("Try to find assets by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink);
List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<AssetEntity> assetEntities = findPageWithTextSearch(new TenantId(tenantId), ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Arrays.asList(eq(ASSET_CUSTOMER_ID_PROPERTY, customerId),
eq(ASSET_TENANT_ID_PROPERTY, tenantId)),
pageLink);
@ -130,7 +131,7 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao<AssetEntit
@Override
public List<Asset> findAssetsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
log.debug("Try to find assets by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink);
List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<AssetEntity> assetEntities = findPageWithTextSearch(new TenantId(tenantId), ASSET_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Arrays.asList(eq(ASSET_TYPE_PROPERTY, type),
eq(ASSET_CUSTOMER_ID_PROPERTY, customerId),
eq(ASSET_TENANT_ID_PROPERTY, tenantId)),
@ -148,7 +149,7 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao<AssetEntit
query.and(eq(ASSET_TENANT_ID_PROPERTY, tenantId));
query.and(eq(ASSET_CUSTOMER_ID_PROPERTY, customerId));
query.and(in(ID_PROPERTY, assetIds));
return findListByStatementAsync(query);
return findListByStatementAsync(new TenantId(tenantId), query);
}
@Override
@ -157,7 +158,7 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao<AssetEntit
Select.Where query = select.where();
query.and(eq(ASSET_TENANT_ID_PROPERTY, tenantId));
query.and(eq(ASSET_NAME_PROPERTY, assetName));
AssetEntity assetEntity = (AssetEntity) findOneByStatement(query);
AssetEntity assetEntity = (AssetEntity) findOneByStatement(new TenantId(tenantId), query);
return Optional.ofNullable(DaoUtil.getData(assetEntity));
}
@ -168,7 +169,7 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao<AssetEntit
query.and(eq(ENTITY_SUBTYPE_TENANT_ID_PROPERTY, tenantId));
query.and(eq(ENTITY_SUBTYPE_ENTITY_TYPE_PROPERTY, EntityType.ASSET));
query.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
ResultSetFuture resultSetFuture = executeAsyncRead(query);
ResultSetFuture resultSetFuture = executeAsyncRead(new TenantId(tenantId), query);
return Futures.transform(resultSetFuture, new Function<ResultSet, List<EntitySubtype>>() {
@Nullable
@Override

11
dao/src/main/java/org/thingsboard/server/dao/attributes/AttributesDao.java

@ -17,6 +17,7 @@ package org.thingsboard.server.dao.attributes;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import java.util.Collection;
@ -28,13 +29,13 @@ import java.util.Optional;
*/
public interface AttributesDao {
ListenableFuture<Optional<AttributeKvEntry>> find(EntityId entityId, String attributeType, String attributeKey);
ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String attributeType, String attributeKey);
ListenableFuture<List<AttributeKvEntry>> find(EntityId entityId, String attributeType, Collection<String> attributeKey);
ListenableFuture<List<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String attributeType, Collection<String> attributeKey);
ListenableFuture<List<AttributeKvEntry>> findAll(EntityId entityId, String attributeType);
ListenableFuture<List<AttributeKvEntry>> findAll(TenantId tenantId, EntityId entityId, String attributeType);
ListenableFuture<Void> save(EntityId entityId, String attributeType, AttributeKvEntry attribute);
ListenableFuture<Void> save(TenantId tenantId, EntityId entityId, String attributeType, AttributeKvEntry attribute);
ListenableFuture<List<Void>> removeAll(EntityId entityId, String attributeType, List<String> keys);
ListenableFuture<List<Void>> removeAll(TenantId tenantId, EntityId entityId, String attributeType, List<String> keys);
}

11
dao/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java

@ -17,6 +17,7 @@ package org.thingsboard.server.dao.attributes;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import java.util.Collection;
@ -28,13 +29,13 @@ import java.util.Optional;
*/
public interface AttributesService {
ListenableFuture<Optional<AttributeKvEntry>> find(EntityId entityId, String scope, String attributeKey);
ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String scope, String attributeKey);
ListenableFuture<List<AttributeKvEntry>> find(EntityId entityId, String scope, Collection<String> attributeKeys);
ListenableFuture<List<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String scope, Collection<String> attributeKeys);
ListenableFuture<List<AttributeKvEntry>> findAll(EntityId entityId, String scope);
ListenableFuture<List<AttributeKvEntry>> findAll(TenantId tenantId, EntityId entityId, String scope);
ListenableFuture<List<Void>> save(EntityId entityId, String scope, List<AttributeKvEntry> attributes);
ListenableFuture<List<Void>> save(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes);
ListenableFuture<List<Void>> removeAll(EntityId entityId, String scope, List<String> attributeKeys);
ListenableFuture<List<Void>> removeAll(TenantId tenantId, EntityId entityId, String scope, List<String> attributeKeys);
}

21
dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java

@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.service.Validator;
@ -39,40 +40,40 @@ public class BaseAttributesService implements AttributesService {
private AttributesDao attributesDao;
@Override
public ListenableFuture<Optional<AttributeKvEntry>> find(EntityId entityId, String scope, String attributeKey) {
public ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String scope, String attributeKey) {
validate(entityId, scope);
Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey);
return attributesDao.find(entityId, scope, attributeKey);
return attributesDao.find(tenantId, entityId, scope, attributeKey);
}
@Override
public ListenableFuture<List<AttributeKvEntry>> find(EntityId entityId, String scope, Collection<String> attributeKeys) {
public ListenableFuture<List<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String scope, Collection<String> attributeKeys) {
validate(entityId, scope);
attributeKeys.forEach(attributeKey -> Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey));
return attributesDao.find(entityId, scope, attributeKeys);
return attributesDao.find(tenantId, entityId, scope, attributeKeys);
}
@Override
public ListenableFuture<List<AttributeKvEntry>> findAll(EntityId entityId, String scope) {
public ListenableFuture<List<AttributeKvEntry>> findAll(TenantId tenantId, EntityId entityId, String scope) {
validate(entityId, scope);
return attributesDao.findAll(entityId, scope);
return attributesDao.findAll(tenantId, entityId, scope);
}
@Override
public ListenableFuture<List<Void>> save(EntityId entityId, String scope, List<AttributeKvEntry> attributes) {
public ListenableFuture<List<Void>> save(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes) {
validate(entityId, scope);
attributes.forEach(attribute -> validate(attribute));
List<ListenableFuture<Void>> futures = Lists.newArrayListWithExpectedSize(attributes.size());
for (AttributeKvEntry attribute : attributes) {
futures.add(attributesDao.save(entityId, scope, attribute));
futures.add(attributesDao.save(tenantId, entityId, scope, attribute));
}
return Futures.allAsList(futures);
}
@Override
public ListenableFuture<List<Void>> removeAll(EntityId entityId, String scope, List<String> keys) {
public ListenableFuture<List<Void>> removeAll(TenantId tenantId, EntityId entityId, String scope, List<String> keys) {
validate(entityId, scope);
return attributesDao.removeAll(entityId, scope, keys);
return attributesDao.removeAll(tenantId, entityId, scope, keys);
}
private static void validate(EntityId id, String scope) {

25
dao/src/main/java/org/thingsboard/server/dao/attributes/CassandraBaseAttributesDao.java

@ -28,6 +28,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.dao.model.ModelConstants;
@ -73,22 +74,22 @@ public class CassandraBaseAttributesDao extends CassandraAbstractAsyncDao implem
}
@Override
public ListenableFuture<Optional<AttributeKvEntry>> find(EntityId entityId, String attributeType, String attributeKey) {
public ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String attributeType, String attributeKey) {
Select.Where select = select().from(ATTRIBUTES_KV_CF)
.where(eq(ENTITY_TYPE_COLUMN, entityId.getEntityType()))
.and(eq(ENTITY_ID_COLUMN, entityId.getId()))
.and(eq(ATTRIBUTE_TYPE_COLUMN, attributeType))
.and(eq(ATTRIBUTE_KEY_COLUMN, attributeKey));
log.trace("Generated query [{}] for entityId {} and key {}", select, entityId, attributeKey);
return Futures.transform(executeAsyncRead(select), (Function<? super ResultSet, ? extends Optional<AttributeKvEntry>>) input ->
return Futures.transform(executeAsyncRead(tenantId, select), (Function<? super ResultSet, ? extends Optional<AttributeKvEntry>>) input ->
Optional.ofNullable(convertResultToAttributesKvEntry(attributeKey, input.one()))
, readResultsProcessingExecutor);
}
@Override
public ListenableFuture<List<AttributeKvEntry>> find(EntityId entityId, String attributeType, Collection<String> attributeKeys) {
public ListenableFuture<List<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String attributeType, Collection<String> attributeKeys) {
List<ListenableFuture<Optional<AttributeKvEntry>>> entries = new ArrayList<>();
attributeKeys.forEach(attributeKey -> entries.add(find(entityId, attributeType, attributeKey)));
attributeKeys.forEach(attributeKey -> entries.add(find(tenantId, entityId, attributeType, attributeKey)));
return Futures.transform(Futures.allAsList(entries), (Function<List<Optional<AttributeKvEntry>>, ? extends List<AttributeKvEntry>>) input -> {
List<AttributeKvEntry> result = new ArrayList<>();
input.stream().filter(opt -> opt.isPresent()).forEach(opt -> result.add(opt.get()));
@ -98,19 +99,19 @@ public class CassandraBaseAttributesDao extends CassandraAbstractAsyncDao implem
@Override
public ListenableFuture<List<AttributeKvEntry>> findAll(EntityId entityId, String attributeType) {
public ListenableFuture<List<AttributeKvEntry>> findAll(TenantId tenantId, EntityId entityId, String attributeType) {
Select.Where select = select().from(ATTRIBUTES_KV_CF)
.where(eq(ENTITY_TYPE_COLUMN, entityId.getEntityType()))
.and(eq(ENTITY_ID_COLUMN, entityId.getId()))
.and(eq(ATTRIBUTE_TYPE_COLUMN, attributeType));
log.trace("Generated query [{}] for entityId {} and attributeType {}", select, entityId, attributeType);
return Futures.transform(executeAsyncRead(select), (Function<? super ResultSet, ? extends List<AttributeKvEntry>>) input ->
return Futures.transform(executeAsyncRead(tenantId, select), (Function<? super ResultSet, ? extends List<AttributeKvEntry>>) input ->
convertResultToAttributesKvEntryList(input)
, readResultsProcessingExecutor);
}
@Override
public ListenableFuture<Void> save(EntityId entityId, String attributeType, AttributeKvEntry attribute) {
public ListenableFuture<Void> save(TenantId tenantId, EntityId entityId, String attributeType, AttributeKvEntry attribute) {
BoundStatement stmt = getSaveStmt().bind();
stmt.setString(0, entityId.getEntityType().name());
stmt.setUUID(1, entityId.getId());
@ -137,26 +138,26 @@ public class CassandraBaseAttributesDao extends CassandraAbstractAsyncDao implem
stmt.setToNull(8);
}
log.trace("Generated save stmt [{}] for entityId {} and attributeType {} and attribute", stmt, entityId, attributeType, attribute);
return getFuture(executeAsyncWrite(stmt), rs -> null);
return getFuture(executeAsyncWrite(tenantId, stmt), rs -> null);
}
@Override
public ListenableFuture<List<Void>> removeAll(EntityId entityId, String attributeType, List<String> keys) {
public ListenableFuture<List<Void>> removeAll(TenantId tenantId, EntityId entityId, String attributeType, List<String> keys) {
List<ListenableFuture<Void>> futures = keys
.stream()
.map(key -> delete(entityId, attributeType, key))
.map(key -> delete(tenantId, entityId, attributeType, key))
.collect(Collectors.toList());
return Futures.allAsList(futures);
}
private ListenableFuture<Void> delete(EntityId entityId, String attributeType, String key) {
private ListenableFuture<Void> delete(TenantId tenantId, EntityId entityId, String attributeType, String key) {
Statement delete = QueryBuilder.delete().all().from(ModelConstants.ATTRIBUTES_KV_CF)
.where(eq(ENTITY_TYPE_COLUMN, entityId.getEntityType()))
.and(eq(ENTITY_ID_COLUMN, entityId.getId()))
.and(eq(ATTRIBUTE_TYPE_COLUMN, attributeType))
.and(eq(ATTRIBUTE_KEY_COLUMN, key));
log.debug("Remove request: {}", delete.toString());
return getFuture(executeAsyncWrite(delete), rs -> null);
return getFuture(executeAsyncWrite(tenantId, delete), rs -> null);
}
private PreparedStatement getSaveStmt() {

6
dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java

@ -128,7 +128,7 @@ public class AuditLogServiceImpl implements AuditLogService {
entityName = entity.getName();
} else {
try {
entityName = entityService.fetchEntityNameAsync(entityId).get();
entityName = entityService.fetchEntityNameAsync(tenantId, entityId).get();
} catch (Exception ex) {}
}
if (e != null) {
@ -315,7 +315,7 @@ public class AuditLogServiceImpl implements AuditLogService {
AuditLog auditLogEntry = createAuditLogEntry(tenantId, entityId, entityName, customerId, userId, userName,
actionType, actionData, actionStatus, actionFailureDetails);
log.trace("Executing logAction [{}]", auditLogEntry);
auditLogValidator.validate(auditLogEntry);
auditLogValidator.validate(auditLogEntry, AuditLog::getTenantId);
List<ListenableFuture<Void>> futures = Lists.newArrayListWithExpectedSize(INSERTS_PER_ENTRY);
futures.add(auditLogDao.savePartitionsByTenantId(auditLogEntry));
futures.add(auditLogDao.saveByTenantId(auditLogEntry));
@ -331,7 +331,7 @@ public class AuditLogServiceImpl implements AuditLogService {
private DataValidator<AuditLog> auditLogValidator =
new DataValidator<AuditLog>() {
@Override
protected void validateDataImpl(AuditLog auditLog) {
protected void validateDataImpl(TenantId tenantId, AuditLog auditLog) {
if (auditLog.getEntityId() == null) {
throw new DataValidationException("Entity Id should be specified!");
}

25
dao/src/main/java/org/thingsboard/server/dao/audit/CassandraAuditLogDao.java

@ -32,6 +32,7 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.audit.AuditLog;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.DaoUtil;
@ -142,7 +143,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
long partition = toPartitionTs(LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli());
BoundStatement stmt = getSaveByTenantStmt().bind();
stmt = setSaveStmtVariables(stmt, auditLog, partition);
return getFuture(executeAsyncWrite(stmt), rs -> null);
return getFuture(executeAsyncWrite(auditLog.getTenantId(), stmt), rs -> null);
}
@Override
@ -151,7 +152,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
BoundStatement stmt = getSaveByTenantIdAndEntityIdStmt().bind();
stmt = setSaveStmtVariables(stmt, auditLog, -1);
return getFuture(executeAsyncWrite(stmt), rs -> null);
return getFuture(executeAsyncWrite(auditLog.getTenantId(), stmt), rs -> null);
}
@Override
@ -160,7 +161,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
BoundStatement stmt = getSaveByTenantIdAndCustomerIdStmt().bind();
stmt = setSaveStmtVariables(stmt, auditLog, -1);
return getFuture(executeAsyncWrite(stmt), rs -> null);
return getFuture(executeAsyncWrite(auditLog.getTenantId(), stmt), rs -> null);
}
@Override
@ -169,11 +170,11 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
BoundStatement stmt = getSaveByTenantIdAndUserIdStmt().bind();
stmt = setSaveStmtVariables(stmt, auditLog, -1);
return getFuture(executeAsyncWrite(stmt), rs -> null);
return getFuture(executeAsyncWrite(auditLog.getTenantId(), stmt), rs -> null);
}
private BoundStatement setSaveStmtVariables(BoundStatement stmt, AuditLog auditLog, long partition) {
stmt.setUUID(0, auditLog.getId().getId())
stmt.setUUID(0, auditLog.getId().getId())
.setUUID(1, auditLog.getTenantId().getId())
.setUUID(2, auditLog.getCustomerId().getId())
.setUUID(3, auditLog.getEntityId().getId())
@ -200,7 +201,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
BoundStatement stmt = getPartitionInsertStmt().bind();
stmt = stmt.setUUID(0, auditLog.getTenantId().getId())
.setLong(1, partition);
return getFuture(executeAsyncWrite(stmt), rs -> null);
return getFuture(executeAsyncWrite(auditLog.getTenantId(), stmt), rs -> null);
}
private PreparedStatement getSaveByTenantStmt() {
@ -249,7 +250,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
columnsList.add(ModelConstants.AUDIT_LOG_PARTITION_PROPERTY);
}
StringJoiner values = new StringJoiner(",");
for (int i=0;i<columnsList.size();i++) {
for (int i = 0; i < columnsList.size(); i++) {
values.add("?");
}
String statementString = INSERT_INTO + cfName + " (" + String.join(",", columnsList) + ") VALUES (" + values.toString() + ")";
@ -274,7 +275,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
@Override
public List<AuditLog> findAuditLogsByTenantIdAndEntityId(UUID tenantId, EntityId entityId, TimePageLink pageLink) {
log.trace("Try to find audit logs by tenant [{}], entity [{}] and pageLink [{}]", tenantId, entityId, pageLink);
List<AuditLogEntity> entities = findPageWithTimeSearch(AUDIT_LOG_BY_ENTITY_ID_CF,
List<AuditLogEntity> entities = findPageWithTimeSearch(new TenantId(tenantId), AUDIT_LOG_BY_ENTITY_ID_CF,
Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId),
eq(ModelConstants.AUDIT_LOG_ENTITY_TYPE_PROPERTY, entityId.getEntityType()),
eq(ModelConstants.AUDIT_LOG_ENTITY_ID_PROPERTY, entityId.getId())),
@ -286,7 +287,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
@Override
public List<AuditLog> findAuditLogsByTenantIdAndCustomerId(UUID tenantId, CustomerId customerId, TimePageLink pageLink) {
log.trace("Try to find audit logs by tenant [{}], customer [{}] and pageLink [{}]", tenantId, customerId, pageLink);
List<AuditLogEntity> entities = findPageWithTimeSearch(AUDIT_LOG_BY_CUSTOMER_ID_CF,
List<AuditLogEntity> entities = findPageWithTimeSearch(new TenantId(tenantId), AUDIT_LOG_BY_CUSTOMER_ID_CF,
Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId),
eq(ModelConstants.AUDIT_LOG_CUSTOMER_ID_PROPERTY, customerId.getId())),
pageLink);
@ -297,7 +298,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
@Override
public List<AuditLog> findAuditLogsByTenantIdAndUserId(UUID tenantId, UserId userId, TimePageLink pageLink) {
log.trace("Try to find audit logs by tenant [{}], user [{}] and pageLink [{}]", tenantId, userId, pageLink);
List<AuditLogEntity> entities = findPageWithTimeSearch(AUDIT_LOG_BY_USER_ID_CF,
List<AuditLogEntity> entities = findPageWithTimeSearch(new TenantId(tenantId), AUDIT_LOG_BY_USER_ID_CF,
Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId),
eq(ModelConstants.AUDIT_LOG_USER_ID_PROPERTY, userId.getId())),
pageLink);
@ -339,7 +340,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
if (cursor.isFull() || !cursor.hasNextPartition()) {
return cursor.getData();
} else {
cursor.addData(findPageWithTimeSearch(AUDIT_LOG_BY_TENANT_ID_CF,
cursor.addData(findPageWithTimeSearch(new TenantId(cursor.getTenantId()), AUDIT_LOG_BY_TENANT_ID_CF,
Arrays.asList(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, cursor.getTenantId()),
eq(ModelConstants.AUDIT_LOG_PARTITION_PROPERTY, cursor.getNextPartition())),
cursor.getPageLink()));
@ -352,7 +353,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
.where(eq(ModelConstants.AUDIT_LOG_TENANT_ID_PROPERTY, tenantId));
select.and(QueryBuilder.gte(ModelConstants.PARTITION_COLUMN, minPartition));
select.and(QueryBuilder.lte(ModelConstants.PARTITION_COLUMN, maxPartition));
return executeRead(select);
return executeRead(new TenantId(tenantId), select);
}
}

6
dao/src/main/java/org/thingsboard/server/dao/cache/PreviousDeviceCredentialsIdKeyGenerator.java

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.cache;
import org.springframework.cache.interceptor.KeyGenerator;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
@ -28,9 +29,10 @@ public class PreviousDeviceCredentialsIdKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object o, Method method, Object... objects) {
DeviceCredentialsService deviceCredentialsService = (DeviceCredentialsService) o;
DeviceCredentials deviceCredentials = (DeviceCredentials) objects[0];
TenantId tenantId = (TenantId) objects[0];
DeviceCredentials deviceCredentials = (DeviceCredentials) objects[1];
if (deviceCredentials.getDeviceId() != null) {
DeviceCredentials oldDeviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(deviceCredentials.getDeviceId());
DeviceCredentials oldDeviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, deviceCredentials.getDeviceId());
if (oldDeviceCredentials != null) {
return oldDeviceCredentials.getCredentialsId();
}

34
dao/src/main/java/org/thingsboard/server/dao/component/BaseComponentDescriptorService.java

@ -25,6 +25,8 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.id.ComponentDescriptorId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
@ -49,50 +51,50 @@ public class BaseComponentDescriptorService implements ComponentDescriptorServic
private ComponentDescriptorDao componentDescriptorDao;
@Override
public ComponentDescriptor saveComponent(ComponentDescriptor component) {
componentValidator.validate(component);
Optional<ComponentDescriptor> result = componentDescriptorDao.saveIfNotExist(component);
public ComponentDescriptor saveComponent(TenantId tenantId, ComponentDescriptor component) {
componentValidator.validate(component, data -> new TenantId(EntityId.NULL_UUID));
Optional<ComponentDescriptor> result = componentDescriptorDao.saveIfNotExist(tenantId, component);
if (result.isPresent()) {
return result.get();
} else {
return componentDescriptorDao.findByClazz(component.getClazz());
return componentDescriptorDao.findByClazz(tenantId, component.getClazz());
}
}
@Override
public ComponentDescriptor findById(ComponentDescriptorId componentId) {
public ComponentDescriptor findById(TenantId tenantId, ComponentDescriptorId componentId) {
Validator.validateId(componentId, "Incorrect component id for search request.");
return componentDescriptorDao.findById(componentId);
return componentDescriptorDao.findById(tenantId, componentId);
}
@Override
public ComponentDescriptor findByClazz(String clazz) {
public ComponentDescriptor findByClazz(TenantId tenantId, String clazz) {
Validator.validateString(clazz, "Incorrect clazz for search request.");
return componentDescriptorDao.findByClazz(clazz);
return componentDescriptorDao.findByClazz(tenantId, clazz);
}
@Override
public TextPageData<ComponentDescriptor> findByTypeAndPageLink(ComponentType type, TextPageLink pageLink) {
public TextPageData<ComponentDescriptor> findByTypeAndPageLink(TenantId tenantId, ComponentType type, TextPageLink pageLink) {
Validator.validatePageLink(pageLink, "Incorrect PageLink object for search plugin components request.");
List<ComponentDescriptor> components = componentDescriptorDao.findByTypeAndPageLink(type, pageLink);
List<ComponentDescriptor> components = componentDescriptorDao.findByTypeAndPageLink(tenantId, type, pageLink);
return new TextPageData<>(components, pageLink);
}
@Override
public TextPageData<ComponentDescriptor> findByScopeAndTypeAndPageLink(ComponentScope scope, ComponentType type, TextPageLink pageLink) {
public TextPageData<ComponentDescriptor> findByScopeAndTypeAndPageLink(TenantId tenantId, ComponentScope scope, ComponentType type, TextPageLink pageLink) {
Validator.validatePageLink(pageLink, "Incorrect PageLink object for search plugin components request.");
List<ComponentDescriptor> components = componentDescriptorDao.findByScopeAndTypeAndPageLink(scope, type, pageLink);
List<ComponentDescriptor> components = componentDescriptorDao.findByScopeAndTypeAndPageLink(tenantId, scope, type, pageLink);
return new TextPageData<>(components, pageLink);
}
@Override
public void deleteByClazz(String clazz) {
public void deleteByClazz(TenantId tenantId, String clazz) {
Validator.validateString(clazz, "Incorrect clazz for delete request.");
componentDescriptorDao.deleteByClazz(clazz);
componentDescriptorDao.deleteByClazz(tenantId, clazz);
}
@Override
public boolean validate(ComponentDescriptor component, JsonNode configuration) {
public boolean validate(TenantId tenantId, ComponentDescriptor component, JsonNode configuration) {
JsonValidator validator = JsonSchemaFactory.byDefault().getValidator();
try {
if (!component.getConfigurationDescriptor().has("schema")) {
@ -109,7 +111,7 @@ public class BaseComponentDescriptorService implements ComponentDescriptorServic
private DataValidator<ComponentDescriptor> componentValidator =
new DataValidator<ComponentDescriptor>() {
@Override
protected void validateDataImpl(ComponentDescriptor plugin) {
protected void validateDataImpl(TenantId tenantId, ComponentDescriptor plugin) {
if (plugin.getType() == null) {
throw new DataValidationException("Component type should be specified!.");
}

37
dao/src/main/java/org/thingsboard/server/dao/component/CassandraBaseComponentDescriptorDao.java

@ -23,6 +23,7 @@ import com.datastax.driver.core.utils.UUIDs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.ComponentDescriptorId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentScope;
@ -62,10 +63,10 @@ public class CassandraBaseComponentDescriptorDao extends CassandraAbstractSearch
}
@Override
public Optional<ComponentDescriptor> saveIfNotExist(ComponentDescriptor component) {
public Optional<ComponentDescriptor> saveIfNotExist(TenantId tenantId, ComponentDescriptor component) {
ComponentDescriptorEntity entity = new ComponentDescriptorEntity(component);
log.debug("Save component entity [{}]", entity);
Optional<ComponentDescriptor> result = saveIfNotExist(entity);
Optional<ComponentDescriptor> result = saveIfNotExist(tenantId, entity);
if (log.isTraceEnabled()) {
log.trace("Saved result: [{}] for component entity [{}]", result.isPresent(), result.orElse(null));
} else {
@ -75,9 +76,9 @@ public class CassandraBaseComponentDescriptorDao extends CassandraAbstractSearch
}
@Override
public ComponentDescriptor findById(ComponentDescriptorId componentId) {
public ComponentDescriptor findById(TenantId tenantId, ComponentDescriptorId componentId) {
log.debug("Search component entity by id [{}]", componentId);
ComponentDescriptor componentDescriptor = super.findById(componentId.getId());
ComponentDescriptor componentDescriptor = super.findById(tenantId, componentId.getId());
if (log.isTraceEnabled()) {
log.trace("Search result: [{}] for component entity [{}]", componentDescriptor != null, componentDescriptor);
} else {
@ -87,11 +88,11 @@ public class CassandraBaseComponentDescriptorDao extends CassandraAbstractSearch
}
@Override
public ComponentDescriptor findByClazz(String clazz) {
public ComponentDescriptor findByClazz(TenantId tenantId, String clazz) {
log.debug("Search component entity by clazz [{}]", clazz);
Select.Where query = select().from(getColumnFamilyName()).where(eq(ModelConstants.COMPONENT_DESCRIPTOR_CLASS_PROPERTY, clazz));
log.trace("Execute query [{}]", query);
ComponentDescriptorEntity entity = findOneByStatement(query);
ComponentDescriptorEntity entity = findOneByStatement(tenantId, query);
if (log.isTraceEnabled()) {
log.trace("Search result: [{}] for component entity [{}]", entity != null, entity);
} else {
@ -101,9 +102,9 @@ public class CassandraBaseComponentDescriptorDao extends CassandraAbstractSearch
}
@Override
public List<ComponentDescriptor> findByTypeAndPageLink(ComponentType type, TextPageLink pageLink) {
public List<ComponentDescriptor> findByTypeAndPageLink(TenantId tenantId, ComponentType type, TextPageLink pageLink) {
log.debug("Try to find component by type [{}] and pageLink [{}]", type, pageLink);
List<ComponentDescriptorEntity> entities = findPageWithTextSearch(ModelConstants.COMPONENT_DESCRIPTOR_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<ComponentDescriptorEntity> entities = findPageWithTextSearch(tenantId, ModelConstants.COMPONENT_DESCRIPTOR_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Arrays.asList(eq(ModelConstants.COMPONENT_DESCRIPTOR_TYPE_PROPERTY, type)), pageLink);
if (log.isTraceEnabled()) {
log.trace(SEARCH_RESULT, Arrays.toString(entities.toArray()));
@ -114,9 +115,9 @@ public class CassandraBaseComponentDescriptorDao extends CassandraAbstractSearch
}
@Override
public List<ComponentDescriptor> findByScopeAndTypeAndPageLink(ComponentScope scope, ComponentType type, TextPageLink pageLink) {
public List<ComponentDescriptor> findByScopeAndTypeAndPageLink(TenantId tenantId, ComponentScope scope, ComponentType type, TextPageLink pageLink) {
log.debug("Try to find component by scope [{}] and type [{}] and pageLink [{}]", scope, type, pageLink);
List<ComponentDescriptorEntity> entities = findPageWithTextSearch(ModelConstants.COMPONENT_DESCRIPTOR_BY_SCOPE_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<ComponentDescriptorEntity> entities = findPageWithTextSearch(tenantId, ModelConstants.COMPONENT_DESCRIPTOR_BY_SCOPE_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Arrays.asList(eq(ModelConstants.COMPONENT_DESCRIPTOR_TYPE_PROPERTY, type),
eq(ModelConstants.COMPONENT_DESCRIPTOR_SCOPE_PROPERTY, scope.name())), pageLink);
if (log.isTraceEnabled()) {
@ -127,34 +128,34 @@ public class CassandraBaseComponentDescriptorDao extends CassandraAbstractSearch
return DaoUtil.convertDataList(entities);
}
public boolean removeById(UUID key) {
public boolean removeById(TenantId tenantId, UUID key) {
Statement delete = QueryBuilder.delete().all().from(ModelConstants.COMPONENT_DESCRIPTOR_BY_ID).where(eq(ModelConstants.ID_PROPERTY, key));
log.debug("Remove request: {}", delete.toString());
return executeWrite(delete).wasApplied();
return executeWrite(tenantId, delete).wasApplied();
}
@Override
public void deleteById(ComponentDescriptorId id) {
public void deleteById(TenantId tenantId, ComponentDescriptorId id) {
log.debug("Delete plugin meta-data entity by id [{}]", id);
boolean result = removeById(id.getId());
boolean result = removeById(tenantId, id.getId());
log.debug("Delete result: [{}]", result);
}
@Override
public void deleteByClazz(String clazz) {
public void deleteByClazz(TenantId tenantId, String clazz) {
log.debug("Delete plugin meta-data entity by id [{}]", clazz);
Statement delete = QueryBuilder.delete().all().from(getColumnFamilyName()).where(eq(ModelConstants.COMPONENT_DESCRIPTOR_CLASS_PROPERTY, clazz));
log.debug("Remove request: {}", delete.toString());
ResultSet resultSet = executeWrite(delete);
ResultSet resultSet = executeWrite(tenantId, delete);
log.debug("Delete result: [{}]", resultSet.wasApplied());
}
private Optional<ComponentDescriptor> saveIfNotExist(ComponentDescriptorEntity entity) {
private Optional<ComponentDescriptor> saveIfNotExist(TenantId tenantId, ComponentDescriptorEntity entity) {
if (entity.getId() == null) {
entity.setId(UUIDs.timeBased());
}
ResultSet rs = executeRead(QueryBuilder.insertInto(getColumnFamilyName())
ResultSet rs = executeRead(tenantId, QueryBuilder.insertInto(getColumnFamilyName())
.value(ModelConstants.ID_PROPERTY, entity.getId())
.value(ModelConstants.COMPONENT_DESCRIPTOR_NAME_PROPERTY, entity.getName())
.value(ModelConstants.COMPONENT_DESCRIPTOR_CLASS_PROPERTY, entity.getClazz())

15
dao/src/main/java/org/thingsboard/server/dao/component/ComponentDescriptorDao.java

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.component;
import org.thingsboard.server.common.data.id.ComponentDescriptorId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentScope;
@ -30,18 +31,18 @@ import java.util.Optional;
*/
public interface ComponentDescriptorDao extends Dao<ComponentDescriptor> {
Optional<ComponentDescriptor> saveIfNotExist(ComponentDescriptor component);
Optional<ComponentDescriptor> saveIfNotExist(TenantId tenantId, ComponentDescriptor component);
ComponentDescriptor findById(ComponentDescriptorId componentId);
ComponentDescriptor findById(TenantId tenantId, ComponentDescriptorId componentId);
ComponentDescriptor findByClazz(String clazz);
ComponentDescriptor findByClazz(TenantId tenantId, String clazz);
List<ComponentDescriptor> findByTypeAndPageLink(ComponentType type, TextPageLink pageLink);
List<ComponentDescriptor> findByTypeAndPageLink(TenantId tenantId, ComponentType type, TextPageLink pageLink);
List<ComponentDescriptor> findByScopeAndTypeAndPageLink(ComponentScope scope, ComponentType type, TextPageLink pageLink);
List<ComponentDescriptor> findByScopeAndTypeAndPageLink(TenantId tenantId, ComponentScope scope, ComponentType type, TextPageLink pageLink);
void deleteById(ComponentDescriptorId componentId);
void deleteById(TenantId tenantId, ComponentDescriptorId componentId);
void deleteByClazz(String clazz);
void deleteByClazz(TenantId tenantId, String clazz);
}

15
dao/src/main/java/org/thingsboard/server/dao/component/ComponentDescriptorService.java

@ -17,6 +17,7 @@ package org.thingsboard.server.dao.component;
import com.fasterxml.jackson.databind.JsonNode;
import org.thingsboard.server.common.data.id.ComponentDescriptorId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
@ -28,18 +29,18 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
*/
public interface ComponentDescriptorService {
ComponentDescriptor saveComponent(ComponentDescriptor component);
ComponentDescriptor saveComponent(TenantId tenantId, ComponentDescriptor component);
ComponentDescriptor findById(ComponentDescriptorId componentId);
ComponentDescriptor findById(TenantId tenantId, ComponentDescriptorId componentId);
ComponentDescriptor findByClazz(String clazz);
ComponentDescriptor findByClazz(TenantId tenantId, String clazz);
TextPageData<ComponentDescriptor> findByTypeAndPageLink(ComponentType type, TextPageLink pageLink);
TextPageData<ComponentDescriptor> findByTypeAndPageLink(TenantId tenantId, ComponentType type, TextPageLink pageLink);
TextPageData<ComponentDescriptor> findByScopeAndTypeAndPageLink(ComponentScope scope, ComponentType type, TextPageLink pageLink);
TextPageData<ComponentDescriptor> findByScopeAndTypeAndPageLink(TenantId tenantId, ComponentScope scope, ComponentType type, TextPageLink pageLink);
boolean validate(ComponentDescriptor component, JsonNode configuration);
boolean validate(TenantId tenantId, ComponentDescriptor component, JsonNode configuration);
void deleteByClazz(String clazz);
void deleteByClazz(TenantId tenantId, String clazz);
}

8
dao/src/main/java/org/thingsboard/server/dao/customer/CassandraCustomerDao.java

@ -19,6 +19,7 @@ import com.datastax.driver.core.querybuilder.Select;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.ModelConstants;
@ -36,6 +37,7 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_BY_TENANT_AND_TITLE_VIEW_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_TENANT_ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_TITLE_PROPERTY;
@Component
@Slf4j
@NoSqlDao
@ -54,9 +56,9 @@ public class CassandraCustomerDao extends CassandraAbstractSearchTextDao<Custome
@Override
public List<Customer> findCustomersByTenantId(UUID tenantId, TextPageLink pageLink) {
log.debug("Try to find customers by tenantId [{}] and pageLink [{}]", tenantId, pageLink);
List<CustomerEntity> customerEntities = findPageWithTextSearch(ModelConstants.CUSTOMER_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<CustomerEntity> customerEntities = findPageWithTextSearch(new TenantId(tenantId), ModelConstants.CUSTOMER_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Arrays.asList(eq(ModelConstants.CUSTOMER_TENANT_ID_PROPERTY, tenantId)),
pageLink);
pageLink);
log.trace("Found customers [{}] by tenantId [{}] and pageLink [{}]", customerEntities, tenantId, pageLink);
return DaoUtil.convertDataList(customerEntities);
}
@ -67,7 +69,7 @@ public class CassandraCustomerDao extends CassandraAbstractSearchTextDao<Custome
Select.Where query = select.where();
query.and(eq(CUSTOMER_TENANT_ID_PROPERTY, tenantId));
query.and(eq(CUSTOMER_TITLE_PROPERTY, title));
CustomerEntity customerEntity = findOneByStatement(query);
CustomerEntity customerEntity = findOneByStatement(new TenantId(tenantId), query);
Customer customer = DaoUtil.getData(customerEntity);
return Optional.ofNullable(customer);
}

3
dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.customer;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.Dao;
@ -34,7 +35,7 @@ public interface CustomerDao extends Dao<Customer> {
* @param customer the customer object
* @return saved customer object
*/
Customer save(Customer customer);
Customer save(TenantId tenantId, Customer customer);
/**
* Find customers by tenant id and page link.

6
dao/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java

@ -26,15 +26,15 @@ import java.util.Optional;
public interface CustomerService {
Customer findCustomerById(CustomerId customerId);
Customer findCustomerById(TenantId tenantId, CustomerId customerId);
Optional<Customer> findCustomerByTenantIdAndTitle(TenantId tenantId, String title);
ListenableFuture<Customer> findCustomerByIdAsync(CustomerId customerId);
ListenableFuture<Customer> findCustomerByIdAsync(TenantId tenantId, CustomerId customerId);
Customer saveCustomer(Customer customer);
void deleteCustomer(CustomerId customerId);
void deleteCustomer(TenantId tenantId, CustomerId customerId);
Customer findOrCreatePublicCustomer(TenantId tenantId);

42
dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java

@ -77,10 +77,10 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
private DashboardService dashboardService;
@Override
public Customer findCustomerById(CustomerId customerId) {
public Customer findCustomerById(TenantId tenantId, CustomerId customerId) {
log.trace("Executing findCustomerById [{}]", customerId);
Validator.validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
return customerDao.findById(customerId.getId());
return customerDao.findById(tenantId, customerId.getId());
}
@Override
@ -91,36 +91,36 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
}
@Override
public ListenableFuture<Customer> findCustomerByIdAsync(CustomerId customerId) {
public ListenableFuture<Customer> findCustomerByIdAsync(TenantId tenantId, CustomerId customerId) {
log.trace("Executing findCustomerByIdAsync [{}]", customerId);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
return customerDao.findByIdAsync(customerId.getId());
return customerDao.findByIdAsync(tenantId, customerId.getId());
}
@Override
public Customer saveCustomer(Customer customer) {
log.trace("Executing saveCustomer [{}]", customer);
customerValidator.validate(customer);
Customer savedCustomer = customerDao.save(customer);
dashboardService.updateCustomerDashboards(savedCustomer.getId());
customerValidator.validate(customer, Customer::getTenantId);
Customer savedCustomer = customerDao.save(customer.getTenantId(), customer);
dashboardService.updateCustomerDashboards(savedCustomer.getTenantId(), savedCustomer.getId());
return savedCustomer;
}
@Override
public void deleteCustomer(CustomerId customerId) {
public void deleteCustomer(TenantId tenantId, CustomerId customerId) {
log.trace("Executing deleteCustomer [{}]", customerId);
Validator.validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
Customer customer = findCustomerById(customerId);
Customer customer = findCustomerById(tenantId, customerId);
if (customer == null) {
throw new IncorrectParameterException("Unable to delete non-existent customer.");
}
dashboardService.unassignCustomerDashboards(customerId);
dashboardService.unassignCustomerDashboards(tenantId, customerId);
entityViewService.unassignCustomerEntityViews(customer.getTenantId(), customerId);
assetService.unassignCustomerAssets(customer.getTenantId(), customerId);
deviceService.unassignCustomerDevices(customer.getTenantId(), customerId);
userService.deleteCustomerUsers(customer.getTenantId(), customerId);
deleteEntityRelations(customerId);
customerDao.removeById(customerId.getId());
deleteEntityRelations(tenantId, customerId);
customerDao.removeById(tenantId, customerId.getId());
}
@Override
@ -139,7 +139,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
} catch (IOException e) {
throw new IncorrectParameterException("Unable to create public customer.", e);
}
return customerDao.save(publicCustomer);
return customerDao.save(tenantId, publicCustomer);
}
}
@ -156,14 +156,14 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
public void deleteCustomersByTenantId(TenantId tenantId) {
log.trace("Executing deleteCustomersByTenantId, tenantId [{}]", tenantId);
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId);
customersByTenantRemover.removeEntities(tenantId);
customersByTenantRemover.removeEntities(tenantId, tenantId);
}
private DataValidator<Customer> customerValidator =
new DataValidator<Customer>() {
@Override
protected void validateCreate(Customer customer) {
protected void validateCreate(TenantId tenantId, Customer customer) {
customerDao.findCustomersByTenantIdAndTitle(customer.getTenantId().getId(), customer.getTitle()).ifPresent(
c -> {
throw new DataValidationException("Customer with such title already exists!");
@ -172,7 +172,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
}
@Override
protected void validateUpdate(Customer customer) {
protected void validateUpdate(TenantId tenantId, Customer customer) {
customerDao.findCustomersByTenantIdAndTitle(customer.getTenantId().getId(), customer.getTitle()).ifPresent(
c -> {
if (!c.getId().equals(customer.getId())) {
@ -183,7 +183,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
}
@Override
protected void validateDataImpl(Customer customer) {
protected void validateDataImpl(TenantId tenantId, Customer customer) {
if (StringUtils.isEmpty(customer.getTitle())) {
throw new DataValidationException("Customer title should be specified!");
}
@ -196,7 +196,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
if (customer.getTenantId() == null) {
throw new DataValidationException("Customer should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(customer.getTenantId().getId());
Tenant tenant = tenantDao.findById(tenantId, customer.getTenantId().getId());
if (tenant == null) {
throw new DataValidationException("Customer is referencing to non-existent tenant!");
}
@ -208,13 +208,13 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
new PaginatedRemover<TenantId, Customer>() {
@Override
protected List<Customer> findEntities(TenantId id, TextPageLink pageLink) {
protected List<Customer> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) {
return customerDao.findCustomersByTenantId(id.getId(), pageLink);
}
@Override
protected void removeEntity(Customer entity) {
deleteCustomer(new CustomerId(entity.getUuidId()));
protected void removeEntity(TenantId tenantId, Customer entity) {
deleteCustomer(tenantId, new CustomerId(entity.getUuidId()));
}
};
}

7
dao/src/main/java/org/thingsboard/server/dao/dashboard/CassandraDashboardInfoDao.java

@ -23,6 +23,7 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
@ -64,7 +65,7 @@ public class CassandraDashboardInfoDao extends CassandraAbstractSearchTextDao<Da
@Override
public List<DashboardInfo> findDashboardsByTenantId(UUID tenantId, TextPageLink pageLink) {
log.debug("Try to find dashboards by tenantId [{}] and pageLink [{}]", tenantId, pageLink);
List<DashboardInfoEntity> dashboardEntities = findPageWithTextSearch(DASHBOARD_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<DashboardInfoEntity> dashboardEntities = findPageWithTextSearch(new TenantId(tenantId), DASHBOARD_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Collections.singletonList(eq(DASHBOARD_TENANT_ID_PROPERTY, tenantId)),
pageLink);
@ -76,12 +77,12 @@ public class CassandraDashboardInfoDao extends CassandraAbstractSearchTextDao<Da
public ListenableFuture<List<DashboardInfo>> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TimePageLink pageLink) {
log.debug("Try to find dashboards by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink);
ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new CustomerId(customerId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD, EntityType.DASHBOARD, pageLink);
ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new CustomerId(customerId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD, EntityType.DASHBOARD, pageLink);
return Futures.transformAsync(relations, input -> {
List<ListenableFuture<DashboardInfo>> dashboardFutures = new ArrayList<>(input.size());
for (EntityRelation relation : input) {
dashboardFutures.add(findByIdAsync(relation.getTo().getId()));
dashboardFutures.add(findByIdAsync(new TenantId(tenantId), relation.getTo().getId()));
}
return Futures.successfulAsList(dashboardFutures);
});

3
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.dashboard;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.Dao;
/**
@ -29,6 +30,6 @@ public interface DashboardDao extends Dao<Dashboard> {
* @param dashboard the dashboard object
* @return saved dashboard object
*/
Dashboard save(Dashboard dashboard);
Dashboard save(TenantId tenantId, Dashboard dashboard);
}

18
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java

@ -28,21 +28,21 @@ import org.thingsboard.server.common.data.page.TimePageLink;
public interface DashboardService {
Dashboard findDashboardById(DashboardId dashboardId);
Dashboard findDashboardById(TenantId tenantId, DashboardId dashboardId);
ListenableFuture<Dashboard> findDashboardByIdAsync(DashboardId dashboardId);
ListenableFuture<Dashboard> findDashboardByIdAsync(TenantId tenantId, DashboardId dashboardId);
DashboardInfo findDashboardInfoById(DashboardId dashboardId);
DashboardInfo findDashboardInfoById(TenantId tenantId, DashboardId dashboardId);
ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(DashboardId dashboardId);
ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(TenantId tenantId, DashboardId dashboardId);
Dashboard saveDashboard(Dashboard dashboard);
Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId);
Dashboard assignDashboardToCustomer(TenantId tenantId, DashboardId dashboardId, CustomerId customerId);
Dashboard unassignDashboardFromCustomer(DashboardId dashboardId, CustomerId customerId);
Dashboard unassignDashboardFromCustomer(TenantId tenantId, DashboardId dashboardId, CustomerId customerId);
void deleteDashboard(DashboardId dashboardId);
void deleteDashboard(TenantId tenantId, DashboardId dashboardId);
TextPageData<DashboardInfo> findDashboardsByTenantId(TenantId tenantId, TextPageLink pageLink);
@ -50,8 +50,8 @@ public interface DashboardService {
ListenableFuture<TimePageData<DashboardInfo>> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink);
void unassignCustomerDashboards(CustomerId customerId);
void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId);
void updateCustomerDashboards(CustomerId customerId);
void updateCustomerDashboards(TenantId tenantId, CustomerId customerId);
}

78
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java

@ -69,44 +69,44 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
private CustomerDao customerDao;
@Override
public Dashboard findDashboardById(DashboardId dashboardId) {
public Dashboard findDashboardById(TenantId tenantId, DashboardId dashboardId) {
log.trace("Executing findDashboardById [{}]", dashboardId);
Validator.validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId);
return dashboardDao.findById(dashboardId.getId());
return dashboardDao.findById(tenantId, dashboardId.getId());
}
@Override
public ListenableFuture<Dashboard> findDashboardByIdAsync(DashboardId dashboardId) {
public ListenableFuture<Dashboard> findDashboardByIdAsync(TenantId tenantId, DashboardId dashboardId) {
log.trace("Executing findDashboardByIdAsync [{}]", dashboardId);
validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId);
return dashboardDao.findByIdAsync(dashboardId.getId());
return dashboardDao.findByIdAsync(tenantId, dashboardId.getId());
}
@Override
public DashboardInfo findDashboardInfoById(DashboardId dashboardId) {
public DashboardInfo findDashboardInfoById(TenantId tenantId, DashboardId dashboardId) {
log.trace("Executing findDashboardInfoById [{}]", dashboardId);
Validator.validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId);
return dashboardInfoDao.findById(dashboardId.getId());
return dashboardInfoDao.findById(tenantId, dashboardId.getId());
}
@Override
public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(DashboardId dashboardId) {
public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(TenantId tenantId, DashboardId dashboardId) {
log.trace("Executing findDashboardInfoByIdAsync [{}]", dashboardId);
validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId);
return dashboardInfoDao.findByIdAsync(dashboardId.getId());
return dashboardInfoDao.findByIdAsync(tenantId, dashboardId.getId());
}
@Override
public Dashboard saveDashboard(Dashboard dashboard) {
log.trace("Executing saveDashboard [{}]", dashboard);
dashboardValidator.validate(dashboard);
return dashboardDao.save(dashboard);
dashboardValidator.validate(dashboard, DashboardInfo::getTenantId);
return dashboardDao.save(dashboard.getTenantId(), dashboard);
}
@Override
public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId) {
Dashboard dashboard = findDashboardById(dashboardId);
Customer customer = customerDao.findById(customerId.getId());
public Dashboard assignDashboardToCustomer(TenantId tenantId, DashboardId dashboardId, CustomerId customerId) {
Dashboard dashboard = findDashboardById(tenantId, dashboardId);
Customer customer = customerDao.findById(tenantId, customerId.getId());
if (customer == null) {
throw new DataValidationException("Can't assign dashboard to non-existent customer!");
}
@ -115,7 +115,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
}
if (dashboard.addAssignedCustomer(customer)) {
try {
createRelation(new EntityRelation(customerId, dashboardId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD));
createRelation(tenantId, new EntityRelation(customerId, dashboardId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD));
} catch (ExecutionException | InterruptedException e) {
log.warn("[{}] Failed to create dashboard relation. Customer Id: [{}]", dashboardId, customerId);
throw new RuntimeException(e);
@ -127,15 +127,15 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
}
@Override
public Dashboard unassignDashboardFromCustomer(DashboardId dashboardId, CustomerId customerId) {
Dashboard dashboard = findDashboardById(dashboardId);
Customer customer = customerDao.findById(customerId.getId());
public Dashboard unassignDashboardFromCustomer(TenantId tenantId, DashboardId dashboardId, CustomerId customerId) {
Dashboard dashboard = findDashboardById(tenantId, dashboardId);
Customer customer = customerDao.findById(tenantId, customerId.getId());
if (customer == null) {
throw new DataValidationException("Can't unassign dashboard from non-existent customer!");
}
if (dashboard.removeAssignedCustomer(customer)) {
try {
deleteRelation(new EntityRelation(customerId, dashboardId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD));
deleteRelation(tenantId, new EntityRelation(customerId, dashboardId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD));
} catch (ExecutionException | InterruptedException e) {
log.warn("[{}] Failed to delete dashboard relation. Customer Id: [{}]", dashboardId, customerId);
throw new RuntimeException(e);
@ -146,8 +146,8 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
}
}
private Dashboard updateAssignedCustomer(DashboardId dashboardId, Customer customer) {
Dashboard dashboard = findDashboardById(dashboardId);
private Dashboard updateAssignedCustomer(TenantId tenantId, DashboardId dashboardId, Customer customer) {
Dashboard dashboard = findDashboardById(tenantId, dashboardId);
if (dashboard.updateAssignedCustomer(customer)) {
return saveDashboard(dashboard);
} else {
@ -155,22 +155,22 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
}
}
private void deleteRelation(EntityRelation dashboardRelation) throws ExecutionException, InterruptedException {
private void deleteRelation(TenantId tenantId, EntityRelation dashboardRelation) throws ExecutionException, InterruptedException {
log.debug("Deleting Dashboard relation: {}", dashboardRelation);
relationService.deleteRelationAsync(dashboardRelation).get();
relationService.deleteRelationAsync(tenantId, dashboardRelation).get();
}
private void createRelation(EntityRelation dashboardRelation) throws ExecutionException, InterruptedException {
private void createRelation(TenantId tenantId, EntityRelation dashboardRelation) throws ExecutionException, InterruptedException {
log.debug("Creating Dashboard relation: {}", dashboardRelation);
relationService.saveRelationAsync(dashboardRelation).get();
relationService.saveRelationAsync(tenantId, dashboardRelation).get();
}
@Override
public void deleteDashboard(DashboardId dashboardId) {
public void deleteDashboard(TenantId tenantId, DashboardId dashboardId) {
log.trace("Executing deleteDashboard [{}]", dashboardId);
Validator.validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId);
deleteEntityRelations(dashboardId);
dashboardDao.removeById(dashboardId.getId());
deleteEntityRelations(tenantId, dashboardId);
dashboardDao.removeById(tenantId, dashboardId.getId());
}
@Override
@ -186,7 +186,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
public void deleteDashboardsByTenantId(TenantId tenantId) {
log.trace("Executing deleteDashboardsByTenantId, tenantId [{}]", tenantId);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
tenantDashboardsRemover.removeEntities(tenantId);
tenantDashboardsRemover.removeEntities(tenantId, tenantId);
}
@Override
@ -207,10 +207,10 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
}
@Override
public void unassignCustomerDashboards(CustomerId customerId) {
public void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId) {
log.trace("Executing unassignCustomerDashboards, customerId [{}]", customerId);
Validator.validateId(customerId, "Incorrect customerId " + customerId);
Customer customer = customerDao.findById(customerId.getId());
Customer customer = customerDao.findById(tenantId, customerId.getId());
if (customer == null) {
throw new DataValidationException("Can't unassign dashboards from non-existent customer!");
}
@ -218,10 +218,10 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
}
@Override
public void updateCustomerDashboards(CustomerId customerId) {
public void updateCustomerDashboards(TenantId tenantId, CustomerId customerId) {
log.trace("Executing updateCustomerDashboards, customerId [{}]", customerId);
Validator.validateId(customerId, "Incorrect customerId " + customerId);
Customer customer = customerDao.findById(customerId.getId());
Customer customer = customerDao.findById(tenantId, customerId.getId());
if (customer == null) {
throw new DataValidationException("Can't update dashboards for non-existent customer!");
}
@ -231,14 +231,14 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
private DataValidator<Dashboard> dashboardValidator =
new DataValidator<Dashboard>() {
@Override
protected void validateDataImpl(Dashboard dashboard) {
protected void validateDataImpl(TenantId tenantId, Dashboard dashboard) {
if (StringUtils.isEmpty(dashboard.getTitle())) {
throw new DataValidationException("Dashboard title should be specified!");
}
if (dashboard.getTenantId() == null) {
throw new DataValidationException("Dashboard should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(dashboard.getTenantId().getId());
Tenant tenant = tenantDao.findById(tenantId, dashboard.getTenantId().getId());
if (tenant == null) {
throw new DataValidationException("Dashboard is referencing to non-existent tenant!");
}
@ -250,13 +250,13 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
new PaginatedRemover<TenantId, DashboardInfo>() {
@Override
protected List<DashboardInfo> findEntities(TenantId id, TextPageLink pageLink) {
protected List<DashboardInfo> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) {
return dashboardInfoDao.findDashboardsByTenantId(id.getId(), pageLink);
}
@Override
protected void removeEntity(DashboardInfo entity) {
deleteDashboard(new DashboardId(entity.getUuidId()));
protected void removeEntity(TenantId tenantId, DashboardInfo entity) {
deleteDashboard(tenantId, new DashboardId(entity.getUuidId()));
}
};
@ -280,7 +280,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Override
protected void removeEntity(DashboardInfo entity) {
unassignDashboardFromCustomer(new DashboardId(entity.getUuidId()), this.customer.getId());
unassignDashboardFromCustomer(customer.getTenantId(), new DashboardId(entity.getUuidId()), this.customer.getId());
}
}
@ -305,7 +305,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Override
protected void removeEntity(DashboardInfo entity) {
updateAssignedCustomer(new DashboardId(entity.getUuidId()), this.customer);
updateAssignedCustomer(customer.getTenantId(), new DashboardId(entity.getUuidId()), this.customer);
}
}

9
dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceCredentialsDao.java

@ -18,6 +18,7 @@ package org.thingsboard.server.dao.device;
import com.datastax.driver.core.querybuilder.Select.Where;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.ModelConstants;
@ -46,23 +47,23 @@ public class CassandraDeviceCredentialsDao extends CassandraAbstractModelDao<Dev
}
@Override
public DeviceCredentials findByDeviceId(UUID deviceId) {
public DeviceCredentials findByDeviceId(TenantId tenantId, UUID deviceId) {
log.debug("Try to find device credentials by deviceId [{}] ", deviceId);
Where query = select().from(ModelConstants.DEVICE_CREDENTIALS_BY_DEVICE_COLUMN_FAMILY_NAME)
.where(eq(ModelConstants.DEVICE_CREDENTIALS_DEVICE_ID_PROPERTY, deviceId));
log.trace("Execute query {}", query);
DeviceCredentialsEntity deviceCredentialsEntity = findOneByStatement(query);
DeviceCredentialsEntity deviceCredentialsEntity = findOneByStatement(tenantId, query);
log.trace("Found device credentials [{}] by deviceId [{}]", deviceCredentialsEntity, deviceId);
return DaoUtil.getData(deviceCredentialsEntity);
}
@Override
public DeviceCredentials findByCredentialsId(String credentialsId) {
public DeviceCredentials findByCredentialsId(TenantId tenantId, String credentialsId) {
log.debug("Try to find device credentials by credentialsId [{}] ", credentialsId);
Where query = select().from(ModelConstants.DEVICE_CREDENTIALS_BY_CREDENTIALS_ID_COLUMN_FAMILY_NAME)
.where(eq(ModelConstants.DEVICE_CREDENTIALS_CREDENTIALS_ID_PROPERTY, credentialsId));
log.trace("Execute query {}", query);
DeviceCredentialsEntity deviceCredentialsEntity = findOneByStatement(query);
DeviceCredentialsEntity deviceCredentialsEntity = findOneByStatement(tenantId, query);
log.trace("Found device credentials [{}] by credentialsId [{}]", deviceCredentialsEntity, credentialsId);
return DaoUtil.getData(deviceCredentialsEntity);
}

23
dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java

@ -28,6 +28,7 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.EntitySubtypeEntity;
@ -77,19 +78,19 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEnt
}
@Override
public Device save(Device domain) {
Device savedDevice = super.save(domain);
public Device save(TenantId tenantId, Device domain) {
Device savedDevice = super.save(tenantId, domain);
EntitySubtype entitySubtype = new EntitySubtype(savedDevice.getTenantId(), EntityType.DEVICE, savedDevice.getType());
EntitySubtypeEntity entitySubtypeEntity = new EntitySubtypeEntity(entitySubtype);
Statement saveStatement = cluster.getMapper(EntitySubtypeEntity.class).saveQuery(entitySubtypeEntity);
executeWrite(saveStatement);
executeWrite(tenantId, saveStatement);
return savedDevice;
}
@Override
public List<Device> findDevicesByTenantId(UUID tenantId, TextPageLink pageLink) {
log.debug("Try to find devices by tenantId [{}] and pageLink [{}]", tenantId, pageLink);
List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<DeviceEntity> deviceEntities = findPageWithTextSearch(new TenantId(tenantId), DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Collections.singletonList(eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), pageLink);
log.trace("Found devices [{}] by tenantId [{}] and pageLink [{}]", deviceEntities, tenantId, pageLink);
@ -99,7 +100,7 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEnt
@Override
public List<Device> findDevicesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
log.debug("Try to find devices by tenantId [{}], type [{}] and pageLink [{}]", tenantId, type, pageLink);
List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<DeviceEntity> deviceEntities = findPageWithTextSearch(new TenantId(tenantId), DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type),
eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), pageLink);
log.trace("Found devices [{}] by tenantId [{}], type [{}] and pageLink [{}]", deviceEntities, tenantId, type, pageLink);
@ -113,13 +114,13 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEnt
Select.Where query = select.where();
query.and(eq(DEVICE_TENANT_ID_PROPERTY, tenantId));
query.and(in(ID_PROPERTY, deviceIds));
return findListByStatementAsync(query);
return findListByStatementAsync(new TenantId(tenantId), query);
}
@Override
public List<Device> findDevicesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) {
log.debug("Try to find devices by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink);
List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<DeviceEntity> deviceEntities = findPageWithTextSearch(new TenantId(tenantId), DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId),
eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
pageLink);
@ -131,7 +132,7 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEnt
@Override
public List<Device> findDevicesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
log.debug("Try to find devices by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink);
List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
List<DeviceEntity> deviceEntities = findPageWithTextSearch(new TenantId(tenantId), DEVICE_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type),
eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId),
eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
@ -149,7 +150,7 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEnt
query.and(eq(DEVICE_TENANT_ID_PROPERTY, tenantId));
query.and(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId));
query.and(in(ID_PROPERTY, deviceIds));
return findListByStatementAsync(query);
return findListByStatementAsync(new TenantId(tenantId), query);
}
@Override
@ -158,7 +159,7 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEnt
Select.Where query = select.where();
query.and(eq(DEVICE_TENANT_ID_PROPERTY, tenantId));
query.and(eq(DEVICE_NAME_PROPERTY, deviceName));
return Optional.ofNullable(DaoUtil.getData(findOneByStatement(query)));
return Optional.ofNullable(DaoUtil.getData(findOneByStatement(new TenantId(tenantId), query)));
}
@Override
@ -168,7 +169,7 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEnt
query.and(eq(ENTITY_SUBTYPE_TENANT_ID_PROPERTY, tenantId));
query.and(eq(ENTITY_SUBTYPE_ENTITY_TYPE_PROPERTY, EntityType.DEVICE));
query.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
ResultSetFuture resultSetFuture = executeAsyncRead(query);
ResultSetFuture resultSetFuture = executeAsyncRead(new TenantId(tenantId), query);
return Futures.transform(resultSetFuture, new Function<ResultSet, List<EntitySubtype>>() {
@Nullable
@Override

8
dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsDao.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.device;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.Dao;
@ -28,10 +29,11 @@ public interface DeviceCredentialsDao extends Dao<DeviceCredentials> {
/**
* Save or update device credentials object
*
* @param tenantId the device tenant id
* @param deviceCredentials the device credentials object
* @return saved device credentials object
*/
DeviceCredentials save(DeviceCredentials deviceCredentials);
DeviceCredentials save(TenantId tenantId, DeviceCredentials deviceCredentials);
/**
* Find device credentials by device id.
@ -39,7 +41,7 @@ public interface DeviceCredentialsDao extends Dao<DeviceCredentials> {
* @param deviceId the device id
* @return the device credentials object
*/
DeviceCredentials findByDeviceId(UUID deviceId);
DeviceCredentials findByDeviceId(TenantId tenantId, UUID deviceId);
/**
* Find device credentials by credentials id.
@ -47,6 +49,6 @@ public interface DeviceCredentialsDao extends Dao<DeviceCredentials> {
* @param credentialsId the credentials id
* @return the device credentials object
*/
DeviceCredentials findByCredentialsId(String credentialsId);
DeviceCredentials findByCredentialsId(TenantId tenantId, String credentialsId);
}

9
dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsService.java

@ -16,17 +16,18 @@
package org.thingsboard.server.dao.device;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
public interface DeviceCredentialsService {
DeviceCredentials findDeviceCredentialsByDeviceId(DeviceId deviceId);
DeviceCredentials findDeviceCredentialsByDeviceId(TenantId tenantId, DeviceId deviceId);
DeviceCredentials findDeviceCredentialsByCredentialsId(String credentialsId);
DeviceCredentials updateDeviceCredentials(DeviceCredentials deviceCredentials);
DeviceCredentials updateDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials);
DeviceCredentials createDeviceCredentials(DeviceCredentials deviceCredentials);
DeviceCredentials createDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials);
void deleteDeviceCredentials(DeviceCredentials deviceCredentials);
void deleteDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials);
}

46
dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java

@ -24,6 +24,8 @@ import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.common.msg.EncryptionUtil;
@ -45,38 +47,38 @@ public class DeviceCredentialsServiceImpl implements DeviceCredentialsService {
private DeviceService deviceService;
@Override
public DeviceCredentials findDeviceCredentialsByDeviceId(DeviceId deviceId) {
public DeviceCredentials findDeviceCredentialsByDeviceId(TenantId tenantId, DeviceId deviceId) {
log.trace("Executing findDeviceCredentialsByDeviceId [{}]", deviceId);
validateId(deviceId, "Incorrect deviceId " + deviceId);
return deviceCredentialsDao.findByDeviceId(deviceId.getId());
return deviceCredentialsDao.findByDeviceId(tenantId, deviceId.getId());
}
@Override
@Cacheable(cacheNames = DEVICE_CREDENTIALS_CACHE, unless="#result == null")
@Cacheable(cacheNames = DEVICE_CREDENTIALS_CACHE, unless = "#result == null")
public DeviceCredentials findDeviceCredentialsByCredentialsId(String credentialsId) {
log.trace("Executing findDeviceCredentialsByCredentialsId [{}]", credentialsId);
validateString(credentialsId, "Incorrect credentialsId " + credentialsId);
return deviceCredentialsDao.findByCredentialsId(credentialsId);
return deviceCredentialsDao.findByCredentialsId(new TenantId(EntityId.NULL_UUID), credentialsId);
}
@Override
@CacheEvict(cacheNames = DEVICE_CREDENTIALS_CACHE, keyGenerator="previousDeviceCredentialsId", beforeInvocation = true)
public DeviceCredentials updateDeviceCredentials(DeviceCredentials deviceCredentials) {
return saveOrUpdate(deviceCredentials);
@CacheEvict(cacheNames = DEVICE_CREDENTIALS_CACHE, keyGenerator = "previousDeviceCredentialsId", beforeInvocation = true)
public DeviceCredentials updateDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials) {
return saveOrUpdate(tenantId, deviceCredentials);
}
@Override
public DeviceCredentials createDeviceCredentials(DeviceCredentials deviceCredentials) {
return saveOrUpdate(deviceCredentials);
public DeviceCredentials createDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials) {
return saveOrUpdate(tenantId, deviceCredentials);
}
private DeviceCredentials saveOrUpdate(DeviceCredentials deviceCredentials) {
private DeviceCredentials saveOrUpdate(TenantId tenantId, DeviceCredentials deviceCredentials) {
if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) {
formatCertData(deviceCredentials);
}
log.trace("Executing updateDeviceCredentials [{}]", deviceCredentials);
credentialsValidator.validate(deviceCredentials);
return deviceCredentialsDao.save(deviceCredentials);
credentialsValidator.validate(deviceCredentials, id -> tenantId);
return deviceCredentialsDao.save(tenantId, deviceCredentials);
}
private void formatCertData(DeviceCredentials deviceCredentials) {
@ -87,37 +89,37 @@ public class DeviceCredentialsServiceImpl implements DeviceCredentialsService {
}
@Override
@CacheEvict(cacheNames = DEVICE_CREDENTIALS_CACHE, key="#deviceCredentials.credentialsId")
public void deleteDeviceCredentials(DeviceCredentials deviceCredentials) {
@CacheEvict(cacheNames = DEVICE_CREDENTIALS_CACHE, key = "#deviceCredentials.credentialsId")
public void deleteDeviceCredentials(TenantId tenantId, DeviceCredentials deviceCredentials) {
log.trace("Executing deleteDeviceCredentials [{}]", deviceCredentials);
deviceCredentialsDao.removeById(deviceCredentials.getUuidId());
deviceCredentialsDao.removeById(tenantId, deviceCredentials.getUuidId());
}
private DataValidator<DeviceCredentials> credentialsValidator =
new DataValidator<DeviceCredentials>() {
@Override
protected void validateCreate(DeviceCredentials deviceCredentials) {
DeviceCredentials existingCredentialsEntity = deviceCredentialsDao.findByCredentialsId(deviceCredentials.getCredentialsId());
protected void validateCreate(TenantId tenantId, DeviceCredentials deviceCredentials) {
DeviceCredentials existingCredentialsEntity = deviceCredentialsDao.findByCredentialsId(tenantId, deviceCredentials.getCredentialsId());
if (existingCredentialsEntity != null) {
throw new DataValidationException("Create of existent device credentials!");
}
}
@Override
protected void validateUpdate(DeviceCredentials deviceCredentials) {
DeviceCredentials existingCredentials = deviceCredentialsDao.findById(deviceCredentials.getUuidId());
protected void validateUpdate(TenantId tenantId, DeviceCredentials deviceCredentials) {
DeviceCredentials existingCredentials = deviceCredentialsDao.findById(tenantId, deviceCredentials.getUuidId());
if (existingCredentials == null) {
throw new DataValidationException("Unable to update non-existent device credentials!");
}
DeviceCredentials sameCredentialsId = deviceCredentialsDao.findByCredentialsId(deviceCredentials.getCredentialsId());
DeviceCredentials sameCredentialsId = deviceCredentialsDao.findByCredentialsId(tenantId, deviceCredentials.getCredentialsId());
if (sameCredentialsId != null && !sameCredentialsId.getUuidId().equals(deviceCredentials.getUuidId())) {
throw new DataValidationException("Specified credentials are already registered!");
}
}
@Override
protected void validateDataImpl(DeviceCredentials deviceCredentials) {
protected void validateDataImpl(TenantId tenantId, DeviceCredentials deviceCredentials) {
if (deviceCredentials.getDeviceId() == null) {
throw new DataValidationException("Device credentials should be assigned to device!");
}
@ -127,7 +129,7 @@ public class DeviceCredentialsServiceImpl implements DeviceCredentialsService {
if (StringUtils.isEmpty(deviceCredentials.getCredentialsId())) {
throw new DataValidationException("Device credentials id should be specified!");
}
Device device = deviceService.findDeviceById(deviceCredentials.getDeviceId());
Device device = deviceService.findDeviceById(tenantId, deviceCredentials.getDeviceId());
if (device == null) {
throw new DataValidationException("Can't assign device credentials to non-existent device!");
}

3
dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java

@ -18,6 +18,7 @@ package org.thingsboard.server.dao.device;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.Dao;
@ -37,7 +38,7 @@ public interface DeviceDao extends Dao<Device> {
* @param device the device object
* @return saved device object
*/
Device save(Device device);
Device save(TenantId tenantId, Device device);
/**
* Find devices by tenantId and page link.

12
dao/src/main/java/org/thingsboard/server/dao/device/DeviceService.java

@ -29,19 +29,19 @@ import java.util.List;
public interface DeviceService {
Device findDeviceById(DeviceId deviceId);
Device findDeviceById(TenantId tenantId, DeviceId deviceId);
ListenableFuture<Device> findDeviceByIdAsync(DeviceId deviceId);
ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId);
Device findDeviceByTenantIdAndName(TenantId tenantId, String name);
Device saveDevice(Device device);
Device assignDeviceToCustomer(DeviceId deviceId, CustomerId customerId);
Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, CustomerId customerId);
Device unassignDeviceFromCustomer(DeviceId deviceId);
Device unassignDeviceFromCustomer(TenantId tenantId, DeviceId deviceId);
void deleteDevice(DeviceId deviceId);
void deleteDevice(TenantId tenantId, DeviceId deviceId);
TextPageData<Device> findDevicesByTenantId(TenantId tenantId, TextPageLink pageLink);
@ -59,7 +59,7 @@ public interface DeviceService {
void unassignCustomerDevices(TenantId tenantId, CustomerId customerId);
ListenableFuture<List<Device>> findDevicesByQuery(DeviceSearchQuery query);
ListenableFuture<List<Device>> findDevicesByQuery(TenantId tenantId, DeviceSearchQuery query);
ListenableFuture<List<EntitySubtype>> findDeviceTypesByTenantId(TenantId tenantId);

93
dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java

@ -96,17 +96,17 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
private CacheManager cacheManager;
@Override
public Device findDeviceById(DeviceId deviceId) {
public Device findDeviceById(TenantId tenantId, DeviceId deviceId) {
log.trace("Executing findDeviceById [{}]", deviceId);
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId);
return deviceDao.findById(deviceId.getId());
return deviceDao.findById(tenantId, deviceId.getId());
}
@Override
public ListenableFuture<Device> findDeviceByIdAsync(DeviceId deviceId) {
public ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId) {
log.trace("Executing findDeviceById [{}]", deviceId);
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId);
return deviceDao.findByIdAsync(deviceId.getId());
return deviceDao.findByIdAsync(tenantId, deviceId.getId());
}
@Cacheable(cacheNames = DEVICE_CACHE, key = "{#tenantId, #name}")
@ -122,38 +122,38 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
@Override
public Device saveDevice(Device device) {
log.trace("Executing saveDevice [{}]", device);
deviceValidator.validate(device);
Device savedDevice = deviceDao.save(device);
deviceValidator.validate(device, Device::getTenantId);
Device savedDevice = deviceDao.save(device.getTenantId(), device);
if (device.getId() == null) {
DeviceCredentials deviceCredentials = new DeviceCredentials();
deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId()));
deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
deviceCredentials.setCredentialsId(RandomStringUtils.randomAlphanumeric(20));
deviceCredentialsService.createDeviceCredentials(deviceCredentials);
deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials);
}
return savedDevice;
}
@Override
public Device assignDeviceToCustomer(DeviceId deviceId, CustomerId customerId) {
Device device = findDeviceById(deviceId);
public Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, CustomerId customerId) {
Device device = findDeviceById(tenantId, deviceId);
device.setCustomerId(customerId);
return saveDevice(device);
}
@Override
public Device unassignDeviceFromCustomer(DeviceId deviceId) {
Device device = findDeviceById(deviceId);
public Device unassignDeviceFromCustomer(TenantId tenantId, DeviceId deviceId) {
Device device = findDeviceById(tenantId, deviceId);
device.setCustomerId(null);
return saveDevice(device);
}
@Override
public void deleteDevice(DeviceId deviceId) {
public void deleteDevice(TenantId tenantId, DeviceId deviceId) {
log.trace("Executing deleteDevice [{}]", deviceId);
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId);
Device device = deviceDao.findById(deviceId.getId());
Device device = deviceDao.findById(tenantId, deviceId.getId());
try {
List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), deviceId).get();
if (entityViews != null && !entityViews.isEmpty()) {
@ -164,11 +164,11 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
throw new RuntimeException("Exception while finding entity views for deviceId [" + deviceId + "]", e);
}
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(deviceId);
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, deviceId);
if (deviceCredentials != null) {
deviceCredentialsService.deleteDeviceCredentials(deviceCredentials);
deviceCredentialsService.deleteDeviceCredentials(tenantId, deviceCredentials);
}
deleteEntityRelations(deviceId);
deleteEntityRelations(tenantId, deviceId);
List<Object> list = new ArrayList<>();
list.add(device.getTenantId());
@ -176,7 +176,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
Cache cache = cacheManager.getCache(DEVICE_CACHE);
cache.evict(list);
deviceDao.removeById(deviceId.getId());
deviceDao.removeById(tenantId, deviceId.getId());
}
@Override
@ -211,7 +211,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
public void deleteDevicesByTenantId(TenantId tenantId) {
log.trace("Executing deleteDevicesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
tenantDevicesRemover.removeEntities(tenantId);
tenantDevicesRemover.removeEntities(tenantId, tenantId);
}
@Override
@ -250,19 +250,19 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
log.trace("Executing unassignCustomerDevices, tenantId [{}], customerId [{}]", tenantId, customerId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
new CustomerDevicesUnassigner(tenantId).removeEntities(customerId);
customerDeviceUnasigner.removeEntities(tenantId, customerId);
}
@Override
public ListenableFuture<List<Device>> findDevicesByQuery(DeviceSearchQuery query) {
ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(query.toEntitySearchQuery());
public ListenableFuture<List<Device>> findDevicesByQuery(TenantId tenantId, DeviceSearchQuery query) {
ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(tenantId, query.toEntitySearchQuery());
ListenableFuture<List<Device>> devices = Futures.transformAsync(relations, r -> {
EntitySearchDirection direction = query.toEntitySearchQuery().getParameters().getDirection();
List<ListenableFuture<Device>> futures = new ArrayList<>();
for (EntityRelation relation : r) {
EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom();
if (entityId.getEntityType() == EntityType.DEVICE) {
futures.add(findDeviceByIdAsync(new DeviceId(entityId.getId())));
futures.add(findDeviceByIdAsync(tenantId, new DeviceId(entityId.getId())));
}
}
return Futures.successfulAsList(futures);
@ -285,7 +285,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
ListenableFuture<List<EntitySubtype>> tenantDeviceTypes = deviceDao.findTenantDeviceTypesAsync(tenantId.getId());
return Futures.transform(tenantDeviceTypes,
(Function<List<EntitySubtype>, List<EntitySubtype>>) deviceTypes -> {
deviceTypes -> {
deviceTypes.sort(Comparator.comparing(EntitySubtype::getType));
return deviceTypes;
});
@ -295,7 +295,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
new DataValidator<Device>() {
@Override
protected void validateCreate(Device device) {
protected void validateCreate(TenantId tenantId, Device device) {
deviceDao.findDeviceByTenantIdAndName(device.getTenantId().getId(), device.getName()).ifPresent(
d -> {
throw new DataValidationException("Device with such name already exists!");
@ -304,7 +304,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
}
@Override
protected void validateUpdate(Device device) {
protected void validateUpdate(TenantId tenantId, Device device) {
deviceDao.findDeviceByTenantIdAndName(device.getTenantId().getId(), device.getName()).ifPresent(
d -> {
if (!d.getUuidId().equals(device.getUuidId())) {
@ -315,7 +315,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
}
@Override
protected void validateDataImpl(Device device) {
protected void validateDataImpl(TenantId tenantId, Device device) {
if (StringUtils.isEmpty(device.getType())) {
throw new DataValidationException("Device type should be specified!");
}
@ -325,7 +325,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
if (device.getTenantId() == null) {
throw new DataValidationException("Device should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(device.getTenantId().getId());
Tenant tenant = tenantDao.findById(device.getTenantId(), device.getTenantId().getId());
if (tenant == null) {
throw new DataValidationException("Device is referencing to non-existent tenant!");
}
@ -333,7 +333,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
if (device.getCustomerId() == null) {
device.setCustomerId(new CustomerId(NULL_UUID));
} else if (!device.getCustomerId().getId().equals(NULL_UUID)) {
Customer customer = customerDao.findById(device.getCustomerId().getId());
Customer customer = customerDao.findById(device.getTenantId(), device.getCustomerId().getId());
if (customer == null) {
throw new DataValidationException("Can't assign device to non-existent customer!");
}
@ -345,36 +345,29 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
};
private PaginatedRemover<TenantId, Device> tenantDevicesRemover =
new PaginatedRemover<TenantId, Device>() {
new PaginatedRemover<TenantId, Device>() {
@Override
protected List<Device> findEntities(TenantId id, TextPageLink pageLink) {
return deviceDao.findDevicesByTenantId(id.getId(), pageLink);
}
@Override
protected void removeEntity(Device entity) {
deleteDevice(new DeviceId(entity.getUuidId()));
}
};
private class CustomerDevicesUnassigner extends PaginatedRemover<CustomerId, Device> {
@Override
protected List<Device> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) {
return deviceDao.findDevicesByTenantId(id.getId(), pageLink);
}
private TenantId tenantId;
@Override
protected void removeEntity(TenantId tenantId, Device entity) {
deleteDevice(tenantId, new DeviceId(entity.getUuidId()));
}
};
CustomerDevicesUnassigner(TenantId tenantId) {
this.tenantId = tenantId;
}
private PaginatedRemover<CustomerId, Device> customerDeviceUnasigner = new PaginatedRemover<CustomerId, Device>() {
@Override
protected List<Device> findEntities(CustomerId id, TextPageLink pageLink) {
protected List<Device> findEntities(TenantId tenantId, CustomerId id, TextPageLink pageLink) {
return deviceDao.findDevicesByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink);
}
@Override
protected void removeEntity(Device entity) {
unassignDeviceFromCustomer(new DeviceId(entity.getUuidId()));
protected void removeEntity(TenantId tenantId, Device entity) {
unassignDeviceFromCustomer(tenantId, new DeviceId(entity.getUuidId()));
}
}
};
}

5
dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java

@ -18,6 +18,7 @@ package org.thingsboard.server.dao.entity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.relation.RelationService;
@Slf4j
@ -26,9 +27,9 @@ public abstract class AbstractEntityService {
@Autowired
protected RelationService relationService;
protected void deleteEntityRelations(EntityId entityId) {
protected void deleteEntityRelations(TenantId tenantId, EntityId entityId) {
log.trace("Executing deleteEntityRelations [{}]", entityId);
relationService.deleteEntityRelations(entityId);
relationService.deleteEntityRelations(tenantId, entityId);
}
}

24
dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java

@ -69,42 +69,42 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
private RuleChainService ruleChainService;
@Override
public void deleteEntityRelations(EntityId entityId) {
super.deleteEntityRelations(entityId);
public void deleteEntityRelations(TenantId tenantId, EntityId entityId) {
super.deleteEntityRelations(tenantId, entityId);
}
@Override
public ListenableFuture<String> fetchEntityNameAsync(EntityId entityId) {
public ListenableFuture<String> fetchEntityNameAsync(TenantId tenantId, EntityId entityId) {
log.trace("Executing fetchEntityNameAsync [{}]", entityId);
ListenableFuture<String> entityName;
ListenableFuture<? extends HasName> hasName;
switch (entityId.getEntityType()) {
case ASSET:
hasName = assetService.findAssetByIdAsync(new AssetId(entityId.getId()));
hasName = assetService.findAssetByIdAsync(tenantId, new AssetId(entityId.getId()));
break;
case DEVICE:
hasName = deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId()));
hasName = deviceService.findDeviceByIdAsync(tenantId, new DeviceId(entityId.getId()));
break;
case ENTITY_VIEW:
hasName = entityViewService.findEntityViewByIdAsync(new EntityViewId(entityId.getId()));
hasName = entityViewService.findEntityViewByIdAsync(tenantId, new EntityViewId(entityId.getId()));
break;
case TENANT:
hasName = tenantService.findTenantByIdAsync(new TenantId(entityId.getId()));
hasName = tenantService.findTenantByIdAsync(tenantId, new TenantId(entityId.getId()));
break;
case CUSTOMER:
hasName = customerService.findCustomerByIdAsync(new CustomerId(entityId.getId()));
hasName = customerService.findCustomerByIdAsync(tenantId, new CustomerId(entityId.getId()));
break;
case USER:
hasName = userService.findUserByIdAsync(new UserId(entityId.getId()));
hasName = userService.findUserByIdAsync(tenantId, new UserId(entityId.getId()));
break;
case DASHBOARD:
hasName = dashboardService.findDashboardInfoByIdAsync(new DashboardId(entityId.getId()));
hasName = dashboardService.findDashboardInfoByIdAsync(tenantId, new DashboardId(entityId.getId()));
break;
case ALARM:
hasName = alarmService.findAlarmByIdAsync(new AlarmId(entityId.getId()));
hasName = alarmService.findAlarmByIdAsync(tenantId, new AlarmId(entityId.getId()));
break;
case RULE_CHAIN:
hasName = ruleChainService.findRuleChainByIdAsync(new RuleChainId(entityId.getId()));
hasName = ruleChainService.findRuleChainByIdAsync(tenantId, new RuleChainId(entityId.getId()));
break;
default:
throw new IllegalStateException("Not Implemented!");

5
dao/src/main/java/org/thingsboard/server/dao/entity/EntityService.java

@ -17,11 +17,12 @@ package org.thingsboard.server.dao.entity;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
public interface EntityService {
ListenableFuture<String> fetchEntityNameAsync(EntityId entityId);
ListenableFuture<String> fetchEntityNameAsync(TenantId tenantId, EntityId entityId);
void deleteEntityRelations(EntityId entityId);
void deleteEntityRelations(TenantId tenantId, EntityId entityId);
}

21
dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java

@ -28,6 +28,7 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.EntitySubtypeEntity;
@ -82,12 +83,12 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
}
@Override
public EntityView save(EntityView domain) {
EntityView savedEntityView = super.save(domain);
public EntityView save(TenantId tenantId, EntityView domain) {
EntityView savedEntityView = super.save(domain.getTenantId(), domain);
EntitySubtype entitySubtype = new EntitySubtype(savedEntityView.getTenantId(), EntityType.ENTITY_VIEW, savedEntityView.getType());
EntitySubtypeEntity entitySubtypeEntity = new EntitySubtypeEntity(entitySubtype);
Statement saveStatement = cluster.getMapper(EntitySubtypeEntity.class).saveQuery(entitySubtypeEntity);
executeWrite(saveStatement);
executeWrite(tenantId, saveStatement);
return savedEntityView;
}
@ -95,7 +96,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
public List<EntityView> findEntityViewsByTenantId(UUID tenantId, TextPageLink pageLink) {
log.debug("Try to find entity views by tenantId [{}] and pageLink [{}]", tenantId, pageLink);
List<EntityViewEntity> entityViewEntities =
findPageWithTextSearch(ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_CF,
findPageWithTextSearch(new TenantId(tenantId), ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_CF,
Collections.singletonList(eq(TENANT_ID_PROPERTY, tenantId)), pageLink);
log.trace("Found entity views [{}] by tenantId [{}] and pageLink [{}]",
entityViewEntities, tenantId, pageLink);
@ -106,7 +107,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
public List<EntityView> findEntityViewsByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
log.debug("Try to find entity views by tenantId [{}], type [{}] and pageLink [{}]", tenantId, type, pageLink);
List<EntityViewEntity> entityViewEntities =
findPageWithTextSearch(ENTITY_VIEW_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_CF,
findPageWithTextSearch(new TenantId(tenantId), ENTITY_VIEW_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_CF,
Arrays.asList(eq(ENTITY_VIEW_TYPE_PROPERTY, type),
eq(TENANT_ID_PROPERTY, tenantId)), pageLink);
log.trace("Found entity views [{}] by tenantId [{}], type [{}] and pageLink [{}]",
@ -119,14 +120,14 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
Select.Where query = select().from(ENTITY_VIEW_BY_TENANT_AND_NAME).where();
query.and(eq(ENTITY_VIEW_TENANT_ID_PROPERTY, tenantId));
query.and(eq(ENTITY_VIEW_NAME_PROPERTY, name));
return Optional.ofNullable(DaoUtil.getData(findOneByStatement(query)));
return Optional.ofNullable(DaoUtil.getData(findOneByStatement(new TenantId(tenantId), query)));
}
@Override
public List<EntityView> findEntityViewsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) {
log.debug("Try to find entity views by tenantId [{}], customerId[{}] and pageLink [{}]",
tenantId, customerId, pageLink);
List<EntityViewEntity> entityViewEntities = findPageWithTextSearch(
List<EntityViewEntity> entityViewEntities = findPageWithTextSearch(new TenantId(tenantId),
ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF,
Arrays.asList(eq(CUSTOMER_ID_PROPERTY, customerId), eq(TENANT_ID_PROPERTY, tenantId)),
pageLink);
@ -139,7 +140,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
public List<EntityView> findEntityViewsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
log.debug("Try to find entity views by tenantId [{}], customerId[{}], type [{}] and pageLink [{}]",
tenantId, customerId, type, pageLink);
List<EntityViewEntity> entityViewEntities = findPageWithTextSearch(
List<EntityViewEntity> entityViewEntities = findPageWithTextSearch(new TenantId(tenantId),
ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_TYPE_CF,
Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type), eq(CUSTOMER_ID_PROPERTY, customerId), eq(TENANT_ID_PROPERTY, tenantId)),
pageLink);
@ -154,7 +155,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
Select.Where query = select().from(ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF).where();
query.and(eq(TENANT_ID_PROPERTY, tenantId));
query.and(eq(ENTITY_ID_COLUMN, entityId));
return findListByStatementAsync(query);
return findListByStatementAsync(new TenantId(tenantId), query);
}
@Override
@ -164,7 +165,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
query.and(eq(ENTITY_SUBTYPE_TENANT_ID_PROPERTY, tenantId));
query.and(eq(ENTITY_SUBTYPE_ENTITY_TYPE_PROPERTY, EntityType.ENTITY_VIEW));
query.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
ResultSetFuture resultSetFuture = executeAsyncRead(query);
ResultSetFuture resultSetFuture = executeAsyncRead(new TenantId(tenantId), query);
return Futures.transform(resultSetFuture, new Function<ResultSet, List<EntitySubtype>>() {
@Nullable
@Override

3
dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java

@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.Dao;
@ -37,7 +38,7 @@ public interface EntityViewDao extends Dao<EntityView> {
* @param entityView the entity-view object
* @return saved entity-view object
*/
EntityView save(EntityView entityView);
EntityView save(TenantId tenantId, EntityView entityView);
/**
* Find entity views by tenantId and page link.

13
dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java

@ -18,6 +18,7 @@ package org.thingsboard.server.dao.entityview;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
@ -35,13 +36,13 @@ public interface EntityViewService {
EntityView saveEntityView(EntityView entityView);
EntityView assignEntityViewToCustomer(EntityViewId entityViewId, CustomerId customerId);
EntityView assignEntityViewToCustomer(TenantId tenantId, EntityViewId entityViewId, CustomerId customerId);
EntityView unassignEntityViewFromCustomer(EntityViewId entityViewId);
EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId);
void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId);
EntityView findEntityViewById(EntityViewId entityViewId);
EntityView findEntityViewById(TenantId tenantId, EntityViewId entityViewId);
EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name);
@ -53,13 +54,13 @@ public interface EntityViewService {
TextPageData<EntityView> findEntityViewsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, TextPageLink pageLink, String type);
ListenableFuture<List<EntityView>> findEntityViewsByQuery(EntityViewSearchQuery query);
ListenableFuture<List<EntityView>> findEntityViewsByQuery(TenantId tenantId, EntityViewSearchQuery query);
ListenableFuture<EntityView> findEntityViewByIdAsync(EntityViewId entityViewId);
ListenableFuture<EntityView> findEntityViewByIdAsync(TenantId tenantId, EntityViewId entityViewId);
ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId);
void deleteEntityView(EntityViewId entityViewId);
void deleteEntityView(TenantId tenantId, EntityViewId entityViewId);
void deleteEntityViewsByTenantId(TenantId tenantId);

85
dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java

@ -95,23 +95,23 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
@Override
public EntityView saveEntityView(EntityView entityView) {
log.trace("Executing save entity view [{}]", entityView);
entityViewValidator.validate(entityView);
EntityView savedEntityView = entityViewDao.save(entityView);
entityViewValidator.validate(entityView, EntityView::getTenantId);
EntityView savedEntityView = entityViewDao.save(entityView.getTenantId(), entityView);
return savedEntityView;
}
@CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}")
@Override
public EntityView assignEntityViewToCustomer(EntityViewId entityViewId, CustomerId customerId) {
EntityView entityView = findEntityViewById(entityViewId);
public EntityView assignEntityViewToCustomer(TenantId tenantId, EntityViewId entityViewId, CustomerId customerId) {
EntityView entityView = findEntityViewById(tenantId, entityViewId);
entityView.setCustomerId(customerId);
return saveEntityView(entityView);
}
@CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}")
@Override
public EntityView unassignEntityViewFromCustomer(EntityViewId entityViewId) {
EntityView entityView = findEntityViewById(entityViewId);
public EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId) {
EntityView entityView = findEntityViewById(tenantId, entityViewId);
entityView.setCustomerId(null);
return saveEntityView(entityView);
}
@ -121,15 +121,15 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
log.trace("Executing unassignCustomerEntityViews, tenantId [{}], customerId [{}]", tenantId, customerId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId);
customerEntityViewsUnAssigner.removeEntities(tenantId, customerId);
}
@Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}")
@Override
public EntityView findEntityViewById(EntityViewId entityViewId) {
public EntityView findEntityViewById(TenantId tenantId, EntityViewId entityViewId) {
log.trace("Executing findEntityViewById [{}]", entityViewId);
validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId);
return entityViewDao.findById(entityViewId.getId());
return entityViewDao.findById(tenantId, entityViewId.getId());
}
@Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #name}")
@ -187,15 +187,15 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
}
@Override
public ListenableFuture<List<EntityView>> findEntityViewsByQuery(EntityViewSearchQuery query) {
ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(query.toEntitySearchQuery());
public ListenableFuture<List<EntityView>> findEntityViewsByQuery(TenantId tenantId, EntityViewSearchQuery query) {
ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(tenantId, query.toEntitySearchQuery());
ListenableFuture<List<EntityView>> entityViews = Futures.transformAsync(relations, r -> {
EntitySearchDirection direction = query.toEntitySearchQuery().getParameters().getDirection();
List<ListenableFuture<EntityView>> futures = new ArrayList<>();
for (EntityRelation relation : r) {
EntityId entityId = direction == EntitySearchDirection.FROM ? relation.getTo() : relation.getFrom();
if (entityId.getEntityType() == EntityType.ENTITY_VIEW) {
futures.add(findEntityViewByIdAsync(new EntityViewId(entityId.getId())));
futures.add(findEntityViewByIdAsync(tenantId, new EntityViewId(entityId.getId())));
}
}
return Futures.successfulAsList(futures);
@ -213,10 +213,10 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
}
@Override
public ListenableFuture<EntityView> findEntityViewByIdAsync(EntityViewId entityViewId) {
public ListenableFuture<EntityView> findEntityViewByIdAsync(TenantId tenantId, EntityViewId entityViewId) {
log.trace("Executing findEntityViewById [{}]", entityViewId);
validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId);
return entityViewDao.findByIdAsync(entityViewId.getId());
return entityViewDao.findByIdAsync(tenantId, entityViewId.getId());
}
@Override
@ -253,21 +253,21 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
@CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}")
@Override
public void deleteEntityView(EntityViewId entityViewId) {
public void deleteEntityView(TenantId tenantId, EntityViewId entityViewId) {
log.trace("Executing deleteEntityView [{}]", entityViewId);
validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId);
deleteEntityRelations(entityViewId);
EntityView entityView = entityViewDao.findById(entityViewId.getId());
deleteEntityRelations(tenantId, entityViewId);
EntityView entityView = entityViewDao.findById(tenantId, entityViewId.getId());
cacheManager.getCache(ENTITY_VIEW_CACHE).evict(Arrays.asList(entityView.getTenantId(), entityView.getEntityId()));
cacheManager.getCache(ENTITY_VIEW_CACHE).evict(Arrays.asList(entityView.getTenantId(), entityView.getName()));
entityViewDao.removeById(entityViewId.getId());
entityViewDao.removeById(tenantId, entityViewId.getId());
}
@Override
public void deleteEntityViewsByTenantId(TenantId tenantId) {
log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
tenantEntityViewRemover.removeEntities(tenantId);
tenantEntityViewRemover.removeEntities(tenantId, tenantId);
}
@Override
@ -286,7 +286,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
new DataValidator<EntityView>() {
@Override
protected void validateCreate(EntityView entityView) {
protected void validateCreate(TenantId tenantId, EntityView entityView) {
entityViewDao.findEntityViewByTenantIdAndName(entityView.getTenantId().getId(), entityView.getName())
.ifPresent(e -> {
throw new DataValidationException("Entity view with such name already exists!");
@ -294,7 +294,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
}
@Override
protected void validateUpdate(EntityView entityView) {
protected void validateUpdate(TenantId tenantId, EntityView entityView) {
entityViewDao.findEntityViewByTenantIdAndName(entityView.getTenantId().getId(), entityView.getName())
.ifPresent(e -> {
if (!e.getUuidId().equals(entityView.getUuidId())) {
@ -304,7 +304,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
}
@Override
protected void validateDataImpl(EntityView entityView) {
protected void validateDataImpl(TenantId tenantId, EntityView entityView) {
if (StringUtils.isEmpty(entityView.getType())) {
throw new DataValidationException("Entity View type should be specified!");
}
@ -314,7 +314,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
if (entityView.getTenantId() == null) {
throw new DataValidationException("Entity view should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(entityView.getTenantId().getId());
Tenant tenant = tenantDao.findById(tenantId, entityView.getTenantId().getId());
if (tenant == null) {
throw new DataValidationException("Entity view is referencing to non-existent tenant!");
}
@ -322,7 +322,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
if (entityView.getCustomerId() == null) {
entityView.setCustomerId(new CustomerId(NULL_UUID));
} else if (!entityView.getCustomerId().getId().equals(NULL_UUID)) {
Customer customer = customerDao.findById(entityView.getCustomerId().getId());
Customer customer = customerDao.findById(tenantId, entityView.getCustomerId().getId());
if (customer == null) {
throw new DataValidationException("Can't assign entity view to non-existent customer!");
}
@ -333,36 +333,27 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
}
};
private PaginatedRemover<TenantId, EntityView> tenantEntityViewRemover =
new PaginatedRemover<TenantId, EntityView>() {
@Override
protected List<EntityView> findEntities(TenantId id, TextPageLink pageLink) {
return entityViewDao.findEntityViewsByTenantId(id.getId(), pageLink);
}
@Override
protected void removeEntity(EntityView entity) {
deleteEntityView(new EntityViewId(entity.getUuidId()));
}
};
private class CustomerEntityViewsUnAssigner extends PaginatedRemover<CustomerId, EntityView> {
private TenantId tenantId;
private PaginatedRemover<TenantId, EntityView> tenantEntityViewRemover = new PaginatedRemover<TenantId, EntityView>() {
@Override
protected List<EntityView> findEntities(TenantId tenantId, TenantId id, TextPageLink pageLink) {
return entityViewDao.findEntityViewsByTenantId(id.getId(), pageLink);
}
CustomerEntityViewsUnAssigner(TenantId tenantId) {
this.tenantId = tenantId;
@Override
protected void removeEntity(TenantId tenantId, EntityView entity) {
deleteEntityView(tenantId, new EntityViewId(entity.getUuidId()));
}
};
private PaginatedRemover<CustomerId, EntityView> customerEntityViewsUnAssigner = new PaginatedRemover<CustomerId, EntityView>() {
@Override
protected List<EntityView> findEntities(CustomerId id, TextPageLink pageLink) {
protected List<EntityView> findEntities(TenantId tenantId, CustomerId id, TextPageLink pageLink) {
return entityViewDao.findEntityViewsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink);
}
@Override
protected void removeEntity(EntityView entity) {
unassignEntityViewFromCustomer(new EntityViewId(entity.getUuidId()));
protected void removeEntity(TenantId tenantId, EntityView entity) {
unassignEntityViewFromCustomer(tenantId, new EntityViewId(entity.getUuidId()));
}
}
};
}

10
dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java

@ -40,19 +40,19 @@ public class BaseEventService implements EventService {
@Override
public Event save(Event event) {
eventValidator.validate(event);
return eventDao.save(event);
eventValidator.validate(event, Event::getTenantId);
return eventDao.save(event.getTenantId(), event);
}
@Override
public ListenableFuture<Event> saveAsync(Event event) {
eventValidator.validate(event);
eventValidator.validate(event, Event::getTenantId);
return eventDao.saveAsync(event);
}
@Override
public Optional<Event> saveIfNotExists(Event event) {
eventValidator.validate(event);
eventValidator.validate(event, Event::getTenantId);
if (StringUtils.isEmpty(event.getUid())) {
throw new DataValidationException("Event uid should be specified!.");
}
@ -97,7 +97,7 @@ public class BaseEventService implements EventService {
private DataValidator<Event> eventValidator =
new DataValidator<Event>() {
@Override
protected void validateDataImpl(Event event) {
protected void validateDataImpl(TenantId tenantId, Event event) {
if (event.getEntityId() == null) {
throw new DataValidationException("Entity id should be specified!.");
}

22
dao/src/main/java/org/thingsboard/server/dao/event/CassandraBaseEventDao.java

@ -64,7 +64,7 @@ public class CassandraBaseEventDao extends CassandraAbstractSearchTimeDao<EventE
}
@Override
public Event save(Event event) {
public Event save(TenantId tenantId, Event event) {
try {
return saveAsync(event).get();
} catch (InterruptedException | ExecutionException e) {
@ -85,7 +85,7 @@ public class CassandraBaseEventDao extends CassandraAbstractSearchTimeDao<EventE
if (StringUtils.isEmpty(event.getUid())) {
event.setUid(event.getId().toString());
}
ListenableFuture<Optional<Event>> optionalSave = saveAsync(new EventEntity(event), false);
ListenableFuture<Optional<Event>> optionalSave = saveAsync(event.getTenantId(), new EventEntity(event), false);
return Futures.transform(optionalSave, opt -> opt.orElse(null));
}
@ -98,7 +98,7 @@ public class CassandraBaseEventDao extends CassandraAbstractSearchTimeDao<EventE
if (event.getId() == null) {
event.setId(new EventId(UUIDs.timeBased()));
}
return save(new EventEntity(event), true);
return save(event.getTenantId(), new EventEntity(event), true);
}
@Override
@ -111,7 +111,7 @@ public class CassandraBaseEventDao extends CassandraAbstractSearchTimeDao<EventE
.and(eq(ModelConstants.EVENT_TYPE_PROPERTY, eventType))
.and(eq(ModelConstants.EVENT_UID_PROPERTY, eventUid));
log.trace("Execute query [{}]", query);
EventEntity entity = findOneByStatement(query);
EventEntity entity = findOneByStatement(new TenantId(tenantId), query);
if (log.isTraceEnabled()) {
log.trace("Search result: [{}] for event entity [{}]", entity != null, entity);
} else {
@ -123,7 +123,7 @@ public class CassandraBaseEventDao extends CassandraAbstractSearchTimeDao<EventE
@Override
public List<Event> findEvents(UUID tenantId, EntityId entityId, TimePageLink pageLink) {
log.trace("Try to find events by tenant [{}], entity [{}]and pageLink [{}]", tenantId, entityId, pageLink);
List<EventEntity> entities = findPageWithTimeSearch(EVENT_BY_ID_VIEW_NAME,
List<EventEntity> entities = findPageWithTimeSearch(new TenantId(tenantId), EVENT_BY_ID_VIEW_NAME,
Arrays.asList(eq(ModelConstants.EVENT_TENANT_ID_PROPERTY, tenantId),
eq(ModelConstants.EVENT_ENTITY_TYPE_PROPERTY, entityId.getEntityType()),
eq(ModelConstants.EVENT_ENTITY_ID_PROPERTY, entityId.getId())),
@ -135,7 +135,7 @@ public class CassandraBaseEventDao extends CassandraAbstractSearchTimeDao<EventE
@Override
public List<Event> findEvents(UUID tenantId, EntityId entityId, String eventType, TimePageLink pageLink) {
log.trace("Try to find events by tenant [{}], entity [{}], type [{}] and pageLink [{}]", tenantId, entityId, eventType, pageLink);
List<EventEntity> entities = findPageWithTimeSearch(EVENT_BY_TYPE_AND_ID_VIEW_NAME,
List<EventEntity> entities = findPageWithTimeSearch(new TenantId(tenantId), EVENT_BY_TYPE_AND_ID_VIEW_NAME,
Arrays.asList(eq(ModelConstants.EVENT_TENANT_ID_PROPERTY, tenantId),
eq(ModelConstants.EVENT_ENTITY_TYPE_PROPERTY, entityId.getEntityType()),
eq(ModelConstants.EVENT_ENTITY_ID_PROPERTY, entityId.getId()),
@ -158,19 +158,19 @@ public class CassandraBaseEventDao extends CassandraAbstractSearchTimeDao<EventE
query.and(eq(ModelConstants.EVENT_TYPE_PROPERTY, eventType));
query.limit(limit);
query.orderBy(QueryBuilder.desc(ModelConstants.EVENT_TYPE_PROPERTY), QueryBuilder.desc(ModelConstants.ID_PROPERTY));
List<EventEntity> entities = findListByStatement(query);
List<EventEntity> entities = findListByStatement(new TenantId(tenantId), query);
return DaoUtil.convertDataList(entities);
}
private Optional<Event> save(EventEntity entity, boolean ifNotExists) {
private Optional<Event> save(TenantId tenantId, EventEntity entity, boolean ifNotExists) {
try {
return saveAsync(entity, ifNotExists).get();
return saveAsync(tenantId, entity, ifNotExists).get();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("Could not save EventEntity", e);
}
}
private ListenableFuture<Optional<Event>> saveAsync(EventEntity entity, boolean ifNotExists) {
private ListenableFuture<Optional<Event>> saveAsync(TenantId tenantId, EventEntity entity, boolean ifNotExists) {
if (entity.getId() == null) {
entity.setId(UUIDs.timeBased());
}
@ -185,7 +185,7 @@ public class CassandraBaseEventDao extends CassandraAbstractSearchTimeDao<EventE
if (ifNotExists) {
insert = insert.ifNotExists();
}
ResultSetFuture resultSetFuture = executeAsyncWrite(insert);
ResultSetFuture resultSetFuture = executeAsyncWrite(tenantId, insert);
return Futures.transform(resultSetFuture, rs -> {
if (rs.wasApplied()) {
return Optional.of(DaoUtil.getData(entity));

3
dao/src/main/java/org/thingsboard/server/dao/event/EventDao.java

@ -18,6 +18,7 @@ package org.thingsboard.server.dao.event;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.Dao;
@ -36,7 +37,7 @@ public interface EventDao extends Dao<Event> {
* @param event the event object
* @return saved event object
*/
Event save(Event event);
Event save(TenantId tenantId, Event event);
/**
* Save or update event object async

25
dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java

@ -27,6 +27,7 @@ import com.datastax.driver.core.TypeCodec;
import com.datastax.driver.core.exceptions.CodecNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.cassandra.CassandraCluster;
import org.thingsboard.server.dao.model.type.AuthorityCodec;
import org.thingsboard.server.dao.model.type.ComponentLifecycleStateCodec;
@ -84,37 +85,37 @@ public abstract class CassandraAbstractDao {
}
}
protected ResultSet executeRead(Statement statement) {
return execute(statement, defaultReadLevel);
protected ResultSet executeRead(TenantId tenantId, Statement statement) {
return execute(tenantId, statement, defaultReadLevel);
}
protected ResultSet executeWrite(Statement statement) {
return execute(statement, defaultWriteLevel);
protected ResultSet executeWrite(TenantId tenantId, Statement statement) {
return execute(tenantId, statement, defaultWriteLevel);
}
protected ResultSetFuture executeAsyncRead(Statement statement) {
return executeAsync(statement, defaultReadLevel);
protected ResultSetFuture executeAsyncRead(TenantId tenantId, Statement statement) {
return executeAsync(tenantId, statement, defaultReadLevel);
}
protected ResultSetFuture executeAsyncWrite(Statement statement) {
return executeAsync(statement, defaultWriteLevel);
protected ResultSetFuture executeAsyncWrite(TenantId tenantId, Statement statement) {
return executeAsync(tenantId, statement, defaultWriteLevel);
}
private ResultSet execute(Statement statement, ConsistencyLevel level) {
private ResultSet execute(TenantId tenantId, Statement statement, ConsistencyLevel level) {
if (log.isDebugEnabled()) {
log.debug("Execute cassandra statement {}", statementToString(statement));
}
return executeAsync(statement, level).getUninterruptibly();
return executeAsync(tenantId, statement, level).getUninterruptibly();
}
private ResultSetFuture executeAsync(Statement statement, ConsistencyLevel level) {
private ResultSetFuture executeAsync(TenantId tenantId, Statement statement, ConsistencyLevel level) {
if (log.isDebugEnabled()) {
log.debug("Execute cassandra async statement {}", statementToString(statement));
}
if (statement.getConsistencyLevel() == null) {
statement.setConsistencyLevel(level);
}
return rateLimiter.submit(new CassandraStatementTask(getSession(), statement));
return rateLimiter.submit(new CassandraStatementTask(tenantId, getSession(), statement));
}
private static String statementToString(Statement statement) {

54
dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractModelDao.java

@ -27,6 +27,7 @@ import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.BaseEntity;
@ -56,11 +57,11 @@ public abstract class CassandraAbstractModelDao<E extends BaseEntity<D>, D> exte
return cluster.getMapper(getColumnFamilyClass());
}
protected List<E> findListByStatement(Statement statement) {
protected List<E> findListByStatement(TenantId tenantId, Statement statement) {
List<E> list = Collections.emptyList();
if (statement != null) {
statement.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
ResultSet resultSet = executeRead(statement);
ResultSet resultSet = executeRead(tenantId, statement);
Result<E> result = getMapper().map(resultSet);
if (result != null) {
list = result.all();
@ -69,10 +70,10 @@ public abstract class CassandraAbstractModelDao<E extends BaseEntity<D>, D> exte
return list;
}
protected ListenableFuture<List<D>> findListByStatementAsync(Statement statement) {
protected ListenableFuture<List<D>> findListByStatementAsync(TenantId tenantId, Statement statement) {
if (statement != null) {
statement.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
ResultSetFuture resultSetFuture = executeAsyncRead(statement);
ResultSetFuture resultSetFuture = executeAsyncRead(tenantId, statement);
return Futures.transform(resultSetFuture, new Function<ResultSet, List<D>>() {
@Nullable
@Override
@ -90,11 +91,11 @@ public abstract class CassandraAbstractModelDao<E extends BaseEntity<D>, D> exte
return Futures.immediateFuture(Collections.emptyList());
}
protected E findOneByStatement(Statement statement) {
protected E findOneByStatement(TenantId tenantId, Statement statement) {
E object = null;
if (statement != null) {
statement.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
ResultSet resultSet = executeRead(statement);
ResultSet resultSet = executeRead(tenantId, statement);
Result<E> result = getMapper().map(resultSet);
if (result != null) {
object = result.one();
@ -103,10 +104,10 @@ public abstract class CassandraAbstractModelDao<E extends BaseEntity<D>, D> exte
return object;
}
protected ListenableFuture<D> findOneByStatementAsync(Statement statement) {
protected ListenableFuture<D> findOneByStatementAsync(TenantId tenantId, Statement statement) {
if (statement != null) {
statement.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
ResultSetFuture resultSetFuture = executeAsyncRead(statement);
ResultSetFuture resultSetFuture = executeAsyncRead(tenantId, statement);
return Futures.transform(resultSetFuture, new Function<ResultSet, D>() {
@Nullable
@Override
@ -128,16 +129,16 @@ public abstract class CassandraAbstractModelDao<E extends BaseEntity<D>, D> exte
return getMapper().saveQuery(dto);
}
protected EntityResultSet<E> saveWithResult(E entity) {
protected EntityResultSet<E> saveWithResult(TenantId tenantId, E entity) {
log.debug("Save entity {}", entity);
if (entity.getId() == null) {
entity.setId(UUIDs.timeBased());
} else if (isDeleteOnSave()) {
removeById(entity.getId());
removeById(tenantId, entity.getId());
}
Statement saveStatement = getSaveQuery(entity);
saveStatement.setConsistencyLevel(cluster.getDefaultWriteConsistencyLevel());
ResultSet resultSet = executeWrite(saveStatement);
ResultSet resultSet = executeWrite(tenantId, saveStatement);
return new EntityResultSet<>(resultSet, entity);
}
@ -146,7 +147,7 @@ public abstract class CassandraAbstractModelDao<E extends BaseEntity<D>, D> exte
}
@Override
public D save(D domain) {
public D save(TenantId tenantId, D domain) {
E entity;
try {
entity = getColumnFamilyClass().getConstructor(domain.getClass()).newInstance(domain);
@ -156,48 +157,39 @@ public abstract class CassandraAbstractModelDao<E extends BaseEntity<D>, D> exte
}
entity = updateSearchTextIfPresent(entity);
log.debug("Saving entity {}", entity);
entity = saveWithResult(entity).getEntity();
entity = saveWithResult(tenantId, entity).getEntity();
return DaoUtil.getData(entity);
}
@Override
public D findById(UUID key) {
public D findById(TenantId tenantId, UUID key) {
log.debug("Get entity by key {}", key);
Select.Where query = select().from(getColumnFamilyName()).where(eq(ModelConstants.ID_PROPERTY, key));
log.trace("Execute query {}", query);
E entity = findOneByStatement(query);
E entity = findOneByStatement(tenantId, query);
return DaoUtil.getData(entity);
}
@Override
public ListenableFuture<D> findByIdAsync(UUID key) {
public ListenableFuture<D> findByIdAsync(TenantId tenantId, UUID key) {
log.debug("Get entity by key {}", key);
Select.Where query = select().from(getColumnFamilyName()).where(eq(ModelConstants.ID_PROPERTY, key));
log.trace("Execute query {}", query);
return findOneByStatementAsync(query);
return findOneByStatementAsync(tenantId, query);
}
@Override
public boolean removeById(UUID key) {
public boolean removeById(TenantId tenantId, UUID key) {
Statement delete = QueryBuilder.delete().all().from(getColumnFamilyName()).where(eq(ModelConstants.ID_PROPERTY, key));
log.debug("Remove request: {}", delete.toString());
return executeWrite(delete).wasApplied();
return executeWrite(tenantId, delete).wasApplied();
}
@Override
public List<D> find() {
public List<D> find(TenantId tenantId) {
log.debug("Get all entities from column family {}", getColumnFamilyName());
List<E> entities = findListByStatement(QueryBuilder.select().all().from(getColumnFamilyName()).setConsistencyLevel(cluster.getDefaultReadConsistencyLevel()));
List<E> entities = findListByStatement(tenantId, QueryBuilder.select().all().from(getColumnFamilyName()).setConsistencyLevel(cluster.getDefaultReadConsistencyLevel()));
return DaoUtil.convertDataList(entities);
}
protected static <T> Function<BaseEntity<T>, T> toDataFunction() {
return new Function<BaseEntity<T>, T>() {
@Nullable
@Override
public T apply(@Nullable BaseEntity<T> entity) {
return entity != null ? entity.toData() : null;
}
};
}
}

15
dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractSearchTextDao.java

@ -21,6 +21,7 @@ import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Select.Where;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.model.SearchTextEntity;
@ -43,38 +44,38 @@ public abstract class CassandraAbstractSearchTextDao<E extends SearchTextEntity<
return entity;
}
protected List<E> findPageWithTextSearch(String searchView, List<Clause> clauses, TextPageLink pageLink) {
protected List<E> findPageWithTextSearch(TenantId tenantId, String searchView, List<Clause> clauses, TextPageLink pageLink) {
Select select = select().from(searchView);
Where query = select.where();
for (Clause clause : clauses) {
query.and(clause);
}
}
query.limit(pageLink.getLimit());
if (!StringUtils.isEmpty(pageLink.getTextOffset())) {
query.and(eq(ModelConstants.SEARCH_TEXT_PROPERTY, pageLink.getTextOffset()));
query.and(QueryBuilder.lt(ModelConstants.ID_PROPERTY, pageLink.getIdOffset()));
List<E> result = findListByStatement(query);
List<E> result = findListByStatement(tenantId, query);
if (result.size() < pageLink.getLimit()) {
select = select().from(searchView);
query = select.where();
for (Clause clause : clauses) {
query.and(clause);
}
}
query.and(QueryBuilder.gt(ModelConstants.SEARCH_TEXT_PROPERTY, pageLink.getTextOffset()));
if (!StringUtils.isEmpty(pageLink.getTextSearch())) {
query.and(QueryBuilder.lt(ModelConstants.SEARCH_TEXT_PROPERTY, pageLink.getTextSearchBound()));
}
int limit = pageLink.getLimit() - result.size();
query.limit(limit);
result.addAll(findListByStatement(query));
result.addAll(findListByStatement(tenantId, query));
}
return result;
} else if (!StringUtils.isEmpty(pageLink.getTextSearch())) {
query.and(QueryBuilder.gte(ModelConstants.SEARCH_TEXT_PROPERTY, pageLink.getTextSearch()));
query.and(QueryBuilder.lt(ModelConstants.SEARCH_TEXT_PROPERTY, pageLink.getTextSearchBound()));
return findListByStatement(query);
return findListByStatement(tenantId, query);
} else {
return findListByStatement(query);
return findListByStatement(tenantId, query);
}
}

21
dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractSearchTimeDao.java

@ -21,6 +21,7 @@ import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Select.Where;
import com.datastax.driver.core.utils.UUIDs;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.model.ModelConstants;
@ -35,24 +36,24 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
public abstract class CassandraAbstractSearchTimeDao<E extends BaseEntity<D>, D> extends CassandraAbstractModelDao<E, D> {
protected List<E> findPageWithTimeSearch(String searchView, List<Clause> clauses, TimePageLink pageLink) {
return findPageWithTimeSearch(searchView, clauses, Collections.emptyList(), pageLink);
protected List<E> findPageWithTimeSearch(TenantId tenantId, String searchView, List<Clause> clauses, TimePageLink pageLink) {
return findPageWithTimeSearch(tenantId, searchView, clauses, Collections.emptyList(), pageLink);
}
protected List<E> findPageWithTimeSearch(String searchView, List<Clause> clauses, Ordering ordering, TimePageLink pageLink) {
return findPageWithTimeSearch(searchView, clauses, Collections.singletonList(ordering), pageLink);
protected List<E> findPageWithTimeSearch(TenantId tenantId, String searchView, List<Clause> clauses, Ordering ordering, TimePageLink pageLink) {
return findPageWithTimeSearch(tenantId, searchView, clauses, Collections.singletonList(ordering), pageLink);
}
protected List<E> findPageWithTimeSearch(String searchView, List<Clause> clauses, List<Ordering> topLevelOrderings, TimePageLink pageLink) {
return findPageWithTimeSearch(searchView, clauses, topLevelOrderings, pageLink, ModelConstants.ID_PROPERTY);
protected List<E> findPageWithTimeSearch(TenantId tenantId, String searchView, List<Clause> clauses, List<Ordering> topLevelOrderings, TimePageLink pageLink) {
return findPageWithTimeSearch(tenantId, searchView, clauses, topLevelOrderings, pageLink, ModelConstants.ID_PROPERTY);
}
protected List<E> findPageWithTimeSearch(String searchView, List<Clause> clauses, TimePageLink pageLink, String idColumn) {
return findPageWithTimeSearch(searchView, clauses, Collections.emptyList(), pageLink, idColumn);
protected List<E> findPageWithTimeSearch(TenantId tenantId, String searchView, List<Clause> clauses, TimePageLink pageLink, String idColumn) {
return findPageWithTimeSearch(tenantId, searchView, clauses, Collections.emptyList(), pageLink, idColumn);
}
protected List<E> findPageWithTimeSearch(String searchView, List<Clause> clauses, List<Ordering> topLevelOrderings, TimePageLink pageLink, String idColumn) {
return findListByStatement(buildQuery(searchView, clauses, topLevelOrderings, pageLink, idColumn));
protected List<E> findPageWithTimeSearch(TenantId tenantId, String searchView, List<Clause> clauses, List<Ordering> topLevelOrderings, TimePageLink pageLink, String idColumn) {
return findListByStatement(tenantId, buildQuery(searchView, clauses, topLevelOrderings, pageLink, idColumn));
}
public static Where buildQuery(String searchView, List<Clause> clauses, TimePageLink pageLink, String idColumn) {

15
dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraBufferedRateExecutor.java

@ -22,11 +22,16 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.tools.TbRateLimits;
import org.thingsboard.server.dao.util.AbstractBufferedRateExecutor;
import org.thingsboard.server.dao.util.AsyncTaskContext;
import org.thingsboard.server.dao.util.NoSqlAnyDao;
import javax.annotation.PreDestroy;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Created by ashvayka on 24.10.18.
@ -42,17 +47,19 @@ public class CassandraBufferedRateExecutor extends AbstractBufferedRateExecutor<
@Value("${cassandra.query.permit_max_wait_time}") long maxWaitTime,
@Value("${cassandra.query.dispatcher_threads:2}") int dispatcherThreads,
@Value("${cassandra.query.callback_threads:2}") int callbackThreads,
@Value("${cassandra.query.poll_ms:50}") long pollMs) {
super(queueLimit, concurrencyLimit, maxWaitTime, dispatcherThreads, callbackThreads, pollMs);
@Value("${cassandra.query.poll_ms:50}") long pollMs,
@Value("${cassandra.query.tenant_rate_limits.enabled}") boolean tenantRateLimitsEnabled,
@Value("${cassandra.query.tenant_rate_limits.configuration}") String tenantRateLimitsConfiguration) {
super(queueLimit, concurrencyLimit, maxWaitTime, dispatcherThreads, callbackThreads, pollMs, tenantRateLimitsEnabled, tenantRateLimitsConfiguration);
}
@Scheduled(fixedDelayString = "${cassandra.query.rate_limit_print_interval_ms}")
public void printStats() {
log.info("Permits queueSize [{}] totalAdded [{}] totalLaunched [{}] totalReleased [{}] totalFailed [{}] totalExpired [{}] totalRejected [{}] currBuffer [{}] ",
log.info("Permits queueSize [{}] totalAdded [{}] totalLaunched [{}] totalReleased [{}] totalFailed [{}] totalExpired [{}] totalRejected [{}] totalRateLimited [{}] currBuffer [{}] ",
getQueueSize(),
totalAdded.getAndSet(0), totalLaunched.getAndSet(0), totalReleased.getAndSet(0),
totalFailed.getAndSet(0), totalExpired.getAndSet(0), totalRejected.getAndSet(0),
concurrencyLevel.get());
totalRateLimited.getAndSet(0), concurrencyLevel.get());
}
@PreDestroy

2
dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraStatementTask.java

@ -18,6 +18,7 @@ package org.thingsboard.server.dao.nosql;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.Statement;
import lombok.Data;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.util.AsyncTask;
/**
@ -26,6 +27,7 @@ import org.thingsboard.server.dao.util.AsyncTask;
@Data
public class CassandraStatementTask implements AsyncTask {
private final TenantId tenantId;
private final Session session;
private final Statement statement;

77
dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationDao.java

@ -29,6 +29,7 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
@ -83,45 +84,45 @@ public class BaseRelationDao extends CassandraAbstractAsyncDao implements Relati
}
@Override
public ListenableFuture<List<EntityRelation>> findAllByFrom(EntityId from, RelationTypeGroup typeGroup) {
public ListenableFuture<List<EntityRelation>> findAllByFrom(TenantId tenantId, EntityId from, RelationTypeGroup typeGroup) {
BoundStatement stmt = getFindAllByFromStmt().bind()
.setUUID(0, from.getId())
.setString(1, from.getEntityType().name())
.set(2, typeGroup, relationTypeGroupCodec);
return executeAsyncRead(from, stmt);
return executeAsyncRead(tenantId, from, stmt);
}
@Override
public ListenableFuture<List<EntityRelation>> findAllByFromAndType(EntityId from, String relationType, RelationTypeGroup typeGroup) {
public ListenableFuture<List<EntityRelation>> findAllByFromAndType(TenantId tenantId, EntityId from, String relationType, RelationTypeGroup typeGroup) {
BoundStatement stmt = getFindAllByFromAndTypeStmt().bind()
.setUUID(0, from.getId())
.setString(1, from.getEntityType().name())
.set(2, typeGroup, relationTypeGroupCodec)
.setString(3, relationType);
return executeAsyncRead(from, stmt);
return executeAsyncRead(tenantId, from, stmt);
}
@Override
public ListenableFuture<List<EntityRelation>> findAllByTo(EntityId to, RelationTypeGroup typeGroup) {
public ListenableFuture<List<EntityRelation>> findAllByTo(TenantId tenantId, EntityId to, RelationTypeGroup typeGroup) {
BoundStatement stmt = getFindAllByToStmt().bind()
.setUUID(0, to.getId())
.setString(1, to.getEntityType().name())
.set(2, typeGroup, relationTypeGroupCodec);
return executeAsyncRead(to, stmt);
return executeAsyncRead(tenantId, to, stmt);
}
@Override
public ListenableFuture<List<EntityRelation>> findAllByToAndType(EntityId to, String relationType, RelationTypeGroup typeGroup) {
public ListenableFuture<List<EntityRelation>> findAllByToAndType(TenantId tenantId, EntityId to, String relationType, RelationTypeGroup typeGroup) {
BoundStatement stmt = getFindAllByToAndTypeStmt().bind()
.setUUID(0, to.getId())
.setString(1, to.getEntityType().name())
.set(2, typeGroup, relationTypeGroupCodec)
.setString(3, relationType);
return executeAsyncRead(to, stmt);
return executeAsyncRead(tenantId, to, stmt);
}
@Override
public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
public ListenableFuture<Boolean> checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
BoundStatement stmt = getCheckRelationStmt().bind()
.setUUID(0, from.getId())
.setString(1, from.getEntityType().name())
@ -129,11 +130,11 @@ public class BaseRelationDao extends CassandraAbstractAsyncDao implements Relati
.setString(3, to.getEntityType().name())
.set(4, typeGroup, relationTypeGroupCodec)
.setString(5, relationType);
return getFuture(executeAsyncRead(stmt), rs -> rs != null ? rs.one() != null : false);
return getFuture(executeAsyncRead(tenantId, stmt), rs -> rs != null ? rs.one() != null : false);
}
@Override
public ListenableFuture<EntityRelation> getRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
public ListenableFuture<EntityRelation> getRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
BoundStatement stmt = getCheckRelationStmt().bind()
.setUUID(0, from.getId())
.setString(1, from.getEntityType().name())
@ -141,24 +142,24 @@ public class BaseRelationDao extends CassandraAbstractAsyncDao implements Relati
.setString(3, to.getEntityType().name())
.set(4, typeGroup, relationTypeGroupCodec)
.setString(5, relationType);
return getFuture(executeAsyncRead(stmt), rs -> rs != null ? getEntityRelation(rs.one()) : null);
return getFuture(executeAsyncRead(tenantId, stmt), rs -> rs != null ? getEntityRelation(rs.one()) : null);
}
@Override
public boolean saveRelation(EntityRelation relation) {
BoundStatement stmt = getSaveRelationStatement(relation);
ResultSet rs = executeWrite(stmt);
public boolean saveRelation(TenantId tenantId, EntityRelation relation) {
BoundStatement stmt = getSaveRelationStatement(tenantId, relation);
ResultSet rs = executeWrite(tenantId, stmt);
return rs.wasApplied();
}
@Override
public ListenableFuture<Boolean> saveRelationAsync(EntityRelation relation) {
BoundStatement stmt = getSaveRelationStatement(relation);
ResultSetFuture future = executeAsyncWrite(stmt);
public ListenableFuture<Boolean> saveRelationAsync(TenantId tenantId, EntityRelation relation) {
BoundStatement stmt = getSaveRelationStatement(tenantId, relation);
ResultSetFuture future = executeAsyncWrite(tenantId, stmt);
return getBooleanListenableFuture(future);
}
private BoundStatement getSaveRelationStatement(EntityRelation relation) {
private BoundStatement getSaveRelationStatement(TenantId tenantId, EntityRelation relation) {
BoundStatement stmt = getSaveStmt().bind()
.setUUID(0, relation.getFrom().getId())
.setString(1, relation.getFrom().getEntityType().name())
@ -171,30 +172,30 @@ public class BaseRelationDao extends CassandraAbstractAsyncDao implements Relati
}
@Override
public boolean deleteRelation(EntityRelation relation) {
return deleteRelation(relation.getFrom(), relation.getTo(), relation.getType(), relation.getTypeGroup());
public boolean deleteRelation(TenantId tenantId, EntityRelation relation) {
return deleteRelation(tenantId, relation.getFrom(), relation.getTo(), relation.getType(), relation.getTypeGroup());
}
@Override
public ListenableFuture<Boolean> deleteRelationAsync(EntityRelation relation) {
return deleteRelationAsync(relation.getFrom(), relation.getTo(), relation.getType(), relation.getTypeGroup());
public ListenableFuture<Boolean> deleteRelationAsync(TenantId tenantId, EntityRelation relation) {
return deleteRelationAsync(tenantId, relation.getFrom(), relation.getTo(), relation.getType(), relation.getTypeGroup());
}
@Override
public boolean deleteRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
BoundStatement stmt = getDeleteRelationStatement(from, to, relationType, typeGroup);
ResultSet rs = executeWrite(stmt);
public boolean deleteRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
BoundStatement stmt = getDeleteRelationStatement(tenantId, from, to, relationType, typeGroup);
ResultSet rs = executeWrite(tenantId, stmt);
return rs.wasApplied();
}
@Override
public ListenableFuture<Boolean> deleteRelationAsync(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
BoundStatement stmt = getDeleteRelationStatement(from, to, relationType, typeGroup);
ResultSetFuture future = executeAsyncWrite(stmt);
public ListenableFuture<Boolean> deleteRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
BoundStatement stmt = getDeleteRelationStatement(tenantId, from, to, relationType, typeGroup);
ResultSetFuture future = executeAsyncWrite(tenantId, stmt);
return getBooleanListenableFuture(future);
}
private BoundStatement getDeleteRelationStatement(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
private BoundStatement getDeleteRelationStatement(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
BoundStatement stmt = getDeleteStmt().bind()
.setUUID(0, from.getId())
.setString(1, from.getEntityType().name())
@ -206,26 +207,26 @@ public class BaseRelationDao extends CassandraAbstractAsyncDao implements Relati
}
@Override
public boolean deleteOutboundRelations(EntityId entity) {
public boolean deleteOutboundRelations(TenantId tenantId, EntityId entity) {
BoundStatement stmt = getDeleteAllByEntityStmt().bind()
.setUUID(0, entity.getId())
.setString(1, entity.getEntityType().name());
ResultSet rs = executeWrite(stmt);
ResultSet rs = executeWrite(tenantId, stmt);
return rs.wasApplied();
}
@Override
public ListenableFuture<Boolean> deleteOutboundRelationsAsync(EntityId entity) {
public ListenableFuture<Boolean> deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity) {
BoundStatement stmt = getDeleteAllByEntityStmt().bind()
.setUUID(0, entity.getId())
.setString(1, entity.getEntityType().name());
ResultSetFuture future = executeAsyncWrite(stmt);
ResultSetFuture future = executeAsyncWrite(tenantId, stmt);
return getBooleanListenableFuture(future);
}
@Override
public ListenableFuture<List<EntityRelation>> findRelations(EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType childType, TimePageLink pageLink) {
public ListenableFuture<List<EntityRelation>> findRelations(TenantId tenantId, EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType childType, TimePageLink pageLink) {
Select.Where query = CassandraAbstractSearchTimeDao.buildQuery(ModelConstants.RELATION_BY_TYPE_AND_CHILD_TYPE_VIEW_NAME,
Arrays.asList(eq(ModelConstants.RELATION_FROM_ID_PROPERTY, from.getId()),
eq(ModelConstants.RELATION_FROM_TYPE_PROPERTY, from.getEntityType().name()),
@ -241,7 +242,7 @@ public class BaseRelationDao extends CassandraAbstractAsyncDao implements Relati
QueryBuilder.asc(ModelConstants.RELATION_TO_TYPE_PROPERTY)
),
pageLink, ModelConstants.RELATION_TO_ID_PROPERTY);
return getFuture(executeAsyncRead(query), this::getEntityRelations);
return getFuture(executeAsyncRead(tenantId, query), this::getEntityRelations);
}
private PreparedStatement getSaveStmt() {
@ -347,9 +348,9 @@ public class BaseRelationDao extends CassandraAbstractAsyncDao implements Relati
return EntityIdFactory.getByTypeAndUuid(row.getString(typeColumn), row.getUUID(uuidColumn));
}
private ListenableFuture<List<EntityRelation>> executeAsyncRead(EntityId from, BoundStatement stmt) {
private ListenableFuture<List<EntityRelation>> executeAsyncRead(TenantId tenantId, EntityId from, BoundStatement stmt) {
log.debug("Generated query [{}] for entity {}", stmt, from);
return getFuture(executeAsyncRead(stmt), rs -> getEntityRelations(rs));
return getFuture(executeAsyncRead(tenantId, stmt), rs -> getEntityRelations(rs));
}
private ListenableFuture<Boolean> getBooleanListenableFuture(ResultSetFuture rsFuture) {

132
dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java

@ -26,7 +26,9 @@ import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntityRelationInfo;
import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
@ -66,27 +68,27 @@ public class BaseRelationService implements RelationService {
private CacheManager cacheManager;
@Override
public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
public ListenableFuture<Boolean> checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
log.trace("Executing checkRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup);
validate(from, to, relationType, typeGroup);
return relationDao.checkRelation(from, to, relationType, typeGroup);
return relationDao.checkRelation(tenantId, from, to, relationType, typeGroup);
}
@Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #to, #relationType, #typeGroup}")
@Override
public EntityRelation getRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
public EntityRelation getRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
try {
return getRelationAsync(from, to, relationType, typeGroup).get();
return getRelationAsync(tenantId, from, to, relationType, typeGroup).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
public ListenableFuture<EntityRelation> getRelationAsync(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
public ListenableFuture<EntityRelation> getRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
log.trace("Executing EntityRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup);
validate(from, to, relationType, typeGroup);
return relationDao.getRelation(from, to, relationType, typeGroup);
return relationDao.getRelation(tenantId, from, to, relationType, typeGroup);
}
@Caching(evict = {
@ -97,10 +99,10 @@ public class BaseRelationService implements RelationService {
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup, 'TO'}")
})
@Override
public boolean saveRelation(EntityRelation relation) {
public boolean saveRelation(TenantId tenantId, EntityRelation relation) {
log.trace("Executing saveRelation [{}]", relation);
validate(relation);
return relationDao.saveRelation(relation);
return relationDao.saveRelation(tenantId, relation);
}
@Caching(evict = {
@ -111,10 +113,10 @@ public class BaseRelationService implements RelationService {
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup, 'TO'}")
})
@Override
public ListenableFuture<Boolean> saveRelationAsync(EntityRelation relation) {
public ListenableFuture<Boolean> saveRelationAsync(TenantId tenantId, EntityRelation relation) {
log.trace("Executing saveRelationAsync [{}]", relation);
validate(relation);
return relationDao.saveRelationAsync(relation);
return relationDao.saveRelationAsync(tenantId, relation);
}
@Caching(evict = {
@ -125,10 +127,10 @@ public class BaseRelationService implements RelationService {
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup, 'TO'}")
})
@Override
public boolean deleteRelation(EntityRelation relation) {
public boolean deleteRelation(TenantId tenantId, EntityRelation relation) {
log.trace("Executing deleteRelation [{}]", relation);
validate(relation);
return relationDao.deleteRelation(relation);
return relationDao.deleteRelation(tenantId, relation);
}
@Caching(evict = {
@ -139,10 +141,10 @@ public class BaseRelationService implements RelationService {
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup, 'TO'}")
})
@Override
public ListenableFuture<Boolean> deleteRelationAsync(EntityRelation relation) {
public ListenableFuture<Boolean> deleteRelationAsync(TenantId tenantId, EntityRelation relation) {
log.trace("Executing deleteRelationAsync [{}]", relation);
validate(relation);
return relationDao.deleteRelationAsync(relation);
return relationDao.deleteRelationAsync(tenantId, relation);
}
@Caching(evict = {
@ -153,10 +155,10 @@ public class BaseRelationService implements RelationService {
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType, #typeGroup, 'TO'}")
})
@Override
public boolean deleteRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
public boolean deleteRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
log.trace("Executing deleteRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup);
validate(from, to, relationType, typeGroup);
return relationDao.deleteRelation(from, to, relationType, typeGroup);
return relationDao.deleteRelation(tenantId, from, to, relationType, typeGroup);
}
@Caching(evict = {
@ -167,69 +169,69 @@ public class BaseRelationService implements RelationService {
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType, #typeGroup, 'TO'}")
})
@Override
public ListenableFuture<Boolean> deleteRelationAsync(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
public ListenableFuture<Boolean> deleteRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
log.trace("Executing deleteRelationAsync [{}][{}][{}][{}]", from, to, relationType, typeGroup);
validate(from, to, relationType, typeGroup);
return relationDao.deleteRelationAsync(from, to, relationType, typeGroup);
return relationDao.deleteRelationAsync(tenantId, from, to, relationType, typeGroup);
}
@Override
public void deleteEntityRelations(EntityId entityId) {
public void deleteEntityRelations(TenantId tenantId, EntityId entityId) {
try {
deleteEntityRelationsAsync(entityId).get();
deleteEntityRelationsAsync(tenantId, entityId).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
public ListenableFuture<Void> deleteEntityRelationsAsync(EntityId entityId) {
public ListenableFuture<Void> deleteEntityRelationsAsync(TenantId tenantId, EntityId entityId) {
Cache cache = cacheManager.getCache(RELATIONS_CACHE);
log.trace("Executing deleteEntityRelationsAsync [{}]", entityId);
validate(entityId);
List<ListenableFuture<List<EntityRelation>>> inboundRelationsList = new ArrayList<>();
for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) {
inboundRelationsList.add(relationDao.findAllByTo(entityId, typeGroup));
inboundRelationsList.add(relationDao.findAllByTo(tenantId, entityId, typeGroup));
}
ListenableFuture<List<List<EntityRelation>>> inboundRelations = Futures.allAsList(inboundRelationsList);
List<ListenableFuture<List<EntityRelation>>> outboundRelationsList = new ArrayList<>();
for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) {
outboundRelationsList.add(relationDao.findAllByFrom(entityId, typeGroup));
outboundRelationsList.add(relationDao.findAllByFrom(tenantId, entityId, typeGroup));
}
ListenableFuture<List<List<EntityRelation>>> outboundRelations = Futures.allAsList(outboundRelationsList);
ListenableFuture<List<Boolean>> inboundDeletions = Futures.transformAsync(inboundRelations,
relations -> {
List<ListenableFuture<Boolean>> results = deleteRelationGroupsAsync(relations, cache, true);
List<ListenableFuture<Boolean>> results = deleteRelationGroupsAsync(tenantId, relations, cache, true);
return Futures.allAsList(results);
});
ListenableFuture<List<Boolean>> outboundDeletions = Futures.transformAsync(outboundRelations,
relations -> {
List<ListenableFuture<Boolean>> results = deleteRelationGroupsAsync(relations, cache, false);
List<ListenableFuture<Boolean>> results = deleteRelationGroupsAsync(tenantId, relations, cache, false);
return Futures.allAsList(results);
});
ListenableFuture<List<List<Boolean>>> deletionsFuture = Futures.allAsList(inboundDeletions, outboundDeletions);
return Futures.transform(Futures.transformAsync(deletionsFuture, (deletions) -> relationDao.deleteOutboundRelationsAsync(entityId)), result -> null);
return Futures.transform(Futures.transformAsync(deletionsFuture, (deletions) -> relationDao.deleteOutboundRelationsAsync(tenantId, entityId)), result -> null);
}
private List<ListenableFuture<Boolean>> deleteRelationGroupsAsync(List<List<EntityRelation>> relations, Cache cache, boolean deleteFromDb) {
private List<ListenableFuture<Boolean>> deleteRelationGroupsAsync(TenantId tenantId, List<List<EntityRelation>> relations, Cache cache, boolean deleteFromDb) {
List<ListenableFuture<Boolean>> results = new ArrayList<>();
for (List<EntityRelation> relationList : relations) {
relationList.forEach(relation -> results.add(deleteAsync(cache, relation, deleteFromDb)));
relationList.forEach(relation -> results.add(deleteAsync(tenantId, cache, relation, deleteFromDb)));
}
return results;
}
private ListenableFuture<Boolean> deleteAsync(Cache cache, EntityRelation relation, boolean deleteFromDb) {
private ListenableFuture<Boolean> deleteAsync(TenantId tenantId, Cache cache, EntityRelation relation, boolean deleteFromDb) {
cacheEviction(relation, cache);
if (deleteFromDb) {
return relationDao.deleteRelationAsync(relation);
return relationDao.deleteRelationAsync(tenantId, relation);
} else {
return Futures.immediateFuture(false);
}
@ -272,18 +274,18 @@ public class BaseRelationService implements RelationService {
@Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #typeGroup, 'FROM'}")
@Override
public List<EntityRelation> findByFrom(EntityId from, RelationTypeGroup typeGroup) {
public List<EntityRelation> findByFrom(TenantId tenantId, EntityId from, RelationTypeGroup typeGroup) {
validate(from);
validateTypeGroup(typeGroup);
try {
return relationDao.findAllByFrom(from, typeGroup).get();
return relationDao.findAllByFrom(tenantId, from, typeGroup).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
public ListenableFuture<List<EntityRelation>> findByFromAsync(EntityId from, RelationTypeGroup typeGroup) {
public ListenableFuture<List<EntityRelation>> findByFromAsync(TenantId tenantId, EntityId from, RelationTypeGroup typeGroup) {
log.trace("Executing findByFrom [{}][{}]", from, typeGroup);
validate(from);
validateTypeGroup(typeGroup);
@ -298,7 +300,7 @@ public class BaseRelationService implements RelationService {
if (fromCache != null) {
return Futures.immediateFuture(fromCache);
} else {
ListenableFuture<List<EntityRelation>> relationsFuture = relationDao.findAllByFrom(from, typeGroup);
ListenableFuture<List<EntityRelation>> relationsFuture = relationDao.findAllByFrom(tenantId, from, typeGroup);
Futures.addCallback(relationsFuture,
new FutureCallback<List<EntityRelation>>() {
@Override
@ -313,16 +315,16 @@ public class BaseRelationService implements RelationService {
}
@Override
public ListenableFuture<List<EntityRelationInfo>> findInfoByFrom(EntityId from, RelationTypeGroup typeGroup) {
public ListenableFuture<List<EntityRelationInfo>> findInfoByFrom(TenantId tenantId, EntityId from, RelationTypeGroup typeGroup) {
log.trace("Executing findInfoByFrom [{}][{}]", from, typeGroup);
validate(from);
validateTypeGroup(typeGroup);
ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByFrom(from, typeGroup);
ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByFrom(tenantId, from, typeGroup);
return Futures.transformAsync(relations,
relations1 -> {
List<ListenableFuture<EntityRelationInfo>> futures = new ArrayList<>();
relations1.forEach(relation ->
futures.add(fetchRelationInfoAsync(relation,
futures.add(fetchRelationInfoAsync(tenantId, relation,
EntityRelation::getTo,
EntityRelationInfo::setToName))
);
@ -332,37 +334,37 @@ public class BaseRelationService implements RelationService {
@Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType, #typeGroup, 'FROM'}")
@Override
public List<EntityRelation> findByFromAndType(EntityId from, String relationType, RelationTypeGroup typeGroup) {
public List<EntityRelation> findByFromAndType(TenantId tenantId, EntityId from, String relationType, RelationTypeGroup typeGroup) {
try {
return findByFromAndTypeAsync(from, relationType, typeGroup).get();
return findByFromAndTypeAsync(tenantId, from, relationType, typeGroup).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
public ListenableFuture<List<EntityRelation>> findByFromAndTypeAsync(EntityId from, String relationType, RelationTypeGroup typeGroup) {
public ListenableFuture<List<EntityRelation>> findByFromAndTypeAsync(TenantId tenantId, EntityId from, String relationType, RelationTypeGroup typeGroup) {
log.trace("Executing findByFromAndType [{}][{}][{}]", from, relationType, typeGroup);
validate(from);
validateType(relationType);
validateTypeGroup(typeGroup);
return relationDao.findAllByFromAndType(from, relationType, typeGroup);
return relationDao.findAllByFromAndType(tenantId, from, relationType, typeGroup);
}
@Cacheable(cacheNames = RELATIONS_CACHE, key = "{#to, #typeGroup, 'TO'}")
@Override
public List<EntityRelation> findByTo(EntityId to, RelationTypeGroup typeGroup) {
public List<EntityRelation> findByTo(TenantId tenantId, EntityId to, RelationTypeGroup typeGroup) {
validate(to);
validateTypeGroup(typeGroup);
try {
return relationDao.findAllByTo(to, typeGroup).get();
return relationDao.findAllByTo(tenantId, to, typeGroup).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
public ListenableFuture<List<EntityRelation>> findByToAsync(EntityId to, RelationTypeGroup typeGroup) {
public ListenableFuture<List<EntityRelation>> findByToAsync(TenantId tenantId, EntityId to, RelationTypeGroup typeGroup) {
log.trace("Executing findByTo [{}][{}]", to, typeGroup);
validate(to);
validateTypeGroup(typeGroup);
@ -377,7 +379,7 @@ public class BaseRelationService implements RelationService {
if (fromCache != null) {
return Futures.immediateFuture(fromCache);
} else {
ListenableFuture<List<EntityRelation>> relationsFuture = relationDao.findAllByTo(to, typeGroup);
ListenableFuture<List<EntityRelation>> relationsFuture = relationDao.findAllByTo(tenantId, to, typeGroup);
Futures.addCallback(relationsFuture,
new FutureCallback<List<EntityRelation>>() {
@Override
@ -392,16 +394,16 @@ public class BaseRelationService implements RelationService {
}
@Override
public ListenableFuture<List<EntityRelationInfo>> findInfoByTo(EntityId to, RelationTypeGroup typeGroup) {
public ListenableFuture<List<EntityRelationInfo>> findInfoByTo(TenantId tenantId, EntityId to, RelationTypeGroup typeGroup) {
log.trace("Executing findInfoByTo [{}][{}]", to, typeGroup);
validate(to);
validateTypeGroup(typeGroup);
ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByTo(to, typeGroup);
ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByTo(tenantId, to, typeGroup);
return Futures.transformAsync(relations,
relations1 -> {
List<ListenableFuture<EntityRelationInfo>> futures = new ArrayList<>();
relations1.forEach(relation ->
futures.add(fetchRelationInfoAsync(relation,
futures.add(fetchRelationInfoAsync(tenantId, relation,
EntityRelation::getFrom,
EntityRelationInfo::setFromName))
);
@ -409,10 +411,10 @@ public class BaseRelationService implements RelationService {
});
}
private ListenableFuture<EntityRelationInfo> fetchRelationInfoAsync(EntityRelation relation,
private ListenableFuture<EntityRelationInfo> fetchRelationInfoAsync(TenantId tenantId, EntityRelation relation,
Function<EntityRelation, EntityId> entityIdGetter,
BiConsumer<EntityRelationInfo, String> entityNameSetter) {
ListenableFuture<String> entityName = entityService.fetchEntityNameAsync(entityIdGetter.apply(relation));
ListenableFuture<String> entityName = entityService.fetchEntityNameAsync(tenantId, entityIdGetter.apply(relation));
return Futures.transform(entityName, entityName1 -> {
EntityRelationInfo entityRelationInfo1 = new EntityRelationInfo(relation);
entityNameSetter.accept(entityRelationInfo1, entityName1);
@ -422,25 +424,25 @@ public class BaseRelationService implements RelationService {
@Cacheable(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType, #typeGroup, 'TO'}")
@Override
public List<EntityRelation> findByToAndType(EntityId to, String relationType, RelationTypeGroup typeGroup) {
public List<EntityRelation> findByToAndType(TenantId tenantId, EntityId to, String relationType, RelationTypeGroup typeGroup) {
try {
return findByToAndTypeAsync(to, relationType, typeGroup).get();
return findByToAndTypeAsync(tenantId, to, relationType, typeGroup).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
public ListenableFuture<List<EntityRelation>> findByToAndTypeAsync(EntityId to, String relationType, RelationTypeGroup typeGroup) {
public ListenableFuture<List<EntityRelation>> findByToAndTypeAsync(TenantId tenantId, EntityId to, String relationType, RelationTypeGroup typeGroup) {
log.trace("Executing findByToAndType [{}][{}][{}]", to, relationType, typeGroup);
validate(to);
validateType(relationType);
validateTypeGroup(typeGroup);
return relationDao.findAllByToAndType(to, relationType, typeGroup);
return relationDao.findAllByToAndType(tenantId, to, relationType, typeGroup);
}
@Override
public ListenableFuture<List<EntityRelation>> findByQuery(EntityRelationsQuery query) {
public ListenableFuture<List<EntityRelation>> findByQuery(TenantId tenantId, EntityRelationsQuery query) {
log.trace("Executing findByQuery [{}]", query);
RelationsSearchParameters params = query.getParameters();
final List<EntityTypeFilter> filters = query.getFilters();
@ -451,7 +453,7 @@ public class BaseRelationService implements RelationService {
int maxLvl = params.getMaxLevel() > 0 ? params.getMaxLevel() : Integer.MAX_VALUE;
try {
ListenableFuture<Set<EntityRelation>> relationSet = findRelationsRecursively(params.getEntityId(), params.getDirection(), params.getRelationTypeGroup(), maxLvl, new ConcurrentHashMap<>());
ListenableFuture<Set<EntityRelation>> relationSet = findRelationsRecursively(tenantId, params.getEntityId(), params.getDirection(), params.getRelationTypeGroup(), maxLvl, new ConcurrentHashMap<>());
return Futures.transform(relationSet, input -> {
List<EntityRelation> relations = new ArrayList<>();
if (filters == null || filters.isEmpty()) {
@ -472,15 +474,15 @@ public class BaseRelationService implements RelationService {
}
@Override
public ListenableFuture<List<EntityRelationInfo>> findInfoByQuery(EntityRelationsQuery query) {
public ListenableFuture<List<EntityRelationInfo>> findInfoByQuery(TenantId tenantId, EntityRelationsQuery query) {
log.trace("Executing findInfoByQuery [{}]", query);
ListenableFuture<List<EntityRelation>> relations = findByQuery(query);
ListenableFuture<List<EntityRelation>> relations = findByQuery(tenantId, query);
EntitySearchDirection direction = query.getParameters().getDirection();
return Futures.transformAsync(relations,
relations1 -> {
List<ListenableFuture<EntityRelationInfo>> futures = new ArrayList<>();
relations1.forEach(relation ->
futures.add(fetchRelationInfoAsync(relation,
futures.add(fetchRelationInfoAsync(tenantId, relation,
relation2 -> direction == EntitySearchDirection.FROM ? relation2.getTo() : relation2.getFrom(),
(EntityRelationInfo relationInfo, String entityName) -> {
if (direction == EntitySearchDirection.FROM) {
@ -567,7 +569,7 @@ public class BaseRelationService implements RelationService {
}
}
private ListenableFuture<Set<EntityRelation>> findRelationsRecursively(final EntityId rootId, final EntitySearchDirection direction,
private ListenableFuture<Set<EntityRelation>> findRelationsRecursively(final TenantId tenantId, final EntityId rootId, final EntitySearchDirection direction,
RelationTypeGroup relationTypeGroup, int lvl,
final ConcurrentHashMap<EntityId, Boolean> uniqueMap) throws Exception {
if (lvl == 0) {
@ -575,7 +577,7 @@ public class BaseRelationService implements RelationService {
}
lvl--;
//TODO: try to remove this blocking operation
Set<EntityRelation> children = new HashSet<>(findRelations(rootId, direction, relationTypeGroup).get());
Set<EntityRelation> children = new HashSet<>(findRelations(tenantId, rootId, direction, relationTypeGroup).get());
Set<EntityId> childrenIds = new HashSet<>();
for (EntityRelation childRelation : children) {
log.trace("Found Relation: {}", childRelation);
@ -594,7 +596,7 @@ public class BaseRelationService implements RelationService {
}
List<ListenableFuture<Set<EntityRelation>>> futures = new ArrayList<>();
for (EntityId entityId : childrenIds) {
futures.add(findRelationsRecursively(entityId, direction, relationTypeGroup, lvl, uniqueMap));
futures.add(findRelationsRecursively(tenantId, entityId, direction, relationTypeGroup, lvl, uniqueMap));
}
//TODO: try to remove this blocking operation
List<Set<EntityRelation>> relations = Futures.successfulAsList(futures).get();
@ -602,15 +604,15 @@ public class BaseRelationService implements RelationService {
return Futures.immediateFuture(children);
}
private ListenableFuture<List<EntityRelation>> findRelations(final EntityId rootId, final EntitySearchDirection direction, RelationTypeGroup relationTypeGroup) {
private ListenableFuture<List<EntityRelation>> findRelations(final TenantId tenantId, final EntityId rootId, final EntitySearchDirection direction, RelationTypeGroup relationTypeGroup) {
ListenableFuture<List<EntityRelation>> relations;
if (relationTypeGroup == null) {
relationTypeGroup = RelationTypeGroup.COMMON;
}
if (direction == EntitySearchDirection.FROM) {
relations = findByFromAsync(rootId, relationTypeGroup);
relations = findByFromAsync(tenantId, rootId, relationTypeGroup);
} else {
relations = findByToAsync(rootId, relationTypeGroup);
relations = findByToAsync(tenantId, rootId, relationTypeGroup);
}
return relations;
}

31
dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java

@ -18,6 +18,7 @@ package org.thingsboard.server.dao.relation;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
@ -29,34 +30,34 @@ import java.util.List;
*/
public interface RelationDao {
ListenableFuture<List<EntityRelation>> findAllByFrom(EntityId from, RelationTypeGroup typeGroup);
ListenableFuture<List<EntityRelation>> findAllByFrom(TenantId tenantId, EntityId from, RelationTypeGroup typeGroup);
ListenableFuture<List<EntityRelation>> findAllByFromAndType(EntityId from, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<List<EntityRelation>> findAllByFromAndType(TenantId tenantId, EntityId from, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<List<EntityRelation>> findAllByTo(EntityId to, RelationTypeGroup typeGroup);
ListenableFuture<List<EntityRelation>> findAllByTo(TenantId tenantId, EntityId to, RelationTypeGroup typeGroup);
ListenableFuture<List<EntityRelation>> findAllByToAndType(EntityId to, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<List<EntityRelation>> findAllByToAndType(TenantId tenantId, EntityId to, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<Boolean> checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<EntityRelation> getRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<EntityRelation> getRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup);
boolean saveRelation(EntityRelation relation);
boolean saveRelation(TenantId tenantId, EntityRelation relation);
ListenableFuture<Boolean> saveRelationAsync(EntityRelation relation);
ListenableFuture<Boolean> saveRelationAsync(TenantId tenantId, EntityRelation relation);
boolean deleteRelation(EntityRelation relation);
boolean deleteRelation(TenantId tenantId, EntityRelation relation);
ListenableFuture<Boolean> deleteRelationAsync(EntityRelation relation);
ListenableFuture<Boolean> deleteRelationAsync(TenantId tenantId, EntityRelation relation);
boolean deleteRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup);
boolean deleteRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<Boolean> deleteRelationAsync(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<Boolean> deleteRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup);
boolean deleteOutboundRelations(EntityId entity);
boolean deleteOutboundRelations(TenantId tenantId, EntityId entity);
ListenableFuture<Boolean> deleteOutboundRelationsAsync(EntityId entity);
ListenableFuture<Boolean> deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity);
ListenableFuture<List<EntityRelation>> findRelations(EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType toType, TimePageLink pageLink);
ListenableFuture<List<EntityRelation>> findRelations(TenantId tenantId, EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType toType, TimePageLink pageLink);
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save