Showing
25 changed files
with
130 additions
and
33 deletions
@@ -73,7 +73,7 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService; | @@ -73,7 +73,7 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService; | ||
73 | import org.thingsboard.server.service.executors.SharedEventLoopGroupService; | 73 | import org.thingsboard.server.service.executors.SharedEventLoopGroupService; |
74 | import org.thingsboard.server.service.mail.MailExecutorService; | 74 | import org.thingsboard.server.service.mail.MailExecutorService; |
75 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; | 75 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
76 | -import org.thingsboard.server.service.profile.TbTenantProfileCache; | 76 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
77 | import org.thingsboard.server.service.queue.TbClusterService; | 77 | import org.thingsboard.server.service.queue.TbClusterService; |
78 | import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; | 78 | import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; |
79 | import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; | 79 | import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; |
@@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.Tenant; | @@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.Tenant; | ||
30 | import org.thingsboard.server.common.data.TenantProfile; | 30 | import org.thingsboard.server.common.data.TenantProfile; |
31 | import org.thingsboard.server.common.data.id.EntityId; | 31 | import org.thingsboard.server.common.data.id.EntityId; |
32 | import org.thingsboard.server.common.data.id.TenantId; | 32 | import org.thingsboard.server.common.data.id.TenantId; |
33 | -import org.thingsboard.server.common.data.id.TenantProfileId; | ||
34 | import org.thingsboard.server.common.data.page.PageDataIterable; | 33 | import org.thingsboard.server.common.data.page.PageDataIterable; |
35 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | 34 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
36 | import org.thingsboard.server.common.msg.MsgType; | 35 | import org.thingsboard.server.common.msg.MsgType; |
@@ -41,7 +40,7 @@ import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; | @@ -41,7 +40,7 @@ import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; | ||
41 | import org.thingsboard.server.common.msg.queue.RuleEngineException; | 40 | import org.thingsboard.server.common.msg.queue.RuleEngineException; |
42 | import org.thingsboard.server.common.msg.queue.ServiceType; | 41 | import org.thingsboard.server.common.msg.queue.ServiceType; |
43 | import org.thingsboard.server.dao.tenant.TenantService; | 42 | import org.thingsboard.server.dao.tenant.TenantService; |
44 | -import org.thingsboard.server.service.profile.TbTenantProfileCache; | 43 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
45 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | 44 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
46 | 45 | ||
47 | import java.util.HashSet; | 46 | import java.util.HashSet; |
@@ -35,7 +35,6 @@ import org.thingsboard.server.common.data.asset.AssetInfo; | @@ -35,7 +35,6 @@ import org.thingsboard.server.common.data.asset.AssetInfo; | ||
35 | import org.thingsboard.server.common.data.audit.ActionType; | 35 | import org.thingsboard.server.common.data.audit.ActionType; |
36 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | 36 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
37 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 37 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
38 | -import org.thingsboard.server.common.data.id.*; | ||
39 | import org.thingsboard.server.common.data.id.AlarmId; | 38 | import org.thingsboard.server.common.data.id.AlarmId; |
40 | import org.thingsboard.server.common.data.id.AssetId; | 39 | import org.thingsboard.server.common.data.id.AssetId; |
41 | import org.thingsboard.server.common.data.id.CustomerId; | 40 | import org.thingsboard.server.common.data.id.CustomerId; |
@@ -94,7 +93,7 @@ import org.thingsboard.server.queue.provider.TbQueueProducerProvider; | @@ -94,7 +93,7 @@ import org.thingsboard.server.queue.provider.TbQueueProducerProvider; | ||
94 | import org.thingsboard.server.queue.util.TbCoreComponent; | 93 | import org.thingsboard.server.queue.util.TbCoreComponent; |
95 | import org.thingsboard.server.service.component.ComponentDiscoveryService; | 94 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
96 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; | 95 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
97 | -import org.thingsboard.server.service.profile.TbTenantProfileCache; | 96 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
98 | import org.thingsboard.server.service.queue.TbClusterService; | 97 | import org.thingsboard.server.service.queue.TbClusterService; |
99 | import org.thingsboard.server.service.security.model.SecurityUser; | 98 | import org.thingsboard.server.service.security.model.SecurityUser; |
100 | import org.thingsboard.server.service.security.permission.AccessControlService; | 99 | import org.thingsboard.server.service.security.permission.AccessControlService; |
@@ -392,6 +392,11 @@ public class TelemetryController extends BaseController { | @@ -392,6 +392,11 @@ public class TelemetryController extends BaseController { | ||
392 | if (attributes.isEmpty()) { | 392 | if (attributes.isEmpty()) { |
393 | return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST); | 393 | return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST); |
394 | } | 394 | } |
395 | + for (AttributeKvEntry attributeKvEntry: attributes) { | ||
396 | + if (attributeKvEntry.getKey().isEmpty() || attributeKvEntry.getKey().trim().length() == 0) { | ||
397 | + return getImmediateDeferredResult("Key cannot be empty or contains only spaces", HttpStatus.BAD_REQUEST); | ||
398 | + } | ||
399 | + } | ||
395 | SecurityUser user = getCurrentUser(); | 400 | SecurityUser user = getCurrentUser(); |
396 | return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.WRITE_ATTRIBUTES, entityIdSrc, (result, tenantId, entityId) -> { | 401 | return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.WRITE_ATTRIBUTES, entityIdSrc, (result, tenantId, entityId) -> { |
397 | tsSubService.saveAndNotify(tenantId, entityId, scope, attributes, new FutureCallback<Void>() { | 402 | tsSubService.saveAndNotify(tenantId, entityId, scope, attributes, new FutureCallback<Void>() { |
application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java
@@ -55,7 +55,7 @@ import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | @@ -55,7 +55,7 @@ import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | ||
55 | import org.thingsboard.server.queue.discovery.PartitionService; | 55 | import org.thingsboard.server.queue.discovery.PartitionService; |
56 | import org.thingsboard.server.queue.scheduler.SchedulerComponent; | 56 | import org.thingsboard.server.queue.scheduler.SchedulerComponent; |
57 | import org.thingsboard.server.queue.util.TbCoreComponent; | 57 | import org.thingsboard.server.queue.util.TbCoreComponent; |
58 | -import org.thingsboard.server.service.profile.TbTenantProfileCache; | 58 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
59 | import org.thingsboard.server.service.queue.TbClusterService; | 59 | import org.thingsboard.server.service.queue.TbClusterService; |
60 | import org.thingsboard.server.service.telemetry.InternalTelemetryService; | 60 | import org.thingsboard.server.service.telemetry.InternalTelemetryService; |
61 | 61 |
@@ -55,7 +55,7 @@ import org.thingsboard.server.queue.provider.TbCoreQueueFactory; | @@ -55,7 +55,7 @@ import org.thingsboard.server.queue.provider.TbCoreQueueFactory; | ||
55 | import org.thingsboard.server.queue.util.TbCoreComponent; | 55 | import org.thingsboard.server.queue.util.TbCoreComponent; |
56 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | 56 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; |
57 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; | 57 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
58 | -import org.thingsboard.server.service.profile.TbTenantProfileCache; | 58 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
59 | import org.thingsboard.server.service.queue.processing.AbstractConsumerService; | 59 | import org.thingsboard.server.service.queue.processing.AbstractConsumerService; |
60 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; | 60 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; |
61 | import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; | 61 | import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; |
@@ -45,7 +45,7 @@ import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; | @@ -45,7 +45,7 @@ import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; | ||
45 | import org.thingsboard.server.queue.util.TbRuleEngineComponent; | 45 | import org.thingsboard.server.queue.util.TbRuleEngineComponent; |
46 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | 46 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; |
47 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; | 47 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
48 | -import org.thingsboard.server.service.profile.TbTenantProfileCache; | 48 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
49 | import org.thingsboard.server.service.queue.processing.AbstractConsumerService; | 49 | import org.thingsboard.server.service.queue.processing.AbstractConsumerService; |
50 | import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingDecision; | 50 | import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingDecision; |
51 | import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult; | 51 | import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult; |
@@ -21,11 +21,10 @@ import org.springframework.stereotype.Service; | @@ -21,11 +21,10 @@ import org.springframework.stereotype.Service; | ||
21 | import org.thingsboard.server.common.data.Tenant; | 21 | import org.thingsboard.server.common.data.Tenant; |
22 | import org.thingsboard.server.common.data.TenantProfile; | 22 | import org.thingsboard.server.common.data.TenantProfile; |
23 | import org.thingsboard.server.common.data.id.TenantId; | 23 | import org.thingsboard.server.common.data.id.TenantId; |
24 | -import org.thingsboard.server.dao.tenant.TenantProfileService; | ||
25 | import org.thingsboard.server.dao.tenant.TenantService; | 24 | import org.thingsboard.server.dao.tenant.TenantService; |
26 | import org.thingsboard.server.queue.discovery.TenantRoutingInfo; | 25 | import org.thingsboard.server.queue.discovery.TenantRoutingInfo; |
27 | import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; | 26 | import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; |
28 | -import org.thingsboard.server.service.profile.TbTenantProfileCache; | 27 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
29 | 28 | ||
30 | @Slf4j | 29 | @Slf4j |
31 | @Service | 30 | @Service |
@@ -38,7 +38,7 @@ import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | @@ -38,7 +38,7 @@ import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | ||
38 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | 38 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; |
39 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | 39 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; |
40 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; | 40 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
41 | -import org.thingsboard.server.service.profile.TbTenantProfileCache; | 41 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
42 | import org.thingsboard.server.service.queue.TbPackCallback; | 42 | import org.thingsboard.server.service.queue.TbPackCallback; |
43 | import org.thingsboard.server.service.queue.TbPackProcessingContext; | 43 | import org.thingsboard.server.service.queue.TbPackProcessingContext; |
44 | 44 |
@@ -71,7 +71,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionFailedException; | @@ -71,7 +71,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionFailedException; | ||
71 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | 71 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; |
72 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; | 72 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
73 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; | 73 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
74 | -import org.thingsboard.server.service.profile.TbTenantProfileCache; | 74 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
75 | import org.thingsboard.server.service.queue.TbClusterService; | 75 | import org.thingsboard.server.service.queue.TbClusterService; |
76 | import org.thingsboard.server.service.state.DeviceStateService; | 76 | import org.thingsboard.server.service.state.DeviceStateService; |
77 | 77 |
common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TbTenantProfileCache.java
renamed from
application/src/main/java/org/thingsboard/server/service/profile/TbTenantProfileCache.java
@@ -13,7 +13,7 @@ | @@ -13,7 +13,7 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.service.profile; | 16 | +package org.thingsboard.server.dao.tenant; |
17 | 17 | ||
18 | import org.thingsboard.server.common.data.TenantProfile; | 18 | import org.thingsboard.server.common.data.TenantProfile; |
19 | import org.thingsboard.server.common.data.id.TenantId; | 19 | import org.thingsboard.server.common.data.id.TenantId; |
@@ -87,8 +87,9 @@ public class TbAwsSqsProducerTemplate<T extends TbQueueMsg> implements TbQueuePr | @@ -87,8 +87,9 @@ public class TbAwsSqsProducerTemplate<T extends TbQueueMsg> implements TbQueuePr | ||
87 | sendMsgRequest.withQueueUrl(getQueueUrl(tpi.getFullTopicName())); | 87 | sendMsgRequest.withQueueUrl(getQueueUrl(tpi.getFullTopicName())); |
88 | sendMsgRequest.withMessageBody(gson.toJson(new DefaultTbQueueMsg(msg))); | 88 | sendMsgRequest.withMessageBody(gson.toJson(new DefaultTbQueueMsg(msg))); |
89 | 89 | ||
90 | - sendMsgRequest.withMessageGroupId(tpi.getTopic()); | ||
91 | - sendMsgRequest.withMessageDeduplicationId(UUID.randomUUID().toString()); | 90 | + String sqsMsgId = UUID.randomUUID().toString(); |
91 | + sendMsgRequest.withMessageGroupId(sqsMsgId); | ||
92 | + sendMsgRequest.withMessageDeduplicationId(sqsMsgId); | ||
92 | 93 | ||
93 | ListenableFuture<SendMessageResult> future = producerExecutor.submit(() -> sqsClient.sendMessage(sendMsgRequest)); | 94 | ListenableFuture<SendMessageResult> future = producerExecutor.submit(() -> sqsClient.sendMessage(sendMsgRequest)); |
94 | 95 |
@@ -122,7 +122,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -122,7 +122,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
122 | log.trace("[{}] Processing msg: {}", sessionId, msg); | 122 | log.trace("[{}] Processing msg: {}", sessionId, msg); |
123 | try { | 123 | try { |
124 | if (msg instanceof MqttMessage) { | 124 | if (msg instanceof MqttMessage) { |
125 | - processMqttMsg(ctx, (MqttMessage) msg); | 125 | + MqttMessage message = (MqttMessage) msg; |
126 | + if (message.decoderResult().isSuccess()) { | ||
127 | + processMqttMsg(ctx, message); | ||
128 | + } else { | ||
129 | + log.error("[{}] Message processing failed: {}", sessionId, message.decoderResult().cause().getMessage()); | ||
130 | + ctx.close(); | ||
131 | + } | ||
126 | } else { | 132 | } else { |
127 | ctx.close(); | 133 | ctx.close(); |
128 | } | 134 | } |
@@ -166,4 +166,6 @@ public interface AssetDao extends Dao<Asset> { | @@ -166,4 +166,6 @@ public interface AssetDao extends Dao<Asset> { | ||
166 | */ | 166 | */ |
167 | ListenableFuture<List<EntitySubtype>> findTenantAssetTypesAsync(UUID tenantId); | 167 | ListenableFuture<List<EntitySubtype>> findTenantAssetTypesAsync(UUID tenantId); |
168 | 168 | ||
169 | + Long countAssetsByTenantId(TenantId tenantId); | ||
170 | + | ||
169 | } | 171 | } |
@@ -26,6 +26,7 @@ import org.springframework.cache.Cache; | @@ -26,6 +26,7 @@ import org.springframework.cache.Cache; | ||
26 | import org.springframework.cache.CacheManager; | 26 | import org.springframework.cache.CacheManager; |
27 | import org.springframework.cache.annotation.CacheEvict; | 27 | import org.springframework.cache.annotation.CacheEvict; |
28 | import org.springframework.cache.annotation.Cacheable; | 28 | import org.springframework.cache.annotation.Cacheable; |
29 | +import org.springframework.context.annotation.Lazy; | ||
29 | import org.springframework.stereotype.Service; | 30 | import org.springframework.stereotype.Service; |
30 | import org.springframework.util.StringUtils; | 31 | import org.springframework.util.StringUtils; |
31 | import org.thingsboard.server.common.data.Customer; | 32 | import org.thingsboard.server.common.data.Customer; |
@@ -44,12 +45,14 @@ import org.thingsboard.server.common.data.page.PageData; | @@ -44,12 +45,14 @@ import org.thingsboard.server.common.data.page.PageData; | ||
44 | import org.thingsboard.server.common.data.page.PageLink; | 45 | import org.thingsboard.server.common.data.page.PageLink; |
45 | import org.thingsboard.server.common.data.relation.EntityRelation; | 46 | import org.thingsboard.server.common.data.relation.EntityRelation; |
46 | import org.thingsboard.server.common.data.relation.EntitySearchDirection; | 47 | import org.thingsboard.server.common.data.relation.EntitySearchDirection; |
48 | +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; | ||
47 | import org.thingsboard.server.dao.customer.CustomerDao; | 49 | import org.thingsboard.server.dao.customer.CustomerDao; |
48 | import org.thingsboard.server.dao.entity.AbstractEntityService; | 50 | import org.thingsboard.server.dao.entity.AbstractEntityService; |
49 | import org.thingsboard.server.dao.entityview.EntityViewService; | 51 | import org.thingsboard.server.dao.entityview.EntityViewService; |
50 | import org.thingsboard.server.dao.exception.DataValidationException; | 52 | import org.thingsboard.server.dao.exception.DataValidationException; |
51 | import org.thingsboard.server.dao.service.DataValidator; | 53 | import org.thingsboard.server.dao.service.DataValidator; |
52 | import org.thingsboard.server.dao.service.PaginatedRemover; | 54 | import org.thingsboard.server.dao.service.PaginatedRemover; |
55 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | ||
53 | import org.thingsboard.server.dao.tenant.TenantDao; | 56 | import org.thingsboard.server.dao.tenant.TenantDao; |
54 | 57 | ||
55 | import java.util.ArrayList; | 58 | import java.util.ArrayList; |
@@ -90,6 +93,10 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ | @@ -90,6 +93,10 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ | ||
90 | @Autowired | 93 | @Autowired |
91 | private CacheManager cacheManager; | 94 | private CacheManager cacheManager; |
92 | 95 | ||
96 | + @Autowired | ||
97 | + @Lazy | ||
98 | + private TbTenantProfileCache tenantProfileCache; | ||
99 | + | ||
93 | @Override | 100 | @Override |
94 | public AssetInfo findAssetInfoById(TenantId tenantId, AssetId assetId) { | 101 | public AssetInfo findAssetInfoById(TenantId tenantId, AssetId assetId) { |
95 | log.trace("Executing findAssetInfoById [{}]", assetId); | 102 | log.trace("Executing findAssetInfoById [{}]", assetId); |
@@ -320,6 +327,15 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ | @@ -320,6 +327,15 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ | ||
320 | 327 | ||
321 | @Override | 328 | @Override |
322 | protected void validateCreate(TenantId tenantId, Asset asset) { | 329 | protected void validateCreate(TenantId tenantId, Asset asset) { |
330 | + DefaultTenantProfileConfiguration profileConfiguration = | ||
331 | + (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); | ||
332 | + long maxAssets = profileConfiguration.getMaxAssets(); | ||
333 | + if (maxAssets > 0) { | ||
334 | + long currentAssetsCount = assetDao.countAssetsByTenantId(tenantId); | ||
335 | + if (maxAssets >= currentAssetsCount) { | ||
336 | + throw new DataValidationException("Can't create assets more then " + maxAssets); | ||
337 | + } | ||
338 | + } | ||
323 | } | 339 | } |
324 | 340 | ||
325 | @Override | 341 | @Override |
@@ -203,6 +203,8 @@ public interface DeviceDao extends Dao<Device> { | @@ -203,6 +203,8 @@ public interface DeviceDao extends Dao<Device> { | ||
203 | */ | 203 | */ |
204 | ListenableFuture<Device> findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id); | 204 | ListenableFuture<Device> findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id); |
205 | 205 | ||
206 | + Long countDevicesByTenantId(TenantId tenantId); | ||
207 | + | ||
206 | Long countDevicesByDeviceProfileId(TenantId tenantId, UUID deviceProfileId); | 208 | Long countDevicesByDeviceProfileId(TenantId tenantId, UUID deviceProfileId); |
207 | 209 | ||
208 | /** | 210 | /** |
@@ -27,6 +27,7 @@ import org.springframework.cache.Cache; | @@ -27,6 +27,7 @@ import org.springframework.cache.Cache; | ||
27 | import org.springframework.cache.CacheManager; | 27 | import org.springframework.cache.CacheManager; |
28 | import org.springframework.cache.annotation.CacheEvict; | 28 | import org.springframework.cache.annotation.CacheEvict; |
29 | import org.springframework.cache.annotation.Cacheable; | 29 | import org.springframework.cache.annotation.Cacheable; |
30 | +import org.springframework.context.annotation.Lazy; | ||
30 | import org.springframework.stereotype.Service; | 31 | import org.springframework.stereotype.Service; |
31 | import org.springframework.transaction.annotation.Transactional; | 32 | import org.springframework.transaction.annotation.Transactional; |
32 | import org.springframework.util.CollectionUtils; | 33 | import org.springframework.util.CollectionUtils; |
@@ -57,6 +58,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; | @@ -57,6 +58,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; | ||
57 | import org.thingsboard.server.common.data.relation.EntitySearchDirection; | 58 | import org.thingsboard.server.common.data.relation.EntitySearchDirection; |
58 | import org.thingsboard.server.common.data.security.DeviceCredentials; | 59 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
59 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; | 60 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
61 | +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; | ||
60 | import org.thingsboard.server.dao.customer.CustomerDao; | 62 | import org.thingsboard.server.dao.customer.CustomerDao; |
61 | import org.thingsboard.server.dao.device.provision.ProvisionFailedException; | 63 | import org.thingsboard.server.dao.device.provision.ProvisionFailedException; |
62 | import org.thingsboard.server.dao.device.provision.ProvisionRequest; | 64 | import org.thingsboard.server.dao.device.provision.ProvisionRequest; |
@@ -67,6 +69,7 @@ import org.thingsboard.server.dao.event.EventService; | @@ -67,6 +69,7 @@ import org.thingsboard.server.dao.event.EventService; | ||
67 | import org.thingsboard.server.dao.exception.DataValidationException; | 69 | import org.thingsboard.server.dao.exception.DataValidationException; |
68 | import org.thingsboard.server.dao.service.DataValidator; | 70 | import org.thingsboard.server.dao.service.DataValidator; |
69 | import org.thingsboard.server.dao.service.PaginatedRemover; | 71 | import org.thingsboard.server.dao.service.PaginatedRemover; |
72 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | ||
70 | import org.thingsboard.server.dao.tenant.TenantDao; | 73 | import org.thingsboard.server.dao.tenant.TenantDao; |
71 | import org.thingsboard.server.dao.util.mapping.JacksonUtil; | 74 | import org.thingsboard.server.dao.util.mapping.JacksonUtil; |
72 | 75 | ||
@@ -120,6 +123,10 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | @@ -120,6 +123,10 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | ||
120 | @Autowired | 123 | @Autowired |
121 | private EventService eventService; | 124 | private EventService eventService; |
122 | 125 | ||
126 | + @Autowired | ||
127 | + @Lazy | ||
128 | + private TbTenantProfileCache tenantProfileCache; | ||
129 | + | ||
123 | @Override | 130 | @Override |
124 | public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) { | 131 | public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) { |
125 | log.trace("Executing findDeviceInfoById [{}]", deviceId); | 132 | log.trace("Executing findDeviceInfoById [{}]", deviceId); |
@@ -520,6 +527,15 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | @@ -520,6 +527,15 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | ||
520 | 527 | ||
521 | @Override | 528 | @Override |
522 | protected void validateCreate(TenantId tenantId, Device device) { | 529 | protected void validateCreate(TenantId tenantId, Device device) { |
530 | + DefaultTenantProfileConfiguration profileConfiguration = | ||
531 | + (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); | ||
532 | + long maxDevices = profileConfiguration.getMaxDevices(); | ||
533 | + if (maxDevices > 0) { | ||
534 | + long currentDevicesCount = deviceDao.countDevicesByTenantId(tenantId); | ||
535 | + if (maxDevices >= currentDevicesCount) { | ||
536 | + throw new DataValidationException("Can't create devices more then " + maxDevices); | ||
537 | + } | ||
538 | + } | ||
523 | } | 539 | } |
524 | 540 | ||
525 | @Override | 541 | @Override |
@@ -532,7 +548,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | @@ -532,7 +548,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | ||
532 | 548 | ||
533 | @Override | 549 | @Override |
534 | protected void validateDataImpl(TenantId tenantId, Device device) { | 550 | protected void validateDataImpl(TenantId tenantId, Device device) { |
535 | - if (StringUtils.isEmpty(device.getName())) { | 551 | + if (StringUtils.isEmpty(device.getName()) || device.getName().trim().length() == 0) { |
536 | throw new DataValidationException("Device name should be specified!"); | 552 | throw new DataValidationException("Device name should be specified!"); |
537 | } | 553 | } |
538 | if (device.getTenantId() == null) { | 554 | if (device.getTenantId() == null) { |
@@ -122,4 +122,5 @@ public interface AssetRepository extends PagingAndSortingRepository<AssetEntity, | @@ -122,4 +122,5 @@ public interface AssetRepository extends PagingAndSortingRepository<AssetEntity, | ||
122 | @Query("SELECT DISTINCT a.type FROM AssetEntity a WHERE a.tenantId = :tenantId") | 122 | @Query("SELECT DISTINCT a.type FROM AssetEntity a WHERE a.tenantId = :tenantId") |
123 | List<String> findTenantAssetTypes(@Param("tenantId") UUID tenantId); | 123 | List<String> findTenantAssetTypes(@Param("tenantId") UUID tenantId); |
124 | 124 | ||
125 | + Long countByTenantId(UUID tenantId); | ||
125 | } | 126 | } |
@@ -176,4 +176,10 @@ public class JpaAssetDao extends JpaAbstractSearchTextDao<AssetEntity, Asset> im | @@ -176,4 +176,10 @@ public class JpaAssetDao extends JpaAbstractSearchTextDao<AssetEntity, Asset> im | ||
176 | } | 176 | } |
177 | return list; | 177 | return list; |
178 | } | 178 | } |
179 | + | ||
180 | + @Override | ||
181 | + public Long countAssetsByTenantId(TenantId tenantId) { | ||
182 | + return assetRepository.countByTenantId(tenantId.getId()); | ||
183 | + | ||
184 | + } | ||
179 | } | 185 | } |
@@ -168,4 +168,6 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit | @@ -168,4 +168,6 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit | ||
168 | DeviceEntity findByTenantIdAndId(UUID tenantId, UUID id); | 168 | DeviceEntity findByTenantIdAndId(UUID tenantId, UUID id); |
169 | 169 | ||
170 | Long countByDeviceProfileId(UUID deviceProfileId); | 170 | Long countByDeviceProfileId(UUID deviceProfileId); |
171 | + | ||
172 | + Long countByTenantId(UUID tenantId); | ||
171 | } | 173 | } |
@@ -219,6 +219,11 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> | @@ -219,6 +219,11 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> | ||
219 | return deviceRepository.countByDeviceProfileId(deviceProfileId); | 219 | return deviceRepository.countByDeviceProfileId(deviceProfileId); |
220 | } | 220 | } |
221 | 221 | ||
222 | + @Override | ||
223 | + public Long countDevicesByTenantId(TenantId tenantId) { | ||
224 | + return deviceRepository.countByTenantId(tenantId.getId()); | ||
225 | + } | ||
226 | + | ||
222 | private List<EntitySubtype> convertTenantDeviceTypesToDto(UUID tenantId, List<String> types) { | 227 | private List<EntitySubtype> convertTenantDeviceTypesToDto(UUID tenantId, List<String> types) { |
223 | List<EntitySubtype> list = Collections.emptyList(); | 228 | List<EntitySubtype> list = Collections.emptyList(); |
224 | if (types != null && !types.isEmpty()) { | 229 | if (types != null && !types.isEmpty()) { |
dao/src/main/java/org/thingsboard/server/dao/tenant/DefaultTbTenantProfileCache.java
renamed from
application/src/main/java/org/thingsboard/server/service/profile/DefaultTbTenantProfileCache.java
@@ -13,20 +13,15 @@ | @@ -13,20 +13,15 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.service.profile; | 16 | +package org.thingsboard.server.dao.tenant; |
17 | 17 | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | import org.springframework.stereotype.Service; | 19 | import org.springframework.stereotype.Service; |
20 | -import org.thingsboard.server.common.data.Device; | ||
21 | -import org.thingsboard.server.common.data.DeviceProfile; | ||
22 | import org.thingsboard.server.common.data.Tenant; | 20 | import org.thingsboard.server.common.data.Tenant; |
23 | import org.thingsboard.server.common.data.TenantProfile; | 21 | import org.thingsboard.server.common.data.TenantProfile; |
24 | -import org.thingsboard.server.common.data.id.DeviceId; | ||
25 | -import org.thingsboard.server.common.data.id.DeviceProfileId; | ||
26 | import org.thingsboard.server.common.data.id.TenantId; | 22 | import org.thingsboard.server.common.data.id.TenantId; |
27 | import org.thingsboard.server.common.data.id.TenantProfileId; | 23 | import org.thingsboard.server.common.data.id.TenantProfileId; |
28 | -import org.thingsboard.server.dao.device.DeviceProfileService; | ||
29 | -import org.thingsboard.server.dao.device.DeviceService; | 24 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
30 | import org.thingsboard.server.dao.tenant.TenantProfileService; | 25 | import org.thingsboard.server.dao.tenant.TenantProfileService; |
31 | import org.thingsboard.server.dao.tenant.TenantService; | 26 | import org.thingsboard.server.dao.tenant.TenantService; |
32 | 27 |
@@ -52,11 +52,13 @@ function AwsSqsProducer() { | @@ -52,11 +52,13 @@ function AwsSqsProducer() { | ||
52 | queueUrls.set(responseTopic, responseQueueUrl); | 52 | queueUrls.set(responseTopic, responseQueueUrl); |
53 | } | 53 | } |
54 | 54 | ||
55 | + let msgId = uuid(); | ||
56 | + | ||
55 | let params = { | 57 | let params = { |
56 | MessageBody: msgBody, | 58 | MessageBody: msgBody, |
57 | QueueUrl: responseQueueUrl, | 59 | QueueUrl: responseQueueUrl, |
58 | - MessageGroupId: 'js_eval', | ||
59 | - MessageDeduplicationId: uuid() | 60 | + MessageGroupId: msgId, |
61 | + MessageDeduplicationId: msgId | ||
60 | }; | 62 | }; |
61 | 63 | ||
62 | return new Promise((resolve, reject) => { | 64 | return new Promise((resolve, reject) => { |
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | package org.thingsboard.rule.engine.profile; | 16 | package org.thingsboard.rule.engine.profile; |
17 | 17 | ||
18 | import com.fasterxml.jackson.databind.JsonNode; | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
19 | import lombok.Data; | 20 | import lombok.Data; |
20 | import lombok.extern.slf4j.Slf4j; | 21 | import lombok.extern.slf4j.Slf4j; |
21 | import org.thingsboard.rule.engine.action.TbAlarmResult; | 22 | import org.thingsboard.rule.engine.action.TbAlarmResult; |
@@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; | @@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; | ||
29 | import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; | 30 | import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; |
30 | import org.thingsboard.server.common.data.id.EntityId; | 31 | import org.thingsboard.server.common.data.id.EntityId; |
31 | import org.thingsboard.server.common.data.query.EntityKeyType; | 32 | import org.thingsboard.server.common.data.query.EntityKeyType; |
33 | +import org.thingsboard.server.common.data.query.KeyFilter; | ||
32 | import org.thingsboard.server.common.msg.TbMsg; | 34 | import org.thingsboard.server.common.msg.TbMsg; |
33 | import org.thingsboard.server.common.msg.TbMsgMetaData; | 35 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
34 | import org.thingsboard.server.common.msg.queue.ServiceQueue; | 36 | import org.thingsboard.server.common.msg.queue.ServiceQueue; |
@@ -53,6 +55,7 @@ class AlarmState { | @@ -53,6 +55,7 @@ class AlarmState { | ||
53 | private volatile boolean initialFetchDone; | 55 | private volatile boolean initialFetchDone; |
54 | private volatile TbMsgMetaData lastMsgMetaData; | 56 | private volatile TbMsgMetaData lastMsgMetaData; |
55 | private volatile String lastMsgQueueName; | 57 | private volatile String lastMsgQueueName; |
58 | + private volatile DataSnapshot dataSnapshot; | ||
56 | 59 | ||
57 | AlarmState(ProfileState deviceProfile, EntityId originator, DeviceProfileAlarm alarmDefinition, PersistedAlarmState alarmState) { | 60 | AlarmState(ProfileState deviceProfile, EntityId originator, DeviceProfileAlarm alarmDefinition, PersistedAlarmState alarmState) { |
58 | this.deviceProfile = deviceProfile; | 61 | this.deviceProfile = deviceProfile; |
@@ -74,7 +77,7 @@ class AlarmState { | @@ -74,7 +77,7 @@ class AlarmState { | ||
74 | 77 | ||
75 | public <T> boolean createOrClearAlarms(TbContext ctx, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, AlarmEvalResult> evalFunction) { | 78 | public <T> boolean createOrClearAlarms(TbContext ctx, T data, SnapshotUpdate update, BiFunction<AlarmRuleState, T, AlarmEvalResult> evalFunction) { |
76 | boolean stateUpdate = false; | 79 | boolean stateUpdate = false; |
77 | - AlarmSeverity resultSeverity = null; | 80 | + AlarmRuleState resultState = null; |
78 | log.debug("[{}] processing update: {}", alarmDefinition.getId(), data); | 81 | log.debug("[{}] processing update: {}", alarmDefinition.getId(), data); |
79 | for (AlarmRuleState state : createRulesSortedBySeverityDesc) { | 82 | for (AlarmRuleState state : createRulesSortedBySeverityDesc) { |
80 | if (!validateUpdate(update, state)) { | 83 | if (!validateUpdate(update, state)) { |
@@ -84,15 +87,15 @@ class AlarmState { | @@ -84,15 +87,15 @@ class AlarmState { | ||
84 | AlarmEvalResult evalResult = evalFunction.apply(state, data); | 87 | AlarmEvalResult evalResult = evalFunction.apply(state, data); |
85 | stateUpdate |= state.checkUpdate(); | 88 | stateUpdate |= state.checkUpdate(); |
86 | if (AlarmEvalResult.TRUE.equals(evalResult)) { | 89 | if (AlarmEvalResult.TRUE.equals(evalResult)) { |
87 | - resultSeverity = state.getSeverity(); | 90 | + resultState = state; |
88 | break; | 91 | break; |
89 | } else if (AlarmEvalResult.FALSE.equals(evalResult)) { | 92 | } else if (AlarmEvalResult.FALSE.equals(evalResult)) { |
90 | state.clear(); | 93 | state.clear(); |
91 | stateUpdate |= state.checkUpdate(); | 94 | stateUpdate |= state.checkUpdate(); |
92 | } | 95 | } |
93 | } | 96 | } |
94 | - if (resultSeverity != null) { | ||
95 | - TbAlarmResult result = calculateAlarmResult(ctx, resultSeverity); | 97 | + if (resultState != null) { |
98 | + TbAlarmResult result = calculateAlarmResult(ctx, resultState); | ||
96 | if (result != null) { | 99 | if (result != null) { |
97 | pushMsg(ctx, result); | 100 | pushMsg(ctx, result); |
98 | } | 101 | } |
@@ -187,7 +190,8 @@ class AlarmState { | @@ -187,7 +190,8 @@ class AlarmState { | ||
187 | } | 190 | } |
188 | } | 191 | } |
189 | 192 | ||
190 | - private TbAlarmResult calculateAlarmResult(TbContext ctx, AlarmSeverity severity) { | 193 | + private <T> TbAlarmResult calculateAlarmResult(TbContext ctx, AlarmRuleState ruleState) { |
194 | + AlarmSeverity severity = ruleState.getSeverity(); | ||
191 | if (currentAlarm != null) { | 195 | if (currentAlarm != null) { |
192 | // TODO: In some extremely rare cases, we might miss the event of alarm clear (If one use in-mem queue and restarted the server) or (if one manipulated the rule chain). | 196 | // TODO: In some extremely rare cases, we might miss the event of alarm clear (If one use in-mem queue and restarted the server) or (if one manipulated the rule chain). |
193 | // Maybe we should fetch alarm every time? | 197 | // Maybe we should fetch alarm every time? |
@@ -213,7 +217,7 @@ class AlarmState { | @@ -213,7 +217,7 @@ class AlarmState { | ||
213 | currentAlarm.setSeverity(severity); | 217 | currentAlarm.setSeverity(severity); |
214 | currentAlarm.setStartTs(System.currentTimeMillis()); | 218 | currentAlarm.setStartTs(System.currentTimeMillis()); |
215 | currentAlarm.setEndTs(currentAlarm.getStartTs()); | 219 | currentAlarm.setEndTs(currentAlarm.getStartTs()); |
216 | - currentAlarm.setDetails(JacksonUtil.OBJECT_MAPPER.createObjectNode()); | 220 | + currentAlarm.setDetails(createDetails(ruleState)); |
217 | currentAlarm.setOriginator(originator); | 221 | currentAlarm.setOriginator(originator); |
218 | currentAlarm.setTenantId(ctx.getTenantId()); | 222 | currentAlarm.setTenantId(ctx.getTenantId()); |
219 | currentAlarm.setPropagate(alarmDefinition.isPropagate()); | 223 | currentAlarm.setPropagate(alarmDefinition.isPropagate()); |
@@ -226,6 +230,44 @@ class AlarmState { | @@ -226,6 +230,44 @@ class AlarmState { | ||
226 | } | 230 | } |
227 | } | 231 | } |
228 | 232 | ||
233 | + private <T> JsonNode createDetails(AlarmRuleState ruleState) { | ||
234 | + ObjectNode details = JacksonUtil.OBJECT_MAPPER.createObjectNode(); | ||
235 | + String alarmDetails = ruleState.getAlarmRule().getAlarmDetails(); | ||
236 | + | ||
237 | + if (alarmDetails != null) { | ||
238 | + for (KeyFilter keyFilter : ruleState.getAlarmRule().getCondition().getCondition()) { | ||
239 | + EntityKeyValue entityKeyValue = dataSnapshot.getValue(keyFilter.getKey()); | ||
240 | + alarmDetails = alarmDetails.replaceAll(String.format("\\$\\{%s}", keyFilter.getKey().getKey()), getValueAsString(entityKeyValue)); | ||
241 | + } | ||
242 | + | ||
243 | + details.put("data", alarmDetails); | ||
244 | + } | ||
245 | + | ||
246 | + return details; | ||
247 | + } | ||
248 | + | ||
249 | + private static String getValueAsString(EntityKeyValue entityKeyValue) { | ||
250 | + Object result = null; | ||
251 | + switch (entityKeyValue.getDataType()) { | ||
252 | + case STRING: | ||
253 | + result = entityKeyValue.getStrValue(); | ||
254 | + break; | ||
255 | + case JSON: | ||
256 | + result = entityKeyValue.getJsonValue(); | ||
257 | + break; | ||
258 | + case LONG: | ||
259 | + result = entityKeyValue.getLngValue(); | ||
260 | + break; | ||
261 | + case DOUBLE: | ||
262 | + result = entityKeyValue.getDblValue(); | ||
263 | + break; | ||
264 | + case BOOLEAN: | ||
265 | + result = entityKeyValue.getBoolValue(); | ||
266 | + break; | ||
267 | + } | ||
268 | + return String.valueOf(result); | ||
269 | + } | ||
270 | + | ||
229 | public boolean processAlarmClear(TbContext ctx, Alarm alarmNf) { | 271 | public boolean processAlarmClear(TbContext ctx, Alarm alarmNf) { |
230 | boolean updated = false; | 272 | boolean updated = false; |
231 | if (currentAlarm != null && currentAlarm.getId().equals(alarmNf.getId())) { | 273 | if (currentAlarm != null && currentAlarm.getId().equals(alarmNf.getId())) { |