Commit 53bf6af23bea0dbfbaef09aea10e0051a12bf070

Authored by Andrii Shvaika
2 parents 9b01f67d 5465703d

Merge branch 'master' of github.com:thingsboard/thingsboard into feature/firmware

Showing 67 changed files with 784 additions and 409 deletions
@@ -41,6 +41,7 @@ import org.thingsboard.server.common.data.EntityType; @@ -41,6 +41,7 @@ import org.thingsboard.server.common.data.EntityType;
41 import org.thingsboard.server.common.data.TenantProfile; 41 import org.thingsboard.server.common.data.TenantProfile;
42 import org.thingsboard.server.common.data.alarm.Alarm; 42 import org.thingsboard.server.common.data.alarm.Alarm;
43 import org.thingsboard.server.common.data.asset.Asset; 43 import org.thingsboard.server.common.data.asset.Asset;
  44 +import org.thingsboard.server.common.data.id.CustomerId;
44 import org.thingsboard.server.common.data.id.DeviceId; 45 import org.thingsboard.server.common.data.id.DeviceId;
45 import org.thingsboard.server.common.data.id.EdgeId; 46 import org.thingsboard.server.common.data.id.EdgeId;
46 import org.thingsboard.server.common.data.id.EntityId; 47 import org.thingsboard.server.common.data.id.EntityId;
@@ -269,7 +270,12 @@ class DefaultTbContext implements TbContext { @@ -269,7 +270,12 @@ class DefaultTbContext implements TbContext {
269 270
270 @Override 271 @Override
271 public TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) { 272 public TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) {
272 - return TbMsg.newMsg(queueName, type, originator, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId()); 273 + return newMsg(queueName, type, originator, null, metaData, data);
  274 + }
  275 +
  276 + @Override
  277 + public TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
  278 + return TbMsg.newMsg(queueName, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId());
273 } 279 }
274 280
275 @Override 281 @Override
@@ -106,7 +106,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod @@ -106,7 +106,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
106 int ruleNodeCount = tbMsg.getAndIncrementRuleNodeCounter(); 106 int ruleNodeCount = tbMsg.getAndIncrementRuleNodeCounter();
107 int maxRuleNodeExecutionsPerMessage = getTenantProfileConfiguration().getMaxRuleNodeExecsPerMessage(); 107 int maxRuleNodeExecutionsPerMessage = getTenantProfileConfiguration().getMaxRuleNodeExecsPerMessage();
108 if (maxRuleNodeExecutionsPerMessage == 0 || ruleNodeCount < maxRuleNodeExecutionsPerMessage) { 108 if (maxRuleNodeExecutionsPerMessage == 0 || ruleNodeCount < maxRuleNodeExecutionsPerMessage) {
109 - apiUsageClient.report(tenantId, ApiUsageRecordKey.RE_EXEC_COUNT); 109 + apiUsageClient.report(tenantId, tbMsg.getCustomerId(), ApiUsageRecordKey.RE_EXEC_COUNT);
110 if (ruleNode.isDebugMode()) { 110 if (ruleNode.isDebugMode()) {
111 systemContext.persistDebugInput(tenantId, entityId, msg.getMsg(), "Self"); 111 systemContext.persistDebugInput(tenantId, entityId, msg.getMsg(), "Self");
112 } 112 }
@@ -127,7 +127,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod @@ -127,7 +127,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
127 int ruleNodeCount = tbMsg.getAndIncrementRuleNodeCounter(); 127 int ruleNodeCount = tbMsg.getAndIncrementRuleNodeCounter();
128 int maxRuleNodeExecutionsPerMessage = getTenantProfileConfiguration().getMaxRuleNodeExecsPerMessage(); 128 int maxRuleNodeExecutionsPerMessage = getTenantProfileConfiguration().getMaxRuleNodeExecsPerMessage();
129 if (maxRuleNodeExecutionsPerMessage == 0 || ruleNodeCount < maxRuleNodeExecutionsPerMessage) { 129 if (maxRuleNodeExecutionsPerMessage == 0 || ruleNodeCount < maxRuleNodeExecutionsPerMessage) {
130 - apiUsageClient.report(tenantId, ApiUsageRecordKey.RE_EXEC_COUNT); 130 + apiUsageClient.report(tenantId, tbMsg.getCustomerId(), ApiUsageRecordKey.RE_EXEC_COUNT);
131 if (ruleNode.isDebugMode()) { 131 if (ruleNode.isDebugMode()) {
132 systemContext.persistDebugInput(tenantId, entityId, msg.getMsg(), msg.getFromRelationType()); 132 systemContext.persistDebugInput(tenantId, entityId, msg.getMsg(), msg.getFromRelationType());
133 } 133 }
@@ -958,7 +958,7 @@ public abstract class BaseController { @@ -958,7 +958,7 @@ public abstract class BaseController {
958 entityNode.put("endTs", extractParameter(Long.class, 2, additionalInfo)); 958 entityNode.put("endTs", extractParameter(Long.class, 2, additionalInfo));
959 } 959 }
960 } 960 }
961 - TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode)); 961 + TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode));
962 TenantId tenantId = user.getTenantId(); 962 TenantId tenantId = user.getTenantId();
963 if (tenantId.isNullUid()) { 963 if (tenantId.isNullUid()) {
964 if (entity instanceof HasTenantId) { 964 if (entity instanceof HasTenantId) {
@@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.id.EdgeId; @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.id.EdgeId;
38 import org.thingsboard.server.common.data.id.TenantId; 38 import org.thingsboard.server.common.data.id.TenantId;
39 import org.thingsboard.server.common.data.page.PageData; 39 import org.thingsboard.server.common.data.page.PageData;
40 import org.thingsboard.server.common.data.page.PageLink; 40 import org.thingsboard.server.common.data.page.PageLink;
  41 +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
41 import org.thingsboard.server.queue.util.TbCoreComponent; 42 import org.thingsboard.server.queue.util.TbCoreComponent;
42 import org.thingsboard.server.service.security.permission.Operation; 43 import org.thingsboard.server.service.security.permission.Operation;
43 import org.thingsboard.server.service.security.permission.Resource; 44 import org.thingsboard.server.service.security.permission.Resource;
@@ -148,6 +149,7 @@ public class CustomerController extends BaseController { @@ -148,6 +149,7 @@ public class CustomerController extends BaseController {
148 ActionType.DELETED, null, strCustomerId); 149 ActionType.DELETED, null, strCustomerId);
149 150
150 sendDeleteNotificationMsg(getTenantId(), customerId, relatedEdgeIds); 151 sendDeleteNotificationMsg(getTenantId(), customerId, relatedEdgeIds);
  152 + tbClusterService.onEntityStateChange(getTenantId(), customerId, ComponentLifecycleEvent.DELETED);
151 } catch (Exception e) { 153 } catch (Exception e) {
152 154
153 logEntityAction(emptyId(EntityType.CUSTOMER), 155 logEntityAction(emptyId(EntityType.CUSTOMER),
@@ -658,7 +658,7 @@ public class DeviceController extends BaseController { @@ -658,7 +658,7 @@ public class DeviceController extends BaseController {
658 private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) { 658 private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
659 String data = entityToStr(assignedDevice); 659 String data = entityToStr(assignedDevice);
660 if (data != null) { 660 if (data != null) {
661 - TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data); 661 + TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(), assignedDevice.getCustomerId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data);
662 tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null); 662 tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null);
663 } 663 }
664 } 664 }
@@ -119,7 +119,7 @@ public class RpcController extends BaseController { @@ -119,7 +119,7 @@ public class RpcController extends BaseController {
119 expTime, 119 expTime,
120 body 120 body
121 ); 121 );
122 - deviceRpcService.processRestApiRpcRequest(rpcRequest, fromDeviceRpcResponse -> reply(new LocalRequestMetaData(rpcRequest, currentUser, result), fromDeviceRpcResponse)); 122 + deviceRpcService.processRestApiRpcRequest(rpcRequest, fromDeviceRpcResponse -> reply(new LocalRequestMetaData(rpcRequest, currentUser, result), fromDeviceRpcResponse), currentUser);
123 } 123 }
124 124
125 @Override 125 @Override
@@ -48,6 +48,7 @@ import org.thingsboard.server.common.data.EntityType; @@ -48,6 +48,7 @@ import org.thingsboard.server.common.data.EntityType;
48 import org.thingsboard.server.common.data.TenantProfile; 48 import org.thingsboard.server.common.data.TenantProfile;
49 import org.thingsboard.server.common.data.audit.ActionType; 49 import org.thingsboard.server.common.data.audit.ActionType;
50 import org.thingsboard.server.common.data.exception.ThingsboardException; 50 import org.thingsboard.server.common.data.exception.ThingsboardException;
  51 +import org.thingsboard.server.common.data.id.CustomerId;
