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 41 import org.thingsboard.server.common.data.TenantProfile;
42 42 import org.thingsboard.server.common.data.alarm.Alarm;
43 43 import org.thingsboard.server.common.data.asset.Asset;
  44 +import org.thingsboard.server.common.data.id.CustomerId;
44 45 import org.thingsboard.server.common.data.id.DeviceId;
45 46 import org.thingsboard.server.common.data.id.EdgeId;
46 47 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -269,7 +270,12 @@ class DefaultTbContext implements TbContext {
269 270
270 271 @Override
271 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 281 @Override
... ...
... ... @@ -106,7 +106,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
106 106 int ruleNodeCount = tbMsg.getAndIncrementRuleNodeCounter();
107 107 int maxRuleNodeExecutionsPerMessage = getTenantProfileConfiguration().getMaxRuleNodeExecsPerMessage();
108 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 110 if (ruleNode.isDebugMode()) {
111 111 systemContext.persistDebugInput(tenantId, entityId, msg.getMsg(), "Self");
112 112 }
... ... @@ -127,7 +127,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
127 127 int ruleNodeCount = tbMsg.getAndIncrementRuleNodeCounter();
128 128 int maxRuleNodeExecutionsPerMessage = getTenantProfileConfiguration().getMaxRuleNodeExecsPerMessage();
129 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 131 if (ruleNode.isDebugMode()) {
132 132 systemContext.persistDebugInput(tenantId, entityId, msg.getMsg(), msg.getFromRelationType());
133 133 }
... ...
... ... @@ -958,7 +958,7 @@ public abstract class BaseController {
958 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 962 TenantId tenantId = user.getTenantId();
963 963 if (tenantId.isNullUid()) {
964 964 if (entity instanceof HasTenantId) {
... ...
... ... @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.id.EdgeId;
38 38 import org.thingsboard.server.common.data.id.TenantId;
39 39 import org.thingsboard.server.common.data.page.PageData;
40 40 import org.thingsboard.server.common.data.page.PageLink;
  41 +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
41 42 import org.thingsboard.server.queue.util.TbCoreComponent;
42 43 import org.thingsboard.server.service.security.permission.Operation;
43 44 import org.thingsboard.server.service.security.permission.Resource;
... ... @@ -148,6 +149,7 @@ public class CustomerController extends BaseController {
148 149 ActionType.DELETED, null, strCustomerId);
149 150
150 151 sendDeleteNotificationMsg(getTenantId(), customerId, relatedEdgeIds);
  152 + tbClusterService.onEntityStateChange(getTenantId(), customerId, ComponentLifecycleEvent.DELETED);
151 153 } catch (Exception e) {
152 154
153 155 logEntityAction(emptyId(EntityType.CUSTOMER),
... ...
... ... @@ -658,7 +658,7 @@ public class DeviceController extends BaseController {
658 658 private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
659 659 String data = entityToStr(assignedDevice);
660 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 662 tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null);
663 663 }
664 664 }
... ...
... ... @@ -119,7 +119,7 @@ public class RpcController extends BaseController {
119 119 expTime,
120 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 125 @Override
... ...
... ... @@ -48,6 +48,7 @@ import org.thingsboard.server.common.data.EntityType;
48 48 import org.thingsboard.server.common.data.TenantProfile;
49 49 import org.thingsboard.server.common.data.audit.ActionType;
50 50 import org.thingsboard.server.common.data.exception.ThingsboardException;
  51 +import org.thingsboard.server.common.data.id.CustomerId;
51 52 import org.thingsboard.server.common.data.id.DeviceId;
52 53 import org.thingsboard.server.common.data.id.EntityId;
53 54 import org.thingsboard.server.common.data.id.EntityIdFactory;
... ... @@ -449,7 +450,7 @@ public class TelemetryController extends BaseController {
449 450 TenantProfile tenantProfile = tenantProfileCache.get(tenantId);
450 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 454 @Override
454 455 public void onSuccess(@Nullable Void tmp) {
455 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 29 import org.thingsboard.server.common.data.ApiUsageState;
30 30 import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
31 31 import org.thingsboard.server.common.data.ApiUsageStateValue;
  32 +import org.thingsboard.server.common.data.EntityType;
32 33 import org.thingsboard.server.common.data.Tenant;
33 34 import org.thingsboard.server.common.data.TenantProfile;
34 35 import org.thingsboard.server.common.data.exception.ThingsboardException;
35 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 39 import org.thingsboard.server.common.data.id.TenantId;
37 40 import org.thingsboard.server.common.data.id.TenantProfileId;
38 41 import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
... ... @@ -45,6 +48,7 @@ import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
45 48 import org.thingsboard.server.common.msg.queue.ServiceType;
46 49 import org.thingsboard.server.common.msg.queue.TbCallback;
47 50 import org.thingsboard.server.common.msg.tools.SchedulerUtils;
  51 +import org.thingsboard.server.dao.customer.CustomerService;
48 52 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
49 53 import org.thingsboard.server.dao.tenant.TenantService;
50 54 import org.thingsboard.server.dao.timeseries.TimeseriesService;
... ... @@ -63,6 +67,7 @@ import javax.annotation.PostConstruct;
63 67 import javax.annotation.PreDestroy;
64 68 import java.util.ArrayList;
65 69 import java.util.Arrays;
  70 +import java.util.Collections;
66 71 import java.util.HashSet;
67 72 import java.util.List;
68 73 import java.util.Map;
... ... @@ -95,6 +100,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
95 100 private final TbClusterService clusterService;
96 101 private final PartitionService partitionService;
97 102 private final TenantService tenantService;
  103 + private final CustomerService customerService;
98 104 private final TimeseriesService tsService;
99 105 private final ApiUsageStateService apiUsageStateService;
100 106 private final SchedulerComponent scheduler;
... ... @@ -105,10 +111,12 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
105 111 @Autowired
106 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 121 @Value("${usage.stats.report.enabled:true}")
114 122 private boolean enabled;
... ... @@ -123,13 +131,16 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
123 131 public DefaultTbApiUsageStateService(TbClusterService clusterService,
124 132 PartitionService partitionService,
125 133 TenantService tenantService,
  134 + CustomerService customerService,
126 135 TimeseriesService tsService,
127 136 ApiUsageStateService apiUsageStateService,
128 137 SchedulerComponent scheduler,
129   - TbTenantProfileCache tenantProfileCache, MailService mailService) {
  138 + TbTenantProfileCache tenantProfileCache,
  139 + MailService mailService) {
130 140 this.clusterService = clusterService;
131 141 this.partitionService = partitionService;
132 142 this.tenantService = tenantService;
  143 + this.customerService = customerService;
133 144 this.tsService = tsService;
134 145 this.apiUsageStateService = apiUsageStateService;
135 146 this.scheduler = scheduler;
... ... @@ -150,74 +161,92 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
150 161 @Override
151 162 public void process(TbProtoQueueMsg<ToUsageStatsServiceMsg> msg, TbCallback callback) {
152 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 181 List<TsKvEntry> updatedEntries;
161 182 Map<ApiFeature, ApiUsageStateValue> result;
  183 +
162 184 updateLock.lock();
163 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 189 long newHourTs = SchedulerUtils.getStartOfCurrentHour();
168 190 if (newHourTs != hourTs) {
169   - tenantState.setHour(newHourTs);
  191 + usageState.setHour(newHourTs);
170 192 }
171 193 updatedEntries = new ArrayList<>(ApiUsageRecordKey.values().length);
172 194 Set<ApiFeature> apiFeatures = new HashSet<>();
173   - for (UsageStatsKVProto kvProto : statsMsg.getValuesList()) {
  195 + for (UsageStatsKVProto kvProto : values) {
174 196 ApiUsageRecordKey recordKey = ApiUsageRecordKey.valueOf(kvProto.getKey());
175   - long newValue = tenantState.add(recordKey, kvProto.getValue());
  197 + long newValue = usageState.add(recordKey, kvProto.getValue());
176 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 200 updatedEntries.add(new BasicTsKvEntry(newHourTs, new LongDataEntry(recordKey.getApiCountKey() + HOURLY, newHourlyValue)));
179 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 208 } finally {
183 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 212 if (!result.isEmpty()) {
187   - persistAndNotify(tenantState, result);
  213 + persistAndNotify(usageState, result);
188 214 }
189   - callback.onSuccess();
190 215 }
191 216
192 217 @Override
193 218 protected void onTbApplicationEvent(PartitionChangeEvent partitionChangeEvent) {
194 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 226 initStatesFromDataBase();
198 227 }
199 228 }
200 229
201 230 @Override
202 231 public ApiUsageState getApiUsageState(TenantId tenantId) {
203   - TenantApiUsageState tenantState = myTenantStates.get(tenantId);
  232 + TenantApiUsageState tenantState = (TenantApiUsageState) myUsageStates.get(tenantId);
204 233 if (tenantState != null) {
205 234 return tenantState.getApiUsageState();
206 235 } else {
207   - ApiUsageState state = otherTenantStates.get(tenantId);
  236 + ApiUsageState state = otherUsageStates.get(tenantId);
208 237 if (state != null) {
209 238 return state;
210 239 } else {
211 240 if (partitionService.resolve(ServiceType.TB_CORE, tenantId, tenantId).isMyPartition()) {
212   - return getOrFetchState(tenantId).getApiUsageState();
  241 + return getOrFetchState(tenantId, tenantId).getApiUsageState();
213 242 } else {
214 243 updateLock.lock();
215 244 try {
216   - state = otherTenantStates.get(tenantId);
  245 + state = otherUsageStates.get(tenantId);
217 246 if (state == null) {
218 247 state = apiUsageStateService.findTenantApiUsageState(tenantId);
219 248 if (state != null) {
220   - otherTenantStates.put(tenantId, state);
  249 + otherUsageStates.put(tenantId, state);
221 250 }
222 251 }
223 252 } finally {
... ... @@ -231,7 +260,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
231 260
232 261 @Override
233 262 public void onApiUsageStateUpdate(TenantId tenantId) {
234   - otherTenantStates.remove(tenantId);
  263 + otherUsageStates.remove(tenantId);
235 264 }
236 265
237 266 @Override
... ... @@ -240,11 +269,14 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
240 269 TenantProfile tenantProfile = tenantProfileCache.get(tenantProfileId);
241 270 updateLock.lock();
242 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 280 } finally {
249 281 updateLock.unlock();
250 282 }
... ... @@ -256,7 +288,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
256 288 TenantProfile tenantProfile = tenantProfileCache.get(tenantId);
257 289 updateLock.lock();
258 290 try {
259   - TenantApiUsageState state = myTenantStates.get(tenantId);
  291 + TenantApiUsageState state = (TenantApiUsageState) myUsageStates.get(tenantId);
260 292 if (state != null && !state.getTenantProfileId().equals(tenantProfile.getId())) {
261 293 updateTenantState(state, tenantProfile);
262 294 }
... ... @@ -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 342 apiUsageStateService.update(state.getApiUsageState());
299 343 clusterService.onApiStateChange(state.getApiUsageState(), null);
300 344 long ts = System.currentTimeMillis();
301 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 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 395 updateLock.lock();
351 396 try {
352 397 long now = System.currentTimeMillis();
353   - myTenantStates.values().forEach(state -> {
  398 + myUsageStates.values().forEach(state -> {
354 399 if ((state.getNextCycleTs() < now) && (now - state.getNextCycleTs() < TimeUnit.HOURS.toMillis(1))) {
355   - TenantId tenantId = state.getTenantId();
356 400 state.setCycles(state.getNextCycleTs(), SchedulerUtils.getStartOfNextNextMonth());
357 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 408 } finally {
... ... @@ -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 414 List<TsKvEntry> counts = keys.stream()
368 415 .map(key -> new BasicTsKvEntry(state.getCurrentCycleTs(), new LongDataEntry(key.getApiCountKey(), 0L)))
369 416 .collect(Collectors.toList());
... ... @@ -371,52 +418,66 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
371 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 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 483 private void initStatesFromDataBase() {
... ... @@ -429,11 +490,11 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa
429 490 PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, 1024);
430 491 List<Future<?>> futures = new ArrayList<>();
431 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 494 log.debug("[{}] Initializing tenant state.", tenant.getId());
434 495 futures.add(tmpInitExecutor.submit(() -> {
435 496 try {
436   - updateTenantState(getOrFetchState(tenant.getId()), tenantProfileCache.get(tenant.getTenantProfileId()));
  497 + updateTenantState((TenantApiUsageState) getOrFetchState(tenant.getId(), tenant.getId()), tenantProfileCache.get(tenant.getTenantProfileId()));
437 498 log.debug("[{}] Initialized tenant state.", tenant.getId());
438 499 } catch (Exception e) {
439 500 log.warn("[{}] Failed to initialize tenant API state", tenant.getId(), e);
... ...
... ... @@ -17,6 +17,7 @@ package org.thingsboard.server.service.apiusage;
17 17
18 18 import org.springframework.context.ApplicationListener;
19 19 import org.thingsboard.server.common.data.ApiUsageState;
  20 +import org.thingsboard.server.common.data.id.CustomerId;
20 21 import org.thingsboard.server.common.data.id.TenantId;
21 22 import org.thingsboard.server.common.data.id.TenantProfileId;
22 23 import org.thingsboard.server.common.msg.queue.TbCallback;
... ... @@ -34,5 +35,9 @@ public interface TbApiUsageStateService extends ApplicationListener<PartitionCha
34 35
35 36 void onTenantUpdate(TenantId tenantId);
36 37
  38 + void onTenantDelete(TenantId tenantId);
  39 +
  40 + void onCustomerDelete(CustomerId customerId);
  41 +
37 42 void onApiUsageStateUpdate(TenantId tenantId);
38 43 }
... ...
... ... @@ -22,85 +22,33 @@ import org.thingsboard.server.common.data.ApiFeature;
22 22 import org.thingsboard.server.common.data.ApiUsageRecordKey;
23 23 import org.thingsboard.server.common.data.ApiUsageState;
24 24 import org.thingsboard.server.common.data.ApiUsageStateValue;
  25 +import org.thingsboard.server.common.data.EntityType;
25 26 import org.thingsboard.server.common.data.TenantProfile;
26   -import org.thingsboard.server.common.data.id.TenantId;
27 27 import org.thingsboard.server.common.data.id.TenantProfileId;
28 28 import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
29   -import org.thingsboard.server.common.msg.tools.SchedulerUtils;
30 29
31 30 import java.util.Arrays;
32 31 import java.util.HashMap;
33 32 import java.util.HashSet;
34 33 import java.util.Map;
35 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 37 @Getter
44 38 @Setter
45 39 private TenantProfileId tenantProfileId;
46 40 @Getter
47 41 @Setter
48 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 44 public TenantApiUsageState(TenantProfile tenantProfile, ApiUsageState apiUsageState) {
  45 + super(apiUsageState);
59 46 this.tenantProfileId = tenantProfile.getId();
60 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 54 public long getProfileThreshold(ApiUsageRecordKey key) {
... ... @@ -111,53 +59,25 @@ public class TenantApiUsageState {
111 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 82 public Map<ApiFeature, ApiUsageStateValue> checkStateUpdatedDueToThresholds() {
163 83 return checkStateUpdatedDueToThreshold(new HashSet<>(Arrays.asList(ApiFeature.values())));
... ... @@ -174,23 +94,9 @@ public class TenantApiUsageState {
174 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 230 private void pushProvisionEventToRuleEngine(ProvisionRequest request, Device device, String type) {
231 231 try {
232 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 234 sendToRuleEngine(device.getTenantId(), msg, null);
235 235 } catch (IllegalArgumentException e) {
236 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 240 private void pushDeviceCreatedEventToRuleEngine(Device device) {
241 241 try {
242 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 244 sendToRuleEngine(device.getTenantId(), msg, null);
245 245 } catch (JsonProcessingException | IllegalArgumentException e) {
246 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 920 try {
921 921 if (uplinkMsg.getEntityDataCount() > 0) {
922 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 926 if (uplinkMsg.getDeviceUpdateMsgCount() > 0) {
... ...
... ... @@ -231,7 +231,7 @@ public class DeviceProcessor extends BaseProcessor {
231 231 try {
232 232 DeviceId deviceId = device.getId();
233 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 235 getActionTbMsgMetaData(edge, device.getCustomerId()), TbMsgDataType.JSON, mapper.writeValueAsString(entityNode));
236 236 tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() {
237 237 @Override
... ...
... ... @@ -70,7 +70,7 @@ public class TelemetryProcessor extends BaseProcessor {
70 70
71 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 74 log.trace("[{}] onTelemetryUpdate [{}]", tenantId, entityData);
75 75 List<ListenableFuture<Void>> result = new ArrayList<>();
76 76 EntityId entityId = constructEntityId(entityData);
... ... @@ -80,14 +80,14 @@ public class TelemetryProcessor extends BaseProcessor {
80 80 TbMsgMetaData metaData = new TbMsgMetaData();
81 81 metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE);
82 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 85 if (entityData.hasAttributesUpdatedMsg()) {
86 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 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 93 if (entityData.hasAttributeDeleteMsg()) {
... ... @@ -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 152 SettableFuture<Void> futureToSet = SettableFuture.create();
153 153 for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) {
154 154 JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
... ... @@ -156,7 +156,7 @@ public class TelemetryProcessor extends BaseProcessor {
156 156 Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
157 157 String queueName = defaultQueueAndRuleChain.getKey();
158 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 160 tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
161 161 @Override
162 162 public void onSuccess(TbQueueMsgMetadata metadata) {
... ... @@ -173,13 +173,13 @@ public class TelemetryProcessor extends BaseProcessor {
173 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 177 SettableFuture<Void> futureToSet = SettableFuture.create();
178 178 JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
179 179 Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
180 180 String queueName = defaultQueueAndRuleChain.getKey();
181 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 183 tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
184 184 @Override
185 185 public void onSuccess(TbQueueMsgMetadata metadata) {
... ... @@ -195,7 +195,7 @@ public class TelemetryProcessor extends BaseProcessor {
195 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 199 SettableFuture<Void> futureToSet = SettableFuture.create();
200 200 JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
201 201 Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(json);
... ... @@ -206,7 +206,7 @@ public class TelemetryProcessor extends BaseProcessor {
206 206 Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId);
207 207 String queueName = defaultQueueAndRuleChain.getKey();
208 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 210 tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
211 211 @Override
212 212 public void onSuccess(TbQueueMsgMetadata metadata) {
... ...
... ... @@ -390,7 +390,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
390 390 pageData = tenantService.findTenants(pageLink);
391 391 for (Tenant tenant : pageData.getData()) {
392 392 try {
393   - apiUsageStateService.createDefaultApiUsageState(tenant.getId());
  393 + apiUsageStateService.createDefaultApiUsageState(tenant.getId(), null);
394 394 } catch (Exception e) {
395 395 }
396 396 List<EntitySubtype> deviceTypes = deviceService.findDeviceTypesByTenantId(tenant.getId()).get();
... ...
... ... @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
36 36 import org.thingsboard.server.common.data.ApiUsageStateValue;
37 37 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
38 38 import org.thingsboard.server.common.data.exception.ThingsboardException;
  39 +import org.thingsboard.server.common.data.id.CustomerId;
39 40 import org.thingsboard.server.common.data.id.EntityId;
40 41 import org.thingsboard.server.common.data.id.TenantId;
41 42 import org.thingsboard.server.dao.exception.IncorrectParameterException;
... ... @@ -233,7 +234,7 @@ public class DefaultMailService implements MailService {
233 234 }
234 235
235 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 238 if (apiUsageStateService.getApiUsageState(tenantId).isEmailSendEnabled()) {
238 239 MimeMessage mailMsg = mailSender.createMimeMessage();
239 240 MimeMessageHelper helper = new MimeMessageHelper(mailMsg, "UTF-8");
... ... @@ -248,7 +249,7 @@ public class DefaultMailService implements MailService {
248 249 helper.setSubject(subject);
249 250 helper.setText(body);
250 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 253 } else {
253 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 29 import org.thingsboard.server.common.data.TbResource;
30 30 import org.thingsboard.server.common.data.Tenant;
31 31 import org.thingsboard.server.common.data.TenantProfile;
  32 +import org.thingsboard.server.common.data.id.CustomerId;
32 33 import org.thingsboard.server.common.data.id.DeviceId;
33 34 import org.thingsboard.server.common.data.id.DeviceProfileId;
34 35 import org.thingsboard.server.common.data.id.EdgeId;
... ...
... ... @@ -18,14 +18,15 @@ package org.thingsboard.server.service.queue.processing;
18 18 import com.google.protobuf.ByteString;
19 19 import lombok.extern.slf4j.Slf4j;
20 20 import org.springframework.boot.context.event.ApplicationReadyEvent;
21   -import org.springframework.context.ApplicationListener;
22 21 import org.springframework.context.event.EventListener;
23 22 import org.springframework.core.annotation.Order;
24 23 import org.thingsboard.common.util.ThingsBoardThreadFactory;
25 24 import org.thingsboard.server.actors.ActorSystemContext;
26 25 import org.thingsboard.server.common.data.EntityType;
  26 +import org.thingsboard.server.common.data.id.CustomerId;
27 27 import org.thingsboard.server.common.data.id.DeviceId;
28 28 import org.thingsboard.server.common.data.id.DeviceProfileId;
  29 +import org.thingsboard.server.common.data.id.TenantId;
29 30 import org.thingsboard.server.common.data.id.TenantProfileId;
30 31 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
31 32 import org.thingsboard.server.common.msg.TbActorMsg;
... ... @@ -72,7 +73,8 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
72 73 protected final TbQueueConsumer<TbProtoQueueMsg<N>> nfConsumer;
73 74
74 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 78 this.actorContext = actorContext;
77 79 this.encodingService = encodingService;
78 80 this.tenantProfileCache = tenantProfileCache;
... ... @@ -166,6 +168,8 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
166 168 tenantProfileCache.evict(componentLifecycleMsg.getTenantId());
167 169 if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.UPDATED)) {
168 170 apiUsageStateService.onTenantUpdate(componentLifecycleMsg.getTenantId());
  171 + } else if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.DELETED)) {
  172 + apiUsageStateService.onTenantDelete((TenantId) componentLifecycleMsg.getEntityId());
169 173 }
170 174 } else if (EntityType.DEVICE_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
171 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 177 deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceId(componentLifecycleMsg.getEntityId().getId()));
174 178 } else if (EntityType.API_USAGE_STATE.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
175 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 186 log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg);
... ...
... ... @@ -34,6 +34,7 @@ import org.thingsboard.server.dao.device.DeviceService;
34 34 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
35 35 import org.thingsboard.server.queue.util.TbCoreComponent;
36 36 import org.thingsboard.server.service.queue.TbClusterService;
  37 +import org.thingsboard.server.service.security.model.SecurityUser;
37 38
38 39 import javax.annotation.PostConstruct;
39 40 import javax.annotation.PreDestroy;
... ... @@ -95,11 +96,11 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
95 96 }
96 97
97 98 @Override
98   - public void processRestApiRpcRequest(ToDeviceRpcRequest request, Consumer<FromDeviceRpcResponse> responseConsumer) {
  99 + public void processRestApiRpcRequest(ToDeviceRpcRequest request, Consumer<FromDeviceRpcResponse> responseConsumer, SecurityUser currentUser) {
99 100 log.trace("[{}][{}] Processing REST API call to rule engine [{}]", request.getTenantId(), request.getId(), request.getDeviceId());
100 101 UUID requestId = request.getId();
101 102 localToRuleEngineRpcRequests.put(requestId, responseConsumer);
102   - sendRpcRequestToRuleEngine(request);
  103 + sendRpcRequestToRuleEngine(request, currentUser);
103 104 scheduleToRuleEngineTimeout(request, requestId);
104 105 }
105 106
... ... @@ -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 154 ObjectNode entityNode = json.createObjectNode();
154 155 TbMsgMetaData metaData = new TbMsgMetaData();
155 156 metaData.putValue("requestUUID", msg.getId().toString());
... ... @@ -167,7 +168,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
167 168 entityNode.put("params", msg.getBody().getParams());
168 169
169 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 172 clusterService.pushMsgToRuleEngine(msg.getTenantId(), msg.getDeviceId(), tbMsg, null);
172 173 } catch (JsonProcessingException e) {
173 174 throw new RuntimeException(e);
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.service.rpc;
17 17
18 18 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
  19 +import org.thingsboard.server.service.security.model.SecurityUser;
19 20
20 21 import java.util.function.Consumer;
21 22
... ... @@ -27,11 +28,11 @@ public interface TbCoreDeviceRpcService {
27 28 /**
28 29 * Handles REST API calls that contain RPC requests to Device and pushes them to Rule Engine.
29 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 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 38 * Handles the RPC response from the Rule Engine.
... ...
... ... @@ -20,6 +20,7 @@ import com.google.common.util.concurrent.ListenableFuture;
20 20 import lombok.extern.slf4j.Slf4j;
21 21 import org.thingsboard.common.util.ThingsBoardThreadFactory;
22 22 import org.thingsboard.server.common.data.ApiUsageRecordKey;
  23 +import org.thingsboard.server.common.data.id.CustomerId;
23 24 import org.thingsboard.server.common.data.id.TenantId;
24 25 import org.thingsboard.server.queue.usagestats.TbApiUsageClient;
25 26 import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
... ... @@ -73,14 +74,14 @@ public abstract class AbstractJsInvokeService implements JsInvokeService {
73 74 }
74 75
75 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 78 if (apiUsageStateService.getApiUsageState(tenantId).isJsExecEnabled()) {
78 79 String functionName = scriptIdToNameMap.get(scriptId);
79 80 if (functionName == null) {
80 81 return Futures.immediateFailedFuture(new RuntimeException("No compiled script found for scriptId: [" + scriptId + "]!"));
81 82 }
82 83 if (!isDisabled(scriptId)) {
83   - apiUsageClient.report(tenantId, ApiUsageRecordKey.JS_EXEC_COUNT, 1);
  84 + apiUsageClient.report(tenantId, customerId, ApiUsageRecordKey.JS_EXEC_COUNT, 1);
84 85 return doInvokeFunction(scriptId, functionName, args);
85 86 } else {
86 87 return Futures.immediateFailedFuture(
... ...
... ... @@ -16,7 +16,7 @@
16 16 package org.thingsboard.server.service.script;
17 17
18 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 20 import org.thingsboard.server.common.data.id.TenantId;
21 21
22 22 import java.util.UUID;
... ... @@ -25,7 +25,7 @@ public interface JsInvokeService {
25 25
26 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 30 ListenableFuture<Void> release(UUID scriptId);
31 31
... ...
... ... @@ -218,7 +218,7 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S
218 218 private JsonNode executeScript(TbMsg msg) throws ScriptException {
219 219 try {
220 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 222 return mapper.readTree(eval);
223 223 } catch (ExecutionException e) {
224 224 if (e.getCause() instanceof ScriptException) {
... ... @@ -235,7 +235,7 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S
235 235
236 236 private ListenableFuture<JsonNode> executeScriptAsync(TbMsg msg) {
237 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 239 o -> {
240 240 try {
241 241 return Futures.immediateFuture(mapper.readTree(o.toString()));
... ...
... ... @@ -22,6 +22,7 @@ import org.springframework.stereotype.Service;
22 22 import org.thingsboard.rule.engine.api.SmsService;
23 23 import org.thingsboard.rule.engine.api.sms.SmsSender;
24 24 import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
  25 +import org.thingsboard.server.common.data.id.CustomerId;
25 26 import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration;
26 27 import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
27 28 import org.thingsboard.server.common.data.AdminSettings;
... ... @@ -94,7 +95,7 @@ public class DefaultSmsService implements SmsService {
94 95 }
95 96
96 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 99 if (apiUsageStateService.getApiUsageState(tenantId).isSmsSendEnabled()) {
99 100 int smsCount = 0;
100 101 try {
... ... @@ -103,7 +104,7 @@ public class DefaultSmsService implements SmsService {
103 104 }
104 105 } finally {
105 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 110 } else {
... ...
... ... @@ -468,6 +468,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
468 468 md.putValue("deviceName", device.getName());
469 469 md.putValue("deviceType", device.getType());
470 470 return DeviceStateData.builder()
  471 + .customerId(device.getCustomerId())
471 472 .tenantId(device.getTenantId())
472 473 .deviceId(device.getId())
473 474 .deviceCreationTime(device.getCreatedTime())
... ... @@ -507,7 +508,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
507 508 if(!persistToTelemetry){
508 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 512 clusterService.pushMsgToRuleEngine(stateData.getTenantId(), stateData.getDeviceId(), tbMsg, null);
512 513 } catch (Exception e) {
513 514 log.warn("[{}] Failed to push inactivity alarm: {}", stateData.getDeviceId(), state, e);
... ...
... ... @@ -17,6 +17,7 @@ package org.thingsboard.server.service.state;
17 17
18 18 import lombok.Builder;
19 19 import lombok.Data;
  20 +import org.thingsboard.server.common.data.id.CustomerId;
20 21 import org.thingsboard.server.common.data.id.DeviceId;
21 22 import org.thingsboard.server.common.data.id.TenantId;
22 23 import org.thingsboard.server.common.msg.TbMsgMetaData;
... ... @@ -29,6 +30,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
29 30 class DeviceStateData {
30 31
31 32 private final TenantId tenantId;
  33 + private final CustomerId customerId;
32 34 private final DeviceId deviceId;
33 35 private final long deviceCreationTime;
34 36 private TbMsgMetaData metaData;
... ...
... ... @@ -25,7 +25,7 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory;
25 25 import org.thingsboard.server.common.data.ApiUsageRecordKey;
26 26 import org.thingsboard.server.common.data.EntityType;
27 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 29 import org.thingsboard.server.common.data.id.EntityId;
30 30 import org.thingsboard.server.common.data.id.TenantId;
31 31 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
... ... @@ -35,13 +35,11 @@ import org.thingsboard.server.common.data.kv.DoubleDataEntry;
35 35 import org.thingsboard.server.common.data.kv.LongDataEntry;
36 36 import org.thingsboard.server.common.data.kv.StringDataEntry;
37 37 import org.thingsboard.server.common.data.kv.TsKvEntry;
38   -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
39 38 import org.thingsboard.server.common.msg.queue.ServiceType;
40 39 import org.thingsboard.server.common.msg.queue.TbCallback;
41 40 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
42 41 import org.thingsboard.server.dao.attributes.AttributesService;
43 42 import org.thingsboard.server.dao.entityview.EntityViewService;
44   -import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
45 43 import org.thingsboard.server.dao.timeseries.TimeseriesService;
46 44 import org.thingsboard.server.gen.transport.TransportProtos;
47 45 import org.thingsboard.server.queue.discovery.PartitionService;
... ... @@ -115,11 +113,11 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
115 113
116 114 @Override
117 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 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 121 checkInternalEntity(entityId);
124 122 boolean sysTenant = TenantId.SYS_TENANT_ID.equals(tenantId) || tenantId == null;
125 123 if (sysTenant || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) {
... ... @@ -127,7 +125,7 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
127 125 @Override
128 126 public void onSuccess(Integer result) {
129 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 130 callback.onSuccess(null);
133 131 }
... ...
... ... @@ -86,6 +86,7 @@ import org.thingsboard.server.service.queue.TbClusterService;
86 86 import org.thingsboard.server.service.resource.TbResourceService;
87 87 import org.thingsboard.server.service.state.DeviceStateService;
88 88
  89 +import java.util.Optional;
89 90 import java.util.UUID;
90 91 import java.util.concurrent.ConcurrentHashMap;
91 92 import java.util.concurrent.ConcurrentMap;
... ... @@ -284,7 +285,7 @@ public class DefaultTransportApiService implements TransportApiService {
284 285
285 286 DeviceId deviceId = device.getId();
286 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 289 tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, null);
289 290 }
290 291 GetOrCreateDeviceFromGatewayResponseMsg.Builder builder = GetOrCreateDeviceFromGatewayResponseMsg.newBuilder()
... ... @@ -423,6 +424,8 @@ public class DefaultTransportApiService implements TransportApiService {
423 424 return DeviceInfoProto.newBuilder()
424 425 .setTenantIdMSB(device.getTenantId().getId().getMostSignificantBits())
425 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 429 .setDeviceIdMSB(device.getId().getId().getMostSignificantBits())
427 430 .setDeviceIdLSB(device.getId().getId().getLeastSignificantBits())
428 431 .setDeviceName(device.getName())
... ...
... ... @@ -124,6 +124,7 @@ usage:
124 124 stats:
125 125 report:
126 126 enabled: "${USAGE_STATS_REPORT_ENABLED:true}"
  127 + enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}"
127 128 interval: "${USAGE_STATS_REPORT_INTERVAL:10}"
128 129 check:
129 130 cycle: "${USAGE_STATS_CHECK_CYCLE:60000}"
... ...
... ... @@ -21,12 +21,12 @@ import org.checkerframework.checker.nullness.qual.Nullable;
21 21 import org.junit.After;
22 22 import org.junit.Assert;
23 23 import org.junit.Before;
24   -import org.junit.Ignore;
25 24 import org.junit.Test;
26 25 import org.springframework.beans.factory.annotation.Autowired;
27 26 import org.thingsboard.server.common.data.Device;
28 27 import org.thingsboard.server.common.data.Tenant;
29 28 import org.thingsboard.server.common.data.User;
  29 +import org.thingsboard.server.common.data.id.CustomerId;
30 30 import org.thingsboard.server.common.data.kv.Aggregation;
31 31 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
32 32 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
... ... @@ -750,7 +750,7 @@ public class BaseWebsocketApiTest extends AbstractWebsocketTest {
750 750
751 751 private void sendTelemetry(Device device, List<TsKvEntry> tsData) throws InterruptedException {
752 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 754 @Override
755 755 public void onSuccess(@Nullable Void result) {
756 756 latch.countDown();
... ...
... ... @@ -17,17 +17,22 @@ package org.thingsboard.server.dao.usagerecord;
17 17
18 18 import org.thingsboard.server.common.data.ApiUsageState;
19 19 import org.thingsboard.server.common.data.id.ApiUsageStateId;
  20 +import org.thingsboard.server.common.data.id.EntityId;
20 21 import org.thingsboard.server.common.data.id.TenantId;
21 22
22 23 public interface ApiUsageStateService {
23 24
24   - ApiUsageState createDefaultApiUsageState(TenantId id);
  25 + ApiUsageState createDefaultApiUsageState(TenantId id, EntityId entityId);
25 26
26 27 ApiUsageState update(ApiUsageState apiUsageState);
27 28
28 29 ApiUsageState findTenantApiUsageState(TenantId tenantId);
29 30
  31 + ApiUsageState findApiUsageStateByEntityId(EntityId entityId);
  32 +
30 33 void deleteApiUsageStateByTenantId(TenantId tenantId);
31 34
  35 + void deleteApiUsageStateByEntityId(EntityId entityId);
  36 +
32 37 ApiUsageState findApiUsageStateById(TenantId tenantId, ApiUsageStateId id);
33 38 }
... ...
... ... @@ -16,10 +16,13 @@
16 16 package org.thingsboard.server.common.data.query;
17 17
18 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 21 @Data
22 22 public class ApiUsageStateFilter implements EntityFilter {
  23 +
  24 + private CustomerId customerId;
  25 +
23 26 @Override
24 27 public EntityFilterType getType() {
25 28 return EntityFilterType.API_USAGE_STATE;
... ...
... ... @@ -19,10 +19,11 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
19 19 import com.google.protobuf.ByteString;
20 20 import com.google.protobuf.InvalidProtocolBufferException;
21 21 import lombok.AccessLevel;
22   -import lombok.Builder;
23 22 import lombok.Data;
24 23 import lombok.Getter;
25 24 import lombok.extern.slf4j.Slf4j;
  25 +import org.thingsboard.server.common.data.EntityType;
  26 +import org.thingsboard.server.common.data.id.CustomerId;
26 27 import org.thingsboard.server.common.data.id.EntityId;
27 28 import org.thingsboard.server.common.data.id.EntityIdFactory;
28 29 import org.thingsboard.server.common.data.id.RuleChainId;
... ... @@ -47,6 +48,7 @@ public final class TbMsg implements Serializable {
47 48 private final long ts;
48 49 private final String type;
49 50 private final EntityId originator;
  51 + private final CustomerId customerId;
50 52 private final TbMsgMetaData metaData;
51 53 private final TbMsgDataType dataType;
52 54 private final String data;
... ... @@ -55,6 +57,7 @@ public final class TbMsg implements Serializable {
55 57 @Getter(value = AccessLevel.NONE)
56 58 private final AtomicInteger ruleNodeExecCounter;
57 59
  60 +
58 61 public int getAndIncrementRuleNodeCounter() {
59 62 return ruleNodeExecCounter.getAndIncrement();
60 63 }
... ... @@ -64,60 +67,81 @@ public final class TbMsg implements Serializable {
64 67 transient private final TbMsgCallback callback;
65 68
66 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 75 metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, 0, TbMsgCallback.EMPTY);
69 76 }
70 77
71 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 86 // REALLY NEW MSG
76 87
77 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 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 104 // For Tests only
86 105
87 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 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 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 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 126 tbMsg.data, ruleChainId, null, tbMsg.ruleNodeExecCounter.get(), tbMsg.getCallback());
103 127 }
104 128
105 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 131 tbMsg.data, tbMsg.getRuleChainId(), null, tbMsg.ruleNodeExecCounter.get(), tbMsg.getCallback());
108 132 }
109 133
110 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 136 tbMsg.data, ruleChainId, null, tbMsg.ruleNodeExecCounter.get(), tbMsg.getCallback());
113 137 }
114 138
115 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 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 145 RuleChainId ruleChainId, RuleNodeId ruleNodeId, int ruleNodeExecCounter, TbMsgCallback callback) {
122 146 this.id = id;
123 147 this.queueName = queueName != null ? queueName : ServiceQueue.MAIN;
... ... @@ -128,6 +152,15 @@ public final class TbMsg implements Serializable {
128 152 }
129 153 this.type = type;
130 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 164 this.metaData = metaData;
132 165 this.dataType = dataType;
133 166 this.data = data;
... ... @@ -154,6 +187,11 @@ public final class TbMsg implements Serializable {
154 187 builder.setEntityIdMSB(msg.getOriginator().getId().getMostSignificantBits());
155 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 195 if (msg.getRuleChainId() != null) {
158 196 builder.setRuleChainIdMSB(msg.getRuleChainId().getId().getMostSignificantBits());
159 197 builder.setRuleChainIdLSB(msg.getRuleChainId().getId().getLeastSignificantBits());
... ... @@ -179,16 +217,21 @@ public final class TbMsg implements Serializable {
179 217 MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(data);
180 218 TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap());
181 219 EntityId entityId = EntityIdFactory.getByTypeAndUuid(proto.getEntityType(), new UUID(proto.getEntityIdMSB(), proto.getEntityIdLSB()));
  220 + CustomerId customerId = null;
182 221 RuleChainId ruleChainId = null;
183 222 RuleNodeId ruleNodeId = null;
  223 + if (proto.getCustomerIdMSB() != 0L && proto.getCustomerIdLSB() != 0L) {
  224 + customerId = new CustomerId(new UUID(proto.getCustomerIdMSB(), proto.getCustomerIdLSB()));
  225 + }
184 226 if (proto.getRuleChainIdMSB() != 0L && proto.getRuleChainIdLSB() != 0L) {
185 227 ruleChainId = new RuleChainId(new UUID(proto.getRuleChainIdMSB(), proto.getRuleChainIdLSB()));
186 228 }
187 229 if (proto.getRuleNodeIdMSB() != 0L && proto.getRuleNodeIdLSB() != 0L) {
188 230 ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleNodeIdLSB()));
189 231 }
  232 +
190 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 235 } catch (InvalidProtocolBufferException e) {
193 236 throw new IllegalStateException("Could not parse protobuf for TbMsg", e);
194 237 }
... ... @@ -199,11 +242,11 @@ public final class TbMsg implements Serializable {
199 242 }
200 243
201 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 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 252 public TbMsgCallback getCallback() {
... ...
... ... @@ -46,4 +46,7 @@ message TbMsgProto {
46 46
47 47 int64 ts = 15;
48 48 int32 ruleNodeExecCounter = 16;
  49 +
  50 + int64 customerIdMSB = 17;
  51 + int64 customerIdLSB = 18;
49 52 }
\ No newline at end of file
... ...
... ... @@ -15,10 +15,14 @@
15 15 */
16 16 package org.thingsboard.server.queue.usagestats;
17 17
  18 +import lombok.Data;
18 19 import lombok.extern.slf4j.Slf4j;
19 20 import org.springframework.beans.factory.annotation.Value;
20 21 import org.springframework.stereotype.Component;
21 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 26 import org.thingsboard.server.common.data.id.TenantId;
23 27 import org.thingsboard.server.common.msg.queue.ServiceType;
24 28 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
... ... @@ -31,6 +35,8 @@ import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
31 35 import org.thingsboard.server.queue.scheduler.SchedulerComponent;
32 36
33 37 import javax.annotation.PostConstruct;
  38 +import java.util.EnumMap;
  39 +import java.util.Optional;
34 40 import java.util.Random;
35 41 import java.util.UUID;
36 42 import java.util.concurrent.ConcurrentHashMap;
... ... @@ -44,11 +50,13 @@ public class DefaultTbApiUsageClient implements TbApiUsageClient {
44 50
45 51 @Value("${usage.stats.report.enabled:true}")
46 52 private boolean enabled;
  53 + @Value("${usage.stats.report.enabled_per_customer:false}")
  54 + private boolean enabledPerCustomer;
47 55 @Value("${usage.stats.report.interval:10}")
48 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 60 private final PartitionService partitionService;
53 61 private final SchedulerComponent scheduler;
54 62 private final TbQueueProducerProvider producerProvider;
... ... @@ -65,55 +73,93 @@ public class DefaultTbApiUsageClient implements TbApiUsageClient {
65 73 if (enabled) {
66 74 msgProducer = this.producerProvider.getTbUsageStatsMsgProducer();
67 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 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 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 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 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 16 package org.thingsboard.server.queue.usagestats;
17 17
18 18 import org.thingsboard.server.common.data.ApiUsageRecordKey;
  19 +import org.thingsboard.server.common.data.id.CustomerId;
19 20 import org.thingsboard.server.common.data.id.TenantId;
20 21
21 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 53 int64 gwSessionIdLSB = 11;
54 54 int64 deviceProfileIdMSB = 12;
55 55 int64 deviceProfileIdLSB = 13;
  56 + int64 customerIdMSB = 14;
  57 + int64 customerIdLSB = 15;
56 58 }
57 59
58 60 enum SessionEvent {
... ... @@ -110,6 +112,8 @@ message DeviceInfoProto {
110 112 string additionalInfo = 7;
111 113 int64 deviceProfileIdMSB = 8;
112 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 660 int64 entityIdMSB = 3;
657 661 int64 entityIdLSB = 4;
658 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 141 .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB())
142 142 .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB())
143 143 .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB())
  144 + .setCustomerIdMSB(msg.getDeviceInfo().getCustomerIdMSB())
  145 + .setCustomerIdLSB(msg.getDeviceInfo().getCustomerIdLSB())
144 146 .setDeviceName(msg.getDeviceInfo().getDeviceName())
145 147 .setDeviceType(msg.getDeviceInfo().getDeviceType())
146 148 .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB())
... ...
... ... @@ -1177,6 +1177,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1177 1177 .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB())
1178 1178 .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB())
1179 1179 .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB())
  1180 + .setCustomerIdMSB(msg.getDeviceInfo().getCustomerIdMSB())
  1181 + .setCustomerIdLSB(msg.getDeviceInfo().getCustomerIdLSB())
1180 1182 .setDeviceName(msg.getDeviceInfo().getDeviceName())
1181 1183 .setDeviceType(msg.getDeviceInfo().getDeviceType())
1182 1184 .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB())
... ...
... ... @@ -45,6 +45,8 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple
45 45 .setDeviceIdLSB(deviceInfo.getDeviceId().getId().getLeastSignificantBits())
46 46 .setTenantIdMSB(deviceInfo.getTenantId().getId().getMostSignificantBits())
47 47 .setTenantIdLSB(deviceInfo.getTenantId().getId().getLeastSignificantBits())
  48 + .setCustomerIdMSB(deviceInfo.getCustomerId().getId().getMostSignificantBits())
  49 + .setCustomerIdLSB(deviceInfo.getCustomerId().getId().getLeastSignificantBits())
48 50 .setDeviceName(deviceInfo.getDeviceName())
49 51 .setDeviceType(deviceInfo.getDeviceType())
50 52 .setGwSessionIdMSB(parent.getSessionId().getMostSignificantBits())
... ...
... ... @@ -40,6 +40,8 @@ public class SessionInfoCreator {
40 40 .setDeviceIdLSB(msg.getDeviceInfo().getDeviceId().getId().getLeastSignificantBits())
41 41 .setTenantIdMSB(msg.getDeviceInfo().getTenantId().getId().getMostSignificantBits())
42 42 .setTenantIdLSB(msg.getDeviceInfo().getTenantId().getId().getLeastSignificantBits())
  43 + .setCustomerIdMSB(msg.getDeviceInfo().getCustomerId().getId().getMostSignificantBits())
  44 + .setCustomerIdLSB(msg.getDeviceInfo().getCustomerId().getId().getLeastSignificantBits())
43 45 .setDeviceName(msg.getDeviceInfo().getDeviceName())
44 46 .setDeviceType(msg.getDeviceInfo().getDeviceType())
45 47 .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileId().getId().getMostSignificantBits())
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.common.transport.auth;
17 17
18 18 import lombok.Data;
  19 +import org.thingsboard.server.common.data.id.CustomerId;
19 20 import org.thingsboard.server.common.data.id.DeviceId;
20 21 import org.thingsboard.server.common.data.id.DeviceProfileId;
21 22 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -24,6 +25,7 @@ import org.thingsboard.server.common.data.id.TenantId;
24 25 public class TransportDeviceInfo {
25 26
26 27 private TenantId tenantId;
  28 + private CustomerId customerId;
27 29 private DeviceProfileId deviceProfileId;
28 30 private DeviceId deviceId;
29 31 private String deviceName;
... ...
... ... @@ -33,8 +33,10 @@ import org.thingsboard.server.common.data.DeviceTransportType;
33 33 import org.thingsboard.server.common.data.EntityType;
34 34 import org.thingsboard.server.common.data.ResourceType;
35 35 import org.thingsboard.server.common.data.Tenant;
  36 +import org.thingsboard.server.common.data.id.CustomerId;
36 37 import org.thingsboard.server.common.data.id.DeviceId;
37 38 import org.thingsboard.server.common.data.id.DeviceProfileId;
  39 +import org.thingsboard.server.common.data.id.EntityId;
38 40 import org.thingsboard.server.common.data.id.RuleChainId;
39 41 import org.thingsboard.server.common.data.id.TenantId;
40 42 import org.thingsboard.server.common.data.id.TenantProfileId;
... ... @@ -359,6 +361,7 @@ public class DefaultTransportService implements TransportService {
359 361 private TransportDeviceInfo getTransportDeviceInfo(TransportProtos.DeviceInfoProto di) {
360 362 TransportDeviceInfo tdi = new TransportDeviceInfo();
361 363 tdi.setTenantId(new TenantId(new UUID(di.getTenantIdMSB(), di.getTenantIdLSB())));
  364 + tdi.setCustomerId(new CustomerId(new UUID(di.getCustomerIdMSB(), di.getCustomerIdLSB())));
362 365 tdi.setDeviceId(new DeviceId(new UUID(di.getDeviceIdMSB(), di.getDeviceIdLSB())));
363 366 tdi.setDeviceProfileId(new DeviceProfileId(new UUID(di.getDeviceProfileIdMSB(), di.getDeviceProfileIdLSB())));
364 367 tdi.setAdditionalInfo(di.getAdditionalInfo());
... ... @@ -403,17 +406,17 @@ public class DefaultTransportService implements TransportService {
403 406 }
404 407 if (checkLimits(sessionInfo, msg, callback, dataPoints)) {
405 408 reportActivityInternal(sessionInfo);
406   - TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB()));
  409 + TenantId tenantId = getTenantId(sessionInfo);
407 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 413 for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) {
410 414 TbMsgMetaData metaData = new TbMsgMetaData();
411 415 metaData.putValue("deviceName", sessionInfo.getDeviceName());
412 416 metaData.putValue("deviceType", sessionInfo.getDeviceType());
413 417 metaData.putValue("ts", tsKv.getTs() + "");
414 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 425 public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.PostAttributeMsg msg, TransportServiceCallback<Void> callback) {
423 426 if (checkLimits(sessionInfo, msg, callback, msg.getKvCount())) {
424 427 reportActivityInternal(sessionInfo);
425   - TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB()));
  428 + TenantId tenantId = getTenantId(sessionInfo);
426 429 DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()));
427 430 JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
428 431 TbMsgMetaData metaData = new TbMsgMetaData();
429 432 metaData.putValue("deviceName", sessionInfo.getDeviceName());
430 433 metaData.putValue("deviceType", sessionInfo.getDeviceType());
431 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 443 if (checkLimits(sessionInfo, msg, callback)) {
440 444 reportActivityInternal(sessionInfo);
441 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 452 if (checkLimits(sessionInfo, msg, callback)) {
449 453 SessionMetaData sessionMetaData = reportActivityInternal(sessionInfo);
450 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 462 if (checkLimits(sessionInfo, msg, callback)) {
459 463 SessionMetaData sessionMetaData = reportActivityInternal(sessionInfo);
460 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 471 public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToDeviceRpcResponseMsg msg, TransportServiceCallback<Void> callback) {
468 472 if (checkLimits(sessionInfo, msg, callback)) {
469 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 515 metaData.putValue("requestId", Integer.toString(msg.getRequestId()));
512 516 metaData.putValue("serviceId", serviceInfoProvider.getServiceId());
513 517 metaData.putValue("sessionId", sessionId.toString());
514   - sendToRuleEngine(tenantId, deviceId, sessionInfo, json, metaData,
  518 + sendToRuleEngine(tenantId, deviceId, getCustomerId(sessionInfo), sessionInfo, json, metaData,
515 519 SessionMsgType.TO_SERVER_RPC_REQUEST, new TransportTbQueueCallback(callback));
516 520 String requestId = sessionId + "-" + msg.getRequestId();
517 521 toServerRpcPendingMap.put(requestId, new RpcRequestMetadata(sessionId, msg.getRequestId()));
... ... @@ -809,6 +813,16 @@ public class DefaultTransportService implements TransportService {
809 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 826 protected DeviceId getDeviceId(TransportProtos.SessionInfoProto sessionInfo) {
813 827 return new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()));
814 828 }
... ... @@ -847,7 +861,7 @@ public class DefaultTransportService implements TransportService {
847 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 865 TbMsgMetaData metaData, SessionMsgType sessionMsgType, TbQueueCallback callback) {
852 866 DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
853 867 DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId);
... ... @@ -864,7 +878,7 @@ public class DefaultTransportService implements TransportService {
864 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 882 sendToRuleEngine(tenantId, tbMsg, callback);
869 883 }
870 884
... ... @@ -934,11 +948,13 @@ public class DefaultTransportService implements TransportService {
934 948
935 949 private class ApiStatsProxyCallback<T> implements TransportServiceCallback<T> {
936 950 private final TenantId tenantId;
  951 + private final CustomerId customerId;
937 952 private final int dataPoints;
938 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 956 this.tenantId = tenantId;
  957 + this.customerId = customerId;
942 958 this.dataPoints = dataPoints;
943 959 this.callback = callback;
944 960 }
... ... @@ -946,8 +962,8 @@ public class DefaultTransportService implements TransportService {
946 962 @Override
947 963 public void onSuccess(T msg) {
948 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 967 } finally {
952 968 callback.onSuccess(msg);
953 969 }
... ...
... ... @@ -43,6 +43,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover;
43 43 import org.thingsboard.server.dao.service.Validator;
44 44 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
45 45 import org.thingsboard.server.dao.tenant.TenantDao;
  46 +import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
46 47 import org.thingsboard.server.dao.user.UserService;
47 48
48 49 import java.io.IOException;
... ... @@ -80,6 +81,9 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
80 81 private DashboardService dashboardService;
81 82
82 83 @Autowired
  84 + private ApiUsageStateService apiUsageStateService;
  85 +
  86 + @Autowired
83 87 @Lazy
84 88 private TbTenantProfileCache tenantProfileCache;
85 89
... ... @@ -128,6 +132,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
128 132 edgeService.unassignCustomerEdges(customer.getTenantId(), customerId);
129 133 userService.deleteCustomerUsers(customer.getTenantId(), customerId);
130 134 deleteEntityRelations(tenantId, customerId);
  135 + apiUsageStateService.deleteApiUsageStateByEntityId(customerId);
131 136 customerDao.removeById(tenantId, customerId.getId());
132 137 }
133 138
... ...
... ... @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
25 25 import org.thingsboard.server.common.data.id.EntityId;
26 26 import org.thingsboard.server.common.data.id.TenantId;
27 27 import org.thingsboard.server.common.data.page.PageData;
  28 +import org.thingsboard.server.common.data.query.ApiUsageStateFilter;
28 29 import org.thingsboard.server.common.data.query.AssetSearchQueryFilter;
29 30 import org.thingsboard.server.common.data.query.AssetTypeFilter;
30 31 import org.thingsboard.server.common.data.query.DeviceSearchQueryFilter;
... ... @@ -219,8 +220,9 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
219 220 " THEN (select additional_info from edge where id = entity_id)" +
220 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 227 static {
226 228 entityTableMap.put(EntityType.ASSET, "asset");
... ... @@ -466,6 +468,22 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
466 468 case ENTITY_VIEW_SEARCH_QUERY:
467 469 case EDGE_SEARCH_QUERY:
468 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 487 default:
470 488 if (ctx.getEntityType() == EntityType.TENANT) {
471 489 ctx.addUuidParameter("permissions_tenant_id", ctx.getTenantId().getId());
... ...
... ... @@ -33,8 +33,14 @@ public interface ApiUsageStateRepository extends CrudRepository<ApiUsageStateEnt
33 33 "AND ur.entityId = :tenantId AND ur.entityType = 'TENANT' ")
34 34 ApiUsageStateEntity findByTenantId(@Param("tenantId") UUID tenantId);
35 35
  36 + ApiUsageStateEntity findByEntityIdAndEntityType(UUID entityId, String entityType);
  37 +
36 38 @Transactional
37 39 @Modifying
38 40 @Query("DELETE FROM ApiUsageStateEntity ur WHERE ur.tenantId = :tenantId")
39 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 18 import org.springframework.data.repository.CrudRepository;
19 19 import org.springframework.stereotype.Component;
20 20 import org.thingsboard.server.common.data.ApiUsageState;
  21 +import org.thingsboard.server.common.data.id.EntityId;
21 22 import org.thingsboard.server.common.data.id.TenantId;
22 23 import org.thingsboard.server.dao.DaoUtil;
23 24 import org.thingsboard.server.dao.model.sql.ApiUsageStateEntity;
... ... @@ -54,7 +55,17 @@ public class JpaApiUsageStateDao extends JpaAbstractDao<ApiUsageStateEntity, Api
54 55 }
55 56
56 57 @Override
  58 + public ApiUsageState findApiUsageStateByEntityId(EntityId entityId) {
  59 + return DaoUtil.getData(apiUsageStateRepository.findByEntityIdAndEntityType(entityId.getId(), entityId.getEntityType().name()));
  60 + }
  61 +
  62 + @Override
57 63 public void deleteApiUsageStateByTenantId(TenantId tenantId) {
58 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 125 Tenant savedTenant = tenantDao.save(tenant.getId(), tenant);
126 126 if (tenant.getId() == null) {
127 127 deviceProfileService.createDefaultDeviceProfile(savedTenant.getId());
128   - apiUsageStateService.createDefaultApiUsageState(savedTenant.getId());
  128 + apiUsageStateService.createDefaultApiUsageState(savedTenant.getId(), null);
129 129 }
130 130 return savedTenant;
131 131 }
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.dao.usagerecord;
17 17
18 18 import org.thingsboard.server.common.data.ApiUsageState;
  19 +import org.thingsboard.server.common.data.id.EntityId;
19 20 import org.thingsboard.server.common.data.id.TenantId;
20 21 import org.thingsboard.server.dao.Dao;
21 22
... ... @@ -39,10 +40,14 @@ public interface ApiUsageStateDao extends Dao<ApiUsageState> {
39 40 */
40 41 ApiUsageState findTenantApiUsageState(UUID tenantId);
41 42
  43 + ApiUsageState findApiUsageStateByEntityId(EntityId entityId);
  44 +
42 45 /**
43 46 * Delete usage record by tenantId.
44 47 *
45 48 * @param tenantId the tenantId
46 49 */
47 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 25 import org.thingsboard.server.common.data.Tenant;
26 26 import org.thingsboard.server.common.data.TenantProfile;
27 27 import org.thingsboard.server.common.data.id.ApiUsageStateId;
  28 +import org.thingsboard.server.common.data.id.EntityId;
28 29 import org.thingsboard.server.common.data.id.TenantId;
29 30 import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
30 31 import org.thingsboard.server.common.data.kv.LongDataEntry;
... ... @@ -40,6 +41,7 @@ import org.thingsboard.server.dao.timeseries.TimeseriesService;
40 41
41 42 import java.util.ArrayList;
42 43 import java.util.List;
  44 +import java.util.Objects;
43 45
44 46 import static org.thingsboard.server.dao.service.Validator.validateId;
45 47
... ... @@ -68,12 +70,20 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
68 70 }
69 71
70 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 83 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
74 84 ApiUsageState apiUsageState = new ApiUsageState();
75 85 apiUsageState.setTenantId(tenantId);
76   - apiUsageState.setEntityId(tenantId);
  86 + apiUsageState.setEntityId(entityId);
77 87 apiUsageState.setTransportState(ApiUsageStateValue.ENABLED);
78 88 apiUsageState.setReExecState(ApiUsageStateValue.ENABLED);
79 89 apiUsageState.setJsExecState(ApiUsageStateValue.ENABLED);
... ... @@ -84,9 +94,6 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
84 94
85 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 97 List<TsKvEntry> apiUsageStates = new ArrayList<>();
91 98 apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(),
92 99 new StringDataEntry(ApiFeature.TRANSPORT.getApiStateKey(), ApiUsageStateValue.ENABLED.name())));
... ... @@ -102,12 +109,19 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
102 109 new StringDataEntry(ApiFeature.SMS.getApiStateKey(), ApiUsageStateValue.ENABLED.name())));
103 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 125 return saved;
112 126 }
113 127
... ... @@ -127,6 +141,12 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
127 141 }
128 142
129 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 150 public ApiUsageState findApiUsageStateById(TenantId tenantId, ApiUsageStateId id) {
131 151 log.trace("Executing findApiUsageStateById, tenantId [{}], apiUsageStateId [{}]", tenantId, id);
132 152 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
... ... @@ -142,16 +162,14 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
142 162 throw new DataValidationException("ApiUsageState should be assigned to tenant!");
143 163 } else {
144 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 169 if (apiUsageState.getEntityId() == null) {
150 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 20 import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
21 21 import org.thingsboard.server.common.data.ApiUsageStateValue;
22 22 import org.thingsboard.server.common.data.exception.ThingsboardException;
  23 +import org.thingsboard.server.common.data.id.CustomerId;
23 24 import org.thingsboard.server.common.data.id.TenantId;
24 25
25 26 import javax.mail.MessagingException;
... ... @@ -40,7 +41,7 @@ public interface MailService {
40 41
41 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 46 void sendAccountLockoutEmail( String lockoutEmail, String email, Integer maxFailedLoginAttempts) throws ThingsboardException;
46 47
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.rule.engine.api;
17 17
18 18 import com.google.common.util.concurrent.FutureCallback;
  19 +import org.thingsboard.server.common.data.id.CustomerId;
19 20 import org.thingsboard.server.common.data.id.EntityId;
20 21 import org.thingsboard.server.common.data.id.TenantId;
21 22 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
... ... @@ -31,7 +32,7 @@ public interface RuleEngineTelemetryService {
31 32
32 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 37 void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes, FutureCallback<Void> callback);
37 38
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.rule.engine.api;
17 17
  18 +import org.thingsboard.server.common.data.id.CustomerId;
18 19 import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
19 20 import org.thingsboard.server.common.data.exception.ThingsboardException;
20 21 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -23,7 +24,7 @@ public interface SmsService {
23 24
24 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 29 void sendTestSms(TestSmsRequest testSmsRequest) throws ThingsboardException;
29 30
... ...
... ... @@ -16,16 +16,15 @@
16 16 package org.thingsboard.rule.engine.api;
17 17
18 18 import io.netty.channel.EventLoopGroup;
19   -import org.springframework.data.redis.core.RedisTemplate;
20 19 import org.thingsboard.common.util.ListeningExecutor;
21 20 import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
22   -import org.thingsboard.server.common.data.ApiUsageRecordKey;
23 21 import org.thingsboard.server.common.data.Customer;
24 22 import org.thingsboard.server.common.data.Device;
25 23 import org.thingsboard.server.common.data.DeviceProfile;
26 24 import org.thingsboard.server.common.data.TenantProfile;
27 25 import org.thingsboard.server.common.data.alarm.Alarm;
28 26 import org.thingsboard.server.common.data.asset.Asset;
  27 +import org.thingsboard.server.common.data.id.CustomerId;
29 28 import org.thingsboard.server.common.data.id.DeviceId;
30 29 import org.thingsboard.server.common.data.id.EdgeId;
31 30 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -144,6 +143,8 @@ public interface TbContext {
144 143
145 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 148 TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data);
148 149
149 150 TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId);
... ...
... ... @@ -136,7 +136,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
136 136 }
137 137
138 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 142 private boolean attributeContainsInEntityView(String scope, String attrKey, EntityView entityView) {
... ...
... ... @@ -63,7 +63,7 @@ public class TbMsgCountNode implements TbNode {
63 63 TbMsgCountNodeConfiguration config = TbNodeUtils.convert(configuration, TbMsgCountNodeConfiguration.class);
64 64 this.delay = TimeUnit.SECONDS.toMillis(config.getInterval());
65 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 78 TbMsgMetaData metaData = new TbMsgMetaData();
79 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 82 ctx.enqueueForTellNext(tbMsg, SUCCESS);
83   - scheduleTickMsg(ctx);
  83 + scheduleTickMsg(ctx, tbMsg);
84 84 } else {
85 85 messagesProcessed.incrementAndGet();
86 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 91 long curTs = System.currentTimeMillis();
92 92 if (lastScheduledTs == 0L) {
93 93 lastScheduledTs = curTs;
94 94 }
95 95 lastScheduledTs = lastScheduledTs + delay;
96 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 98 nextTickId = tickMsg.getId();
99 99 ctx.tellSelf(tickMsg, curDelay);
100 100 }
... ...
... ... @@ -100,7 +100,7 @@ public class TbMsgGeneratorNode implements TbNode {
100 100 @Override
101 101 public void onMsg(TbContext ctx, TbMsg msg) {
102 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 104 m -> {
105 105 if (initialized && (config.getMsgCount() == TbMsgGeneratorNodeConfiguration.UNLIMITED_MSG_COUNT || currentMsgCount < config.getMsgCount())) {
106 106 ctx.enqueueForTellNext(m, SUCCESS);
... ... @@ -130,16 +130,16 @@ public class TbMsgGeneratorNode implements TbNode {
130 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 134 return ctx.getJsExecutor().executeAsync(() -> {
135 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 138 if (initialized) {
139 139 ctx.logJsEvalRequest();
140 140 TbMsg generated = jsEngine.executeGenerate(prevMsg);
141 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 144 return prevMsg;
145 145 });
... ...
... ... @@ -70,7 +70,7 @@ public class TbMsgDelayNode implements TbNode {
70 70 } else {
71 71 if (pendingMsgs.size() < config.getMaxPendingMsgs()) {
72 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 74 ctx.tellSelf(tickMsg, getDelay(msg));
75 75 ctx.ack(msg);
76 76 } else {
... ...
... ... @@ -26,7 +26,6 @@ import org.thingsboard.rule.engine.api.TbNode;
26 26 import org.thingsboard.rule.engine.api.TbNodeConfiguration;
27 27 import org.thingsboard.rule.engine.api.TbNodeException;
28 28 import org.thingsboard.rule.engine.api.util.TbNodeUtils;
29   -import org.thingsboard.server.common.data.ApiUsageRecordKey;
30 29 import org.thingsboard.server.common.data.plugin.ComponentType;
31 30 import org.thingsboard.server.common.msg.TbMsg;
32 31
... ... @@ -76,7 +75,7 @@ public class TbSendEmailNode implements TbNode {
76 75 validateType(msg.getType());
77 76 EmailPojo email = getEmail(msg);
78 77 withCallback(ctx.getMailExecutor().executeAsync(() -> {
79   - sendEmail(ctx, email);
  78 + sendEmail(ctx, msg, email);
80 79 return null;
81 80 }),
82 81 ok -> ctx.tellSuccess(msg),
... ... @@ -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 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 91 email.getBcc(), email.getSubject(), email.getBody());
93 92 } else {
94 93 MimeMessage mailMsg = mailSender.createMimeMessage();
... ...
... ... @@ -74,15 +74,15 @@ class AlarmState {
74 74 lastMsgMetaData = msg.getMetaData();
75 75 lastMsgQueueName = msg.getQueueName();
76 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 80 public boolean process(TbContext ctx, long ts) throws ExecutionException, InterruptedException {
81 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 86 boolean stateUpdate = false;
87 87 AlarmRuleState resultState = null;
88 88 log.debug("[{}] processing update: {}", alarmDefinition.getId(), data);
... ... @@ -103,7 +103,7 @@ class AlarmState {
103 103 if (resultState != null) {
104 104 TbAlarmResult result = calculateAlarmResult(ctx, resultState);
105 105 if (result != null) {
106   - pushMsg(ctx, result, resultState);
  106 + pushMsg(ctx, msg, result, resultState);
107 107 }
108 108 stateUpdate = clearAlarmState(stateUpdate, clearState);
109 109 } else if (currentAlarm != null && clearState != null) {
... ... @@ -122,7 +122,7 @@ class AlarmState {
122 122 );
123 123 DonAsynchron.withCallback(alarmClearOperationResult,
124 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 127 throwable -> {
128 128 throw new RuntimeException(throwable);
... ... @@ -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 169 JsonNode jsonNodes = JacksonUtil.valueToTree(alarmResult.getAlarm());
170 170 String data = jsonNodes.toString();
171 171 TbMsgMetaData metaData = lastMsgMetaData != null ? lastMsgMetaData.copy() : new TbMsgMetaData();
... ... @@ -185,7 +185,8 @@ class AlarmState {
185 185 metaData.putValue(DataConstants.IS_CLEARED_ALARM, Boolean.TRUE.toString());
186 186 }
187 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 190 ctx.tellNext(newMsg, relationType);
190 191 }
191 192
... ...
... ... @@ -74,7 +74,7 @@ public class TbDeviceProfileNode implements TbNode {
74 74 this.config = TbNodeUtils.convert(configuration, TbDeviceProfileNodeConfiguration.class);
75 75 this.cache = ctx.getDeviceProfileCache();
76 76 this.ctx = ctx;
77   - scheduleAlarmHarvesting(ctx);
  77 + scheduleAlarmHarvesting(ctx, null);
78 78 ctx.addDeviceProfileListeners(this::onProfileUpdate, this::onDeviceUpdate);
79 79 if (config.isFetchAlarmRulesStateOnStart()) {
80 80 log.info("[{}] Fetching alarm rule state", ctx.getSelfId());
... ... @@ -108,7 +108,7 @@ public class TbDeviceProfileNode implements TbNode {
108 108 public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException {
109 109 EntityType originatorType = msg.getOriginator().getEntityType();
110 110 if (msg.getType().equals(PERIODIC_MSG_TYPE)) {
111   - scheduleAlarmHarvesting(ctx);
  111 + scheduleAlarmHarvesting(ctx, msg);
112 112 harvestAlarms(ctx, System.currentTimeMillis());
113 113 } else if (msg.getType().equals(PROFILE_UPDATE_MSG_TYPE)) {
114 114 updateProfile(ctx, new DeviceProfileId(UUID.fromString(msg.getData())));
... ... @@ -168,8 +168,8 @@ public class TbDeviceProfileNode implements TbNode {
168 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 173 ctx.tellSelf(periodicCheck, TimeUnit.MINUTES.toMillis(1));
174 174 }
175 175
... ...
... ... @@ -16,10 +16,6 @@
16 16 package org.thingsboard.rule.engine.rpc;
17 17
18 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 19 import com.google.gson.Gson;
24 20 import com.google.gson.JsonElement;
25 21 import com.google.gson.JsonObject;
... ... @@ -116,10 +112,10 @@ public class TbSendRPCRequestNode implements TbNode {
116 112
117 113 ctx.getRpcService().sendRpcRequestToDevice(request, ruleEngineDeviceRpcResponse -> {
118 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 116 ctx.enqueueForTellNext(next, TbRelationTypes.SUCCESS);
121 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 119 ctx.tellFailure(next, new RuntimeException(ruleEngineDeviceRpcResponse.getError().get().name()));
124 120 }
125 121 });
... ...
... ... @@ -76,7 +76,7 @@ public class TbSendSmsNode implements TbNode {
76 76 String message = TbNodeUtils.processPattern(this.config.getSmsMessageTemplate(), msg);
77 77 String[] numbersToList = numbersTo.split(",");
78 78 if (this.config.isUseSystemSmsSettings()) {
79   - ctx.getSmsService().sendSms(ctx.getTenantId(), numbersToList, message);
  79 + ctx.getSmsService().sendSms(ctx.getTenantId(), msg.getCustomerId(), numbersToList, message);
80 80 } else {
81 81 for (String numberTo : numbersToList) {
82 82 this.smsSender.sendSms(numberTo, message);
... ...
... ... @@ -25,6 +25,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
25 25 import org.thingsboard.rule.engine.api.TbNodeException;
26 26 import org.thingsboard.server.common.data.TenantProfile;
27 27 import org.thingsboard.rule.engine.api.util.TbNodeUtils;
  28 +import org.thingsboard.server.common.data.id.CustomerId;
28 29 import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
29 30 import org.thingsboard.server.common.data.kv.KvEntry;
30 31 import org.thingsboard.server.common.data.kv.TsKvEntry;
... ... @@ -93,7 +94,7 @@ public class TbMsgTimeseriesNode implements TbNode {
93 94 if (ttl == 0L) {
94 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 100 public static long getTs(TbMsg msg) {
... ...
... ... @@ -183,7 +183,7 @@ public class TbDeviceProfileNodeTest {
183 183 Mockito.when(alarmService.createOrUpdateAlarm(Mockito.any())).thenAnswer(AdditionalAnswers.returnsFirstArg());
184 184
185 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 188 ObjectNode data = mapper.createObjectNode();
189 189 data.put("temperature", 42);
... ... @@ -195,7 +195,7 @@ public class TbDeviceProfileNodeTest {
195 195 verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any());
196 196
197 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 201 TbMsg msg2 = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(),
... ... @@ -274,7 +274,7 @@ public class TbDeviceProfileNodeTest {
274 274 .thenReturn(attrListListenableFuture);
275 275
276 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 278 .thenReturn(theMsg);
279 279
280 280 ObjectNode data = mapper.createObjectNode();
... ... @@ -361,7 +361,7 @@ public class TbDeviceProfileNodeTest {
361 361 .thenReturn(attrListListenableFuture);
362 362
363 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 365 .thenReturn(theMsg);
366 366
367 367 ObjectNode data = mapper.createObjectNode();
... ... @@ -430,7 +430,7 @@ public class TbDeviceProfileNodeTest {
430 430 .thenReturn(listListenableFutureWithLess);
431 431
432 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 434 .thenReturn(theMsg);
435 435
436 436 ObjectNode data = mapper.createObjectNode();
... ... @@ -510,7 +510,7 @@ public class TbDeviceProfileNodeTest {
510 510 .thenReturn(optionalListenableFutureWithLess);
511 511
512 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 514 .thenReturn(theMsg);
515 515
516 516 ObjectNode data = mapper.createObjectNode();
... ... @@ -584,7 +584,7 @@ public class TbDeviceProfileNodeTest {
584 584 .thenReturn(optionalListenableFutureWithLess);
585 585
586 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 588 .thenReturn(theMsg);
589 589
590 590 ObjectNode data = mapper.createObjectNode();
... ... @@ -668,7 +668,7 @@ public class TbDeviceProfileNodeTest {
668 668 .thenReturn(optionalListenableFutureWithLess);
669 669
670 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 672 .thenReturn(theMsg);
673 673
674 674 ObjectNode data = mapper.createObjectNode();
... ... @@ -754,7 +754,7 @@ public class TbDeviceProfileNodeTest {
754 754 .thenReturn(optionalListenableFutureWithLess);
755 755
756 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 758 .thenReturn(theMsg);
759 759
760 760 ObjectNode data = mapper.createObjectNode();
... ...