51 import org.thingsboard.server.common.data.id.DeviceId; 52 import org.thingsboard.server.common.data.id.DeviceId;
52 import org.thingsboard.server.common.data.id.EntityId; 53 import org.thingsboard.server.common.data.id.EntityId;
53 import org.thingsboard.server.common.data.id.EntityIdFactory; 54 import org.thingsboard.server.common.data.id.EntityIdFactory;
@@ -449,7 +450,7 @@ public class TelemetryController extends BaseController { @@ -449,7 +450,7 @@ public class TelemetryController extends BaseController {
449 TenantProfile tenantProfile = tenantProfileCache.get(tenantId); 450 TenantProfile tenantProfile = tenantProfileCache.get(tenantId);
450 tenantTtl = TimeUnit.DAYS.toSeconds(((DefaultTenantProfileConfiguration) tenantProfile.getProfileData().getConfiguration()).getDefaultStorageTtlDays()); 451 tenantTtl = TimeUnit.DAYS.toSeconds(((DefaultTenantProfileConfiguration) tenantProfile.getProfileData().getConfiguration()).getDefaultStorageTtlDays());
451 } 452 }
452 - tsSubService.saveAndNotify(tenantId, entityId, entries, tenantTtl, new FutureCallback<Void>() { 453 + tsSubService.saveAndNotify(tenantId, user.getCustomerId(), entityId, entries, tenantTtl, new FutureCallback<Void>() {
453 @Override 454 @Override
454 public void onSuccess(@Nullable Void tmp) { 455 public void onSuccess(@Nullable Void tmp) {
455 logTelemetryUpdated(user, entityId, entries, null); 456 logTelemetryUpdated(user, entityId, entries, null);
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.apiusage;
  17 +
  18 +import lombok.Getter;
  19 +import org.springframework.data.util.Pair;
  20 +import org.thingsboard.server.common.data.ApiFeature;
  21 +import org.thingsboard.server.common.data.ApiUsageRecordKey;
  22 +import org.thingsboard.server.common.data.ApiUsageState;
  23 +import org.thingsboard.server.common.data.ApiUsageStateValue;
  24 +import org.thingsboard.server.common.data.EntityType;
  25 +import org.thingsboard.server.common.data.id.EntityId;
  26 +import org.thingsboard.server.common.data.id.TenantId;
  27 +import org.thingsboard.server.common.msg.tools.SchedulerUtils;
  28 +
  29 +import java.util.Arrays;
  30 +import java.util.HashMap;
  31 +import java.util.HashSet;
  32 +import java.util.Map;
  33 +import java.util.Set;
  34 +import java.util.concurrent.ConcurrentHashMap;
  35 +
  36 +public abstract class BaseApiUsageState {
  37 + private final Map<ApiUsageRecordKey, Long> currentCycleValues = new ConcurrentHashMap<>();
  38 + private final Map<ApiUsageRecordKey, Long> currentHourValues = new ConcurrentHashMap<>();
  39 +
  40 + @Getter
  41 + private final ApiUsageState apiUsageState;
  42 + @Getter
  43 + private volatile long currentCycleTs;
  44 + @Getter
  45 + private volatile long nextCycleTs;
  46 + @Getter
  47 + private volatile long currentHourTs;
  48 +
  49 + public BaseApiUsageState(ApiUsageState apiUsageState) {
  50 + this.apiUsageState = apiUsageState;
  51 + this.currentCycleTs = SchedulerUtils.getStartOfCurrentMonth();
  52 + this.nextCycleTs = SchedulerUtils.getStartOfNextMonth();
  53 + this.currentHourTs = SchedulerUtils.getStartOfCurrentHour();
  54 + }
  55 +
  56 + public void put(ApiUsageRecordKey key, Long value) {
  57 + currentCycleValues.put(key, value);
  58 + }
  59 +
  60 + public void putHourly(ApiUsageRecordKey key, Long value) {
  61 + currentHourValues.put(key, value);
  62 + }
  63 +
  64 + public long add(ApiUsageRecordKey key, long value) {
  65 + long result = currentCycleValues.getOrDefault(key, 0L) + value;
  66 + currentCycleValues.put(key, result);
  67 + return result;
  68 + }
  69 +
  70 + public long get(ApiUsageRecordKey key) {
  71 + return currentCycleValues.getOrDefault(key, 0L);
  72 + }
  73 +
  74 + public long addToHourly(ApiUsageRecordKey key, long value) {
  75 + long result = currentHourValues.getOrDefault(key, 0L) + value;
  76 + currentHourValues.put(key, result);
  77 + return result;
  78 + }
  79 +
  80 + public void setHour(long currentHourTs) {
  81 + this.currentHourTs = currentHourTs;
  82 + for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {
  83 + currentHourValues.put(key, 0L);
  84 + }
  85 + }
  86 +
  87 + public void setCycles(long currentCycleTs, long nextCycleTs) {
  88 + this.currentCycleTs = currentCycleTs;
  89 + this.nextCycleTs = nextCycleTs;
  90 + for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {
  91 + currentCycleValues.put(key, 0L);
  92 + }
  93 + }
  94 +
  95 + public ApiUsageStateValue getFeatureValue(ApiFeature feature) {
  96 + switch (feature) {
  97 + case TRANSPORT:
  98 + return apiUsageState.getTransportState();
  99 + case RE:
  100 + return apiUsageState.getReExecState();
  101 + case DB:
  102 + return apiUsageState.getDbStorageState();
  103 + case JS:
  104 + return apiUsageState.getJsExecState();
  105 + case EMAIL:
  106 + return apiUsageState.getEmailExecState();
  107 + case SMS:
  108 + return apiUsageState.getSmsExecState();
  109 + default:
  110 + return ApiUsageStateValue.ENABLED;
  111 + }
  112 + }
  113 +
  114 + public boolean setFeatureValue(ApiFeature feature, ApiUsageStateValue value) {
  115 + ApiUsageStateValue currentValue = getFeatureValue(feature);
  116 + switch (feature) {
  117 + case TRANSPORT:
  118 + apiUsageState.setTransportState(value);
  119 + break;
  120 + case RE:
  121 + apiUsageState.setReExecState(value);
  122 + break;
  123 + case DB:
  124 + apiUsageState.setDbStorageState(value);
  125 + break;
  126 + case JS:
  127 + apiUsageState.setJsExecState(value);
  128 + break;
  129 + case EMAIL:
  130 + apiUsageState.setEmailExecState(value);
  131 + break;
  132 + case SMS:
  133 + apiUsageState.setSmsExecState(value);
  134 + break;
  135 + }
  136 + return !currentValue.equals(value);
  137 + }
  138 +
  139 + public abstract EntityType getEntityType();
  140 +
  141 + public TenantId getTenantId() {
  142 + return getApiUsageState().getTenantId();
  143 + }
  144 +
  145 + public EntityId getEntityId() {
  146 + return getApiUsageState().getEntityId();
  147 + }
  148 +}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.apiusage;
  17 +
  18 +import org.thingsboard.server.common.data.ApiUsageState;
  19 +import org.thingsboard.server.common.data.EntityType;
  20 +
  21 +public class CustomerApiUsageState extends BaseApiUsageState {
  22 + public CustomerApiUsageState(ApiUsageState apiUsageState) {
  23 + super(apiUsageState);
  24 + }
  25 +
  26 + @Override
  27 + public EntityType getEntityType() {
  28 + return EntityType.CUSTOMER;
  29 + }
  30 +}
@@ -29,10 +29,13 @@ import org.thingsboard.server.common.data.ApiUsageRecordKey; @@ -29,10 +29,13 @@ import org.thingsboard.server.common.data.ApiUsageRecordKey;
29 import org.thingsboard.server.common.data.ApiUsageState; 29 import org.thingsboard.server.common.data.ApiUsageState;
30 import org.thingsboard.server.common.data.ApiUsageStateMailMessage; 30 import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
31 import org.thingsboard.server.common.data.ApiUsageStateValue; 31 import org.thingsboard.server.common.data.ApiUsageStateValue;
  32 +import org.thingsboard.server.common.data.EntityType;
32 import org.thingsboard.server.common.data.Tenant; 33 import org.thingsboard.server.common.data.Tenant;
33 import org.thingsboard.server.common.data.TenantProfile; 34 import org.thingsboard.server.common.data.TenantProfile;
34 import org.thingsboard.server.common.data.exception.ThingsboardException; 35 import org.thingsboard.server.common.data.exception.ThingsboardException;
35 import org.thingsboard.server.common.data.id.ApiUsageStateId; 36 import org.thingsboard.server.common.data.id.ApiUsageStateId;
  37 +import org.thingsboard.server.common.data.id.CustomerId;
  38 +import org.thingsboard.server.common.data.id.EntityId;
36 import org.thingsboard.server.common.data.id.TenantId; 39 import org.thingsboard.server.common.data.id.TenantId;
37 import org.thingsboard.server.common.data.id.TenantProfileId; 40 import org.thingsboard.server.common.data.id.TenantProfileId;
38 import org.thingsboard.server.common.data.kv.BasicTsKvEntry; 41 import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
@@ -45,6 +48,7 @@ import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; @@ -45,6 +48,7 @@ import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
45 import org.thingsboard.server.common.msg.queue.ServiceType; 48 import org.thingsboard.server.common.msg.queue.ServiceType;
46 import org.thingsboard.server.common.msg.queue.TbCallback; 49 import org.thingsboard.server.common.msg.queue.TbCallback;
47 import org.thingsboard.server.common.msg.tools.SchedulerUtils; 50 import org.thingsboard.server.common.msg.tools.SchedulerUtils;
  51 +import org.thingsboard.server.dao.customer.CustomerService;
48 import org.thingsboard.server.dao.tenant.TbTenantProfileCache; 52 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
49 import org.thingsboard.server.dao.tenant.TenantService; 53 import org.thingsboard.server.dao.tenant.TenantService;
50 import org.thingsboard.server.dao.timeseries.TimeseriesService; 54 import org.thingsboard.server.dao.timeseries.TimeseriesService;
@@ -63,6 +67,7 @@ import javax.annotation.PostConstruct; @@ -63,6 +67,7 @@ import javax.annotation.PostConstruct;
63 import javax.annotation.PreDestroy; 67 import javax.annotation.PreDestroy;
64 import java.util.ArrayList; 68 import java.util.ArrayList;
65 import java.util.Arrays; 69 import java.util.Arrays;
  70 +import java.util.Collections;
66 import java.util.HashSet; 71 import java.util.HashSet;
67 import java.util.List; 72 import java.util.List;
68 import java.util.Map; 73 import java.util.Map;
@@ -95,6 +100,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -95,6 +100,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
95 private final TbClusterService clusterService; 100 private final TbClusterService clusterService;
96 private final PartitionService partitionService; 101 private final PartitionService partitionService;
97 private final TenantService tenantService; 102 private final TenantService tenantService;
  103 + private final CustomerService customerService;
98 private final TimeseriesService tsService; 104 private final TimeseriesService tsService;
99 private final ApiUsageStateService apiUsageStateService; 105 private final ApiUsageStateService apiUsageStateService;
100 private final SchedulerComponent scheduler; 106 private final SchedulerComponent scheduler;
@@ -105,10 +111,12 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -105,10 +111,12 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
105 @Autowired 111 @Autowired
106 private InternalTelemetryService tsWsService; 112 private InternalTelemetryService tsWsService;
107 113
108 - // Tenants that should be processed on this server  
109 - private final Map<TenantId, TenantApiUsageState> myTenantStates = new ConcurrentHashMap<>();  
110 - // Tenants that should be processed on other servers  
111 - private final Map<TenantId, ApiUsageState> otherTenantStates = new ConcurrentHashMap<>(); 114 + // Entities that should be processed on this server
  115 + private final Map<EntityId, BaseApiUsageState> myUsageStates = new ConcurrentHashMap<>();
  116 + // Entities that should be processed on other servers
  117 + private final Map<EntityId, ApiUsageState> otherUsageStates = new ConcurrentHashMap<>();
  118 +
  119 + private final Set<EntityId> deletedEntities = Collections.newSetFromMap(new ConcurrentHashMap<>());
112 120
113 @Value("${usage.stats.report.enabled:true}") 121 @Value("${usage.stats.report.enabled:true}")
114 private boolean enabled; 122 private boolean enabled;
@@ -123,13 +131,16 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -123,13 +131,16 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
123 public DefaultTbApiUsageStateService(TbClusterService clusterService, 131 public DefaultTbApiUsageStateService(TbClusterService clusterService,
124 PartitionService partitionService, 132 PartitionService partitionService,
125 TenantService tenantService, 133 TenantService tenantService,
  134 + CustomerService customerService,
126 TimeseriesService tsService, 135 TimeseriesService tsService,
127 ApiUsageStateService apiUsageStateService, 136 ApiUsageStateService apiUsageStateService,
128 SchedulerComponent scheduler, 137 SchedulerComponent scheduler,
129 - TbTenantProfileCache tenantProfileCache, MailService mailService) { 138 + TbTenantProfileCache tenantProfileCache,
  139 + MailService mailService) {
130 this.clusterService = clusterService; 140 this.clusterService = clusterService;
131 this.partitionService = partitionService; 141 this.partitionService = partitionService;
132 this.tenantService = tenantService; 142 this.tenantService = tenantService;
  143 + this.customerService = customerService;
133 this.tsService = tsService; 144 this.tsService = tsService;
134 this.apiUsageStateService = apiUsageStateService; 145 this.apiUsageStateService = apiUsageStateService;
135 this.scheduler = scheduler; 146 this.scheduler = scheduler;
@@ -150,74 +161,92 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -150,74 +161,92 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
150 @Override 161 @Override
151 public void process(TbProtoQueueMsg<ToUsageStatsServiceMsg> msg, TbCallback callback) { 162 public void process(TbProtoQueueMsg<ToUsageStatsServiceMsg> msg, TbCallback callback) {
152 ToUsageStatsServiceMsg statsMsg = msg.getValue(); 163 ToUsageStatsServiceMsg statsMsg = msg.getValue();
153 - TenantId tenantId = new TenantId(new UUID(statsMsg.getTenantIdMSB(), statsMsg.getTenantIdLSB()));  
154 164
155 - if (tenantProfileCache.get(tenantId) == null) {  
156 - return; 165 + TenantId tenantId = new TenantId(new UUID(statsMsg.getTenantIdMSB(), statsMsg.getTenantIdLSB()));
  166 + EntityId entityId;
  167 + if (statsMsg.getCustomerIdMSB() != 0 && statsMsg.getCustomerIdLSB() != 0) {
  168 + entityId = new CustomerId(new UUID(statsMsg.getCustomerIdMSB(), statsMsg.getCustomerIdLSB()));
  169 + } else {
  170 + entityId = tenantId;
157 } 171 }
158 172
159 - TenantApiUsageState tenantState; 173 + processEntityUsageStats(tenantId, entityId, statsMsg.getValuesList());
  174 + callback.onSuccess();
  175 + }
  176 +
  177 + private void processEntityUsageStats(TenantId tenantId, EntityId entityId, List<UsageStatsKVProto> values) {
  178 + if (deletedEntities.contains(entityId)) return;
  179 +
  180 + BaseApiUsageState usageState;
160 List<TsKvEntry> updatedEntries; 181 List<TsKvEntry> updatedEntries;
161 Map<ApiFeature, ApiUsageStateValue> result; 182 Map<ApiFeature, ApiUsageStateValue> result;
  183 +
162 updateLock.lock(); 184 updateLock.lock();
163 try { 185 try {
164 - tenantState = getOrFetchState(tenantId);  
165 - long ts = tenantState.getCurrentCycleTs();  
166 - long hourTs = tenantState.getCurrentHourTs(); 186 + usageState = getOrFetchState(tenantId, entityId);
  187 + long ts = usageState.getCurrentCycleTs();
  188 + long hourTs = usageState.getCurrentHourTs();
167 long newHourTs = SchedulerUtils.getStartOfCurrentHour(); 189 long newHourTs = SchedulerUtils.getStartOfCurrentHour();
168 if (newHourTs != hourTs) { 190 if (newHourTs != hourTs) {
169 - tenantState.setHour(newHourTs); 191 + usageState.setHour(newHourTs);
170 } 192 }
171 updatedEntries = new ArrayList<>(ApiUsageRecordKey.values().length); 193 updatedEntries = new ArrayList<>(ApiUsageRecordKey.values().length);
172 Set<ApiFeature> apiFeatures = new HashSet<>(); 194 Set<ApiFeature> apiFeatures = new HashSet<>();
173 - for (UsageStatsKVProto kvProto : statsMsg.getValuesList()) { 195 + for (UsageStatsKVProto kvProto : values) {
174 ApiUsageRecordKey recordKey = ApiUsageRecordKey.valueOf(kvProto.getKey()); 196 ApiUsageRecordKey recordKey = ApiUsageRecordKey.valueOf(kvProto.getKey());
175 - long newValue = tenantState.add(recordKey, kvProto.getValue()); 197 + long newValue = usageState.add(recordKey, kvProto.getValue());
176 updatedEntries.add(new BasicTsKvEntry(ts, new LongDataEntry(recordKey.getApiCountKey(), newValue))); 198 updatedEntries.add(new BasicTsKvEntry(ts, new LongDataEntry(recordKey.getApiCountKey(), newValue)));
177 - long newHourlyValue = tenantState.addToHourly(recordKey, kvProto.getValue()); 199 + long newHourlyValue = usageState.addToHourly(recordKey, kvProto.getValue());
178 updatedEntries.add(new BasicTsKvEntry(newHourTs, new LongDataEntry(recordKey.getApiCountKey() + HOURLY, newHourlyValue))); 200 updatedEntries.add(new BasicTsKvEntry(newHourTs, new LongDataEntry(recordKey.getApiCountKey() + HOURLY, newHourlyValue)));
179 apiFeatures.add(recordKey.getApiFeature()); 201 apiFeatures.add(recordKey.getApiFeature());
180 } 202 }
181 - result = tenantState.checkStateUpdatedDueToThreshold(apiFeatures); 203 + if (usageState.getEntityType() == EntityType.TENANT && !usageState.getEntityId().equals(TenantId.SYS_TENANT_ID)) {
  204 + result = ((TenantApiUsageState) usageState).checkStateUpdatedDueToThreshold(apiFeatures);
  205 + } else {
  206 + result = Collections.emptyMap();
  207 + }
182 } finally { 208 } finally {
183 updateLock.unlock(); 209 updateLock.unlock();
184 } 210 }
185 - tsWsService.saveAndNotifyInternal(tenantId, tenantState.getApiUsageState().getId(), updatedEntries, VOID_CALLBACK); 211 + tsWsService.saveAndNotifyInternal(tenantId, usageState.getApiUsageState().getId(), updatedEntries, VOID_CALLBACK);
186 if (!result.isEmpty()) { 212 if (!result.isEmpty()) {
187 - persistAndNotify(tenantState, result); 213 + persistAndNotify(usageState, result);
188 } 214 }
189 - callback.onSuccess();  
190 } 215 }
191 216
192 @Override 217 @Override
193 protected void onTbApplicationEvent(PartitionChangeEvent partitionChangeEvent) { 218 protected void onTbApplicationEvent(PartitionChangeEvent partitionChangeEvent) {
194 if (partitionChangeEvent.getServiceType().equals(ServiceType.TB_CORE)) { 219 if (partitionChangeEvent.getServiceType().equals(ServiceType.TB_CORE)) {
195 - myTenantStates.entrySet().removeIf(entry -> !partitionService.resolve(ServiceType.TB_CORE, entry.getKey(), entry.getKey()).isMyPartition());  
196 - otherTenantStates.entrySet().removeIf(entry -> partitionService.resolve(ServiceType.TB_CORE, entry.getKey(), entry.getKey()).isMyPartition()); 220 + myUsageStates.entrySet().removeIf(entry -> {
  221 + return !partitionService.resolve(ServiceType.TB_CORE, entry.getValue().getTenantId(), entry.getKey()).isMyPartition();
  222 + });
  223 + otherUsageStates.entrySet().removeIf(entry -> {
  224 + return partitionService.resolve(ServiceType.TB_CORE, entry.getValue().getTenantId(), entry.getKey()).isMyPartition();
  225 + });
197 initStatesFromDataBase(); 226 initStatesFromDataBase();
198 } 227 }
199 } 228 }
200 229
201 @Override 230 @Override
202 public ApiUsageState getApiUsageState(TenantId tenantId) { 231 public ApiUsageState getApiUsageState(TenantId tenantId) {
203 - TenantApiUsageState tenantState = myTenantStates.get(tenantId); 232 + TenantApiUsageState tenantState = (TenantApiUsageState) myUsageStates.get(tenantId);
204 if (tenantState != null) { 233 if (tenantState != null) {
205 return tenantState.getApiUsageState(); 234 return tenantState.getApiUsageState();
206 } else { 235 } else {
207 - ApiUsageState state = otherTenantStates.get(tenantId); 236 + ApiUsageState state = otherUsageStates.get(tenantId);
208 if (state != null) { 237 if (state != null) {
209 return state; 238 return state;
210 } else { 239 } else {
211 if (partitionService.resolve(ServiceType.TB_CORE, tenantId, tenantId).isMyPartition()) { 240 if (partitionService.resolve(ServiceType.TB_CORE, tenantId, tenantId).isMyPartition()) {
212 - return getOrFetchState(tenantId).getApiUsageState(); 241 + return getOrFetchState(tenantId, tenantId).getApiUsageState();
213 } else { 242 } else {
214 updateLock.lock(); 243 updateLock.lock();
215 try { 244 try {
216 - state = otherTenantStates.get(tenantId); 245 + state = otherUsageStates.get(tenantId);
217 if (state == null) { 246 if (state == null) {
218 state = apiUsageStateService.findTenantApiUsageState(tenantId); 247 state = apiUsageStateService.findTenantApiUsageState(tenantId);
219 if (state != null) { 248 if (state != null) {
220 - otherTenantStates.put(tenantId, state); 249 + otherUsageStates.put(tenantId, state);
221 } 250 }
222 } 251 }
223 } finally { 252 } finally {
@@ -231,7 +260,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -231,7 +260,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
231 260
232 @Override 261 @Override
233 public void onApiUsageStateUpdate(TenantId tenantId) { 262 public void onApiUsageStateUpdate(TenantId tenantId) {
234 - otherTenantStates.remove(tenantId); 263 + otherUsageStates.remove(tenantId);
235 } 264 }
236 265
237 @Override 266 @Override
@@ -240,11 +269,14 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -240,11 +269,14 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
240 TenantProfile tenantProfile = tenantProfileCache.get(tenantProfileId); 269 TenantProfile tenantProfile = tenantProfileCache.get(tenantProfileId);
241 updateLock.lock(); 270 updateLock.lock();
242 try { 271 try {
243 - myTenantStates.values().forEach(state -> {  
244 - if (tenantProfile.getId().equals(state.getTenantProfileId())) {  
245 - updateTenantState(state, tenantProfile);  
246 - }  
247 - }); 272 + myUsageStates.values().stream()
  273 + .filter(state -> state.getEntityType() == EntityType.TENANT)
  274 + .map(state -> (TenantApiUsageState) state)
  275 + .forEach(state -> {
  276 + if (tenantProfile.getId().equals(state.getTenantProfileId())) {
  277 + updateTenantState(state, tenantProfile);
  278 + }
  279 + });
248 } finally { 280 } finally {
249 updateLock.unlock(); 281 updateLock.unlock();
250 } 282 }
@@ -256,7 +288,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -256,7 +288,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
256 TenantProfile tenantProfile = tenantProfileCache.get(tenantId); 288 TenantProfile tenantProfile = tenantProfileCache.get(tenantId);
257 updateLock.lock(); 289 updateLock.lock();
258 try { 290 try {
259 - TenantApiUsageState state = myTenantStates.get(tenantId); 291 + TenantApiUsageState state = (TenantApiUsageState) myUsageStates.get(tenantId);
260 if (state != null && !state.getTenantProfileId().equals(tenantProfile.getId())) { 292 if (state != null && !state.getTenantProfileId().equals(tenantProfile.getId())) {
261 updateTenantState(state, tenantProfile); 293 updateTenantState(state, tenantProfile);
262 } 294 }
@@ -293,29 +325,42 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -293,29 +325,42 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
293 } 325 }
294 } 326 }
295 327
296 - private void persistAndNotify(TenantApiUsageState state, Map<ApiFeature, ApiUsageStateValue> result) {  
297 - log.info("[{}] Detected update of the API state: {}", state.getTenantId(), result); 328 + public void onTenantDelete(TenantId tenantId) {
  329 + deletedEntities.add(tenantId);
  330 + myUsageStates.remove(tenantId);
  331 + otherUsageStates.remove(tenantId);
  332 + }
  333 +
  334 + @Override
  335 + public void onCustomerDelete(CustomerId customerId) {
  336 + deletedEntities.add(customerId);
  337 + myUsageStates.remove(customerId);
  338 + }
  339 +
  340 + private void persistAndNotify(BaseApiUsageState state, Map<ApiFeature, ApiUsageStateValue> result) {
  341 + log.info("[{}] Detected update of the API state for {}: {}", state.getEntityId(), state.getEntityType(), result);
298 apiUsageStateService.update(state.getApiUsageState()); 342 apiUsageStateService.update(state.getApiUsageState());
299 clusterService.onApiStateChange(state.getApiUsageState(), null); 343 clusterService.onApiStateChange(state.getApiUsageState(), null);
300 long ts = System.currentTimeMillis(); 344 long ts = System.currentTimeMillis();
301 List<TsKvEntry> stateTelemetry = new ArrayList<>(); 345 List<TsKvEntry> stateTelemetry = new ArrayList<>();
302 - result.forEach(((apiFeature, aState) -> stateTelemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(apiFeature.getApiStateKey(), aState.name()))))); 346 + result.forEach((apiFeature, aState) -> stateTelemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(apiFeature.getApiStateKey(), aState.name()))));
303 tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK); 347 tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK);
304 348
305 - String email = tenantService.findTenantById(state.getTenantId()).getEmail();  
306 -  
307 - if (StringUtils.isNotEmpty(email)) {  
308 - result.forEach((apiFeature, stateValue) -> {  
309 - mailExecutor.submit(() -> {  
310 - try {  
311 - mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, createStateMailMessage(state, apiFeature, stateValue));  
312 - } catch (ThingsboardException e) {  
313 - log.warn("[{}] Can't send update of the API state to tenant with provided email [{}]", state.getTenantId(), email, e);  
314 - } 349 + if (state.getEntityType() == EntityType.TENANT && !state.getEntityId().equals(TenantId.SYS_TENANT_ID)) {
  350 + String email = tenantService.findTenantById(state.getTenantId()).getEmail();
  351 + if (StringUtils.isNotEmpty(email)) {
  352 + result.forEach((apiFeature, stateValue) -> {
  353 + mailExecutor.submit(() -> {
  354 + try {
  355 + mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, createStateMailMessage((TenantApiUsageState) state, apiFeature, stateValue));
  356 + } catch (ThingsboardException e) {
  357 + log.warn("[{}] Can't send update of the API state to tenant with provided email [{}]", state.getTenantId(), email, e);
  358 + }
  359 + });
315 }); 360 });
316 - });  
317 - } else {  
318 - log.warn("[{}] Can't send update of the API state to tenant with empty email!", state.getTenantId()); 361 + } else {
  362 + log.warn("[{}] Can't send update of the API state to tenant with empty email!", state.getTenantId());
  363 + }
319 } 364 }
320 } 365 }
321 366
@@ -350,12 +395,14 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -350,12 +395,14 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
350 updateLock.lock(); 395 updateLock.lock();
351 try { 396 try {
352 long now = System.currentTimeMillis(); 397 long now = System.currentTimeMillis();
353 - myTenantStates.values().forEach(state -> { 398 + myUsageStates.values().forEach(state -> {
354 if ((state.getNextCycleTs() < now) && (now - state.getNextCycleTs() < TimeUnit.HOURS.toMillis(1))) { 399 if ((state.getNextCycleTs() < now) && (now - state.getNextCycleTs() < TimeUnit.HOURS.toMillis(1))) {
355 - TenantId tenantId = state.getTenantId();  
356 state.setCycles(state.getNextCycleTs(), SchedulerUtils.getStartOfNextNextMonth()); 400 state.setCycles(state.getNextCycleTs(), SchedulerUtils.getStartOfNextNextMonth());
357 saveNewCounts(state, Arrays.asList(ApiUsageRecordKey.values())); 401 saveNewCounts(state, Arrays.asList(ApiUsageRecordKey.values()));
358 - updateTenantState(state, tenantProfileCache.get(tenantId)); 402 + if (state.getEntityType() == EntityType.TENANT && !state.getEntityId().equals(TenantId.SYS_TENANT_ID)) {
  403 + TenantId tenantId = state.getTenantId();
  404 + updateTenantState((TenantApiUsageState) state, tenantProfileCache.get(tenantId));
  405 + }
359 } 406 }
360 }); 407 });
361 } finally { 408 } finally {
@@ -363,7 +410,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -363,7 +410,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
363 } 410 }
364 } 411 }
365 412
366 - private void saveNewCounts(TenantApiUsageState state, List<ApiUsageRecordKey> keys) { 413 + private void saveNewCounts(BaseApiUsageState state, List<ApiUsageRecordKey> keys) {
367 List<TsKvEntry> counts = keys.stream() 414 List<TsKvEntry> counts = keys.stream()
368 .map(key -> new BasicTsKvEntry(state.getCurrentCycleTs(), new LongDataEntry(key.getApiCountKey(), 0L))) 415 .map(key -> new BasicTsKvEntry(state.getCurrentCycleTs(), new LongDataEntry(key.getApiCountKey(), 0L)))
369 .collect(Collectors.toList()); 416 .collect(Collectors.toList());
@@ -371,52 +418,66 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -371,52 +418,66 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
371 tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), counts, VOID_CALLBACK); 418 tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), counts, VOID_CALLBACK);
372 } 419 }
373 420
374 - private TenantApiUsageState getOrFetchState(TenantId tenantId) {  
375 - TenantApiUsageState tenantState = myTenantStates.get(tenantId);  
376 - if (tenantState == null) {  
377 - ApiUsageState dbStateEntity = apiUsageStateService.findTenantApiUsageState(tenantId);  
378 - if (dbStateEntity == null) {  
379 - try {  
380 - dbStateEntity = apiUsageStateService.createDefaultApiUsageState(tenantId);  
381 - } catch (Exception e) {  
382 - dbStateEntity = apiUsageStateService.findTenantApiUsageState(tenantId);  
383 - }  
384 - }  
385 - TenantProfile tenantProfile = tenantProfileCache.get(tenantId);  
386 - tenantState = new TenantApiUsageState(tenantProfile, dbStateEntity);  
387 - List<ApiUsageRecordKey> newCounts = new ArrayList<>(); 421 + private BaseApiUsageState getOrFetchState(TenantId tenantId, EntityId entityId) {
  422 + if (entityId == null || entityId.isNullUid()) {
  423 + entityId = tenantId;
  424 + }
  425 + BaseApiUsageState state = myUsageStates.get(entityId);
  426 + if (state != null) {
  427 + return state;
  428 + }
  429 +
  430 + ApiUsageState storedState = apiUsageStateService.findApiUsageStateByEntityId(entityId);
  431 + if (storedState == null) {
388 try { 432 try {
389 - List<TsKvEntry> dbValues = tsService.findAllLatest(tenantId, dbStateEntity.getId()).get();  
390 - for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {  
391 - boolean cycleEntryFound = false;  
392 - boolean hourlyEntryFound = false;  
393 - for (TsKvEntry tsKvEntry : dbValues) {  
394 - if (tsKvEntry.getKey().equals(key.getApiCountKey())) {  
395 - cycleEntryFound = true;  
396 -  
397 - boolean oldCount = tsKvEntry.getTs() == tenantState.getCurrentCycleTs();  
398 - tenantState.put(key, oldCount ? tsKvEntry.getLongValue().get() : 0L);  
399 -  
400 - if (!oldCount) {  
401 - newCounts.add(key);  
402 - }  
403 - } else if (tsKvEntry.getKey().equals(key.getApiCountKey() + HOURLY)) {  
404 - hourlyEntryFound = true;  
405 - tenantState.putHourly(key, tsKvEntry.getTs() == tenantState.getCurrentHourTs() ? tsKvEntry.getLongValue().get() : 0L);  
406 - }  
407 - if (cycleEntryFound && hourlyEntryFound) {  
408 - break; 433 + storedState = apiUsageStateService.createDefaultApiUsageState(tenantId, entityId);
  434 + } catch (Exception e) {
  435 + storedState = apiUsageStateService.findApiUsageStateByEntityId(entityId);
  436 + }
  437 + }
  438 + if (entityId.getEntityType() == EntityType.TENANT) {
  439 + if (!entityId.equals(TenantId.SYS_TENANT_ID)) {
  440 + state = new TenantApiUsageState(tenantProfileCache.get((TenantId) entityId), storedState);
  441 + } else {
  442 + state = new TenantApiUsageState(storedState);
  443 + }
  444 + } else {
  445 + state = new CustomerApiUsageState(storedState);
  446 + }
  447 +
  448 + List<ApiUsageRecordKey> newCounts = new ArrayList<>();
  449 + try {
  450 + List<TsKvEntry> dbValues = tsService.findAllLatest(tenantId, storedState.getId()).get();
  451 + for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {
  452 + boolean cycleEntryFound = false;
  453 + boolean hourlyEntryFound = false;
  454 + for (TsKvEntry tsKvEntry : dbValues) {
  455 + if (tsKvEntry.getKey().equals(key.getApiCountKey())) {
  456 + cycleEntryFound = true;
  457 +
  458 + boolean oldCount = tsKvEntry.getTs() == state.getCurrentCycleTs();
  459 + state.put(key, oldCount ? tsKvEntry.getLongValue().get() : 0L);
  460 +
  461 + if (!oldCount) {
  462 + newCounts.add(key);
409 } 463 }
  464 + } else if (tsKvEntry.getKey().equals(key.getApiCountKey() + HOURLY)) {
  465 + hourlyEntryFound = true;
  466 + state.putHourly(key, tsKvEntry.getTs() == state.getCurrentHourTs() ? tsKvEntry.getLongValue().get() : 0L);
  467 + }
  468 + if (cycleEntryFound && hourlyEntryFound) {
  469 + break;
410 } 470 }
411 } 471 }
412 - log.debug("[{}] Initialized state: {}", tenantId, dbStateEntity);  
413 - myTenantStates.put(tenantId, tenantState);  
414 - saveNewCounts(tenantState, newCounts);  
415 - } catch (InterruptedException | ExecutionException e) {  
416 - log.warn("[{}] Failed to fetch api usage state from db.", tenantId, e);  
417 } 472 }
  473 + log.debug("[{}] Initialized state: {}", entityId, storedState);
  474 + myUsageStates.put(entityId, state);
  475 + saveNewCounts(state, newCounts);
  476 + } catch (InterruptedException | ExecutionException e) {
  477 + log.warn("[{}] Failed to fetch api usage state from db.", tenantId, e);
418 } 478 }
419 - return tenantState; 479 +
  480 + return state;
420 } 481 }
421 482
422 private void initStatesFromDataBase() { 483 private void initStatesFromDataBase() {
@@ -429,11 +490,11 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa @@ -429,11 +490,11 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
429 PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, 1024); 490 PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, 1024);
430 List<Future<?>> futures = new ArrayList<>(); 491 List<Future<?>> futures = new ArrayList<>();
431 for (Tenant tenant : tenantIterator) { 492 for (Tenant tenant : tenantIterator) {
432 - if (!myTenantStates.containsKey(tenant.getId()) && partitionService.resolve(ServiceType.TB_CORE, tenant.getId(), tenant.getId()).isMyPartition()) { 493 + if (!myUsageStates.containsKey(tenant.getId()) && partitionService.resolve(ServiceType.TB_CORE, tenant.getId(), tenant.getId()).isMyPartition()) {
433 log.debug("[{}] Initializing tenant state.", tenant.getId()); 494 log.debug("[{}] Initializing tenant state.", tenant.getId());
434 futures.add(tmpInitExecutor.submit(() -> { 495 futures.add(tmpInitExecutor.submit(() -> {
435 try { 496 try {
436 - updateTenantState(getOrFetchState(tenant.getId()), tenantProfileCache.get(tenant.getTenantProfileId())); 497 + updateTenantState((TenantApiUsageState) getOrFetchState(tenant.getId(), tenant.getId()), tenantProfileCache.get(tenant.getTenantProfileId()));
437 log.debug("[{}] Initialized tenant state.", tenant.getId()); 498 log.debug("[{}] Initialized tenant state.", tenant.getId());
438 } catch (Exception e) { 499 } catch (Exception e) {
439 log.warn("[{}] Failed to initialize tenant API state", tenant.getId(), e); 500 log.warn("[{}] Failed to initialize tenant API state", tenant.getId(), e);
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.apiusage; @@ -17,6 +17,7 @@ package org.thingsboard.server.service.apiusage;
17 17
18 import org.springframework.context.ApplicationListener; 18 import org.springframework.context.ApplicationListener;
19 import org.thingsboard.server.common.data.ApiUsageState; 19 import org.thingsboard.server.common.data.ApiUsageState;
  20 +import org.thingsboard.server.common.data.id.CustomerId;
20 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
21 import org.thingsboard.server.common.data.id.TenantProfileId; 22 import org.thingsboard.server.common.data.id.TenantProfileId;
22 import org.thingsboard.server.common.msg.queue.TbCallback; 23 import org.thingsboard.server.common.msg.queue.TbCallback;
@@ -34,5 +35,9 @@ public interface TbApiUsageStateService extends ApplicationListener<PartitionCha @@ -34,5 +35,9 @@ public interface TbApiUsageStateService extends ApplicationListener<PartitionCha
34 35
35 void onTenantUpdate(TenantId tenantId); 36 void onTenantUpdate(TenantId tenantId);
36 37
  38 + void onTenantDelete(TenantId tenantId);
  39 +
  40 + void onCustomerDelete(CustomerId customerId);
  41 +
37 void onApiUsageStateUpdate(TenantId tenantId); 42 void onApiUsageStateUpdate(TenantId tenantId);
38 } 43 }
@@ -22,85 +22,33 @@ import org.thingsboard.server.common.data.ApiFeature; @@ -22,85 +22,33 @@ import org.thingsboard.server.common.data.ApiFeature;
22 import org.thingsboard.server.common.data.ApiUsageRecordKey; 22 import org.thingsboard.server.common.data.ApiUsageRecordKey;
23 import org.thingsboard.server.common.data.ApiUsageState; 23 import org.thingsboard.server.common.data.ApiUsageState;
24 import org.thingsboard.server.common.data.ApiUsageStateValue; 24 import org.thingsboard.server.common.data.ApiUsageStateValue;
  25 +import org.thingsboard.server.common.data.EntityType;
25 import org.thingsboard.server.common.data.TenantProfile; 26 import org.thingsboard.server.common.data.TenantProfile;
26 -import org.thingsboard.server.common.data.id.TenantId;  
27 import org.thingsboard.server.common.data.id.TenantProfileId; 27 import org.thingsboard.server.common.data.id.TenantProfileId;
28 import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; 28 import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
29 -import org.thingsboard.server.common.msg.tools.SchedulerUtils;  
30 29
31 import java.util.Arrays; 30 import java.util.Arrays;
32 import java.util.HashMap; 31 import java.util.HashMap;
33 import java.util.HashSet; 32 import java.util.HashSet;
34 import java.util.Map; 33 import java.util.Map;
35 import java.util.Set; 34 import java.util.Set;
36 -import java.util.concurrent.ConcurrentHashMap;  
37 -  
38 -public class TenantApiUsageState {  
39 -  
40 - private final Map<ApiUsageRecordKey, Long> currentCycleValues = new ConcurrentHashMap<>();  
41 - private final Map<ApiUsageRecordKey, Long> currentHourValues = new ConcurrentHashMap<>();  
42 35
  36 +public class TenantApiUsageState extends BaseApiUsageState {
43 @Getter 37 @Getter
44 @Setter 38 @Setter
45 private TenantProfileId tenantProfileId; 39 private TenantProfileId tenantProfileId;
46 @Getter 40 @Getter
47 @Setter 41 @Setter
48 private TenantProfileData tenantProfileData; 42 private TenantProfileData tenantProfileData;
49 - @Getter  
50 - private final ApiUsageState apiUsageState;  
51 - @Getter  
52 - private volatile long currentCycleTs;  
53 - @Getter  
54 - private volatile long nextCycleTs;  
55 - @Getter  
56 - private volatile long currentHourTs;  
57 43
58 public TenantApiUsageState(TenantProfile tenantProfile, ApiUsageState apiUsageState) { 44 public TenantApiUsageState(TenantProfile tenantProfile, ApiUsageState apiUsageState) {
  45 + super(apiUsageState);
59 this.tenantProfileId = tenantProfile.getId(); 46 this.tenantProfileId = tenantProfile.getId();
60 this.tenantProfileData = tenantProfile.getProfileData(); 47 this.tenantProfileData = tenantProfile.getProfileData();
61 - this.apiUsageState = apiUsageState;  
62 - this.currentCycleTs = SchedulerUtils.getStartOfCurrentMonth();  
63 - this.nextCycleTs = SchedulerUtils.getStartOfNextMonth();  
64 - this.currentHourTs = SchedulerUtils.getStartOfCurrentHour();  
65 - }  
66 -  
67 - public void put(ApiUsageRecordKey key, Long value) {  
68 - currentCycleValues.put(key, value);  
69 } 48 }
70 49
71 - public void putHourly(ApiUsageRecordKey key, Long value) {  
72 - currentHourValues.put(key, value);  
73 - }  
74 -  
75 - public long add(ApiUsageRecordKey key, long value) {  
76 - long result = currentCycleValues.getOrDefault(key, 0L) + value;  
77 - currentCycleValues.put(key, result);  
78 - return result;  
79 - }  
80 -  
81 - public long get(ApiUsageRecordKey key) {  
82 - return currentCycleValues.getOrDefault(key, 0L);  
83 - }  
84 -  
85 - public long addToHourly(ApiUsageRecordKey key, long value) {  
86 - long result = currentHourValues.getOrDefault(key, 0L) + value;  
87 - currentHourValues.put(key, result);  
88 - return result;  
89 - }  
90 -  
91 - public void setHour(long currentHourTs) {  
92 - this.currentHourTs = currentHourTs;  
93 - for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {  
94 - currentHourValues.put(key, 0L);  
95 - }  
96 - }  
97 -  
98 - public void setCycles(long currentCycleTs, long nextCycleTs) {  
99 - this.currentCycleTs = currentCycleTs;  
100 - this.nextCycleTs = nextCycleTs;  
101 - for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {  
102 - currentCycleValues.put(key, 0L);  
103 - } 50 + public TenantApiUsageState(ApiUsageState apiUsageState) {
  51 + super(apiUsageState);
104 } 52 }
105 53
106 public long getProfileThreshold(ApiUsageRecordKey key) { 54 public long getProfileThreshold(ApiUsageRecordKey key) {
@@ -111,53 +59,25 @@ public class TenantApiUsageState { @@ -111,53 +59,25 @@ public class TenantApiUsageState {
111 return tenantProfileData.getConfiguration().getWarnThreshold(key); 59 return tenantProfileData.getConfiguration().getWarnThreshold(key);
112 } 60 }
113 61
114 - public TenantId getTenantId() {  
115 - return apiUsageState.getTenantId();  
116 - }  
117 -  
118 - public ApiUsageStateValue getFeatureValue(ApiFeature feature) {  
119 - switch (feature) {  
120 - case TRANSPORT:  
121 - return apiUsageState.getTransportState();  
122 - case RE:  
123 - return apiUsageState.getReExecState();  
124 - case DB:  
125 - return apiUsageState.getDbStorageState();  
126 - case JS:  
127 - return apiUsageState.getJsExecState();  
128 - case EMAIL:  
129 - return apiUsageState.getEmailExecState();  
130 - case SMS:  
131 - return apiUsageState.getSmsExecState();  
132 - default:  
133 - return ApiUsageStateValue.ENABLED; 62 + private Pair<ApiFeature, ApiUsageStateValue> checkStateUpdatedDueToThreshold(ApiFeature feature) {
  63 + ApiUsageStateValue featureValue = ApiUsageStateValue.ENABLED;
  64 + for (ApiUsageRecordKey recordKey : ApiUsageRecordKey.getKeys(feature)) {
  65 + long value = get(recordKey);
  66 + long threshold = getProfileThreshold(recordKey);
  67 + long warnThreshold = getProfileWarnThreshold(recordKey);
  68 + ApiUsageStateValue tmpValue;
  69 + if (threshold == 0 || value == 0 || value < warnThreshold) {
  70 + tmpValue = ApiUsageStateValue.ENABLED;
  71 + } else if (value < threshold) {
  72 + tmpValue = ApiUsageStateValue.WARNING;
  73 + } else {
  74 + tmpValue = ApiUsageStateValue.DISABLED;
  75 + }
  76 + featureValue = ApiUsageStateValue.toMoreRestricted(featureValue, tmpValue);
134 } 77 }
  78 + return setFeatureValue(feature, featureValue) ? Pair.of(feature, featureValue) : null;
135 } 79 }
136 80
137 - public boolean setFeatureValue(ApiFeature feature, ApiUsageStateValue value) {  
138 - ApiUsageStateValue currentValue = getFeatureValue(feature);  
139 - switch (feature) {  
140 - case TRANSPORT:  
141 - apiUsageState.setTransportState(value);  
142 - break;  
143 - case RE:  
144 - apiUsageState.setReExecState(value);  
145 - break;  
146 - case DB:  
147 - apiUsageState.setDbStorageState(value);  
148 - break;  
149 - case JS:  
150 - apiUsageState.setJsExecState(value);  
151 - break;  
152 - case EMAIL:  
153 - apiUsageState.setEmailExecState(value);  
154 - break;  
155 - case SMS:  
156 - apiUsageState.setSmsExecState(value);  
157 - break;  
158 - }  
159 - return !currentValue.equals(value);  
160 - }  
161 81
162 public Map<ApiFeature, ApiUsageStateValue> checkStateUpdatedDueToThresholds() { 82 public Map<ApiFeature, ApiUsageStateValue> checkStateUpdatedDueToThresholds() {
163 return checkStateUpdatedDueToThreshold(new HashSet<>(Arrays.asList(ApiFeature.values()))); 83 return checkStateUpdatedDueToThreshold(new HashSet<>(Arrays.asList(ApiFeature.values())));
@@ -174,23 +94,9 @@ public class TenantApiUsageState { @@ -174,23 +94,9 @@ public class TenantApiUsageState {
174 return result; 94 return result;
175 } 95 }
176 96
177 - public Pair<ApiFeature, ApiUsageStateValue> checkStateUpdatedDueToThreshold(ApiFeature feature) {  
178 - ApiUsageStateValue featureValue = ApiUsageStateValue.ENABLED;  
179 - for (ApiUsageRecordKey recordKey : ApiUsageRecordKey.getKeys(feature)) {  
180 - long value = get(recordKey);  
181 - long threshold = getProfileThreshold(recordKey);  
182 - long warnThreshold = getProfileWarnThreshold(recordKey);  
183 - ApiUsageStateValue tmpValue;  
184 - if (threshold == 0 || value == 0 || value < warnThreshold) {  
185 - tmpValue = ApiUsageStateValue.ENABLED;  
186 - } else if (value < threshold) {  
187 - tmpValue = ApiUsageStateValue.WARNING;  
188 - } else {  
189 - tmpValue = ApiUsageStateValue.DISABLED;  
190 - }  
191 - featureValue = ApiUsageStateValue.toMoreRestricted(featureValue, tmpValue);  
192 - }  
193 - return setFeatureValue(feature, featureValue) ? Pair.of(feature, featureValue) : null; 97 + @Override
  98 + public EntityType getEntityType() {
  99 + return EntityType.TENANT;
194 } 100 }
195 101
196 } 102 }
@@ -230,7 +230,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { @@ -230,7 +230,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
230 private void pushProvisionEventToRuleEngine(ProvisionRequest request, Device device, String type) { 230 private void pushProvisionEventToRuleEngine(ProvisionRequest request, Device device, String type) {
231 try { 231 try {
232 JsonNode entityNode = JacksonUtil.valueToTree(request); 232 JsonNode entityNode = JacksonUtil.valueToTree(request);
233 - TbMsg msg = TbMsg.newMsg(type, device.getId(), createTbMsgMetaData(device), JacksonUtil.toString(entityNode)); 233 + TbMsg msg = TbMsg.newMsg(type, device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.toString(entityNode));
234 sendToRuleEngine(device.getTenantId(), msg, null); 234 sendToRuleEngine(device.getTenantId(), msg, null);
235 } catch (IllegalArgumentException e) { 235 } catch (IllegalArgumentException e) {
236 log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), type, e); 236 log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), type, e);
@@ -240,7 +240,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { @@ -240,7 +240,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
240 private void pushDeviceCreatedEventToRuleEngine(Device device) { 240 private void pushDeviceCreatedEventToRuleEngine(Device device) {
241 try { 241 try {
242 ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device); 242 ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device);
243 - TbMsg msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, device.getId(), createTbMsgMetaData(device), JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); 243 + TbMsg msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode));
244 sendToRuleEngine(device.getTenantId(), msg, null); 244 sendToRuleEngine(device.getTenantId(), msg, null);
245 } catch (JsonProcessingException | IllegalArgumentException e) { 245 } catch (JsonProcessingException | IllegalArgumentException e) {
246 log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), DataConstants.ENTITY_CREATED, e); 246 log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), DataConstants.ENTITY_CREATED, e);
@@ -920,7 +920,7 @@ public final class EdgeGrpcSession implements Closeable { @@ -920,7 +920,7 @@ public final class EdgeGrpcSession implements Closeable {
920 try { 920 try {
921 if (uplinkMsg.getEntityDataCount() > 0) { 921 if (uplinkMsg.getEntityDataCount() > 0) {
922 for (EntityDataProto entityData : uplinkMsg.getEntityDataList()) { 922 for (EntityDataProto entityData : uplinkMsg.getEntityDataList()) {
923 - result.addAll(ctx.getTelemetryProcessor().onTelemetryUpdate(edge.getTenantId(), entityData)); 923 + result.addAll(ctx.getTelemetryProcessor().onTelemetryUpdate(edge.getTenantId(), edge.getCustomerId(), entityData));
924 } 924 }
925 } 925 }
926 if (uplinkMsg.getDeviceUpdateMsgCount() > 0) { 926 if (uplinkMsg.getDeviceUpdateMsgCount() > 0) {
@@ -231,7 +231,7 @@ public class DeviceProcessor extends BaseProcessor { @@ -231,7 +231,7 @@ public class DeviceProcessor extends BaseProcessor {
231 try { 231 try {
232 DeviceId deviceId = device.getId(); 232 DeviceId deviceId = device.getId();
233 ObjectNode entityNode = mapper.valueToTree(device); 233 ObjectNode entityNode = mapper.valueToTree(device);
234 - TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, 234 + TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, device.getCustomerId(),
235 getActionTbMsgMetaData(edge, device.getCustomerId()), TbMsgDataType.JSON, mapper.writeValueAsString(entityNode)); 235 getActionTbMsgMetaData(edge, device.getCustomerId()), TbMsgDataType.JSON, mapper.writeValueAsString(entityNode));
236 tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() { 236 tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() {
237 @Override 237 @Override
@@ -70,7 +70,7 @@ public class TelemetryProcessor extends BaseProcessor { @@ -70,7 +70,7 @@ public class TelemetryProcessor extends BaseProcessor {
70 70
71 private final Gson gson = new Gson(); 71 private final Gson gson = new Gson();
72 72
73 - public List<ListenableFuture<Void>> onTelemetryUpdate(TenantId tenantId, EntityDataProto entityData) { 73 + public List<ListenableFuture<Void>> onTelemetryUpdate(TenantId tenantId, CustomerId customerId, EntityDataProto entityData) {
74 log.trace("[{}] onTelemetryUpdate [{}]", tenantId, entityData); 74 log.trace("[{}] onTelemetryUpdate [{}]", tenantId, entityData);
75 List<ListenableFuture<Void>> result = new ArrayList<>(); 75 List<ListenableFuture<Void>> result = new ArrayList<>();
76 EntityId entityId = constructEntityId(entityData); 76 EntityId entityId = constructEntityId(entityData);
@@ -80,14 +80,14 @@ public class TelemetryProcessor extends BaseProcessor { @@ -80,14 +80,14 @@ public class TelemetryProcessor extends BaseProcessor {
80 TbMsgMetaData metaData = new TbMsgMetaData(); 80 TbMsgMetaData metaData = new TbMsgMetaData();
81 metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE); 81 metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE);
82 if (entityData.hasPostAttributesMsg()) { 82 if (entityData.hasPostAttributesMsg()) {
83 - result.add(processPostAttributes(tenantId, entityId, entityData.getPostAttributesMsg(), metaData)); 83 + result.add(processPostAttributes(tenantId, customerId, entityId, entityData.getPostAttributesMsg(), metaData));
84 } 84 }
85 if (entityData.hasAttributesUpdatedMsg()) { 85 if (entityData.hasAttributesUpdatedMsg()) {
86 metaData.putValue("scope", entityData.getPostAttributeScope()); 86 metaData.putValue("scope", entityData.getPostAttributeScope());
87 - result.add(processAttributesUpdate(tenantId, entityId, entityData.getAttributesUpdatedMsg(), metaData)); 87 + result.add(processAttributesUpdate(tenantId, customerId, entityId, entityData.getAttributesUpdatedMsg(), metaData));
88 } 88 }
89 if (entityData.hasPostTelemetryMsg()) { 89 if (entityData.hasPostTelemetryMsg()) {
90 - result.add(processPostTelemetry(tenantId, entityId, entityData.getPostTelemetryMsg(), metaData)); 90 + result.add(processPostTelemetry(tenantId, customerId, entityId, entityData.getPostTelemetryMsg(), metaData));
91 } 91 }
92 } 92 }
93 if (entityData.hasAttributeDeleteMsg()) { 93 if (entityData.hasAttributeDeleteMsg()) {
@@ -148,7 +148,7 @@ public class TelemetryProcessor extends BaseProcessor { @@ -148,7 +148,7 @@ public class TelemetryProcessor extends BaseProcessor {
148 } 148 }
149 } 149 }
150 150
151 - private ListenableFuture<Void> processPostTelemetry(TenantId tenantId, EntityId entityId, TransportProtos.PostTelemetryMsg msg, TbMsgMetaData metaData) { 151 + private ListenableFuture<Void> processPostTelemetry(TenantId tenantId, CustomerId customerId, EntityId entityId, TransportProtos.PostTelemetryMsg msg, TbMsgMetaData metaData) {
152 SettableFuture<Void> futureToSet = SettableFuture.create(); 152 SettableFuture<Void> futureToSet = SettableFuture.create();
153 for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) { 153 for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) {
154 JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); 154 JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
@@ -156,7 +156,7 @@ public class TelemetryProcessor extends BaseProcessor { @@ -156,7 +156,7 @@ public class TelemetryProcessor extends BaseProcessor {
156 Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); 156 Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
157 String queueName = defaultQueueAndRuleChain.getKey(); 157 String queueName = defaultQueueAndRuleChain.getKey();
158 RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue(); 158 RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
159 - TbMsg tbMsg = TbMsg.newMsg(queueName, SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, metaData, gson.toJson(json), ruleChainId, null); 159 + TbMsg tbMsg = TbMsg.newMsg(queueName, SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
160 tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { 160 tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
161 @Override 161 @Override
162 public void onSuccess(TbQueueMsgMetadata metadata) { 162 public void onSuccess(TbQueueMsgMetadata metadata) {
@@ -173,13 +173,13 @@ public class TelemetryProcessor extends BaseProcessor { @@ -173,13 +173,13 @@ public class TelemetryProcessor extends BaseProcessor {
173 return futureToSet; 173 return futureToSet;
174 } 174 }
175 175
176 - private ListenableFuture<Void> processPostAttributes(TenantId tenantId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) { 176 + private ListenableFuture<Void> processPostAttributes(TenantId tenantId, CustomerId customerId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) {
177 SettableFuture<Void> futureToSet = SettableFuture.create(); 177 SettableFuture<Void> futureToSet = SettableFuture.create();
178 JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); 178 JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
179 Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); 179 Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
180 String queueName = defaultQueueAndRuleChain.getKey(); 180 String queueName = defaultQueueAndRuleChain.getKey();
181 RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue(); 181 RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
182 - TbMsg tbMsg = TbMsg.newMsg(queueName, SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, metaData, gson.toJson(json), ruleChainId, null); 182 + TbMsg tbMsg = TbMsg.newMsg(queueName, SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
183 tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { 183 tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
184 @Override 184 @Override
185 public void onSuccess(TbQueueMsgMetadata metadata) { 185 public void onSuccess(TbQueueMsgMetadata metadata) {
@@ -195,7 +195,7 @@ public class TelemetryProcessor extends BaseProcessor { @@ -195,7 +195,7 @@ public class TelemetryProcessor extends BaseProcessor {
195 return futureToSet; 195 return futureToSet;
196 } 196 }
197 197
198 - private ListenableFuture<Void> processAttributesUpdate(TenantId tenantId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) { 198 + private ListenableFuture<Void> processAttributesUpdate(TenantId tenantId, CustomerId customerId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) {
199 SettableFuture<Void> futureToSet = SettableFuture.create(); 199 SettableFuture<Void> futureToSet = SettableFuture.create();
200 JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); 200 JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
201 Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(json); 201 Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(json);
@@ -206,7 +206,7 @@ public class TelemetryProcessor extends BaseProcessor { @@ -206,7 +206,7 @@ public class TelemetryProcessor extends BaseProcessor {
206 Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); 206 Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
207 String queueName = defaultQueueAndRuleChain.getKey(); 207 String queueName = defaultQueueAndRuleChain.getKey();
208 RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue(); 208 RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue();
209 - TbMsg tbMsg = TbMsg.newMsg(queueName, DataConstants.ATTRIBUTES_UPDATED, entityId, metaData, gson.toJson(json), ruleChainId, null); 209 + TbMsg tbMsg = TbMsg.newMsg(queueName, DataConstants.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), ruleChainId, null);
210 tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { 210 tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
211 @Override 211 @Override
212 public void onSuccess(TbQueueMsgMetadata metadata) { 212 public void onSuccess(TbQueueMsgMetadata metadata) {
@@ -390,7 +390,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService @@ -390,7 +390,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
390 pageData = tenantService.findTenants(pageLink); 390 pageData = tenantService.findTenants(pageLink);
391 for (Tenant tenant : pageData.getData()) { 391 for (Tenant tenant : pageData.getData()) {
392 try { 392 try {
393 - apiUsageStateService.createDefaultApiUsageState(tenant.getId()); 393 + apiUsageStateService.createDefaultApiUsageState(tenant.getId(), null);
394 } catch (Exception e) { 394 } catch (Exception e) {
395 } 395 }
396 List<EntitySubtype> deviceTypes = deviceService.findDeviceTypesByTenantId(tenant.getId()).get(); 396 List<EntitySubtype> deviceTypes = deviceService.findDeviceTypesByTenantId(tenant.getId()).get();
@@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.ApiUsageStateMailMessage; @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
36 import org.thingsboard.server.common.data.ApiUsageStateValue; 36 import org.thingsboard.server.common.data.ApiUsageStateValue;
37 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; 37 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
38 import org.thingsboard.server.common.data.exception.ThingsboardException; 38 import org.thingsboard.server.common.data.exception.ThingsboardException;
  39 +import org.thingsboard.server.common.data.id.CustomerId;
39 import org.thingsboard.server.common.data.id.EntityId; 40 import org.thingsboard.server.common.data.id.EntityId;
40 import org.thingsboard.server.common.data.id.TenantId; 41 import org.thingsboard.server.common.data.id.TenantId;
41 import org.thingsboard.server.dao.exception.IncorrectParameterException; 42 import org.thingsboard.server.dao.exception.IncorrectParameterException;
@@ -233,7 +234,7 @@ public class DefaultMailService implements MailService { @@ -233,7 +234,7 @@ public class DefaultMailService implements MailService {
233 } 234 }
234 235
235 @Override 236 @Override
236 - public void send(TenantId tenantId, String from, String to, String cc, String bcc, String subject, String body) throws MessagingException { 237 + public void send(TenantId tenantId, CustomerId customerId, String from, String to, String cc, String bcc, String subject, String body) throws MessagingException {
237 if (apiUsageStateService.getApiUsageState(tenantId).isEmailSendEnabled()) { 238 if (apiUsageStateService.getApiUsageState(tenantId).isEmailSendEnabled()) {
238 MimeMessage mailMsg = mailSender.createMimeMessage(); 239 MimeMessage mailMsg = mailSender.createMimeMessage();
239 MimeMessageHelper helper = new MimeMessageHelper(mailMsg, "UTF-8"); 240 MimeMessageHelper helper = new MimeMessageHelper(mailMsg, "UTF-8");
@@ -248,7 +249,7 @@ public class DefaultMailService implements MailService { @@ -248,7 +249,7 @@ public class DefaultMailService implements MailService {
248 helper.setSubject(subject); 249 helper.setSubject(subject);
249 helper.setText(body); 250 helper.setText(body);
250 mailSender.send(helper.getMimeMessage()); 251 mailSender.send(helper.getMimeMessage());
251 - apiUsageClient.report(tenantId, ApiUsageRecordKey.EMAIL_EXEC_COUNT, 1); 252 + apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.EMAIL_EXEC_COUNT, 1);
252 } else { 253 } else {
253 throw new RuntimeException("Email sending is disabled due to API limits!"); 254 throw new RuntimeException("Email sending is disabled due to API limits!");
254 } 255 }
@@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.HasName; @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.HasName;
29 import org.thingsboard.server.common.data.TbResource; 29 import org.thingsboard.server.common.data.TbResource;
30 import org.thingsboard.server.common.data.Tenant; 30 import org.thingsboard.server.common.data.Tenant;
31 import org.thingsboard.server.common.data.TenantProfile; 31 import org.thingsboard.server.common.data.TenantProfile;
  32 +import org.thingsboard.server.common.data.id.CustomerId;
32 import org.thingsboard.server.common.data.id.DeviceId; 33 import org.thingsboard.server.common.data.id.DeviceId;
33 import org.thingsboard.server.common.data.id.DeviceProfileId; 34 import org.thingsboard.server.common.data.id.DeviceProfileId;
34 import org.thingsboard.server.common.data.id.EdgeId; 35 import org.thingsboard.server.common.data.id.EdgeId;
@@ -18,14 +18,15 @@ package org.thingsboard.server.service.queue.processing; @@ -18,14 +18,15 @@ package org.thingsboard.server.service.queue.processing;
18 import com.google.protobuf.ByteString; 18 import com.google.protobuf.ByteString;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
20 import org.springframework.boot.context.event.ApplicationReadyEvent; 20 import org.springframework.boot.context.event.ApplicationReadyEvent;
21 -import org.springframework.context.ApplicationListener;  
22 import org.springframework.context.event.EventListener; 21 import org.springframework.context.event.EventListener;
23 import org.springframework.core.annotation.Order; 22 import org.springframework.core.annotation.Order;
24 import org.thingsboard.common.util.ThingsBoardThreadFactory; 23 import org.thingsboard.common.util.ThingsBoardThreadFactory;
25 import org.thingsboard.server.actors.ActorSystemContext; 24 import org.thingsboard.server.actors.ActorSystemContext;
26 import org.thingsboard.server.common.data.EntityType; 25 import org.thingsboard.server.common.data.EntityType;
  26 +import org.thingsboard.server.common.data.id.CustomerId;
27 import org.thingsboard.server.common.data.id.DeviceId; 27 import org.thingsboard.server.common.data.id.DeviceId;
28 import org.thingsboard.server.common.data.id.DeviceProfileId; 28 import org.thingsboard.server.common.data.id.DeviceProfileId;
  29 +import org.thingsboard.server.common.data.id.TenantId;
29 import org.thingsboard.server.common.data.id.TenantProfileId; 30 import org.thingsboard.server.common.data.id.TenantProfileId;
30 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 31 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
31 import org.thingsboard.server.common.msg.TbActorMsg; 32 import org.thingsboard.server.common.msg.TbActorMsg;
@@ -72,7 +73,8 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene @@ -72,7 +73,8 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
72 protected final TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer; 73 protected final TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer;
73 74
74 public AbstractConsumerService(ActorSystemContext actorContext, DataDecodingEncodingService encodingService, 75 public AbstractConsumerService(ActorSystemContext actorContext, DataDecodingEncodingService encodingService,
75 - TbTenantProfileCache tenantProfileCache, TbDeviceProfileCache deviceProfileCache, TbApiUsageStateService apiUsageStateService, TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer) { 76 + TbTenantProfileCache tenantProfileCache, TbDeviceProfileCache deviceProfileCache,
  77 + TbApiUsageStateService apiUsageStateService, TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer) {
76 this.actorContext = actorContext; 78 this.actorContext = actorContext;
77 this.encodingService = encodingService; 79 this.encodingService = encodingService;
78 this.tenantProfileCache = tenantProfileCache; 80 this.tenantProfileCache = tenantProfileCache;
@@ -166,6 +168,8 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene @@ -166,6 +168,8 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
166 tenantProfileCache.evict(componentLifecycleMsg.getTenantId()); 168 tenantProfileCache.evict(componentLifecycleMsg.getTenantId());
167 if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.UPDATED)) { 169 if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.UPDATED)) {
168 apiUsageStateService.onTenantUpdate(componentLifecycleMsg.getTenantId()); 170 apiUsageStateService.onTenantUpdate(componentLifecycleMsg.getTenantId());
  171 + } else if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.DELETED)) {
  172 + apiUsageStateService.onTenantDelete((TenantId) componentLifecycleMsg.getEntityId());
169 } 173 }
170 } else if (EntityType.DEVICE_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { 174 } else if (EntityType.DEVICE_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
171 deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceProfileId(componentLifecycleMsg.getEntityId().getId())); 175 deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceProfileId(componentLifecycleMsg.getEntityId().getId()));
@@ -173,6 +177,10 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene @@ -173,6 +177,10 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
173 deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceId(componentLifecycleMsg.getEntityId().getId())); 177 deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceId(componentLifecycleMsg.getEntityId().getId()));
174 } else if (EntityType.API_USAGE_STATE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { 178 } else if (EntityType.API_USAGE_STATE.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
175 apiUsageStateService.onApiUsageStateUpdate(componentLifecycleMsg.getTenantId()); 179 apiUsageStateService.onApiUsageStateUpdate(componentLifecycleMsg.getTenantId());
  180 + } else if (EntityType.CUSTOMER.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
  181 + if (componentLifecycleMsg.getEvent() == ComponentLifecycleEvent.DELETED) {
  182 + apiUsageStateService.onCustomerDelete((CustomerId) componentLifecycleMsg.getEntityId());
  183 + }
176 } 184 }
177 } 185 }
178 log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg); 186 log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg);
@@ -34,6 +34,7 @@ import org.thingsboard.server.dao.device.DeviceService; @@ -34,6 +34,7 @@ import org.thingsboard.server.dao.device.DeviceService;
34 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; 34 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
35 import org.thingsboard.server.queue.util.TbCoreComponent; 35 import org.thingsboard.server.queue.util.TbCoreComponent;
36 import org.thingsboard.server.service.queue.TbClusterService; 36 import org.thingsboard.server.service.queue.TbClusterService;
  37 +import org.thingsboard.server.service.security.model.SecurityUser;
37 38
38 import javax.annotation.PostConstruct; 39 import javax.annotation.PostConstruct;
39 import javax.annotation.PreDestroy; 40 import javax.annotation.PreDestroy;
@@ -95,11 +96,11 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { @@ -95,11 +96,11 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
95 } 96 }
96 97
97 @Override 98 @Override
98 - public void processRestApiRpcRequest(ToDeviceRpcRequest request, Consumer<FromDeviceRpcResponse> responseConsumer) { 99 + public void processRestApiRpcRequest(ToDeviceRpcRequest request, Consumer<FromDeviceRpcResponse> responseConsumer, SecurityUser currentUser) {
99 log.trace("[{}][{}] Processing REST API call to rule engine [{}]", request.getTenantId(), request.getId(), request.getDeviceId()); 100 log.trace("[{}][{}] Processing REST API call to rule engine [{}]", request.getTenantId(), request.getId(), request.getDeviceId());
100 UUID requestId = request.getId(); 101 UUID requestId = request.getId();
101 localToRuleEngineRpcRequests.put(requestId, responseConsumer); 102 localToRuleEngineRpcRequests.put(requestId, responseConsumer);
102 - sendRpcRequestToRuleEngine(request); 103 + sendRpcRequestToRuleEngine(request, currentUser);
103 scheduleToRuleEngineTimeout(request, requestId); 104 scheduleToRuleEngineTimeout(request, requestId);
104 } 105 }
105 106
@@ -149,7 +150,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { @@ -149,7 +150,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
149 } 150 }
150 } 151 }
151 152
152 - private void sendRpcRequestToRuleEngine(ToDeviceRpcRequest msg) { 153 + private void sendRpcRequestToRuleEngine(ToDeviceRpcRequest msg, SecurityUser currentUser) {
153 ObjectNode entityNode = json.createObjectNode(); 154 ObjectNode entityNode = json.createObjectNode();
154 TbMsgMetaData metaData = new TbMsgMetaData(); 155 TbMsgMetaData metaData = new TbMsgMetaData();
155 metaData.putValue("requestUUID", msg.getId().toString()); 156 metaData.putValue("requestUUID", msg.getId().toString());
@@ -167,7 +168,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { @@ -167,7 +168,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
167 entityNode.put("params", msg.getBody().getParams()); 168 entityNode.put("params", msg.getBody().getParams());
168 169
169 try { 170 try {
170 - TbMsg tbMsg = TbMsg.newMsg(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE, msg.getDeviceId(), metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode)); 171 + TbMsg tbMsg = TbMsg.newMsg(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE, msg.getDeviceId(), currentUser.getCustomerId(), metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode));
171 clusterService.pushMsgToRuleEngine(msg.getTenantId(), msg.getDeviceId(), tbMsg, null); 172 clusterService.pushMsgToRuleEngine(msg.getTenantId(), msg.getDeviceId(), tbMsg, null);
172 } catch (JsonProcessingException e) { 173 } catch (JsonProcessingException e) {
173 throw new RuntimeException(e); 174 throw new RuntimeException(e);
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 package org.thingsboard.server.service.rpc; 16 package org.thingsboard.server.service.rpc;
17 17
18 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 18 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
  19 +import org.thingsboard.server.service.security.model.SecurityUser;
19 20
20 import java.util.function.Consumer; 21 import java.util.function.Consumer;
21 22
@@ -27,11 +28,11 @@ public interface TbCoreDeviceRpcService { @@ -27,11 +28,11 @@ public interface TbCoreDeviceRpcService {
27 /** 28 /**
28 * Handles REST API calls that contain RPC requests to Device and pushes them to Rule Engine. 29 * Handles REST API calls that contain RPC requests to Device and pushes them to Rule Engine.
29 * Schedules the timeout for the RPC call based on the {@link ToDeviceRpcRequest} 30 * Schedules the timeout for the RPC call based on the {@link ToDeviceRpcRequest}
30 - *  
31 - * @param request the RPC request 31 + * @param request the RPC request
32 * @param responseConsumer the consumer of the RPC response 32 * @param responseConsumer the consumer of the RPC response
  33 + * @param currentUser
33 */ 34 */
34 - void processRestApiRpcRequest(ToDeviceRpcRequest request, Consumer<FromDeviceRpcResponse> responseConsumer); 35 + void processRestApiRpcRequest(ToDeviceRpcRequest request, Consumer<FromDeviceRpcResponse> responseConsumer, SecurityUser currentUser);
35 36
36 /** 37 /**
37 * Handles the RPC response from the Rule Engine. 38 * Handles the RPC response from the Rule Engine.
@@ -20,6 +20,7 @@ import com.google.common.util.concurrent.ListenableFuture; @@ -20,6 +20,7 @@ import com.google.common.util.concurrent.ListenableFuture;
20 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
21 import org.thingsboard.common.util.ThingsBoardThreadFactory; 21 import org.thingsboard.common.util.ThingsBoardThreadFactory;
22 import org.thingsboard.server.common.data.ApiUsageRecordKey; 22 import org.thingsboard.server.common.data.ApiUsageRecordKey;
  23 +import org.thingsboard.server.common.data.id.CustomerId;
23 import org.thingsboard.server.common.data.id.TenantId; 24 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.queue.usagestats.TbApiUsageClient; 25 import org.thingsboard.server.queue.usagestats.TbApiUsageClient;
25 import org.thingsboard.server.service.apiusage.TbApiUsageStateService; 26 import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
@@ -73,14 +74,14 @@ public abstract class AbstractJsInvokeService implements JsInvokeService { @@ -73,14 +74,14 @@ public abstract class AbstractJsInvokeService implements JsInvokeService {
73 } 74 }
74 75
75 @Override 76 @Override
76 - public ListenableFuture<Object> invokeFunction(TenantId tenantId, UUID scriptId, Object... args) { 77 + public ListenableFuture<Object> invokeFunction(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args) {
77 if (apiUsageStateService.getApiUsageState(tenantId).isJsExecEnabled()) { 78 if (apiUsageStateService.getApiUsageState(tenantId).isJsExecEnabled()) {
78 String functionName = scriptIdToNameMap.get(scriptId); 79 String functionName = scriptIdToNameMap.get(scriptId);
79 if (functionName == null) { 80 if (functionName == null) {
80 return Futures.immediateFailedFuture(new RuntimeException("No compiled script found for scriptId: [" + scriptId + "]!")); 81 return Futures.immediateFailedFuture(new RuntimeException("No compiled script found for scriptId: [" + scriptId + "]!"));
81 } 82 }
82 if (!isDisabled(scriptId)) { 83 if (!isDisabled(scriptId)) {
83 - apiUsageClient.report(tenantId, ApiUsageRecordKey.JS_EXEC_COUNT, 1); 84 + apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.JS_EXEC_COUNT, 1);
84 return doInvokeFunction(scriptId, functionName, args); 85 return doInvokeFunction(scriptId, functionName, args);
85 } else { 86 } else {
86 return Futures.immediateFailedFuture( 87 return Futures.immediateFailedFuture(
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 package org.thingsboard.server.service.script; 16 package org.thingsboard.server.service.script;
17 17
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
19 -import org.thingsboard.server.common.data.id.EntityId; 19 +import org.thingsboard.server.common.data.id.CustomerId;
20 import org.thingsboard.server.common.data.id.TenantId; 20 import org.thingsboard.server.common.data.id.TenantId;
21 21
22 import java.util.UUID; 22 import java.util.UUID;
@@ -25,7 +25,7 @@ public interface JsInvokeService { @@ -25,7 +25,7 @@ public interface JsInvokeService {
25 25
26 ListenableFuture<UUID> eval(TenantId tenantId, JsScriptType scriptType, String scriptBody, String... argNames); 26 ListenableFuture<UUID> eval(TenantId tenantId, JsScriptType scriptType, String scriptBody, String... argNames);
27 27
28 - ListenableFuture<Object> invokeFunction(TenantId tenantId, UUID scriptId, Object... args); 28 + ListenableFuture<Object> invokeFunction(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args);
29 29
30 ListenableFuture<Void> release(UUID scriptId); 30 ListenableFuture<Void> release(UUID scriptId);
31 31
@@ -218,7 +218,7 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S @@ -218,7 +218,7 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S
218 private JsonNode executeScript(TbMsg msg) throws ScriptException { 218 private JsonNode executeScript(TbMsg msg) throws ScriptException {
219 try { 219 try {
220 String[] inArgs = prepareArgs(msg); 220 String[] inArgs = prepareArgs(msg);
221 - String eval = sandboxService.invokeFunction(tenantId, this.scriptId, inArgs[0], inArgs[1], inArgs[2]).get().toString(); 221 + String eval = sandboxService.invokeFunction(tenantId, msg.getCustomerId(), this.scriptId, inArgs[0], inArgs[1], inArgs[2]).get().toString();
222 return mapper.readTree(eval); 222 return mapper.readTree(eval);
223 } catch (ExecutionException e) { 223 } catch (ExecutionException e) {
224 if (e.getCause() instanceof ScriptException) { 224 if (e.getCause() instanceof ScriptException) {
@@ -235,7 +235,7 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S @@ -235,7 +235,7 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S
235 235
236 private ListenableFuture<JsonNode> executeScriptAsync(TbMsg msg) { 236 private ListenableFuture<JsonNode> executeScriptAsync(TbMsg msg) {
237 String[] inArgs = prepareArgs(msg); 237 String[] inArgs = prepareArgs(msg);
238 - return Futures.transformAsync(sandboxService.invokeFunction(tenantId, this.scriptId, inArgs[0], inArgs[1], inArgs[2]), 238 + return Futures.transformAsync(sandboxService.invokeFunction(tenantId, msg.getCustomerId(), this.scriptId, inArgs[0], inArgs[1], inArgs[2]),
239 o -> { 239 o -> {
240 try { 240 try {
241 return Futures.immediateFuture(mapper.readTree(o.toString())); 241 return Futures.immediateFuture(mapper.readTree(o.toString()));
@@ -22,6 +22,7 @@ import org.springframework.stereotype.Service; @@ -22,6 +22,7 @@ import org.springframework.stereotype.Service;
22 import org.thingsboard.rule.engine.api.SmsService; 22 import org.thingsboard.rule.engine.api.SmsService;
23 import org.thingsboard.rule.engine.api.sms.SmsSender; 23 import org.thingsboard.rule.engine.api.sms.SmsSender;
24 import org.thingsboard.rule.engine.api.sms.SmsSenderFactory; 24 import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
  25 +import org.thingsboard.server.common.data.id.CustomerId;
25 import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration; 26 import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration;
26 import org.thingsboard.server.common.data.sms.config.TestSmsRequest; 27 import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
27 import org.thingsboard.server.common.data.AdminSettings; 28 import org.thingsboard.server.common.data.AdminSettings;
@@ -94,7 +95,7 @@ public class DefaultSmsService implements SmsService { @@ -94,7 +95,7 @@ public class DefaultSmsService implements SmsService {
94 } 95 }
95 96
96 @Override 97 @Override
97 - public void sendSms(TenantId tenantId, String[] numbersTo, String message) throws ThingsboardException { 98 + public void sendSms(TenantId tenantId, CustomerId customerId, String[] numbersTo, String message) throws ThingsboardException {
98 if (apiUsageStateService.getApiUsageState(tenantId).isSmsSendEnabled()) { 99 if (apiUsageStateService.getApiUsageState(tenantId).isSmsSendEnabled()) {
99 int smsCount = 0; 100 int smsCount = 0;
100 try { 101 try {
@@ -103,7 +104,7 @@ public class DefaultSmsService implements SmsService { @@ -103,7 +104,7 @@ public class DefaultSmsService implements SmsService {
103 } 104 }
104 } finally { 105 } finally {
105 if (smsCount > 0) { 106 if (smsCount > 0) {
106 - apiUsageClient.report(tenantId, ApiUsageRecordKey.SMS_EXEC_COUNT, smsCount); 107 + apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.SMS_EXEC_COUNT, smsCount);
107 } 108 }
108 } 109 }
109 } else { 110 } else {
@@ -468,6 +468,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -468,6 +468,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
468 md.putValue("deviceName", device.getName()); 468 md.putValue("deviceName", device.getName());
469 md.putValue("deviceType", device.getType()); 469 md.putValue("deviceType", device.getType());
470 return DeviceStateData.builder() 470 return DeviceStateData.builder()
  471 + .customerId(device.getCustomerId())
471 .tenantId(device.getTenantId()) 472 .tenantId(device.getTenantId())
472 .deviceId(device.getId()) 473 .deviceId(device.getId())
473 .deviceCreationTime(device.getCreatedTime()) 474 .deviceCreationTime(device.getCreatedTime())
@@ -507,7 +508,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -507,7 +508,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
507 if(!persistToTelemetry){ 508 if(!persistToTelemetry){
508 md.putValue(DataConstants.SCOPE, SERVER_SCOPE); 509 md.putValue(DataConstants.SCOPE, SERVER_SCOPE);
509 } 510 }
510 - TbMsg tbMsg = TbMsg.newMsg(msgType, stateData.getDeviceId(), md, TbMsgDataType.JSON, data); 511 + TbMsg tbMsg = TbMsg.newMsg(msgType, stateData.getDeviceId(), stateData.getCustomerId(), md, TbMsgDataType.JSON, data);
511 clusterService.pushMsgToRuleEngine(stateData.getTenantId(), stateData.getDeviceId(), tbMsg, null); 512 clusterService.pushMsgToRuleEngine(stateData.getTenantId(), stateData.getDeviceId(), tbMsg, null);
512 } catch (Exception e) { 513 } catch (Exception e) {
513 log.warn("[{}] Failed to push inactivity alarm: {}", stateData.getDeviceId(), state, e); 514 log.warn("[{}] Failed to push inactivity alarm: {}", stateData.getDeviceId(), state, e);
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.state; @@ -17,6 +17,7 @@ package org.thingsboard.server.service.state;
17 17
18 import lombok.Builder; 18 import lombok.Builder;
19 import lombok.Data; 19 import lombok.Data;
  20 +import org.thingsboard.server.common.data.id.CustomerId;
20 import org.thingsboard.server.common.data.id.DeviceId; 21 import org.thingsboard.server.common.data.id.DeviceId;
21 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
22 import org.thingsboard.server.common.msg.TbMsgMetaData; 23 import org.thingsboard.server.common.msg.TbMsgMetaData;
@@ -29,6 +30,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -29,6 +30,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
29 class DeviceStateData { 30 class DeviceStateData {
30 31
31 private final TenantId tenantId; 32 private final TenantId tenantId;
  33 + private final CustomerId customerId;
32 private final DeviceId deviceId; 34 private final DeviceId deviceId;
33 private final long deviceCreationTime; 35 private final long deviceCreationTime;
34 private TbMsgMetaData metaData; 36 private TbMsgMetaData metaData;
@@ -25,7 +25,7 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -25,7 +25,7 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory;
25 import org.thingsboard.server.common.data.ApiUsageRecordKey; 25 import org.thingsboard.server.common.data.ApiUsageRecordKey;
26 import org.thingsboard.server.common.data.EntityType; 26 import org.thingsboard.server.common.data.EntityType;
27 import org.thingsboard.server.common.data.EntityView; 27 import org.thingsboard.server.common.data.EntityView;
28 -import org.thingsboard.server.common.data.TenantProfile; 28 +import org.thingsboard.server.common.data.id.CustomerId;
29 import org.thingsboard.server.common.data.id.EntityId; 29 import org.thingsboard.server.common.data.id.EntityId;
30 import org.thingsboard.server.common.data.id.TenantId; 30 import org.thingsboard.server.common.data.id.TenantId;
31 import org.thingsboard.server.common.data.kv.AttributeKvEntry; 31 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
@@ -35,13 +35,11 @@ import org.thingsboard.server.common.data.kv.DoubleDataEntry; @@ -35,13 +35,11 @@ import org.thingsboard.server.common.data.kv.DoubleDataEntry;
35 import org.thingsboard.server.common.data.kv.LongDataEntry; 35 import org.thingsboard.server.common.data.kv.LongDataEntry;
36 import org.thingsboard.server.common.data.kv.StringDataEntry; 36 import org.thingsboard.server.common.data.kv.StringDataEntry;
37 import org.thingsboard.server.common.data.kv.TsKvEntry; 37 import org.thingsboard.server.common.data.kv.TsKvEntry;
38 -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;  
39 import org.thingsboard.server.common.msg.queue.ServiceType; 38 import org.thingsboard.server.common.msg.queue.ServiceType;
40 import org.thingsboard.server.common.msg.queue.TbCallback; 39 import org.thingsboard.server.common.msg.queue.TbCallback;
41 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; 40 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
42 import org.thingsboard.server.dao.attributes.AttributesService; 41 import org.thingsboard.server.dao.attributes.AttributesService;
43 import org.thingsboard.server.dao.entityview.EntityViewService; 42 import org.thingsboard.server.dao.entityview.EntityViewService;
44 -import org.thingsboard.server.dao.tenant.TbTenantProfileCache;  
45 import org.thingsboard.server.dao.timeseries.TimeseriesService; 43 import org.thingsboard.server.dao.timeseries.TimeseriesService;
46 import org.thingsboard.server.gen.transport.TransportProtos; 44 import org.thingsboard.server.gen.transport.TransportProtos;
47 import org.thingsboard.server.queue.discovery.PartitionService; 45 import org.thingsboard.server.queue.discovery.PartitionService;
@@ -115,11 +113,11 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer @@ -115,11 +113,11 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
115 113
116 @Override 114 @Override
117 public void saveAndNotify(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, FutureCallback<Void> callback) { 115 public void saveAndNotify(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, FutureCallback<Void> callback) {
118 - saveAndNotify(tenantId, entityId, ts, 0L, callback); 116 + saveAndNotify(tenantId, null, entityId, ts, 0L, callback);
119 } 117 }
120 118
121 @Override 119 @Override
122 - public void saveAndNotify(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, long ttl, FutureCallback<Void> callback) { 120 + public void saveAndNotify(TenantId tenantId, CustomerId customerId, EntityId entityId, List<TsKvEntry> ts, long ttl, FutureCallback<Void> callback) {
123 checkInternalEntity(entityId); 121 checkInternalEntity(entityId);
124 boolean sysTenant = TenantId.SYS_TENANT_ID.equals(tenantId) || tenantId == null; 122 boolean sysTenant = TenantId.SYS_TENANT_ID.equals(tenantId) || tenantId == null;
125 if (sysTenant || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) { 123 if (sysTenant || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) {
@@ -127,7 +125,7 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer @@ -127,7 +125,7 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
127 @Override 125 @Override
128 public void onSuccess(Integer result) { 126 public void onSuccess(Integer result) {
129 if (!sysTenant && result != null && result > 0) { 127 if (!sysTenant && result != null && result > 0) {
130 - apiUsageClient.report(tenantId, ApiUsageRecordKey.STORAGE_DP_COUNT, result); 128 + apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.STORAGE_DP_COUNT, result);
131 } 129 }
132 callback.onSuccess(null); 130 callback.onSuccess(null);
133 } 131 }
@@ -86,6 +86,7 @@ import org.thingsboard.server.service.queue.TbClusterService; @@ -86,6 +86,7 @@ import org.thingsboard.server.service.queue.TbClusterService;
86 import org.thingsboard.server.service.resource.TbResourceService; 86 import org.thingsboard.server.service.resource.TbResourceService;
87 import org.thingsboard.server.service.state.DeviceStateService; 87 import org.thingsboard.server.service.state.DeviceStateService;
88 88
  89 +import java.util.Optional;
89 import java.util.UUID; 90 import java.util.UUID;
90 import java.util.concurrent.ConcurrentHashMap; 91 import java.util.concurrent.ConcurrentHashMap;
91 import java.util.concurrent.ConcurrentMap; 92 import java.util.concurrent.ConcurrentMap;
@@ -284,7 +285,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -284,7 +285,7 @@ public class DefaultTransportApiService implements TransportApiService {
284 285
285 DeviceId deviceId = device.getId(); 286 DeviceId deviceId = device.getId();
286 ObjectNode entityNode = mapper.valueToTree(device); 287 ObjectNode entityNode = mapper.valueToTree(device);
287 - TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, mapper.writeValueAsString(entityNode)); 288 + TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, customerId, metaData, TbMsgDataType.JSON, mapper.writeValueAsString(entityNode));
288 tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, null); 289 tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, null);
289 } 290 }
290 GetOrCreateDeviceFromGatewayResponseMsg.Builder builder = GetOrCreateDeviceFromGatewayResponseMsg.newBuilder() 291 GetOrCreateDeviceFromGatewayResponseMsg.Builder builder = GetOrCreateDeviceFromGatewayResponseMsg.newBuilder()
@@ -423,6 +424,8 @@ public class DefaultTransportApiService implements TransportApiService { @@ -423,6 +424,8 @@ public class DefaultTransportApiService implements TransportApiService {
423 return DeviceInfoProto.newBuilder() 424 return DeviceInfoProto.newBuilder()
424 .setTenantIdMSB(device.getTenantId().getId().getMostSignificantBits()) 425 .setTenantIdMSB(device.getTenantId().getId().getMostSignificantBits())
425 .setTenantIdLSB(device.getTenantId().getId().getLeastSignificantBits()) 426 .setTenantIdLSB(device.getTenantId().getId().getLeastSignificantBits())
  427 + .setCustomerIdMSB(Optional.ofNullable(device.getCustomerId()).map(customerId -> customerId.getId().getMostSignificantBits()).orElse(0L))
  428 + .setCustomerIdLSB(Optional.ofNullable(device.getCustomerId()).map(customerId -> customerId.getId().getLeastSignificantBits()).orElse(0L))
426 .setDeviceIdMSB(device.getId().getId().getMostSignificantBits()) 429 .setDeviceIdMSB(device.getId().getId().getMostSignificantBits())
427 .setDeviceIdLSB(device.getId().getId().getLeastSignificantBits()) 430 .setDeviceIdLSB(device.getId().getId().getLeastSignificantBits())
428 .setDeviceName(device.getName()) 431 .setDeviceName(device.getName())
@@ -124,6 +124,7 @@ usage: @@ -124,6 +124,7 @@ usage:
124 stats: 124 stats:
125 report: 125 report:
126 enabled: "${USAGE_STATS_REPORT_ENABLED:true}" 126 enabled: "${USAGE_STATS_REPORT_ENABLED:true}"
  127 + enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}"
127 interval: "${USAGE_STATS_REPORT_INTERVAL:10}" 128 interval: "${USAGE_STATS_REPORT_INTERVAL:10}"
128 check: 129 check:
129 cycle: "${USAGE_STATS_CHECK_CYCLE:60000}" 130 cycle: "${USAGE_STATS_CHECK_CYCLE:60000}"
@@ -21,12 +21,12 @@ import org.checkerframework.checker.nullness.qual.Nullable; @@ -21,12 +21,12 @@ import org.checkerframework.checker.nullness.qual.Nullable;
21 import org.junit.After; 21 import org.junit.After;
22 import org.junit.Assert; 22 import org.junit.Assert;
23 import org.junit.Before; 23 import org.junit.Before;
24 -import org.junit.Ignore;  
25 import org.junit.Test; 24 import org.junit.Test;
26 import org.springframework.beans.factory.annotation.Autowired; 25 import org.springframework.beans.factory.annotation.Autowired;
27 import org.thingsboard.server.common.data.Device; 26 import org.thingsboard.server.common.data.Device;
28 import org.thingsboard.server.common.data.Tenant; 27 import org.thingsboard.server.common.data.Tenant;
29 import org.thingsboard.server.common.data.User; 28 import org.thingsboard.server.common.data.User;
  29 +import org.thingsboard.server.common.data.id.CustomerId;
30 import org.thingsboard.server.common.data.kv.Aggregation; 30 import org.thingsboard.server.common.data.kv.Aggregation;
31 import org.thingsboard.server.common.data.kv.AttributeKvEntry; 31 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
32 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; 32 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
@@ -750,7 +750,7 @@ public class BaseWebsocketApiTest extends AbstractWebsocketTest { @@ -750,7 +750,7 @@ public class BaseWebsocketApiTest extends AbstractWebsocketTest {
750 750
751 private void sendTelemetry(Device device, List<TsKvEntry> tsData) throws InterruptedException { 751 private void sendTelemetry(Device device, List<TsKvEntry> tsData) throws InterruptedException {
752 CountDownLatch latch = new CountDownLatch(1); 752 CountDownLatch latch = new CountDownLatch(1);
753 - tsService.saveAndNotify(device.getTenantId(), device.getId(), tsData, 0, new FutureCallback<Void>() { 753 + tsService.saveAndNotify(device.getTenantId(), null, device.getId(), tsData, 0, new FutureCallback<Void>() {
754 @Override 754 @Override
755 public void onSuccess(@Nullable Void result) { 755 public void onSuccess(@Nullable Void result) {
756 latch.countDown(); 756 latch.countDown();
@@ -17,17 +17,22 @@ package org.thingsboard.server.dao.usagerecord; @@ -17,17 +17,22 @@ package org.thingsboard.server.dao.usagerecord;
17 17
18 import org.thingsboard.server.common.data.ApiUsageState; 18 import org.thingsboard.server.common.data.ApiUsageState;
19 import org.thingsboard.server.common.data.id.ApiUsageStateId; 19 import org.thingsboard.server.common.data.id.ApiUsageStateId;
  20 +import org.thingsboard.server.common.data.id.EntityId;
20 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
21 22
22 public interface ApiUsageStateService { 23 public interface ApiUsageStateService {
23 24
24 - ApiUsageState createDefaultApiUsageState(TenantId id); 25 + ApiUsageState createDefaultApiUsageState(TenantId id, EntityId entityId);
25 26
26 ApiUsageState update(ApiUsageState apiUsageState); 27 ApiUsageState update(ApiUsageState apiUsageState);
27 28
28 ApiUsageState findTenantApiUsageState(TenantId tenantId); 29 ApiUsageState findTenantApiUsageState(TenantId tenantId);
29 30
  31 + ApiUsageState findApiUsageStateByEntityId(EntityId entityId);
  32 +
30 void deleteApiUsageStateByTenantId(TenantId tenantId); 33 void deleteApiUsageStateByTenantId(TenantId tenantId);
31 34
  35 + void deleteApiUsageStateByEntityId(EntityId entityId);
  36 +
32 ApiUsageState findApiUsageStateById(TenantId tenantId, ApiUsageStateId id); 37 ApiUsageState findApiUsageStateById(TenantId tenantId, ApiUsageStateId id);
33 } 38 }
@@ -16,10 +16,13 @@ @@ -16,10 +16,13 @@
16 package org.thingsboard.server.common.data.query; 16 package org.thingsboard.server.common.data.query;
17 17
18 import lombok.Data; 18 import lombok.Data;
19 -import org.thingsboard.server.common.data.id.EntityId; 19 +import org.thingsboard.server.common.data.id.CustomerId;
20 20
21 @Data 21 @Data
22 public class ApiUsageStateFilter implements EntityFilter { 22 public class ApiUsageStateFilter implements EntityFilter {
  23 +
  24 + private CustomerId customerId;
  25 +
23 @Override 26 @Override
24 public EntityFilterType getType() { 27 public EntityFilterType getType() {
25 return EntityFilterType.API_USAGE_STATE; 28 return EntityFilterType.API_USAGE_STATE;
@@ -19,10 +19,11 @@ import com.fasterxml.jackson.annotation.JsonIgnore; @@ -19,10 +19,11 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
19 import com.google.protobuf.ByteString; 19 import com.google.protobuf.ByteString;
20 import com.google.protobuf.InvalidProtocolBufferException; 20 import com.google.protobuf.InvalidProtocolBufferException;
21 import lombok.AccessLevel; 21 import lombok.AccessLevel;
22 -import lombok.Builder;  
23 import lombok.Data; 22 import lombok.Data;
24 import lombok.Getter; 23 import lombok.Getter;
25 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
  25 +import org.thingsboard.server.common.data.EntityType;
  26 +import org.thingsboard.server.common.data.id.CustomerId;
26 import org.thingsboard.server.common.data.id.EntityId; 27 import org.thingsboard.server.common.data.id.EntityId;
27 import org.thingsboard.server.common.data.id.EntityIdFactory; 28 import org.thingsboard.server.common.data.id.EntityIdFactory;
28 import org.thingsboard.server.common.data.id.RuleChainId; 29 import org.thingsboard.server.common.data.id.RuleChainId;
@@ -47,6 +48,7 @@ public final class TbMsg implements Serializable { @@ -47,6 +48,7 @@ public final class TbMsg implements Serializable {
47 private final long ts; 48 private final long ts;
48 private final String type; 49 private final String type;
49 private final EntityId originator; 50 private final EntityId originator;
  51 + private final CustomerId customerId;
50 private final TbMsgMetaData metaData; 52 private final TbMsgMetaData metaData;
51 private final TbMsgDataType dataType; 53 private final TbMsgDataType dataType;
52 private final String data; 54 private final String data;
@@ -55,6 +57,7 @@ public final class TbMsg implements Serializable { @@ -55,6 +57,7 @@ public final class TbMsg implements Serializable {
55 @Getter(value = AccessLevel.NONE) 57 @Getter(value = AccessLevel.NONE)
56 private final AtomicInteger ruleNodeExecCounter; 58 private final AtomicInteger ruleNodeExecCounter;
57 59
  60 +
58 public int getAndIncrementRuleNodeCounter() { 61 public int getAndIncrementRuleNodeCounter() {
59 return ruleNodeExecCounter.getAndIncrement(); 62 return ruleNodeExecCounter.getAndIncrement();
60 } 63 }
@@ -64,60 +67,81 @@ public final class TbMsg implements Serializable { @@ -64,60 +67,81 @@ public final class TbMsg implements Serializable {
64 transient private final TbMsgCallback callback; 67 transient private final TbMsgCallback callback;
65 68
66 public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { 69 public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
67 - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, 70 + return newMsg(queueName, type, originator, null, metaData, data, ruleChainId, ruleNodeId);
  71 + }
  72 +
  73 + public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
  74 + return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId,
68 metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, 0, TbMsgCallback.EMPTY); 75 metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, 0, TbMsgCallback.EMPTY);
69 } 76 }
70 77
71 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { 78 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) {
72 - return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, 0, TbMsgCallback.EMPTY); 79 + return newMsg(type, originator, null, metaData, data);
  80 + }
  81 +
  82 + public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
  83 + return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, null, null, 0, TbMsgCallback.EMPTY);
73 } 84 }
74 85
75 // REALLY NEW MSG 86 // REALLY NEW MSG
76 87
77 public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) { 88 public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) {
78 - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, 0, TbMsgCallback.EMPTY); 89 + return newMsg(queueName, type, originator, null, metaData, data);
  90 + }
  91 +
  92 + public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) {
  93 + return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, null, null, 0, TbMsgCallback.EMPTY);
  94 + }
  95 +
  96 + public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) {
  97 + return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), dataType, data, null, null, 0, TbMsgCallback.EMPTY);
79 } 98 }
80 99
81 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { 100 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) {
82 - return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), dataType, data, null, null, 0, TbMsgCallback.EMPTY); 101 + return newMsg(type, originator, null, metaData, dataType, data);
83 } 102 }
84 103
85 // For Tests only 104 // For Tests only
86 105
87 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { 106 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
88 - return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), dataType, data, ruleChainId, ruleNodeId, 0, TbMsgCallback.EMPTY); 107 + return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, metaData.copy(), dataType, data, ruleChainId, ruleNodeId, 0, TbMsgCallback.EMPTY);
89 } 108 }
90 109
91 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) { 110 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) {
92 - return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, 0, callback); 111 + return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, metaData.copy(), TbMsgDataType.JSON, data, null, null, 0, callback);
93 } 112 }
94 113
95 public static TbMsg transformMsg(TbMsg tbMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { 114 public static TbMsg transformMsg(TbMsg tbMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) {
96 - return new TbMsg(tbMsg.getQueueName(), tbMsg.getId(), tbMsg.getTs(), type, originator, metaData.copy(), tbMsg.getDataType(),  
97 - data, tbMsg.getRuleChainId(), tbMsg.getRuleNodeId(), tbMsg.ruleNodeExecCounter.get(), tbMsg.getCallback()); 115 + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType,
  116 + data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ruleNodeExecCounter.get(), tbMsg.callback);
  117 + }
  118 +
  119 + public static TbMsg transformMsg(TbMsg tbMsg, CustomerId customerId) {
  120 + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType,
  121 + tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ruleNodeExecCounter.get(), tbMsg.getCallback());
98 } 122 }
99 123
100 public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId) { 124 public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId) {
101 - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.metaData, tbMsg.dataType, 125 + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
102 tbMsg.data, ruleChainId, null, tbMsg.ruleNodeExecCounter.get(), tbMsg.getCallback()); 126 tbMsg.data, ruleChainId, null, tbMsg.ruleNodeExecCounter.get(), tbMsg.getCallback());
103 } 127 }
104 128
105 public static TbMsg transformMsg(TbMsg tbMsg, String queueName) { 129 public static TbMsg transformMsg(TbMsg tbMsg, String queueName) {
106 - return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.metaData, tbMsg.dataType, 130 + return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
107 tbMsg.data, tbMsg.getRuleChainId(), null, tbMsg.ruleNodeExecCounter.get(), tbMsg.getCallback()); 131 tbMsg.data, tbMsg.getRuleChainId(), null, tbMsg.ruleNodeExecCounter.get(), tbMsg.getCallback());
108 } 132 }
109 133
110 public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId, String queueName) { 134 public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId, String queueName) {
111 - return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.metaData, tbMsg.dataType, 135 + return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType,
112 tbMsg.data, ruleChainId, null, tbMsg.ruleNodeExecCounter.get(), tbMsg.getCallback()); 136 tbMsg.data, ruleChainId, null, tbMsg.ruleNodeExecCounter.get(), tbMsg.getCallback());
113 } 137 }
114 138
115 public static TbMsg newMsg(TbMsg tbMsg, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { 139 public static TbMsg newMsg(TbMsg tbMsg, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
116 - return new TbMsg(tbMsg.getQueueName(), UUID.randomUUID(), tbMsg.getTs(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.getMetaData().copy(), 140 + return new TbMsg(tbMsg.getQueueName(), UUID.randomUUID(), tbMsg.getTs(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.customerId, tbMsg.getMetaData().copy(),
117 tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, tbMsg.ruleNodeExecCounter.get(), TbMsgCallback.EMPTY); 141 tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, tbMsg.ruleNodeExecCounter.get(), TbMsgCallback.EMPTY);
118 } 142 }
119 143
120 - private TbMsg(String queueName, UUID id, long ts, String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, 144 + private TbMsg(String queueName, UUID id, long ts, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data,
121 RuleChainId ruleChainId, RuleNodeId ruleNodeId, int ruleNodeExecCounter, TbMsgCallback callback) { 145 RuleChainId ruleChainId, RuleNodeId ruleNodeId, int ruleNodeExecCounter, TbMsgCallback callback) {
122 this.id = id; 146 this.id = id;
123 this.queueName = queueName != null ? queueName : ServiceQueue.MAIN; 147 this.queueName = queueName != null ? queueName : ServiceQueue.MAIN;
@@ -128,6 +152,15 @@ public final class TbMsg implements Serializable { @@ -128,6 +152,15 @@ public final class TbMsg implements Serializable {
128 } 152 }
129 this.type = type; 153 this.type = type;
130 this.originator = originator; 154 this.originator = originator;
  155 + if (customerId == null || customerId.isNullUid()) {
  156 + if (originator != null && originator.getEntityType() == EntityType.CUSTOMER) {
  157 + this.customerId = (CustomerId) originator;
  158 + } else {
  159 + this.customerId = null;
  160 + }
  161 + } else {
  162 + this.customerId = customerId;
  163 + }
131 this.metaData = metaData; 164 this.metaData = metaData;
132 this.dataType = dataType; 165 this.dataType = dataType;
133 this.data = data; 166 this.data = data;
@@ -154,6 +187,11 @@ public final class TbMsg implements Serializable { @@ -154,6 +187,11 @@ public final class TbMsg implements Serializable {
154 builder.setEntityIdMSB(msg.getOriginator().getId().getMostSignificantBits()); 187 builder.setEntityIdMSB(msg.getOriginator().getId().getMostSignificantBits());
155 builder.setEntityIdLSB(msg.getOriginator().getId().getLeastSignificantBits()); 188 builder.setEntityIdLSB(msg.getOriginator().getId().getLeastSignificantBits());
156 189
  190 + if (msg.getCustomerId() != null) {
  191 + builder.setCustomerIdMSB(msg.getCustomerId().getId().getMostSignificantBits());
  192 + builder.setCustomerIdLSB(msg.getCustomerId().getId().getLeastSignificantBits());
  193 + }
  194 +
157 if (msg.getRuleChainId() != null) { 195 if (msg.getRuleChainId() != null) {
158 builder.setRuleChainIdMSB(msg.getRuleChainId().getId().getMostSignificantBits()); 196 builder.setRuleChainIdMSB(msg.getRuleChainId().getId().getMostSignificantBits());
159 builder.setRuleChainIdLSB(msg.getRuleChainId().getId().getLeastSignificantBits()); 197 builder.setRuleChainIdLSB(msg.getRuleChainId().getId().getLeastSignificantBits());
@@ -179,16 +217,21 @@ public final class TbMsg implements Serializable { @@ -179,16 +217,21 @@ public final class TbMsg implements Serializable {
179 MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(data); 217 MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(data);
180 TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap()); 218 TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap());
181 EntityId entityId = EntityIdFactory.getByTypeAndUuid(proto.getEntityType(), new UUID(proto.getEntityIdMSB(), proto.getEntityIdLSB())); 219 EntityId entityId = EntityIdFactory.getByTypeAndUuid(proto.getEntityType(), new UUID(proto.getEntityIdMSB(), proto.getEntityIdLSB()));
  220 + CustomerId customerId = null;
182 RuleChainId ruleChainId = null; 221 RuleChainId ruleChainId = null;
183 RuleNodeId ruleNodeId = null; 222 RuleNodeId ruleNodeId = null;
  223 + if (proto.getCustomerIdMSB() != 0L && proto.getCustomerIdLSB() != 0L) {
  224 + customerId = new CustomerId(new UUID(proto.getCustomerIdMSB(), proto.getCustomerIdLSB()));
  225 + }
184 if (proto.getRuleChainIdMSB() != 0L && proto.getRuleChainIdLSB() != 0L) { 226 if (proto.getRuleChainIdMSB() != 0L && proto.getRuleChainIdLSB() != 0L) {
185 ruleChainId = new RuleChainId(new UUID(proto.getRuleChainIdMSB(), proto.getRuleChainIdLSB())); 227 ruleChainId = new RuleChainId(new UUID(proto.getRuleChainIdMSB(), proto.getRuleChainIdLSB()));
186 } 228 }
187 if (proto.getRuleNodeIdMSB() != 0L && proto.getRuleNodeIdLSB() != 0L) { 229 if (proto.getRuleNodeIdMSB() != 0L && proto.getRuleNodeIdLSB() != 0L) {
188 ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleNodeIdLSB())); 230 ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleNodeIdLSB()));
189 } 231 }
  232 +
190 TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; 233 TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()];
191 - return new TbMsg(queueName, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, proto.getRuleNodeExecCounter(), callback); 234 + return new TbMsg(queueName, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, customerId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, proto.getRuleNodeExecCounter(), callback);
192 } catch (InvalidProtocolBufferException e) { 235 } catch (InvalidProtocolBufferException e) {
193 throw new IllegalStateException("Could not parse protobuf for TbMsg", e); 236 throw new IllegalStateException("Could not parse protobuf for TbMsg", e);
194 } 237 }
@@ -199,11 +242,11 @@ public final class TbMsg implements Serializable { @@ -199,11 +242,11 @@ public final class TbMsg implements Serializable {
199 } 242 }
200 243
201 public TbMsg copyWithRuleChainId(RuleChainId ruleChainId, UUID msgId) { 244 public TbMsg copyWithRuleChainId(RuleChainId ruleChainId, UUID msgId) {
202 - return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, null, this.ruleNodeExecCounter.get(), callback); 245 + return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, this.metaData, this.dataType, this.data, ruleChainId, null, this.ruleNodeExecCounter.get(), callback);
203 } 246 }
204 247
205 public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId, UUID msgId) { 248 public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId, UUID msgId) {
206 - return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ruleNodeExecCounter.get(), callback); 249 + return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ruleNodeExecCounter.get(), callback);
207 } 250 }
208 251
209 public TbMsgCallback getCallback() { 252 public TbMsgCallback getCallback() {
@@ -46,4 +46,7 @@ message TbMsgProto { @@ -46,4 +46,7 @@ message TbMsgProto {
46 46
47 int64 ts = 15; 47 int64 ts = 15;
48 int32 ruleNodeExecCounter = 16; 48 int32 ruleNodeExecCounter = 16;
  49 +
  50 + int64 customerIdMSB = 17;
  51 + int64 customerIdLSB = 18;
49 } 52 }
@@ -15,10 +15,14 @@ @@ -15,10 +15,14 @@
15 */ 15 */
16 package org.thingsboard.server.queue.usagestats; 16 package org.thingsboard.server.queue.usagestats;
17 17
  18 +import lombok.Data;
18 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
19 import org.springframework.beans.factory.annotation.Value; 20 import org.springframework.beans.factory.annotation.Value;
20 import org.springframework.stereotype.Component; 21 import org.springframework.stereotype.Component;
21 import org.thingsboard.server.common.data.ApiUsageRecordKey; 22 import org.thingsboard.server.common.data.ApiUsageRecordKey;
  23 +import org.thingsboard.server.common.data.EntityType;
  24 +import org.thingsboard.server.common.data.id.CustomerId;
  25 +import org.thingsboard.server.common.data.id.EntityId;
22 import org.thingsboard.server.common.data.id.TenantId; 26 import org.thingsboard.server.common.data.id.TenantId;
23 import org.thingsboard.server.common.msg.queue.ServiceType; 27 import org.thingsboard.server.common.msg.queue.ServiceType;
24 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; 28 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
@@ -31,6 +35,8 @@ import org.thingsboard.server.queue.provider.TbQueueProducerProvider; @@ -31,6 +35,8 @@ import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
31 import org.thingsboard.server.queue.scheduler.SchedulerComponent; 35 import org.thingsboard.server.queue.scheduler.SchedulerComponent;
32 36
33 import javax.annotation.PostConstruct; 37 import javax.annotation.PostConstruct;
  38 +import java.util.EnumMap;
  39 +import java.util.Optional;
34 import java.util.Random; 40 import java.util.Random;
35 import java.util.UUID; 41 import java.util.UUID;
36 import java.util.concurrent.ConcurrentHashMap; 42 import java.util.concurrent.ConcurrentHashMap;
@@ -44,11 +50,13 @@ public class DefaultTbApiUsageClient implements TbApiUsageClient { @@ -44,11 +50,13 @@ public class DefaultTbApiUsageClient implements TbApiUsageClient {
44 50
45 @Value("${usage.stats.report.enabled:true}") 51 @Value("${usage.stats.report.enabled:true}")
46 private boolean enabled; 52 private boolean enabled;
  53 + @Value("${usage.stats.report.enabled_per_customer:false}")
  54 + private boolean enabledPerCustomer;
47 @Value("${usage.stats.report.interval:10}") 55 @Value("${usage.stats.report.interval:10}")
48 private int interval; 56 private int interval;
49 57
50 - @SuppressWarnings("unchecked")  
51 - private final ConcurrentMap<TenantId, AtomicLong>[] values = new ConcurrentMap[ApiUsageRecordKey.values().length]; 58 + private final EnumMap<ApiUsageRecordKey, ConcurrentMap<OwnerId, AtomicLong>> stats = new EnumMap<>(ApiUsageRecordKey.class);
  59 +
52 private final PartitionService partitionService; 60 private final PartitionService partitionService;
53 private final SchedulerComponent scheduler; 61 private final SchedulerComponent scheduler;
54 private final TbQueueProducerProvider producerProvider; 62 private final TbQueueProducerProvider producerProvider;
@@ -65,55 +73,93 @@ public class DefaultTbApiUsageClient implements TbApiUsageClient { @@ -65,55 +73,93 @@ public class DefaultTbApiUsageClient implements TbApiUsageClient {
65 if (enabled) { 73 if (enabled) {
66 msgProducer = this.producerProvider.getTbUsageStatsMsgProducer(); 74 msgProducer = this.producerProvider.getTbUsageStatsMsgProducer();
67 for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) { 75 for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {
68 - values[key.ordinal()] = new ConcurrentHashMap<>(); 76 + stats.put(key, new ConcurrentHashMap<>());
69 } 77 }
70 - scheduler.scheduleWithFixedDelay(this::reportStats, new Random().nextInt(interval), interval, TimeUnit.SECONDS); 78 + scheduler.scheduleWithFixedDelay(() -> {
  79 + try {
  80 + reportStats();
  81 + } catch (Exception e) {
  82 + log.warn("Failed to report statistics: ", e);
  83 + }
  84 + }, new Random().nextInt(interval), interval, TimeUnit.SECONDS);
71 } 85 }
72 } 86 }
73 87
74 private void reportStats() { 88 private void reportStats() {
75 - try {  
76 - ConcurrentMap<TenantId, ToUsageStatsServiceMsg.Builder> report = new ConcurrentHashMap<>(); 89 + ConcurrentMap<OwnerId, ToUsageStatsServiceMsg.Builder> report = new ConcurrentHashMap<>();
77 90
78 - for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {  
79 - values[key.ordinal()].forEach(((tenantId, atomicLong) -> {  
80 - long value = atomicLong.getAndSet(0);  
81 - if (value > 0) {  
82 - ToUsageStatsServiceMsg.Builder msgBuilder = report.computeIfAbsent(tenantId, id -> {  
83 - ToUsageStatsServiceMsg.Builder msg = ToUsageStatsServiceMsg.newBuilder();  
84 - msg.setTenantIdMSB(tenantId.getId().getMostSignificantBits());  
85 - msg.setTenantIdLSB(tenantId.getId().getLeastSignificantBits());  
86 - return msg;  
87 - });  
88 - msgBuilder.addValues(UsageStatsKVProto.newBuilder().setKey(key.name()).setValue(value).build()); 91 + for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {
  92 + ConcurrentMap<OwnerId, AtomicLong> statsForKey = stats.get(key);
  93 + statsForKey.forEach((ownerId, statsValue) -> {
  94 + long value = statsValue.get();
  95 + if (value == 0) return;
  96 +
  97 + ToUsageStatsServiceMsg.Builder statsMsgBuilder = report.computeIfAbsent(ownerId, id -> {
  98 + ToUsageStatsServiceMsg.Builder newStatsMsgBuilder = ToUsageStatsServiceMsg.newBuilder();
  99 +
  100 + TenantId tenantId = ownerId.getTenantId();
  101 + newStatsMsgBuilder.setTenantIdMSB(tenantId.getId().getMostSignificantBits());
  102 + newStatsMsgBuilder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits());
  103 +
  104 + EntityId entityId = ownerId.getEntityId();
  105 + if (entityId != null && entityId.getEntityType() == EntityType.CUSTOMER) {
  106 + newStatsMsgBuilder.setCustomerIdMSB(entityId.getId().getMostSignificantBits());
  107 + newStatsMsgBuilder.setCustomerIdLSB(entityId.getId().getLeastSignificantBits());
89 } 108 }
90 - }));  
91 - }  
92 109
93 - report.forEach(((tenantId, builder) -> {  
94 - //TODO: figure out how to minimize messages into the queue. Maybe group by 100s of messages?  
95 - TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, tenantId).newByTopic(msgProducer.getDefaultTopic());  
96 - msgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), builder.build()), null);  
97 - }));  
98 - if (!report.isEmpty()) {  
99 - log.info("Report statistics for: {} tenants", report.size());  
100 - }  
101 - } catch (Exception e) {  
102 - log.warn("Failed to report statistics: ", e); 110 + return newStatsMsgBuilder;
  111 + });
  112 +
  113 + statsMsgBuilder.addValues(UsageStatsKVProto.newBuilder().setKey(key.name()).setValue(value).build());
  114 + });
  115 + statsForKey.clear();
  116 + }
  117 +
  118 + report.forEach(((ownerId, statsMsg) -> {
  119 + //TODO: figure out how to minimize messages into the queue. Maybe group by 100s of messages?
  120 +
  121 + TenantId tenantId = ownerId.getTenantId();
  122 + EntityId entityId = Optional.ofNullable(ownerId.getEntityId()).orElse(tenantId);
  123 + TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, entityId).newByTopic(msgProducer.getDefaultTopic());
  124 + msgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), statsMsg.build()), null);
  125 + }));
  126 +
  127 + if (!report.isEmpty()) {
  128 + log.info("Reporting API usage statistics for {} tenants and customers", report.size());
103 } 129 }
104 } 130 }
105 131
106 @Override 132 @Override
107 - public void report(TenantId tenantId, ApiUsageRecordKey key, long value) { 133 + public void report(TenantId tenantId, CustomerId customerId, ApiUsageRecordKey key, long value) {
108 if (enabled) { 134 if (enabled) {
109 - ConcurrentMap<TenantId, AtomicLong> map = values[key.ordinal()];  
110 - AtomicLong atomicValue = map.computeIfAbsent(tenantId, id -> new AtomicLong());  
111 - atomicValue.addAndGet(value); 135 + ConcurrentMap<OwnerId, AtomicLong> statsForKey = stats.get(key);
  136 +
  137 + statsForKey.computeIfAbsent(new OwnerId(tenantId), id -> new AtomicLong()).addAndGet(value);
  138 + statsForKey.computeIfAbsent(new OwnerId(TenantId.SYS_TENANT_ID), id -> new AtomicLong()).addAndGet(value);
  139 +
  140 + if (enabledPerCustomer && customerId != null && !customerId.isNullUid()) {
  141 + statsForKey.computeIfAbsent(new OwnerId(tenantId, customerId), id -> new AtomicLong()).addAndGet(value);
  142 + }
112 } 143 }
113 } 144 }
114 145
115 @Override 146 @Override
116 - public void report(TenantId tenantId, ApiUsageRecordKey key) {  
117 - report(tenantId, key, 1L); 147 + public void report(TenantId tenantId, CustomerId customerId, ApiUsageRecordKey key) {
  148 + report(tenantId, customerId, key, 1);
  149 + }
  150 +
  151 + @Data
  152 + private static class OwnerId {
  153 + private TenantId tenantId;
  154 + private EntityId entityId;
  155 +
  156 + public OwnerId(TenantId tenantId) {
  157 + this.tenantId = tenantId;
  158 + }
  159 +
  160 + public OwnerId(TenantId tenantId, EntityId entityId) {
  161 + this.tenantId = tenantId;
  162 + this.entityId = entityId;
  163 + }
118 } 164 }
119 } 165 }
@@ -16,12 +16,13 @@ @@ -16,12 +16,13 @@
16 package org.thingsboard.server.queue.usagestats; 16 package org.thingsboard.server.queue.usagestats;
17 17
18 import org.thingsboard.server.common.data.ApiUsageRecordKey; 18 import org.thingsboard.server.common.data.ApiUsageRecordKey;
  19 +import org.thingsboard.server.common.data.id.CustomerId;
19 import org.thingsboard.server.common.data.id.TenantId; 20 import org.thingsboard.server.common.data.id.TenantId;
20 21
21 public interface TbApiUsageClient { 22 public interface TbApiUsageClient {
22 23
23 - void report(TenantId tenantId, ApiUsageRecordKey key, long value); 24 + void report(TenantId tenantId, CustomerId customerId, ApiUsageRecordKey key, long value);
24 25
25 - void report(TenantId tenantId, ApiUsageRecordKey key); 26 + void report(TenantId tenantId, CustomerId customerId, ApiUsageRecordKey key);
26 27
27 } 28 }
@@ -53,6 +53,8 @@ message SessionInfoProto { @@ -53,6 +53,8 @@ message SessionInfoProto {
53 int64 gwSessionIdLSB = 11; 53 int64 gwSessionIdLSB = 11;
54 int64 deviceProfileIdMSB = 12; 54 int64 deviceProfileIdMSB = 12;
55 int64 deviceProfileIdLSB = 13; 55 int64 deviceProfileIdLSB = 13;
  56 + int64 customerIdMSB = 14;
  57 + int64 customerIdLSB = 15;
56 } 58 }
57 59
58 enum SessionEvent { 60 enum SessionEvent {
@@ -110,6 +112,8 @@ message DeviceInfoProto { @@ -110,6 +112,8 @@ message DeviceInfoProto {
110 string additionalInfo = 7; 112 string additionalInfo = 7;
111 int64 deviceProfileIdMSB = 8; 113 int64 deviceProfileIdMSB = 8;
112 int64 deviceProfileIdLSB = 9; 114 int64 deviceProfileIdLSB = 9;
  115 + int64 customerIdMSB = 10;
  116 + int64 customerIdLSB = 11;
113 } 117 }
114 118
115 /** 119 /**
@@ -656,4 +660,6 @@ message ToUsageStatsServiceMsg { @@ -656,4 +660,6 @@ message ToUsageStatsServiceMsg {
656 int64 entityIdMSB = 3; 660 int64 entityIdMSB = 3;
657 int64 entityIdLSB = 4; 661 int64 entityIdLSB = 4;
658 repeated UsageStatsKVProto values = 5; 662 repeated UsageStatsKVProto values = 5;
  663 + int64 customerIdMSB = 6;
  664 + int64 customerIdLSB = 7;
659 } 665 }
@@ -141,6 +141,8 @@ public class LwM2mTransportContextServer extends TransportContext { @@ -141,6 +141,8 @@ public class LwM2mTransportContextServer extends TransportContext {
141 .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB()) 141 .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB())
142 .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB()) 142 .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB())
143 .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB()) 143 .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB())
  144 + .setCustomerIdMSB(msg.getDeviceInfo().getCustomerIdMSB())
  145 + .setCustomerIdLSB(msg.getDeviceInfo().getCustomerIdLSB())
144 .setDeviceName(msg.getDeviceInfo().getDeviceName()) 146 .setDeviceName(msg.getDeviceInfo().getDeviceName())
145 .setDeviceType(msg.getDeviceInfo().getDeviceType()) 147 .setDeviceType(msg.getDeviceInfo().getDeviceType())
146 .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB()) 148 .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB())
@@ -1177,6 +1177,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { @@ -1177,6 +1177,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1177 .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB()) 1177 .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB())
1178 .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB()) 1178 .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB())
1179 .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB()) 1179 .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB())
  1180 + .setCustomerIdMSB(msg.getDeviceInfo().getCustomerIdMSB())
  1181 + .setCustomerIdLSB(msg.getDeviceInfo().getCustomerIdLSB())
1180 .setDeviceName(msg.getDeviceInfo().getDeviceName()) 1182 .setDeviceName(msg.getDeviceInfo().getDeviceName())
1181 .setDeviceType(msg.getDeviceInfo().getDeviceType()) 1183 .setDeviceType(msg.getDeviceInfo().getDeviceType())
1182 .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB()) 1184 .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB())
@@ -45,6 +45,8 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple @@ -45,6 +45,8 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple
45 .setDeviceIdLSB(deviceInfo.getDeviceId().getId().getLeastSignificantBits()) 45 .setDeviceIdLSB(deviceInfo.getDeviceId().getId().getLeastSignificantBits())
46 .setTenantIdMSB(deviceInfo.getTenantId().getId().getMostSignificantBits()) 46 .setTenantIdMSB(deviceInfo.getTenantId().getId().getMostSignificantBits())
47 .setTenantIdLSB(deviceInfo.getTenantId().getId().getLeastSignificantBits()) 47 .setTenantIdLSB(deviceInfo.getTenantId().getId().getLeastSignificantBits())
  48 + .setCustomerIdMSB(deviceInfo.getCustomerId().getId().getMostSignificantBits())
  49 + .setCustomerIdLSB(deviceInfo.getCustomerId().getId().getLeastSignificantBits())
48 .setDeviceName(deviceInfo.getDeviceName()) 50 .setDeviceName(deviceInfo.getDeviceName())
49 .setDeviceType(deviceInfo.getDeviceType()) 51 .setDeviceType(deviceInfo.getDeviceType())
50 .setGwSessionIdMSB(parent.getSessionId().getMostSignificantBits()) 52 .setGwSessionIdMSB(parent.getSessionId().getMostSignificantBits())
@@ -40,6 +40,8 @@ public class SessionInfoCreator { @@ -40,6 +40,8 @@ public class SessionInfoCreator {
40 .setDeviceIdLSB(msg.getDeviceInfo().getDeviceId().getId().getLeastSignificantBits()) 40 .setDeviceIdLSB(msg.getDeviceInfo().getDeviceId().getId().getLeastSignificantBits())
41 .setTenantIdMSB(msg.getDeviceInfo().getTenantId().getId().getMostSignificantBits()) 41 .setTenantIdMSB(msg.getDeviceInfo().getTenantId().getId().getMostSignificantBits())
42 .setTenantIdLSB(msg.getDeviceInfo().getTenantId().getId().getLeastSignificantBits()) 42 .setTenantIdLSB(msg.getDeviceInfo().getTenantId().getId().getLeastSignificantBits())
  43 + .setCustomerIdMSB(msg.getDeviceInfo().getCustomerId().getId().getMostSignificantBits())
  44 + .setCustomerIdLSB(msg.getDeviceInfo().getCustomerId().getId().getLeastSignificantBits())
43 .setDeviceName(msg.getDeviceInfo().getDeviceName()) 45 .setDeviceName(msg.getDeviceInfo().getDeviceName())
44 .setDeviceType(msg.getDeviceInfo().getDeviceType()) 46 .setDeviceType(msg.getDeviceInfo().getDeviceType())
45 .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileId().getId().getMostSignificantBits()) 47 .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileId().getId().getMostSignificantBits())
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 package org.thingsboard.server.common.transport.auth; 16 package org.thingsboard.server.common.transport.auth;
17 17
18 import lombok.Data; 18 import lombok.Data;
  19 +import org.thingsboard.server.common.data.id.CustomerId;
19 import org.thingsboard.server.common.data.id.DeviceId; 20 import org.thingsboard.server.common.data.id.DeviceId;
20 import org.thingsboard.server.common.data.id.DeviceProfileId; 21 import org.thingsboard.server.common.data.id.DeviceProfileId;
21 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
@@ -24,6 +25,7 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -24,6 +25,7 @@ import org.thingsboard.server.common.data.id.TenantId;
24 public class TransportDeviceInfo { 25 public class TransportDeviceInfo {
25 26
26 private TenantId tenantId; 27 private TenantId tenantId;
  28 + private CustomerId customerId;
27 private DeviceProfileId deviceProfileId; 29 private DeviceProfileId deviceProfileId;
28 private DeviceId deviceId; 30 private DeviceId deviceId;
29 private String deviceName; 31 private String deviceName;
@@ -33,8 +33,10 @@ import org.thingsboard.server.common.data.DeviceTransportType; @@ -33,8 +33,10 @@ import org.thingsboard.server.common.data.DeviceTransportType;
33 import org.thingsboard.server.common.data.EntityType; 33 import org.thingsboard.server.common.data.EntityType;
34 import org.thingsboard.server.common.data.ResourceType; 34 import org.thingsboard.server.common.data.ResourceType;
35 import org.thingsboard.server.common.data.Tenant; 35 import org.thingsboard.server.common.data.Tenant;
  36 +import org.thingsboard.server.common.data.id.CustomerId;
36 import org.thingsboard.server.common.data.id.DeviceId; 37 import org.thingsboard.server.common.data.id.DeviceId;
37 import org.thingsboard.server.common.data.id.DeviceProfileId; 38 import org.thingsboard.server.common.data.id.DeviceProfileId;
  39 +import org.thingsboard.server.common.data.id.EntityId;
38 import org.thingsboard.server.common.data.id.RuleChainId; 40 import org.thingsboard.server.common.data.id.RuleChainId;
39 import org.thingsboard.server.common.data.id.TenantId; 41 import org.thingsboard.server.common.data.id.TenantId;
40 import org.thingsboard.server.common.data.id.TenantProfileId; 42 import org.thingsboard.server.common.data.id.TenantProfileId;
@@ -359,6 +361,7 @@ public class DefaultTransportService implements TransportService { @@ -359,6 +361,7 @@ public class DefaultTransportService implements TransportService {
359 private TransportDeviceInfo getTransportDeviceInfo(TransportProtos.DeviceInfoProto di) { 361 private TransportDeviceInfo getTransportDeviceInfo(TransportProtos.DeviceInfoProto di) {
360 TransportDeviceInfo tdi = new TransportDeviceInfo(); 362 TransportDeviceInfo tdi = new TransportDeviceInfo();
361 tdi.setTenantId(new TenantId(new UUID(di.getTenantIdMSB(), di.getTenantIdLSB()))); 363 tdi.setTenantId(new TenantId(new UUID(di.getTenantIdMSB(), di.getTenantIdLSB())));
  364 + tdi.setCustomerId(new CustomerId(new UUID(di.getCustomerIdMSB(), di.getCustomerIdLSB())));
362 tdi.setDeviceId(new DeviceId(new UUID(di.getDeviceIdMSB(), di.getDeviceIdLSB()))); 365 tdi.setDeviceId(new DeviceId(new UUID(di.getDeviceIdMSB(), di.getDeviceIdLSB())));
363 tdi.setDeviceProfileId(new DeviceProfileId(new UUID(di.getDeviceProfileIdMSB(), di.getDeviceProfileIdLSB()))); 366 tdi.setDeviceProfileId(new DeviceProfileId(new UUID(di.getDeviceProfileIdMSB(), di.getDeviceProfileIdLSB())));
364 tdi.setAdditionalInfo(di.getAdditionalInfo()); 367 tdi.setAdditionalInfo(di.getAdditionalInfo());
@@ -403,17 +406,17 @@ public class DefaultTransportService implements TransportService { @@ -403,17 +406,17 @@ public class DefaultTransportService implements TransportService {
403 } 406 }
404 if (checkLimits(sessionInfo, msg, callback, dataPoints)) { 407 if (checkLimits(sessionInfo, msg, callback, dataPoints)) {
405 reportActivityInternal(sessionInfo); 408 reportActivityInternal(sessionInfo);
406 - TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); 409 + TenantId tenantId = getTenantId(sessionInfo);
407 DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); 410 DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()));
408 - MsgPackCallback packCallback = new MsgPackCallback(msg.getTsKvListCount(), new ApiStatsProxyCallback<>(tenantId, dataPoints, callback)); 411 + CustomerId customerId = getCustomerId(sessionInfo);
  412 + MsgPackCallback packCallback = new MsgPackCallback(msg.getTsKvListCount(), new ApiStatsProxyCallback<>(tenantId, customerId, dataPoints, callback));
409 for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) { 413 for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) {
410 TbMsgMetaData metaData = new TbMsgMetaData(); 414 TbMsgMetaData metaData = new TbMsgMetaData();
411 metaData.putValue("deviceName", sessionInfo.getDeviceName()); 415 metaData.putValue("deviceName", sessionInfo.getDeviceName());
412 metaData.putValue("deviceType", sessionInfo.getDeviceType()); 416 metaData.putValue("deviceType", sessionInfo.getDeviceType());
413 metaData.putValue("ts", tsKv.getTs() + ""); 417 metaData.putValue("ts", tsKv.getTs() + "");
414 JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); 418 JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
415 - sendToRuleEngine(tenantId, deviceId, sessionInfo, json, metaData, SessionMsgType.POST_TELEMETRY_REQUEST, packCallback);  
416 - 419 + sendToRuleEngine(tenantId, deviceId, customerId, sessionInfo, json, metaData, SessionMsgType.POST_TELEMETRY_REQUEST, packCallback);
417 } 420 }
418 } 421 }
419 } 422 }
@@ -422,15 +425,16 @@ public class DefaultTransportService implements TransportService { @@ -422,15 +425,16 @@ public class DefaultTransportService implements TransportService {
422 public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.PostAttributeMsg msg, TransportServiceCallback<Void> callback) { 425 public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.PostAttributeMsg msg, TransportServiceCallback<Void> callback) {
423 if (checkLimits(sessionInfo, msg, callback, msg.getKvCount())) { 426 if (checkLimits(sessionInfo, msg, callback, msg.getKvCount())) {
424 reportActivityInternal(sessionInfo); 427 reportActivityInternal(sessionInfo);
425 - TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); 428 + TenantId tenantId = getTenantId(sessionInfo);
426 DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); 429 DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()));
427 JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); 430 JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
428 TbMsgMetaData metaData = new TbMsgMetaData(); 431 TbMsgMetaData metaData = new TbMsgMetaData();
429 metaData.putValue("deviceName", sessionInfo.getDeviceName()); 432 metaData.putValue("deviceName", sessionInfo.getDeviceName());
430 metaData.putValue("deviceType", sessionInfo.getDeviceType()); 433 metaData.putValue("deviceType", sessionInfo.getDeviceType());
431 metaData.putValue("notifyDevice", "false"); 434 metaData.putValue("notifyDevice", "false");
432 - sendToRuleEngine(tenantId, deviceId, sessionInfo, json, metaData, SessionMsgType.POST_ATTRIBUTES_REQUEST,  
433 - new TransportTbQueueCallback(new ApiStatsProxyCallback<>(tenantId, msg.getKvList().size(), callback))); 435 + CustomerId customerId = getCustomerId(sessionInfo);
  436 + sendToRuleEngine(tenantId, deviceId, customerId, sessionInfo, json, metaData, SessionMsgType.POST_ATTRIBUTES_REQUEST,
  437 + new TransportTbQueueCallback(new ApiStatsProxyCallback<>(tenantId, customerId, msg.getKvList().size(), callback)));
434 } 438 }
435 } 439 }
436 440
@@ -439,7 +443,7 @@ public class DefaultTransportService implements TransportService { @@ -439,7 +443,7 @@ public class DefaultTransportService implements TransportService {
439 if (checkLimits(sessionInfo, msg, callback)) { 443 if (checkLimits(sessionInfo, msg, callback)) {
440 reportActivityInternal(sessionInfo); 444 reportActivityInternal(sessionInfo);
441 sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo) 445 sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo)
442 - .setGetAttributes(msg).build(), new ApiStatsProxyCallback<>(getTenantId(sessionInfo), 1, callback)); 446 + .setGetAttributes(msg).build(), new ApiStatsProxyCallback<>(getTenantId(sessionInfo), getCustomerId(sessionInfo), 1, callback));
443 } 447 }
444 } 448 }
445 449
@@ -448,8 +452,8 @@ public class DefaultTransportService implements TransportService { @@ -448,8 +452,8 @@ public class DefaultTransportService implements TransportService {
448 if (checkLimits(sessionInfo, msg, callback)) { 452 if (checkLimits(sessionInfo, msg, callback)) {
449 SessionMetaData sessionMetaData = reportActivityInternal(sessionInfo); 453 SessionMetaData sessionMetaData = reportActivityInternal(sessionInfo);
450 sessionMetaData.setSubscribedToAttributes(!msg.getUnsubscribe()); 454 sessionMetaData.setSubscribedToAttributes(!msg.getUnsubscribe());
451 - sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo)  
452 - .setSubscribeToAttributes(msg).build(), new ApiStatsProxyCallback<>(getTenantId(sessionInfo), 1, callback)); 455 + sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setSubscribeToAttributes(msg).build(),
  456 + new ApiStatsProxyCallback<>(getTenantId(sessionInfo), getCustomerId(sessionInfo), 1, callback));
453 } 457 }
454 } 458 }
455 459
@@ -458,8 +462,8 @@ public class DefaultTransportService implements TransportService { @@ -458,8 +462,8 @@ public class DefaultTransportService implements TransportService {
458 if (checkLimits(sessionInfo, msg, callback)) { 462 if (checkLimits(sessionInfo, msg, callback)) {
459 SessionMetaData sessionMetaData = reportActivityInternal(sessionInfo); 463 SessionMetaData sessionMetaData = reportActivityInternal(sessionInfo);
460 sessionMetaData.setSubscribedToRPC(!msg.getUnsubscribe()); 464 sessionMetaData.setSubscribedToRPC(!msg.getUnsubscribe());
461 - sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo)  
462 - .setSubscribeToRPC(msg).build(), new ApiStatsProxyCallback<>(getTenantId(sessionInfo), 1, callback)); 465 + sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setSubscribeToRPC(msg).build(),
  466 + new ApiStatsProxyCallback<>(getTenantId(sessionInfo), getCustomerId(sessionInfo), 1, callback));
463 } 467 }
464 } 468 }
465 469
@@ -467,8 +471,8 @@ public class DefaultTransportService implements TransportService { @@ -467,8 +471,8 @@ public class DefaultTransportService implements TransportService {
467 public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToDeviceRpcResponseMsg msg, TransportServiceCallback<Void> callback) { 471 public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToDeviceRpcResponseMsg msg, TransportServiceCallback<Void> callback) {
468 if (checkLimits(sessionInfo, msg, callback)) { 472 if (checkLimits(sessionInfo, msg, callback)) {
469 reportActivityInternal(sessionInfo); 473 reportActivityInternal(sessionInfo);
470 - sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo)  
471 - .setToDeviceRPCCallResponse(msg).build(), new ApiStatsProxyCallback<>(getTenantId(sessionInfo), 1, callback)); 474 + sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setToDeviceRPCCallResponse(msg).build(),
  475 + new ApiStatsProxyCallback<>(getTenantId(sessionInfo), getCustomerId(sessionInfo), 1, callback));
472 } 476 }
473 } 477 }
474 478
@@ -511,7 +515,7 @@ public class DefaultTransportService implements TransportService { @@ -511,7 +515,7 @@ public class DefaultTransportService implements TransportService {
511 metaData.putValue("requestId", Integer.toString(msg.getRequestId())); 515 metaData.putValue("requestId", Integer.toString(msg.getRequestId()));
512 metaData.putValue("serviceId", serviceInfoProvider.getServiceId()); 516 metaData.putValue("serviceId", serviceInfoProvider.getServiceId());
513 metaData.putValue("sessionId", sessionId.toString()); 517 metaData.putValue("sessionId", sessionId.toString());
514 - sendToRuleEngine(tenantId, deviceId, sessionInfo, json, metaData, 518 + sendToRuleEngine(tenantId, deviceId, getCustomerId(sessionInfo), sessionInfo, json, metaData,
515 SessionMsgType.TO_SERVER_RPC_REQUEST, new TransportTbQueueCallback(callback)); 519 SessionMsgType.TO_SERVER_RPC_REQUEST, new TransportTbQueueCallback(callback));
516 String requestId = sessionId + "-" + msg.getRequestId(); 520 String requestId = sessionId + "-" + msg.getRequestId();
517 toServerRpcPendingMap.put(requestId, new RpcRequestMetadata(sessionId, msg.getRequestId())); 521 toServerRpcPendingMap.put(requestId, new RpcRequestMetadata(sessionId, msg.getRequestId()));
@@ -809,6 +813,16 @@ public class DefaultTransportService implements TransportService { @@ -809,6 +813,16 @@ public class DefaultTransportService implements TransportService {
809 return new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); 813 return new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB()));
810 } 814 }
811 815
  816 + protected CustomerId getCustomerId(TransportProtos.SessionInfoProto sessionInfo) {
  817 + long msb = sessionInfo.getCustomerIdMSB();
  818 + long lsb = sessionInfo.getCustomerIdLSB();
  819 + if (msb != 0 && lsb != 0) {
  820 + return new CustomerId(new UUID(msb, lsb));
  821 + } else {
  822 + return new CustomerId(EntityId.NULL_UUID);
  823 + }
  824 + }
  825 +
812 protected DeviceId getDeviceId(TransportProtos.SessionInfoProto sessionInfo) { 826 protected DeviceId getDeviceId(TransportProtos.SessionInfoProto sessionInfo) {
813 return new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); 827 return new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()));
814 } 828 }
@@ -847,7 +861,7 @@ public class DefaultTransportService implements TransportService { @@ -847,7 +861,7 @@ public class DefaultTransportService implements TransportService {
847 ruleEngineMsgProducer.send(tpi, new TbProtoQueueMsg<>(tbMsg.getId(), msg), wrappedCallback); 861 ruleEngineMsgProducer.send(tpi, new TbProtoQueueMsg<>(tbMsg.getId(), msg), wrappedCallback);
848 } 862 }
849 863
850 - private void sendToRuleEngine(TenantId tenantId, DeviceId deviceId, TransportProtos.SessionInfoProto sessionInfo, JsonObject json, 864 + private void sendToRuleEngine(TenantId tenantId, DeviceId deviceId, CustomerId customerId, TransportProtos.SessionInfoProto sessionInfo, JsonObject json,
851 TbMsgMetaData metaData, SessionMsgType sessionMsgType, TbQueueCallback callback) { 865 TbMsgMetaData metaData, SessionMsgType sessionMsgType, TbQueueCallback callback) {
852 DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); 866 DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
853 DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId); 867 DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId);
@@ -864,7 +878,7 @@ public class DefaultTransportService implements TransportService { @@ -864,7 +878,7 @@ public class DefaultTransportService implements TransportService {
864 queueName = defaultQueueName != null ? defaultQueueName : ServiceQueue.MAIN; 878 queueName = defaultQueueName != null ? defaultQueueName : ServiceQueue.MAIN;
865 } 879 }
866 880
867 - TbMsg tbMsg = TbMsg.newMsg(queueName, sessionMsgType.name(), deviceId, metaData, gson.toJson(json), ruleChainId, null); 881 + TbMsg tbMsg = TbMsg.newMsg(queueName, sessionMsgType.name(), deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null);
868 sendToRuleEngine(tenantId, tbMsg, callback); 882 sendToRuleEngine(tenantId, tbMsg, callback);
869 } 883 }
870 884
@@ -934,11 +948,13 @@ public class DefaultTransportService implements TransportService { @@ -934,11 +948,13 @@ public class DefaultTransportService implements TransportService {
934 948
935 private class ApiStatsProxyCallback<T> implements TransportServiceCallback<T> { 949 private class ApiStatsProxyCallback<T> implements TransportServiceCallback<T> {
936 private final TenantId tenantId; 950 private final TenantId tenantId;
  951 + private final CustomerId customerId;
937 private final int dataPoints; 952 private final int dataPoints;
938 private final TransportServiceCallback<T> callback; 953 private final TransportServiceCallback<T> callback;
939 954
940 - public ApiStatsProxyCallback(TenantId tenantId, int dataPoints, TransportServiceCallback<T> callback) { 955 + public ApiStatsProxyCallback(TenantId tenantId, CustomerId customerId, int dataPoints, TransportServiceCallback<T> callback) {
941 this.tenantId = tenantId; 956 this.tenantId = tenantId;
  957 + this.customerId = customerId;
942 this.dataPoints = dataPoints; 958 this.dataPoints = dataPoints;
943 this.callback = callback; 959 this.callback = callback;
944 } 960 }
@@ -946,8 +962,8 @@ public class DefaultTransportService implements TransportService { @@ -946,8 +962,8 @@ public class DefaultTransportService implements TransportService {
946 @Override 962 @Override
947 public void onSuccess(T msg) { 963 public void onSuccess(T msg) {
948 try { 964 try {
949 - apiUsageClient.report(tenantId, ApiUsageRecordKey.TRANSPORT_MSG_COUNT, 1);  
950 - apiUsageClient.report(tenantId, ApiUsageRecordKey.TRANSPORT_DP_COUNT, dataPoints); 965 + apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.TRANSPORT_MSG_COUNT, 1);
  966 + apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.TRANSPORT_DP_COUNT, dataPoints);
951 } finally { 967 } finally {
952 callback.onSuccess(msg); 968 callback.onSuccess(msg);
953 } 969 }
@@ -43,6 +43,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover; @@ -43,6 +43,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover;
43 import org.thingsboard.server.dao.service.Validator; 43 import org.thingsboard.server.dao.service.Validator;
44 import org.thingsboard.server.dao.tenant.TbTenantProfileCache; 44 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
45 import org.thingsboard.server.dao.tenant.TenantDao; 45 import org.thingsboard.server.dao.tenant.TenantDao;
  46 +import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
46 import org.thingsboard.server.dao.user.UserService; 47 import org.thingsboard.server.dao.user.UserService;
47 48
48 import java.io.IOException; 49 import java.io.IOException;
@@ -80,6 +81,9 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom @@ -80,6 +81,9 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
80 private DashboardService dashboardService; 81 private DashboardService dashboardService;
81 82
82 @Autowired 83 @Autowired
  84 + private ApiUsageStateService apiUsageStateService;
  85 +
  86 + @Autowired
83 @Lazy 87 @Lazy
84 private TbTenantProfileCache tenantProfileCache; 88 private TbTenantProfileCache tenantProfileCache;
85 89
@@ -128,6 +132,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom @@ -128,6 +132,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
128 edgeService.unassignCustomerEdges(customer.getTenantId(), customerId); 132 edgeService.unassignCustomerEdges(customer.getTenantId(), customerId);
129 userService.deleteCustomerUsers(customer.getTenantId(), customerId); 133 userService.deleteCustomerUsers(customer.getTenantId(), customerId);
130 deleteEntityRelations(tenantId, customerId); 134 deleteEntityRelations(tenantId, customerId);
  135 + apiUsageStateService.deleteApiUsageStateByEntityId(customerId);
131 customerDao.removeById(tenantId, customerId.getId()); 136 customerDao.removeById(tenantId, customerId.getId());
132 } 137 }
133 138
@@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.CustomerId; @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
25 import org.thingsboard.server.common.data.id.EntityId; 25 import org.thingsboard.server.common.data.id.EntityId;
26 import org.thingsboard.server.common.data.id.TenantId; 26 import org.thingsboard.server.common.data.id.TenantId;
27 import org.thingsboard.server.common.data.page.PageData; 27 import org.thingsboard.server.common.data.page.PageData;
  28 +import org.thingsboard.server.common.data.query.ApiUsageStateFilter;
28 import org.thingsboard.server.common.data.query.AssetSearchQueryFilter; 29 import org.thingsboard.server.common.data.query.AssetSearchQueryFilter;
29 import org.thingsboard.server.common.data.query.AssetTypeFilter; 30 import org.thingsboard.server.common.data.query.AssetTypeFilter;
30 import org.thingsboard.server.common.data.query.DeviceSearchQueryFilter; 31 import org.thingsboard.server.common.data.query.DeviceSearchQueryFilter;
@@ -219,8 +220,9 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -219,8 +220,9 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
219 " THEN (select additional_info from edge where id = entity_id)" + 220 " THEN (select additional_info from edge where id = entity_id)" +
220 " END as additional_info"; 221 " END as additional_info";
221 222
222 - private static final String SELECT_API_USAGE_STATE = "(select aus.id, aus.created_time, aus.tenant_id, '13814000-1dd2-11b2-8080-808080808080'::uuid as customer_id, " +  
223 - "(select title from tenant where id = aus.tenant_id) as name from api_usage_state as aus)"; 223 + private static final String SELECT_API_USAGE_STATE = "(select aus.id, aus.created_time, aus.tenant_id, aus.entity_id, " +
  224 + "coalesce((select title from tenant where id = aus.entity_id), (select title from customer where id = aus.entity_id)) as name " +
  225 + "from api_usage_state as aus)";
224 226
225 static { 227 static {
226 entityTableMap.put(EntityType.ASSET, "asset"); 228 entityTableMap.put(EntityType.ASSET, "asset");
@@ -466,6 +468,22 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -466,6 +468,22 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
466 case ENTITY_VIEW_SEARCH_QUERY: 468 case ENTITY_VIEW_SEARCH_QUERY:
467 case EDGE_SEARCH_QUERY: 469 case EDGE_SEARCH_QUERY:
468 return this.defaultPermissionQuery(ctx); 470 return this.defaultPermissionQuery(ctx);
  471 + case API_USAGE_STATE:
  472 + CustomerId filterCustomerId = ((ApiUsageStateFilter) entityFilter).getCustomerId();
  473 + if (ctx.getCustomerId() != null && !ctx.getCustomerId().isNullUid()) {
  474 + if (filterCustomerId != null && !filterCustomerId.equals(ctx.getCustomerId())) {
  475 + throw new SecurityException("Customer is not allowed to query other customer's data");
  476 + }
  477 + filterCustomerId = ctx.getCustomerId();
  478 + }
  479 +
  480 + ctx.addUuidParameter("permissions_tenant_id", ctx.getTenantId().getId());
  481 + if (filterCustomerId != null) {
  482 + ctx.addUuidParameter("permissions_customer_id", filterCustomerId.getId());
  483 + return "e.tenant_id=:permissions_tenant_id and e.entity_id=:permissions_customer_id";
  484 + } else {
  485 + return "e.tenant_id=:permissions_tenant_id and e.entity_id=:permissions_tenant_id";
  486 + }
469 default: 487 default:
470 if (ctx.getEntityType() == EntityType.TENANT) { 488 if (ctx.getEntityType() == EntityType.TENANT) {
471 ctx.addUuidParameter("permissions_tenant_id", ctx.getTenantId().getId()); 489 ctx.addUuidParameter("permissions_tenant_id", ctx.getTenantId().getId());
@@ -33,8 +33,14 @@ public interface ApiUsageStateRepository extends CrudRepository<ApiUsageStateEnt @@ -33,8 +33,14 @@ public interface ApiUsageStateRepository extends CrudRepository<ApiUsageStateEnt
33 "AND ur.entityId = :tenantId AND ur.entityType = 'TENANT' ") 33 "AND ur.entityId = :tenantId AND ur.entityType = 'TENANT' ")
34 ApiUsageStateEntity findByTenantId(@Param("tenantId") UUID tenantId); 34 ApiUsageStateEntity findByTenantId(@Param("tenantId") UUID tenantId);
35 35
  36 + ApiUsageStateEntity findByEntityIdAndEntityType(UUID entityId, String entityType);
  37 +
36 @Transactional 38 @Transactional
37 @Modifying 39 @Modifying
38 @Query("DELETE FROM ApiUsageStateEntity ur WHERE ur.tenantId = :tenantId") 40 @Query("DELETE FROM ApiUsageStateEntity ur WHERE ur.tenantId = :tenantId")
39 void deleteApiUsageStateByTenantId(@Param("tenantId") UUID tenantId); 41 void deleteApiUsageStateByTenantId(@Param("tenantId") UUID tenantId);
  42 +
  43 + @Transactional
  44 + @Modifying
  45 + void deleteByEntityIdAndEntityType(UUID entityId, String entityType);
40 } 46 }
@@ -18,6 +18,7 @@ package org.thingsboard.server.dao.sql.usagerecord; @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.sql.usagerecord;
18 import org.springframework.data.repository.CrudRepository; 18 import org.springframework.data.repository.CrudRepository;
19 import org.springframework.stereotype.Component; 19 import org.springframework.stereotype.Component;
20 import org.thingsboard.server.common.data.ApiUsageState; 20 import org.thingsboard.server.common.data.ApiUsageState;
  21 +import org.thingsboard.server.common.data.id.EntityId;
21 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
22 import org.thingsboard.server.dao.DaoUtil; 23 import org.thingsboard.server.dao.DaoUtil;
23 import org.thingsboard.server.dao.model.sql.ApiUsageStateEntity; 24 import org.thingsboard.server.dao.model.sql.ApiUsageStateEntity;
@@ -54,7 +55,17 @@ public class JpaApiUsageStateDao extends JpaAbstractDao<ApiUsageStateEntity, Api @@ -54,7 +55,17 @@ public class JpaApiUsageStateDao extends JpaAbstractDao<ApiUsageStateEntity, Api
54 } 55 }
55 56
56 @Override 57 @Override
  58 + public ApiUsageState findApiUsageStateByEntityId(EntityId entityId) {
  59 + return DaoUtil.getData(apiUsageStateRepository.findByEntityIdAndEntityType(entityId.getId(), entityId.getEntityType().name()));
  60 + }
  61 +
  62 + @Override
57 public void deleteApiUsageStateByTenantId(TenantId tenantId) { 63 public void deleteApiUsageStateByTenantId(TenantId tenantId) {
58 apiUsageStateRepository.deleteApiUsageStateByTenantId(tenantId.getId()); 64 apiUsageStateRepository.deleteApiUsageStateByTenantId(tenantId.getId());
59 } 65 }
  66 +
  67 + @Override
  68 + public void deleteApiUsageStateByEntityId(EntityId entityId) {
  69 + apiUsageStateRepository.deleteByEntityIdAndEntityType(entityId.getId(), entityId.getEntityType().name());
  70 + }
60 } 71 }
@@ -125,7 +125,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @@ -125,7 +125,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
125 Tenant savedTenant = tenantDao.save(tenant.getId(), tenant); 125 Tenant savedTenant = tenantDao.save(tenant.getId(), tenant);
126 if (tenant.getId() == null) { 126 if (tenant.getId() == null) {
127 deviceProfileService.createDefaultDeviceProfile(savedTenant.getId()); 127 deviceProfileService.createDefaultDeviceProfile(savedTenant.getId());
128 - apiUsageStateService.createDefaultApiUsageState(savedTenant.getId()); 128 + apiUsageStateService.createDefaultApiUsageState(savedTenant.getId(), null);
129 } 129 }
130 return savedTenant; 130 return savedTenant;
131 } 131 }
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 package org.thingsboard.server.dao.usagerecord; 16 package org.thingsboard.server.dao.usagerecord;
17 17
18 import org.thingsboard.server.common.data.ApiUsageState; 18 import org.thingsboard.server.common.data.ApiUsageState;
  19 +import org.thingsboard.server.common.data.id.EntityId;
19 import org.thingsboard.server.common.data.id.TenantId; 20 import org.thingsboard.server.common.data.id.TenantId;
20 import org.thingsboard.server.dao.Dao; 21 import org.thingsboard.server.dao.Dao;
21 22
@@ -39,10 +40,14 @@ public interface ApiUsageStateDao extends Dao<ApiUsageState> { @@ -39,10 +40,14 @@ public interface ApiUsageStateDao extends Dao<ApiUsageState> {
39 */ 40 */
40 ApiUsageState findTenantApiUsageState(UUID tenantId); 41 ApiUsageState findTenantApiUsageState(UUID tenantId);
41 42
  43 + ApiUsageState findApiUsageStateByEntityId(EntityId entityId);
  44 +
42 /** 45 /**
43 * Delete usage record by tenantId. 46 * Delete usage record by tenantId.
44 * 47 *
45 * @param tenantId the tenantId 48 * @param tenantId the tenantId
46 */ 49 */
47 void deleteApiUsageStateByTenantId(TenantId tenantId); 50 void deleteApiUsageStateByTenantId(TenantId tenantId);
  51 +
  52 + void deleteApiUsageStateByEntityId(EntityId entityId);
48 } 53 }
@@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.EntityType; @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.EntityType;
25 import org.thingsboard.server.common.data.Tenant; 25 import org.thingsboard.server.common.data.Tenant;
26 import org.thingsboard.server.common.data.TenantProfile; 26 import org.thingsboard.server.common.data.TenantProfile;
27 import org.thingsboard.server.common.data.id.ApiUsageStateId; 27 import org.thingsboard.server.common.data.id.ApiUsageStateId;
  28 +import org.thingsboard.server.common.data.id.EntityId;
28 import org.thingsboard.server.common.data.id.TenantId; 29 import org.thingsboard.server.common.data.id.TenantId;
29 import org.thingsboard.server.common.data.kv.BasicTsKvEntry; 30 import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
30 import org.thingsboard.server.common.data.kv.LongDataEntry; 31 import org.thingsboard.server.common.data.kv.LongDataEntry;
@@ -40,6 +41,7 @@ import org.thingsboard.server.dao.timeseries.TimeseriesService; @@ -40,6 +41,7 @@ import org.thingsboard.server.dao.timeseries.TimeseriesService;
40 41
41 import java.util.ArrayList; 42 import java.util.ArrayList;
42 import java.util.List; 43 import java.util.List;
  44 +import java.util.Objects;
43 45
44 import static org.thingsboard.server.dao.service.Validator.validateId; 46 import static org.thingsboard.server.dao.service.Validator.validateId;
45 47
@@ -68,12 +70,20 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A @@ -68,12 +70,20 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
68 } 70 }
69 71
70 @Override 72 @Override
71 - public ApiUsageState createDefaultApiUsageState(TenantId tenantId) {  
72 - log.trace("Executing createDefaultUsageRecord [{}]", tenantId); 73 + public void deleteApiUsageStateByEntityId(EntityId entityId) {
  74 + log.trace("Executing deleteApiUsageStateByEntityId [{}]", entityId);
  75 + validateId(entityId.getId(), "Invalid entity id");
  76 + apiUsageStateDao.deleteApiUsageStateByEntityId(entityId);
  77 + }
  78 +
  79 + @Override
  80 + public ApiUsageState createDefaultApiUsageState(TenantId tenantId, EntityId entityId) {
  81 + entityId = Objects.requireNonNullElse(entityId, tenantId);
  82 + log.trace("Executing createDefaultUsageRecord [{}]", entityId);
73 validateId(tenantId, INCORRECT_TENANT_ID + tenantId); 83 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
74 ApiUsageState apiUsageState = new ApiUsageState(); 84 ApiUsageState apiUsageState = new ApiUsageState();
75 apiUsageState.setTenantId(tenantId); 85 apiUsageState.setTenantId(tenantId);
76 - apiUsageState.setEntityId(tenantId); 86 + apiUsageState.setEntityId(entityId);
77 apiUsageState.setTransportState(ApiUsageStateValue.ENABLED); 87 apiUsageState.setTransportState(ApiUsageStateValue.ENABLED);
78 apiUsageState.setReExecState(ApiUsageStateValue.ENABLED); 88 apiUsageState.setReExecState(ApiUsageStateValue.ENABLED);
79 apiUsageState.setJsExecState(ApiUsageStateValue.ENABLED); 89 apiUsageState.setJsExecState(ApiUsageStateValue.ENABLED);
@@ -84,9 +94,6 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A @@ -84,9 +94,6 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
84 94
85 ApiUsageState saved = apiUsageStateDao.save(apiUsageState.getTenantId(), apiUsageState); 95 ApiUsageState saved = apiUsageStateDao.save(apiUsageState.getTenantId(), apiUsageState);
86 96
87 - Tenant tenant = tenantDao.findById(tenantId, tenantId.getId());  
88 - TenantProfile tenantProfile = tenantProfileDao.findById(tenantId, tenant.getTenantProfileId().getId());  
89 - TenantProfileConfiguration configuration = tenantProfile.getProfileData().getConfiguration();  
90 List<TsKvEntry> apiUsageStates = new ArrayList<>(); 97 List<TsKvEntry> apiUsageStates = new ArrayList<>();
91 apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(), 98 apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(),
92 new StringDataEntry(ApiFeature.TRANSPORT.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); 99 new StringDataEntry(ApiFeature.TRANSPORT.getApiStateKey(), ApiUsageStateValue.ENABLED.name())));
@@ -102,12 +109,19 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A @@ -102,12 +109,19 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
102 new StringDataEntry(ApiFeature.SMS.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); 109 new StringDataEntry(ApiFeature.SMS.getApiStateKey(), ApiUsageStateValue.ENABLED.name())));
103 tsService.save(tenantId, saved.getId(), apiUsageStates, 0L); 110 tsService.save(tenantId, saved.getId(), apiUsageStates, 0L);
104 111
105 - List<TsKvEntry> profileThresholds = new ArrayList<>();  
106 -  
107 - for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {  
108 - profileThresholds.add(new BasicTsKvEntry(saved.getCreatedTime(), new LongDataEntry(key.getApiLimitKey(), configuration.getProfileThreshold(key)))); 112 + if (entityId.getEntityType() == EntityType.TENANT && !entityId.equals(TenantId.SYS_TENANT_ID)) {
  113 + tenantId = (TenantId) entityId;
  114 + Tenant tenant = tenantDao.findById(tenantId, tenantId.getId());
  115 + TenantProfile tenantProfile = tenantProfileDao.findById(tenantId, tenant.getTenantProfileId().getId());
  116 + TenantProfileConfiguration configuration = tenantProfile.getProfileData().getConfiguration();
  117 +
  118 + List<TsKvEntry> profileThresholds = new ArrayList<>();
  119 + for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {
  120 + profileThresholds.add(new BasicTsKvEntry(saved.getCreatedTime(), new LongDataEntry(key.getApiLimitKey(), configuration.getProfileThreshold(key))));
  121 + }
  122 + tsService.save(tenantId, saved.getId(), profileThresholds, 0L);
109 } 123 }
110 - tsService.save(tenantId, saved.getId(), profileThresholds, 0L); 124 +
111 return saved; 125 return saved;
112 } 126 }
113 127
@@ -127,6 +141,12 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A @@ -127,6 +141,12 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
127 } 141 }
128 142
129 @Override 143 @Override
  144 + public ApiUsageState findApiUsageStateByEntityId(EntityId entityId) {
  145 + validateId(entityId.getId(), "Invalid entity id");
  146 + return apiUsageStateDao.findApiUsageStateByEntityId(entityId);
  147 + }
  148 +
  149 + @Override
130 public ApiUsageState findApiUsageStateById(TenantId tenantId, ApiUsageStateId id) { 150 public ApiUsageState findApiUsageStateById(TenantId tenantId, ApiUsageStateId id) {
131 log.trace("Executing findApiUsageStateById, tenantId [{}], apiUsageStateId [{}]", tenantId, id); 151 log.trace("Executing findApiUsageStateById, tenantId [{}], apiUsageStateId [{}]", tenantId, id);
132 validateId(tenantId, INCORRECT_TENANT_ID + tenantId); 152 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
@@ -142,16 +162,14 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A @@ -142,16 +162,14 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
142 throw new DataValidationException("ApiUsageState should be assigned to tenant!"); 162 throw new DataValidationException("ApiUsageState should be assigned to tenant!");
143 } else { 163 } else {
144 Tenant tenant = tenantDao.findById(requestTenantId, apiUsageState.getTenantId().getId()); 164 Tenant tenant = tenantDao.findById(requestTenantId, apiUsageState.getTenantId().getId());
145 - if (tenant == null) {  
146 - throw new DataValidationException("Asset is referencing to non-existent tenant!"); 165 + if (tenant == null && !requestTenantId.equals(TenantId.SYS_TENANT_ID)) {
  166 + throw new DataValidationException("ApiUsageState is referencing to non-existent tenant!");
147 } 167 }
148 } 168 }
149 if (apiUsageState.getEntityId() == null) { 169 if (apiUsageState.getEntityId() == null) {
150 throw new DataValidationException("UsageRecord should be assigned to entity!"); 170 throw new DataValidationException("UsageRecord should be assigned to entity!");
151 - } else if (!EntityType.TENANT.equals(apiUsageState.getEntityId().getEntityType())) {  
152 - throw new DataValidationException("Only Tenant Usage Records are supported!");  
153 - } else if (!apiUsageState.getTenantId().getId().equals(apiUsageState.getEntityId().getId())) {  
154 - throw new DataValidationException("Can't assign one Usage Record to multiple tenants!"); 171 + } else if (apiUsageState.getEntityId().getEntityType() != EntityType.TENANT && apiUsageState.getEntityId().getEntityType() != EntityType.CUSTOMER) {
  172 + throw new DataValidationException("Only Tenant and Customer Usage Records are supported!");
155 } 173 }
156 } 174 }
157 }; 175 };
@@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.ApiFeature; @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.ApiFeature;
20 import org.thingsboard.server.common.data.ApiUsageStateMailMessage; 20 import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
21 import org.thingsboard.server.common.data.ApiUsageStateValue; 21 import org.thingsboard.server.common.data.ApiUsageStateValue;
22 import org.thingsboard.server.common.data.exception.ThingsboardException; 22 import org.thingsboard.server.common.data.exception.ThingsboardException;
  23 +import org.thingsboard.server.common.data.id.CustomerId;
23 import org.thingsboard.server.common.data.id.TenantId; 24 import org.thingsboard.server.common.data.id.TenantId;
24 25
25 import javax.mail.MessagingException; 26 import javax.mail.MessagingException;
@@ -40,7 +41,7 @@ public interface MailService { @@ -40,7 +41,7 @@ public interface MailService {
40 41
41 void sendPasswordWasResetEmail(String loginLink, String email) throws ThingsboardException; 42 void sendPasswordWasResetEmail(String loginLink, String email) throws ThingsboardException;
42 43
43 - void send(TenantId tenantId, String from, String to, String cc, String bcc, String subject, String body) throws MessagingException; 44 + void send(TenantId tenantId, CustomerId customerId, String from, String to, String cc, String bcc, String subject, String body) throws MessagingException;
44 45
45 void sendAccountLockoutEmail( String lockoutEmail, String email, Integer maxFailedLoginAttempts) throws ThingsboardException; 46 void sendAccountLockoutEmail( String lockoutEmail, String email, Integer maxFailedLoginAttempts) throws ThingsboardException;
46 47
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 package org.thingsboard.rule.engine.api; 16 package org.thingsboard.rule.engine.api;
17 17
18 import com.google.common.util.concurrent.FutureCallback; 18 import com.google.common.util.concurrent.FutureCallback;
  19 +import org.thingsboard.server.common.data.id.CustomerId;
19 import org.thingsboard.server.common.data.id.EntityId; 20 import org.thingsboard.server.common.data.id.EntityId;
20 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
21 import org.thingsboard.server.common.data.kv.AttributeKvEntry; 22 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
@@ -31,7 +32,7 @@ public interface RuleEngineTelemetryService { @@ -31,7 +32,7 @@ public interface RuleEngineTelemetryService {
31 32
32 void saveAndNotify(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, FutureCallback<Void> callback); 33 void saveAndNotify(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, FutureCallback<Void> callback);
33 34
34 - void saveAndNotify(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, long ttl, FutureCallback<Void> callback); 35 + void saveAndNotify(TenantId tenantId, CustomerId id, EntityId entityId, List<TsKvEntry> ts, long ttl, FutureCallback<Void> callback);
35 36
36 void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes, FutureCallback<Void> callback); 37 void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes, FutureCallback<Void> callback);
37 38
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.rule.engine.api; 16 package org.thingsboard.rule.engine.api;
17 17
  18 +import org.thingsboard.server.common.data.id.CustomerId;
18 import org.thingsboard.server.common.data.sms.config.TestSmsRequest; 19 import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
19 import org.thingsboard.server.common.data.exception.ThingsboardException; 20 import org.thingsboard.server.common.data.exception.ThingsboardException;
20 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
@@ -23,7 +24,7 @@ public interface SmsService { @@ -23,7 +24,7 @@ public interface SmsService {
23 24
24 void updateSmsConfiguration(); 25 void updateSmsConfiguration();
25 26
26 - void sendSms(TenantId tenantId, String[] numbersTo, String message) throws ThingsboardException;; 27 + void sendSms(TenantId tenantId, CustomerId customerId, String[] numbersTo, String message) throws ThingsboardException;;
27 28
28 void sendTestSms(TestSmsRequest testSmsRequest) throws ThingsboardException; 29 void sendTestSms(TestSmsRequest testSmsRequest) throws ThingsboardException;
29 30
@@ -16,16 +16,15 @@ @@ -16,16 +16,15 @@
16 package org.thingsboard.rule.engine.api; 16 package org.thingsboard.rule.engine.api;
17 17
18 import io.netty.channel.EventLoopGroup; 18 import io.netty.channel.EventLoopGroup;
19 -import org.springframework.data.redis.core.RedisTemplate;  
20 import org.thingsboard.common.util.ListeningExecutor; 19 import org.thingsboard.common.util.ListeningExecutor;
21 import org.thingsboard.rule.engine.api.sms.SmsSenderFactory; 20 import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
22 -import org.thingsboard.server.common.data.ApiUsageRecordKey;  
23 import org.thingsboard.server.common.data.Customer; 21 import org.thingsboard.server.common.data.Customer;
24 import org.thingsboard.server.common.data.Device; 22 import org.thingsboard.server.common.data.Device;
25 import org.thingsboard.server.common.data.DeviceProfile; 23 import org.thingsboard.server.common.data.DeviceProfile;
26 import org.thingsboard.server.common.data.TenantProfile; 24 import org.thingsboard.server.common.data.TenantProfile;
27 import org.thingsboard.server.common.data.alarm.Alarm; 25 import org.thingsboard.server.common.data.alarm.Alarm;
28 import org.thingsboard.server.common.data.asset.Asset; 26 import org.thingsboard.server.common.data.asset.Asset;
  27 +import org.thingsboard.server.common.data.id.CustomerId;
29 import org.thingsboard.server.common.data.id.DeviceId; 28 import org.thingsboard.server.common.data.id.DeviceId;
30 import org.thingsboard.server.common.data.id.EdgeId; 29 import org.thingsboard.server.common.data.id.EdgeId;
31 import org.thingsboard.server.common.data.id.EntityId; 30 import org.thingsboard.server.common.data.id.EntityId;
@@ -144,6 +143,8 @@ public interface TbContext { @@ -144,6 +143,8 @@ public interface TbContext {
144 143
145 TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data); 144 TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data);
146 145
  146 + TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data);
  147 +
147 TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data); 148 TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data);
148 149
149 TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId); 150 TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId);
@@ -136,7 +136,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { @@ -136,7 +136,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
136 } 136 }
137 137
138 private void transformAndTellNext(TbContext ctx, TbMsg msg, EntityView entityView) { 138 private void transformAndTellNext(TbContext ctx, TbMsg msg, EntityView entityView) {
139 - ctx.enqueueForTellNext(ctx.newMsg(msg.getQueueName(), msg.getType(), entityView.getId(), msg.getMetaData(), msg.getData()), SUCCESS); 139 + ctx.enqueueForTellNext(ctx.newMsg(msg.getQueueName(), msg.getType(), entityView.getId(), msg.getCustomerId(), msg.getMetaData(), msg.getData()), SUCCESS);
140 } 140 }
141 141
142 private boolean attributeContainsInEntityView(String scope, String attrKey, EntityView entityView) { 142 private boolean attributeContainsInEntityView(String scope, String attrKey, EntityView entityView) {
@@ -63,7 +63,7 @@ public class TbMsgCountNode implements TbNode { @@ -63,7 +63,7 @@ public class TbMsgCountNode implements TbNode {
63 TbMsgCountNodeConfiguration config = TbNodeUtils.convert(configuration, TbMsgCountNodeConfiguration.class); 63 TbMsgCountNodeConfiguration config = TbNodeUtils.convert(configuration, TbMsgCountNodeConfiguration.class);
64 this.delay = TimeUnit.SECONDS.toMillis(config.getInterval()); 64 this.delay = TimeUnit.SECONDS.toMillis(config.getInterval());
65 this.telemetryPrefix = config.getTelemetryPrefix(); 65 this.telemetryPrefix = config.getTelemetryPrefix();
66 - scheduleTickMsg(ctx); 66 + scheduleTickMsg(ctx, null);
67 67
68 } 68 }
69 69
@@ -78,23 +78,23 @@ public class TbMsgCountNode implements TbNode { @@ -78,23 +78,23 @@ public class TbMsgCountNode implements TbNode {
78 TbMsgMetaData metaData = new TbMsgMetaData(); 78 TbMsgMetaData metaData = new TbMsgMetaData();
79 metaData.putValue("delta", Long.toString(System.currentTimeMillis() - lastScheduledTs + delay)); 79 metaData.putValue("delta", Long.toString(System.currentTimeMillis() - lastScheduledTs + delay));
80 80
81 - TbMsg tbMsg = TbMsg.newMsg(msg.getQueueName(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), ctx.getTenantId(), metaData, gson.toJson(telemetryJson)); 81 + TbMsg tbMsg = TbMsg.newMsg(msg.getQueueName(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), ctx.getTenantId(), msg.getCustomerId(), metaData, gson.toJson(telemetryJson));
82 ctx.enqueueForTellNext(tbMsg, SUCCESS); 82 ctx.enqueueForTellNext(tbMsg, SUCCESS);
83 - scheduleTickMsg(ctx); 83 + scheduleTickMsg(ctx, tbMsg);
84 } else { 84 } else {
85 messagesProcessed.incrementAndGet(); 85 messagesProcessed.incrementAndGet();
86 ctx.ack(msg); 86 ctx.ack(msg);
87 } 87 }
88 } 88 }
89 89
90 - private void scheduleTickMsg(TbContext ctx) { 90 + private void scheduleTickMsg(TbContext ctx, TbMsg msg) {
91 long curTs = System.currentTimeMillis(); 91 long curTs = System.currentTimeMillis();
92 if (lastScheduledTs == 0L) { 92 if (lastScheduledTs == 0L) {
93 lastScheduledTs = curTs; 93 lastScheduledTs = curTs;
94 } 94 }
95 lastScheduledTs = lastScheduledTs + delay; 95 lastScheduledTs = lastScheduledTs + delay;
96 long curDelay = Math.max(0L, (lastScheduledTs - curTs)); 96 long curDelay = Math.max(0L, (lastScheduledTs - curTs));
97 - TbMsg tickMsg = ctx.newMsg(ServiceQueue.MAIN, TB_MSG_COUNT_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), ""); 97 + TbMsg tickMsg = ctx.newMsg(ServiceQueue.MAIN, TB_MSG_COUNT_NODE_MSG, ctx.getSelfId(), msg != null ? msg.getCustomerId() : null, new TbMsgMetaData(), "");
98 nextTickId = tickMsg.getId(); 98 nextTickId = tickMsg.getId();
99 ctx.tellSelf(tickMsg, curDelay); 99 ctx.tellSelf(tickMsg, curDelay);
100 } 100 }
@@ -100,7 +100,7 @@ public class TbMsgGeneratorNode implements TbNode { @@ -100,7 +100,7 @@ public class TbMsgGeneratorNode implements TbNode {
100 @Override 100 @Override
101 public void onMsg(TbContext ctx, TbMsg msg) { 101 public void onMsg(TbContext ctx, TbMsg msg) {
102 if (initialized && msg.getType().equals(TB_MSG_GENERATOR_NODE_MSG) && msg.getId().equals(nextTickId)) { 102 if (initialized && msg.getType().equals(TB_MSG_GENERATOR_NODE_MSG) && msg.getId().equals(nextTickId)) {
103 - withCallback(generate(ctx), 103 + withCallback(generate(ctx, msg),
104 m -> { 104 m -> {
105 if (initialized && (config.getMsgCount() == TbMsgGeneratorNodeConfiguration.UNLIMITED_MSG_COUNT || currentMsgCount < config.getMsgCount())) { 105 if (initialized && (config.getMsgCount() == TbMsgGeneratorNodeConfiguration.UNLIMITED_MSG_COUNT || currentMsgCount < config.getMsgCount())) {
106 ctx.enqueueForTellNext(m, SUCCESS); 106 ctx.enqueueForTellNext(m, SUCCESS);
@@ -130,16 +130,16 @@ public class TbMsgGeneratorNode implements TbNode { @@ -130,16 +130,16 @@ public class TbMsgGeneratorNode implements TbNode {
130 ctx.tellSelf(tickMsg, curDelay); 130 ctx.tellSelf(tickMsg, curDelay);
131 } 131 }
132 132
133 - private ListenableFuture<TbMsg> generate(TbContext ctx) { 133 + private ListenableFuture<TbMsg> generate(TbContext ctx, TbMsg msg) {
134 return ctx.getJsExecutor().executeAsync(() -> { 134 return ctx.getJsExecutor().executeAsync(() -> {
135 if (prevMsg == null) { 135 if (prevMsg == null) {
136 - prevMsg = ctx.newMsg(ServiceQueue.MAIN, "", originatorId, new TbMsgMetaData(), "{}"); 136 + prevMsg = ctx.newMsg(ServiceQueue.MAIN, "", originatorId, msg.getCustomerId(), new TbMsgMetaData(), "{}");
137 } 137 }
138 if (initialized) { 138 if (initialized) {
139 ctx.logJsEvalRequest(); 139 ctx.logJsEvalRequest();
140 TbMsg generated = jsEngine.executeGenerate(prevMsg); 140 TbMsg generated = jsEngine.executeGenerate(prevMsg);
141 ctx.logJsEvalResponse(); 141 ctx.logJsEvalResponse();
142 - prevMsg = ctx.newMsg(ServiceQueue.MAIN, generated.getType(), originatorId, generated.getMetaData(), generated.getData()); 142 + prevMsg = ctx.newMsg(ServiceQueue.MAIN, generated.getType(), originatorId, msg.getCustomerId(), generated.getMetaData(), generated.getData());
143 } 143 }
144 return prevMsg; 144 return prevMsg;
145 }); 145 });
@@ -70,7 +70,7 @@ public class TbMsgDelayNode implements TbNode { @@ -70,7 +70,7 @@ public class TbMsgDelayNode implements TbNode {
70 } else { 70 } else {
71 if (pendingMsgs.size() < config.getMaxPendingMsgs()) { 71 if (pendingMsgs.size() < config.getMaxPendingMsgs()) {
72 pendingMsgs.put(msg.getId(), msg); 72 pendingMsgs.put(msg.getId(), msg);
73 - TbMsg tickMsg = ctx.newMsg(ServiceQueue.MAIN, TB_MSG_DELAY_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), msg.getId().toString()); 73 + TbMsg tickMsg = ctx.newMsg(ServiceQueue.MAIN, TB_MSG_DELAY_NODE_MSG, ctx.getSelfId(), msg.getCustomerId(), new TbMsgMetaData(), msg.getId().toString());
74 ctx.tellSelf(tickMsg, getDelay(msg)); 74 ctx.tellSelf(tickMsg, getDelay(msg));
75 ctx.ack(msg); 75 ctx.ack(msg);
76 } else { 76 } else {
@@ -26,7 +26,6 @@ import org.thingsboard.rule.engine.api.TbNode; @@ -26,7 +26,6 @@ import org.thingsboard.rule.engine.api.TbNode;
26 import org.thingsboard.rule.engine.api.TbNodeConfiguration; 26 import org.thingsboard.rule.engine.api.TbNodeConfiguration;
27 import org.thingsboard.rule.engine.api.TbNodeException; 27 import org.thingsboard.rule.engine.api.TbNodeException;
28 import org.thingsboard.rule.engine.api.util.TbNodeUtils; 28 import org.thingsboard.rule.engine.api.util.TbNodeUtils;
29 -import org.thingsboard.server.common.data.ApiUsageRecordKey;  
30 import org.thingsboard.server.common.data.plugin.ComponentType; 29 import org.thingsboard.server.common.data.plugin.ComponentType;
31 import org.thingsboard.server.common.msg.TbMsg; 30 import org.thingsboard.server.common.msg.TbMsg;
32 31
@@ -76,7 +75,7 @@ public class TbSendEmailNode implements TbNode { @@ -76,7 +75,7 @@ public class TbSendEmailNode implements TbNode {
76 validateType(msg.getType()); 75 validateType(msg.getType());
77 EmailPojo email = getEmail(msg); 76 EmailPojo email = getEmail(msg);
78 withCallback(ctx.getMailExecutor().executeAsync(() -> { 77 withCallback(ctx.getMailExecutor().executeAsync(() -> {
79 - sendEmail(ctx, email); 78 + sendEmail(ctx, msg, email);
80 return null; 79 return null;
81 }), 80 }),
82 ok -> ctx.tellSuccess(msg), 81 ok -> ctx.tellSuccess(msg),
@@ -86,9 +85,9 @@ public class TbSendEmailNode implements TbNode { @@ -86,9 +85,9 @@ public class TbSendEmailNode implements TbNode {
86 } 85 }
87 } 86 }
88 87
89 - private void sendEmail(TbContext ctx, EmailPojo email) throws Exception { 88 + private void sendEmail(TbContext ctx, TbMsg msg, EmailPojo email) throws Exception {
90 if (this.config.isUseSystemSmtpSettings()) { 89 if (this.config.isUseSystemSmtpSettings()) {
91 - ctx.getMailService().send(ctx.getTenantId(), email.getFrom(), email.getTo(), email.getCc(), 90 + ctx.getMailService().send(ctx.getTenantId(), msg.getCustomerId(), email.getFrom(), email.getTo(), email.getCc(),
92 email.getBcc(), email.getSubject(), email.getBody()); 91 email.getBcc(), email.getSubject(), email.getBody());
93 } else { 92 } else {
94 MimeMessage mailMsg = mailSender.createMimeMessage(); 93 MimeMessage mailMsg = mailSender.createMimeMessage();
@@ -74,15 +74,15 @@ class AlarmState { @@ -74,15 +74,15 @@ class AlarmState {
74 lastMsgMetaData = msg.getMetaData(); 74 lastMsgMetaData = msg.getMetaData();
75 lastMsgQueueName = msg.getQueueName(); 75 lastMsgQueueName = msg.getQueueName();
76 this.dataSnapshot = data; 76 this.dataSnapshot = data;
77 - return createOrClearAlarms(ctx, data, update, AlarmRuleState::eval); 77 + return createOrClearAlarms(ctx, msg, data, update, AlarmRuleState::eval);
78 } 78 }
79 79
80 public boolean process(TbContext ctx, long ts) throws ExecutionException, InterruptedException { 80 public boolean process(TbContext ctx, long ts) throws ExecutionException, InterruptedException {
81 initCurrentAlarm(ctx); 81 initCurrentAlarm(ctx);
82 - return createOrClearAlarms(ctx, ts, null, AlarmRuleState::eval); 82 + return createOrClearAlarms(ctx, null, ts, null, AlarmRuleState::eval);
83 } 83 }
84 84
85 - public <T> boolean createOrClearAlarms(TbContext ctx, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, AlarmEvalResult> evalFunction) { 85 + public <T> boolean createOrClearAlarms(TbContext ctx, TbMsg msg, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, AlarmEvalResult> evalFunction) {
86 boolean stateUpdate = false; 86 boolean stateUpdate = false;
87 AlarmRuleState resultState = null; 87 AlarmRuleState resultState = null;
88 log.debug("[{}] processing update: {}", alarmDefinition.getId(), data); 88 log.debug("[{}] processing update: {}", alarmDefinition.getId(), data);
@@ -103,7 +103,7 @@ class AlarmState { @@ -103,7 +103,7 @@ class AlarmState {
103 if (resultState != null) { 103 if (resultState != null) {
104 TbAlarmResult result = calculateAlarmResult(ctx, resultState); 104 TbAlarmResult result = calculateAlarmResult(ctx, resultState);
105 if (result != null) { 105 if (result != null) {
106 - pushMsg(ctx, result, resultState); 106 + pushMsg(ctx, msg, result, resultState);
107 } 107 }
108 stateUpdate = clearAlarmState(stateUpdate, clearState); 108 stateUpdate = clearAlarmState(stateUpdate, clearState);
109 } else if (currentAlarm != null && clearState != null) { 109 } else if (currentAlarm != null && clearState != null) {
@@ -122,7 +122,7 @@ class AlarmState { @@ -122,7 +122,7 @@ class AlarmState {
122 ); 122 );
123 DonAsynchron.withCallback(alarmClearOperationResult, 123 DonAsynchron.withCallback(alarmClearOperationResult,
124 result -> { 124 result -> {
125 - pushMsg(ctx, new TbAlarmResult(false, false, true, result.getAlarm()), clearState); 125 + pushMsg(ctx, msg, new TbAlarmResult(false, false, true, result.getAlarm()), clearState);
126 }, 126 },
127 throwable -> { 127 throwable -> {
128 throw new RuntimeException(throwable); 128 throw new RuntimeException(throwable);
@@ -165,7 +165,7 @@ class AlarmState { @@ -165,7 +165,7 @@ class AlarmState {
165 } 165 }
166 } 166 }
167 167
168 - public void pushMsg(TbContext ctx, TbAlarmResult alarmResult, AlarmRuleState ruleState) { 168 + public void pushMsg(TbContext ctx, TbMsg msg, TbAlarmResult alarmResult, AlarmRuleState ruleState) {
169 JsonNode jsonNodes = JacksonUtil.valueToTree(alarmResult.getAlarm()); 169 JsonNode jsonNodes = JacksonUtil.valueToTree(alarmResult.getAlarm());
170 String data = jsonNodes.toString(); 170 String data = jsonNodes.toString();
171 TbMsgMetaData metaData = lastMsgMetaData != null ? lastMsgMetaData.copy() : new TbMsgMetaData(); 171 TbMsgMetaData metaData = lastMsgMetaData != null ? lastMsgMetaData.copy() : new TbMsgMetaData();
@@ -185,7 +185,8 @@ class AlarmState { @@ -185,7 +185,8 @@ class AlarmState {
185 metaData.putValue(DataConstants.IS_CLEARED_ALARM, Boolean.TRUE.toString()); 185 metaData.putValue(DataConstants.IS_CLEARED_ALARM, Boolean.TRUE.toString());
186 } 186 }
187 setAlarmConditionMetadata(ruleState, metaData); 187 setAlarmConditionMetadata(ruleState, metaData);
188 - TbMsg newMsg = ctx.newMsg(lastMsgQueueName != null ? lastMsgQueueName : ServiceQueue.MAIN, "ALARM", originator, metaData, data); 188 + TbMsg newMsg = ctx.newMsg(lastMsgQueueName != null ? lastMsgQueueName : ServiceQueue.MAIN, "ALARM",
  189 + originator, msg != null ? msg.getCustomerId() : null, metaData, data);
189 ctx.tellNext(newMsg, relationType); 190 ctx.tellNext(newMsg, relationType);
190 } 191 }
191 192
@@ -74,7 +74,7 @@ public class TbDeviceProfileNode implements TbNode { @@ -74,7 +74,7 @@ public class TbDeviceProfileNode implements TbNode {
74 this.config = TbNodeUtils.convert(configuration, TbDeviceProfileNodeConfiguration.class); 74 this.config = TbNodeUtils.convert(configuration, TbDeviceProfileNodeConfiguration.class);
75 this.cache = ctx.getDeviceProfileCache(); 75 this.cache = ctx.getDeviceProfileCache();
76 this.ctx = ctx; 76 this.ctx = ctx;
77 - scheduleAlarmHarvesting(ctx); 77 + scheduleAlarmHarvesting(ctx, null);
78 ctx.addDeviceProfileListeners(this::onProfileUpdate, this::onDeviceUpdate); 78 ctx.addDeviceProfileListeners(this::onProfileUpdate, this::onDeviceUpdate);
79 if (config.isFetchAlarmRulesStateOnStart()) { 79 if (config.isFetchAlarmRulesStateOnStart()) {
80 log.info("[{}] Fetching alarm rule state", ctx.getSelfId()); 80 log.info("[{}] Fetching alarm rule state", ctx.getSelfId());
@@ -108,7 +108,7 @@ public class TbDeviceProfileNode implements TbNode { @@ -108,7 +108,7 @@ public class TbDeviceProfileNode implements TbNode {
108 public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { 108 public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException {
109 EntityType originatorType = msg.getOriginator().getEntityType(); 109 EntityType originatorType = msg.getOriginator().getEntityType();
110 if (msg.getType().equals(PERIODIC_MSG_TYPE)) { 110 if (msg.getType().equals(PERIODIC_MSG_TYPE)) {
111 - scheduleAlarmHarvesting(ctx); 111 + scheduleAlarmHarvesting(ctx, msg);
112 harvestAlarms(ctx, System.currentTimeMillis()); 112 harvestAlarms(ctx, System.currentTimeMillis());
113 } else if (msg.getType().equals(PROFILE_UPDATE_MSG_TYPE)) { 113 } else if (msg.getType().equals(PROFILE_UPDATE_MSG_TYPE)) {
114 updateProfile(ctx, new DeviceProfileId(UUID.fromString(msg.getData()))); 114 updateProfile(ctx, new DeviceProfileId(UUID.fromString(msg.getData())));
@@ -168,8 +168,8 @@ public class TbDeviceProfileNode implements TbNode { @@ -168,8 +168,8 @@ public class TbDeviceProfileNode implements TbNode {
168 return deviceState; 168 return deviceState;
169 } 169 }
170 170
171 - protected void scheduleAlarmHarvesting(TbContext ctx) {  
172 - TbMsg periodicCheck = TbMsg.newMsg(PERIODIC_MSG_TYPE, ctx.getTenantId(), TbMsgMetaData.EMPTY, "{}"); 171 + protected void scheduleAlarmHarvesting(TbContext ctx, TbMsg msg) {
  172 + TbMsg periodicCheck = TbMsg.newMsg(PERIODIC_MSG_TYPE, ctx.getTenantId(), msg != null ? msg.getCustomerId() : null, TbMsgMetaData.EMPTY, "{}");
173 ctx.tellSelf(periodicCheck, TimeUnit.MINUTES.toMillis(1)); 173 ctx.tellSelf(periodicCheck, TimeUnit.MINUTES.toMillis(1));
174 } 174 }
175 175
@@ -16,10 +16,6 @@ @@ -16,10 +16,6 @@
16 package org.thingsboard.rule.engine.rpc; 16 package org.thingsboard.rule.engine.rpc;
17 17
18 import com.datastax.oss.driver.api.core.uuid.Uuids; 18 import com.datastax.oss.driver.api.core.uuid.Uuids;
19 -import com.fasterxml.jackson.databind.ObjectMapper;  
20 -import com.google.common.util.concurrent.FutureCallback;  
21 -import com.google.common.util.concurrent.Futures;  
22 -import com.google.common.util.concurrent.ListenableFuture;  
23 import com.google.gson.Gson; 19 import com.google.gson.Gson;
24 import com.google.gson.JsonElement; 20 import com.google.gson.JsonElement;
25 import com.google.gson.JsonObject; 21 import com.google.gson.JsonObject;
@@ -116,10 +112,10 @@ public class TbSendRPCRequestNode implements TbNode { @@ -116,10 +112,10 @@ public class TbSendRPCRequestNode implements TbNode {
116 112
117 ctx.getRpcService().sendRpcRequestToDevice(request, ruleEngineDeviceRpcResponse -> { 113 ctx.getRpcService().sendRpcRequestToDevice(request, ruleEngineDeviceRpcResponse -> {
118 if (!ruleEngineDeviceRpcResponse.getError().isPresent()) { 114 if (!ruleEngineDeviceRpcResponse.getError().isPresent()) {
119 - TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().orElse("{}")); 115 + TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().orElse("{}"));
120 ctx.enqueueForTellNext(next, TbRelationTypes.SUCCESS); 116 ctx.enqueueForTellNext(next, TbRelationTypes.SUCCESS);
121 } else { 117 } else {
122 - TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name())); 118 + TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name()));
123 ctx.tellFailure(next, new RuntimeException(ruleEngineDeviceRpcResponse.getError().get().name())); 119 ctx.tellFailure(next, new RuntimeException(ruleEngineDeviceRpcResponse.getError().get().name()));
124 } 120 }
125 }); 121 });
@@ -76,7 +76,7 @@ public class TbSendSmsNode implements TbNode { @@ -76,7 +76,7 @@ public class TbSendSmsNode implements TbNode {
76 String message = TbNodeUtils.processPattern(this.config.getSmsMessageTemplate(), msg); 76 String message = TbNodeUtils.processPattern(this.config.getSmsMessageTemplate(), msg);
77 String[] numbersToList = numbersTo.split(","); 77 String[] numbersToList = numbersTo.split(",");
78 if (this.config.isUseSystemSmsSettings()) { 78 if (this.config.isUseSystemSmsSettings()) {
79 - ctx.getSmsService().sendSms(ctx.getTenantId(), numbersToList, message); 79 + ctx.getSmsService().sendSms(ctx.getTenantId(), msg.getCustomerId(), numbersToList, message);
80 } else { 80 } else {
81 for (String numberTo : numbersToList) { 81 for (String numberTo : numbersToList) {
82 this.smsSender.sendSms(numberTo, message); 82 this.smsSender.sendSms(numberTo, message);
@@ -25,6 +25,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; @@ -25,6 +25,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
25 import org.thingsboard.rule.engine.api.TbNodeException; 25 import org.thingsboard.rule.engine.api.TbNodeException;
26 import org.thingsboard.server.common.data.TenantProfile; 26 import org.thingsboard.server.common.data.TenantProfile;
27 import org.thingsboard.rule.engine.api.util.TbNodeUtils; 27 import org.thingsboard.rule.engine.api.util.TbNodeUtils;
  28 +import org.thingsboard.server.common.data.id.CustomerId;
28 import org.thingsboard.server.common.data.kv.BasicTsKvEntry; 29 import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
29 import org.thingsboard.server.common.data.kv.KvEntry; 30 import org.thingsboard.server.common.data.kv.KvEntry;
30 import org.thingsboard.server.common.data.kv.TsKvEntry; 31 import org.thingsboard.server.common.data.kv.TsKvEntry;
@@ -93,7 +94,7 @@ public class TbMsgTimeseriesNode implements TbNode { @@ -93,7 +94,7 @@ public class TbMsgTimeseriesNode implements TbNode {
93 if (ttl == 0L) { 94 if (ttl == 0L) {
94 ttl = tenantProfileDefaultStorageTtl; 95 ttl = tenantProfileDefaultStorageTtl;
95 } 96 }
96 - ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), msg.getOriginator(), tsKvEntryList, ttl, new TelemetryNodeCallback(ctx, msg)); 97 + ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), msg.getCustomerId(), msg.getOriginator(), tsKvEntryList, ttl, new TelemetryNodeCallback(ctx, msg));
97 } 98 }
98 99
99 public static long getTs(TbMsg msg) { 100 public static long getTs(TbMsg msg) {
@@ -183,7 +183,7 @@ public class TbDeviceProfileNodeTest { @@ -183,7 +183,7 @@ public class TbDeviceProfileNodeTest {
183 Mockito.when(alarmService.createOrUpdateAlarm(Mockito.any())).thenAnswer(AdditionalAnswers.returnsFirstArg()); 183 Mockito.when(alarmService.createOrUpdateAlarm(Mockito.any())).thenAnswer(AdditionalAnswers.returnsFirstArg());
184 184
185 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); 185 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "");
186 - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyString())).thenReturn(theMsg); 186 + Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())).thenReturn(theMsg);
187 187
188 ObjectNode data = mapper.createObjectNode(); 188 ObjectNode data = mapper.createObjectNode();
189 data.put("temperature", 42); 189 data.put("temperature", 42);
@@ -195,7 +195,7 @@ public class TbDeviceProfileNodeTest { @@ -195,7 +195,7 @@ public class TbDeviceProfileNodeTest {
195 verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); 195 verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any());
196 196
197 TbMsg theMsg2 = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "2"); 197 TbMsg theMsg2 = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "2");
198 - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyString())).thenReturn(theMsg2); 198 + Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())).thenReturn(theMsg2);
199 199
200 200
201 TbMsg msg2 = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), 201 TbMsg msg2 = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(),
@@ -274,7 +274,7 @@ public class TbDeviceProfileNodeTest { @@ -274,7 +274,7 @@ public class TbDeviceProfileNodeTest {
274 .thenReturn(attrListListenableFuture); 274 .thenReturn(attrListListenableFuture);
275 275
276 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); 276 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "");
277 - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyString())) 277 + Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString()))
278 .thenReturn(theMsg); 278 .thenReturn(theMsg);
279 279
280 ObjectNode data = mapper.createObjectNode(); 280 ObjectNode data = mapper.createObjectNode();
@@ -361,7 +361,7 @@ public class TbDeviceProfileNodeTest { @@ -361,7 +361,7 @@ public class TbDeviceProfileNodeTest {
361 .thenReturn(attrListListenableFuture); 361 .thenReturn(attrListListenableFuture);
362 362
363 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); 363 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "");
364 - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyString())) 364 + Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString()))
365 .thenReturn(theMsg); 365 .thenReturn(theMsg);
366 366
367 ObjectNode data = mapper.createObjectNode(); 367 ObjectNode data = mapper.createObjectNode();
@@ -430,7 +430,7 @@ public class TbDeviceProfileNodeTest { @@ -430,7 +430,7 @@ public class TbDeviceProfileNodeTest {
430 .thenReturn(listListenableFutureWithLess); 430 .thenReturn(listListenableFutureWithLess);
431 431
432 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); 432 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "");
433 - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyString())) 433 + Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString()))
434 .thenReturn(theMsg); 434 .thenReturn(theMsg);
435 435
436 ObjectNode data = mapper.createObjectNode(); 436 ObjectNode data = mapper.createObjectNode();
@@ -510,7 +510,7 @@ public class TbDeviceProfileNodeTest { @@ -510,7 +510,7 @@ public class TbDeviceProfileNodeTest {
510 .thenReturn(optionalListenableFutureWithLess); 510 .thenReturn(optionalListenableFutureWithLess);
511 511
512 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); 512 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "");
513 - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyString())) 513 + Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString()))
514 .thenReturn(theMsg); 514 .thenReturn(theMsg);
515 515
516 ObjectNode data = mapper.createObjectNode(); 516 ObjectNode data = mapper.createObjectNode();
@@ -584,7 +584,7 @@ public class TbDeviceProfileNodeTest { @@ -584,7 +584,7 @@ public class TbDeviceProfileNodeTest {
584 .thenReturn(optionalListenableFutureWithLess); 584 .thenReturn(optionalListenableFutureWithLess);
585 585
586 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); 586 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "");
587 - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyString())) 587 + Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString()))
588 .thenReturn(theMsg); 588 .thenReturn(theMsg);
589 589
590 ObjectNode data = mapper.createObjectNode(); 590 ObjectNode data = mapper.createObjectNode();
@@ -668,7 +668,7 @@ public class TbDeviceProfileNodeTest { @@ -668,7 +668,7 @@ public class TbDeviceProfileNodeTest {
668 .thenReturn(optionalListenableFutureWithLess); 668 .thenReturn(optionalListenableFutureWithLess);
669 669
670 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); 670 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "");
671 - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyString())) 671 + Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString()))
672 .thenReturn(theMsg); 672 .thenReturn(theMsg);
673 673
674 ObjectNode data = mapper.createObjectNode(); 674 ObjectNode data = mapper.createObjectNode();
@@ -754,7 +754,7 @@ public class TbDeviceProfileNodeTest { @@ -754,7 +754,7 @@ public class TbDeviceProfileNodeTest {
754 .thenReturn(optionalListenableFutureWithLess); 754 .thenReturn(optionalListenableFutureWithLess);
755 755
756 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); 756 TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "");
757 - Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyString())) 757 + Mockito.when(ctx.newMsg(Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString()))
758 .thenReturn(theMsg); 758 .thenReturn(theMsg);
759 759
760 ObjectNode data = mapper.createObjectNode(); 760 ObjectNode data = mapper.createObjectNode();