Commit 6ea39e835e3203bfb4bcc6d6e6f7cf7e4552d16d

Authored by Andrii Shvaika
1 parent 356d4ff2

Transport Rate Limits are now configurable via Tenant Profile

Showing 30 changed files with 785 additions and 211 deletions
@@ -94,7 +94,8 @@ @@ -94,7 +94,8 @@
94 "name": "Device Profile Node", 94 "name": "Device Profile Node",
95 "debugMode": false, 95 "debugMode": false,
96 "configuration": { 96 "configuration": {
97 - "persistAlarmRulesState": false 97 + "persistAlarmRulesState": false,
  98 + "fetchAlarmRulesStateOnStart": false
98 } 99 }
99 } 100 }
100 ], 101 ],
@@ -92,6 +92,7 @@ public class TenantController extends BaseController { @@ -92,6 +92,7 @@ public class TenantController extends BaseController {
92 installScripts.createDefaultRuleChains(tenant.getId()); 92 installScripts.createDefaultRuleChains(tenant.getId());
93 } 93 }
94 tenantProfileCache.evict(tenant.getId()); 94 tenantProfileCache.evict(tenant.getId());
  95 + tbClusterService.onTenantChange(tenant, null);
95 return tenant; 96 return tenant;
96 } catch (Exception e) { 97 } catch (Exception e) {
97 throw handleException(e); 98 throw handleException(e);
@@ -105,9 +106,10 @@ public class TenantController extends BaseController { @@ -105,9 +106,10 @@ public class TenantController extends BaseController {
105 checkParameter("tenantId", strTenantId); 106 checkParameter("tenantId", strTenantId);
106 try { 107 try {
107 TenantId tenantId = new TenantId(toUUID(strTenantId)); 108 TenantId tenantId = new TenantId(toUUID(strTenantId));
108 - checkTenantId(tenantId, Operation.DELETE); 109 + Tenant tenant = checkTenantId(tenantId, Operation.DELETE);
109 tenantService.deleteTenant(tenantId); 110 tenantService.deleteTenant(tenantId);
110 tenantProfileCache.evict(tenantId); 111 tenantProfileCache.evict(tenantId);
  112 + tbClusterService.onTenantDelete(tenant, null);
111 tbClusterService.onEntityStateChange(tenantId, tenantId, ComponentLifecycleEvent.DELETED); 113 tbClusterService.onEntityStateChange(tenantId, tenantId, ComponentLifecycleEvent.DELETED);
112 } catch (Exception e) { 114 } catch (Exception e) {
113 throw handleException(e); 115 throw handleException(e);
@@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.id.TenantProfileId; @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.id.TenantProfileId;
34 import org.thingsboard.server.common.data.page.PageData; 34 import org.thingsboard.server.common.data.page.PageData;
35 import org.thingsboard.server.common.data.page.PageLink; 35 import org.thingsboard.server.common.data.page.PageLink;
36 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 36 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
  37 +import org.thingsboard.server.dao.exception.DataValidationException;
37 import org.thingsboard.server.queue.util.TbCoreComponent; 38 import org.thingsboard.server.queue.util.TbCoreComponent;
38 import org.thingsboard.server.service.security.permission.Operation; 39 import org.thingsboard.server.service.security.permission.Operation;
39 import org.thingsboard.server.service.security.permission.Resource; 40 import org.thingsboard.server.service.security.permission.Resource;
@@ -96,6 +97,7 @@ public class TenantProfileController extends BaseController { @@ -96,6 +97,7 @@ public class TenantProfileController extends BaseController {
96 97
97 tenantProfile = checkNotNull(tenantProfileService.saveTenantProfile(getTenantId(), tenantProfile)); 98 tenantProfile = checkNotNull(tenantProfileService.saveTenantProfile(getTenantId(), tenantProfile));
98 tenantProfileCache.put(tenantProfile); 99 tenantProfileCache.put(tenantProfile);
  100 + tbClusterService.onTenantProfileChange(tenantProfile, null);
99 tbClusterService.onEntityStateChange(TenantId.SYS_TENANT_ID, tenantProfile.getId(), 101 tbClusterService.onEntityStateChange(TenantId.SYS_TENANT_ID, tenantProfile.getId(),
100 newTenantProfile ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); 102 newTenantProfile ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
101 return tenantProfile; 103 return tenantProfile;
@@ -111,8 +113,9 @@ public class TenantProfileController extends BaseController { @@ -111,8 +113,9 @@ public class TenantProfileController extends BaseController {
111 checkParameter("tenantProfileId", strTenantProfileId); 113 checkParameter("tenantProfileId", strTenantProfileId);
112 try { 114 try {
113 TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId)); 115 TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
114 - checkTenantProfileId(tenantProfileId, Operation.DELETE); 116 + TenantProfile profile = checkTenantProfileId(tenantProfileId, Operation.DELETE);
115 tenantProfileService.deleteTenantProfile(getTenantId(), tenantProfileId); 117 tenantProfileService.deleteTenantProfile(getTenantId(), tenantProfileId);
  118 + tbClusterService.onTenantProfileDelete(profile, null);
116 } catch (Exception e) { 119 } catch (Exception e) {
117 throw handleException(e); 120 throw handleException(e);
118 } 121 }
@@ -61,7 +61,7 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { @@ -61,7 +61,7 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache {
61 profile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId); 61 profile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
62 if (profile != null) { 62 if (profile != null) {
63 deviceProfilesMap.put(deviceProfileId, profile); 63 deviceProfilesMap.put(deviceProfileId, profile);
64 - log.info("[{}] Fetch device profile into cache: {}", profile.getId(), profile); 64 + log.debug("[{}] Fetch device profile into cache: {}", profile.getId(), profile);
65 } 65 }
66 } 66 }
67 } finally { 67 } finally {
@@ -91,7 +91,7 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { @@ -91,7 +91,7 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache {
91 public void put(DeviceProfile profile) { 91 public void put(DeviceProfile profile) {
92 if (profile.getId() != null) { 92 if (profile.getId() != null) {
93 deviceProfilesMap.put(profile.getId(), profile); 93 deviceProfilesMap.put(profile.getId(), profile);
94 - log.info("[{}] pushed device profile to cache: {}", profile.getId(), profile); 94 + log.debug("[{}] pushed device profile to cache: {}", profile.getId(), profile);
95 notifyListeners(profile); 95 notifyListeners(profile);
96 } 96 }
97 } 97 }
@@ -99,7 +99,7 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { @@ -99,7 +99,7 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache {
99 @Override 99 @Override
100 public void evict(TenantId tenantId, DeviceProfileId profileId) { 100 public void evict(TenantId tenantId, DeviceProfileId profileId) {
101 DeviceProfile oldProfile = deviceProfilesMap.remove(profileId); 101 DeviceProfile oldProfile = deviceProfilesMap.remove(profileId);
102 - log.info("[{}] evict device profile from cache: {}", profileId, oldProfile); 102 + log.debug("[{}] evict device profile from cache: {}", profileId, oldProfile);
103 DeviceProfile newProfile = get(tenantId, profileId); 103 DeviceProfile newProfile = get(tenantId, profileId);
104 if (newProfile != null) { 104 if (newProfile != null) {
105 notifyListeners(newProfile); 105 notifyListeners(newProfile);
@@ -117,6 +117,16 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { @@ -117,6 +117,16 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache {
117 } 117 }
118 118
119 @Override 119 @Override
  120 + public DeviceProfile find(DeviceProfileId deviceProfileId) {
  121 + return deviceProfileService.findDeviceProfileById(TenantId.SYS_TENANT_ID, deviceProfileId);
  122 + }
  123 +
  124 + @Override
  125 + public DeviceProfile findOrCreateDeviceProfile(TenantId tenantId, String profileName) {
  126 + return deviceProfileService.findOrCreateDeviceProfile(tenantId, profileName);
  127 + }
  128 +
  129 + @Override
120 public void removeListener(TenantId tenantId, EntityId listenerId) { 130 public void removeListener(TenantId tenantId, EntityId listenerId) {
121 ConcurrentMap<EntityId, Consumer<DeviceProfile>> tenantListeners = listeners.get(tenantId); 131 ConcurrentMap<EntityId, Consumer<DeviceProfile>> tenantListeners = listeners.get(tenantId);
122 if (tenantListeners != null) { 132 if (tenantListeners != null) {
@@ -29,4 +29,7 @@ public interface TbDeviceProfileCache extends RuleEngineDeviceProfileCache { @@ -29,4 +29,7 @@ public interface TbDeviceProfileCache extends RuleEngineDeviceProfileCache {
29 29
30 void evict(DeviceId id); 30 void evict(DeviceId id);
31 31
  32 + DeviceProfile find(DeviceProfileId deviceProfileId);
  33 +
  34 + DeviceProfile findOrCreateDeviceProfile(TenantId tenantId, String deviceType);
32 } 35 }
@@ -23,11 +23,15 @@ import org.springframework.stereotype.Service; @@ -23,11 +23,15 @@ import org.springframework.stereotype.Service;
23 import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg; 23 import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg;
24 import org.thingsboard.server.common.data.DeviceProfile; 24 import org.thingsboard.server.common.data.DeviceProfile;
25 import org.thingsboard.server.common.data.EntityType; 25 import org.thingsboard.server.common.data.EntityType;
  26 +import org.thingsboard.server.common.data.HasName;
  27 +import org.thingsboard.server.common.data.Tenant;
  28 +import org.thingsboard.server.common.data.TenantProfile;
26 import org.thingsboard.server.common.data.id.DeviceId; 29 import org.thingsboard.server.common.data.id.DeviceId;
27 import org.thingsboard.server.common.data.id.DeviceProfileId; 30 import org.thingsboard.server.common.data.id.DeviceProfileId;
28 import org.thingsboard.server.common.data.id.EntityId; 31 import org.thingsboard.server.common.data.id.EntityId;
29 import org.thingsboard.server.common.data.id.RuleChainId; 32 import org.thingsboard.server.common.data.id.RuleChainId;
30 import org.thingsboard.server.common.data.id.TenantId; 33 import org.thingsboard.server.common.data.id.TenantId;
  34 +import org.thingsboard.server.common.data.id.TenantProfileId;
31 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 35 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
32 import org.thingsboard.server.common.msg.TbMsg; 36 import org.thingsboard.server.common.msg.TbMsg;
33 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 37 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
@@ -189,21 +193,51 @@ public class DefaultTbClusterService implements TbClusterService { @@ -189,21 +193,51 @@ public class DefaultTbClusterService implements TbClusterService {
189 193
190 @Override 194 @Override
191 public void onDeviceProfileChange(DeviceProfile deviceProfile, TbQueueCallback callback) { 195 public void onDeviceProfileChange(DeviceProfile deviceProfile, TbQueueCallback callback) {
192 - log.trace("[{}][{}] Processing device profile [{}] change event", deviceProfile.getTenantId(), deviceProfile.getId(), deviceProfile.getName());  
193 - TransportProtos.DeviceProfileUpdateMsg profileUpdateMsg = TransportProtos.DeviceProfileUpdateMsg.newBuilder()  
194 - .setData(ByteString.copyFrom(encodingService.encode(deviceProfile))).build();  
195 - ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setDeviceProfileUpdateMsg(profileUpdateMsg).build();  
196 - broadcast(transportMsg); 196 + onEntityChange(deviceProfile.getTenantId(), deviceProfile.getId(), deviceProfile, callback);
  197 + }
  198 +
  199 + @Override
  200 + public void onTenantProfileChange(TenantProfile tenantProfile, TbQueueCallback callback) {
  201 + onEntityChange(TenantId.SYS_TENANT_ID, tenantProfile.getId(), tenantProfile, callback);
  202 + }
  203 +
  204 + @Override
  205 + public void onTenantChange(Tenant tenant, TbQueueCallback callback) {
  206 + onEntityChange(TenantId.SYS_TENANT_ID, tenant.getId(), tenant, callback);
  207 + }
  208 +
  209 + @Override
  210 + public void onDeviceProfileDelete(DeviceProfile entity, TbQueueCallback callback) {
  211 + onEntityDelete(entity.getTenantId(), entity.getId(), entity.getName(), callback);
197 } 212 }
198 213
199 @Override 214 @Override
200 - public void onDeviceProfileDelete(DeviceProfile deviceProfile, TbQueueCallback callback) {  
201 - log.trace("[{}][{}] Processing device profile [{}] delete event", deviceProfile.getTenantId(), deviceProfile.getId(), deviceProfile.getName());  
202 - TransportProtos.DeviceProfileDeleteMsg profileDeleteMsg = TransportProtos.DeviceProfileDeleteMsg.newBuilder()  
203 - .setProfileIdMSB(deviceProfile.getId().getId().getMostSignificantBits())  
204 - .setProfileIdLSB(deviceProfile.getId().getId().getLeastSignificantBits()) 215 + public void onTenantProfileDelete(TenantProfile entity, TbQueueCallback callback) {
  216 + onEntityDelete(TenantId.SYS_TENANT_ID, entity.getId(), entity.getName(), callback);
  217 + }
  218 +
  219 + @Override
  220 + public void onTenantDelete(Tenant entity, TbQueueCallback callback) {
  221 + onEntityDelete(TenantId.SYS_TENANT_ID, entity.getId(), entity.getName(), callback);
  222 + }
  223 +
  224 + public <T extends HasName> void onEntityChange(TenantId tenantId, EntityId entityid, T entity, TbQueueCallback callback) {
  225 + log.trace("[{}][{}][{}] Processing [{}] change event", tenantId, entityid.getEntityType(), entityid.getId(), entity.getName());
  226 + TransportProtos.EntityUpdateMsg entityUpdateMsg = TransportProtos.EntityUpdateMsg.newBuilder()
  227 + .setEntityType(entityid.getEntityType().name())
  228 + .setData(ByteString.copyFrom(encodingService.encode(entity))).build();
  229 + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setEntityUpdateMsg(entityUpdateMsg).build();
  230 + broadcast(transportMsg);
  231 + }
  232 +
  233 + private void onEntityDelete(TenantId tenantId, EntityId entityId, String name, TbQueueCallback callback) {
  234 + log.trace("[{}][{}][{}] Processing [{}] delete event", tenantId, entityId.getEntityType(), entityId.getId(), name);
  235 + TransportProtos.EntityDeleteMsg entityDeleteMsg = TransportProtos.EntityDeleteMsg.newBuilder()
  236 + .setEntityType(entityId.getEntityType().name())
  237 + .setEntityIdMSB(entityId.getId().getMostSignificantBits())
  238 + .setEntityIdLSB(entityId.getId().getLeastSignificantBits())
205 .build(); 239 .build();
206 - ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setDeviceProfileDeleteMsg(profileDeleteMsg).build(); 240 + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setEntityDeleteMsg(entityDeleteMsg).build();
207 broadcast(transportMsg); 241 broadcast(transportMsg);
208 } 242 }
209 243
@@ -17,7 +17,8 @@ package org.thingsboard.server.service.queue; @@ -17,7 +17,8 @@ package org.thingsboard.server.service.queue;
17 17
18 import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg; 18 import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg;
19 import org.thingsboard.server.common.data.DeviceProfile; 19 import org.thingsboard.server.common.data.DeviceProfile;
20 -import org.thingsboard.server.common.data.id.DeviceProfileId; 20 +import org.thingsboard.server.common.data.Tenant;
  21 +import org.thingsboard.server.common.data.TenantProfile;
21 import org.thingsboard.server.common.data.id.EntityId; 22 import org.thingsboard.server.common.data.id.EntityId;
22 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
23 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 24 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
@@ -53,5 +54,13 @@ public interface TbClusterService { @@ -53,5 +54,13 @@ public interface TbClusterService {
53 54
54 void onDeviceProfileChange(DeviceProfile deviceProfile, TbQueueCallback callback); 55 void onDeviceProfileChange(DeviceProfile deviceProfile, TbQueueCallback callback);
55 56
56 - void onDeviceProfileDelete(DeviceProfile deviceProfileId, TbQueueCallback callback); 57 + void onDeviceProfileDelete(DeviceProfile deviceProfile, TbQueueCallback callback);
  58 +
  59 + void onTenantProfileChange(TenantProfile tenantProfile, TbQueueCallback callback);
  60 +
  61 + void onTenantProfileDelete(TenantProfile tenantProfile, TbQueueCallback callback);
  62 +
  63 + void onTenantChange(Tenant tenant, TbQueueCallback callback);
  64 +
  65 + void onTenantDelete(Tenant tenant, TbQueueCallback callback);
57 } 66 }
@@ -28,6 +28,7 @@ import org.springframework.util.StringUtils; @@ -28,6 +28,7 @@ import org.springframework.util.StringUtils;
28 import org.thingsboard.server.common.data.DataConstants; 28 import org.thingsboard.server.common.data.DataConstants;
29 import org.thingsboard.server.common.data.Device; 29 import org.thingsboard.server.common.data.Device;
30 import org.thingsboard.server.common.data.DeviceProfile; 30 import org.thingsboard.server.common.data.DeviceProfile;
  31 +import org.thingsboard.server.common.data.EntityType;
31 import org.thingsboard.server.common.data.TenantProfile; 32 import org.thingsboard.server.common.data.TenantProfile;
32 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; 33 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
33 import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData; 34 import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData;
@@ -45,21 +46,19 @@ import org.thingsboard.server.common.msg.TbMsgDataType; @@ -45,21 +46,19 @@ import org.thingsboard.server.common.msg.TbMsgDataType;
45 import org.thingsboard.server.common.msg.TbMsgMetaData; 46 import org.thingsboard.server.common.msg.TbMsgMetaData;
46 import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; 47 import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
47 import org.thingsboard.server.dao.device.DeviceCredentialsService; 48 import org.thingsboard.server.dao.device.DeviceCredentialsService;
48 -import org.thingsboard.server.dao.device.DeviceProfileService;  
49 import org.thingsboard.server.dao.device.DeviceProvisionService; 49 import org.thingsboard.server.dao.device.DeviceProvisionService;
50 import org.thingsboard.server.dao.device.DeviceService; 50 import org.thingsboard.server.dao.device.DeviceService;
51 import org.thingsboard.server.dao.device.provision.ProvisionRequest; 51 import org.thingsboard.server.dao.device.provision.ProvisionRequest;
52 import org.thingsboard.server.dao.device.provision.ProvisionResponse; 52 import org.thingsboard.server.dao.device.provision.ProvisionResponse;
53 import org.thingsboard.server.dao.relation.RelationService; 53 import org.thingsboard.server.dao.relation.RelationService;
54 -import org.thingsboard.server.dao.tenant.TenantProfileService;  
55 import org.thingsboard.server.dao.tenant.TenantService; 54 import org.thingsboard.server.dao.tenant.TenantService;
56 import org.thingsboard.server.dao.util.mapping.JacksonUtil; 55 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
57 import org.thingsboard.server.gen.transport.TransportProtos; 56 import org.thingsboard.server.gen.transport.TransportProtos;
58 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; 57 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
59 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; 58 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
60 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; 59 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg;
61 -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoRequestMsg;  
62 -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoResponseMsg; 60 +import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg;
  61 +import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg;
63 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; 62 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
64 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; 63 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
65 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; 64 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
@@ -70,6 +69,7 @@ import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -70,6 +69,7 @@ import org.thingsboard.server.queue.common.TbProtoQueueMsg;
70 import org.thingsboard.server.queue.util.TbCoreComponent; 69 import org.thingsboard.server.queue.util.TbCoreComponent;
71 import org.thingsboard.server.dao.device.provision.ProvisionFailedException; 70 import org.thingsboard.server.dao.device.provision.ProvisionFailedException;
72 import org.thingsboard.server.service.executors.DbCallbackExecutorService; 71 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
  72 +import org.thingsboard.server.service.profile.TbDeviceProfileCache;
73 import org.thingsboard.server.service.profile.TbTenantProfileCache; 73 import org.thingsboard.server.service.profile.TbTenantProfileCache;
74 import org.thingsboard.server.service.queue.TbClusterService; 74 import org.thingsboard.server.service.queue.TbClusterService;
75 import org.thingsboard.server.service.state.DeviceStateService; 75 import org.thingsboard.server.service.state.DeviceStateService;
@@ -90,9 +90,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -90,9 +90,7 @@ public class DefaultTransportApiService implements TransportApiService {
90 90
91 private static final ObjectMapper mapper = new ObjectMapper(); 91 private static final ObjectMapper mapper = new ObjectMapper();
92 92
93 - //TODO: Constructor dependencies;  
94 - private final DeviceProfileService deviceProfileService;  
95 - private final TenantService tenantService; 93 + private final TbDeviceProfileCache deviceProfileCache;
96 private final TbTenantProfileCache tenantProfileCache; 94 private final TbTenantProfileCache tenantProfileCache;
97 private final DeviceService deviceService; 95 private final DeviceService deviceService;
98 private final RelationService relationService; 96 private final RelationService relationService;
@@ -103,17 +101,15 @@ public class DefaultTransportApiService implements TransportApiService { @@ -103,17 +101,15 @@ public class DefaultTransportApiService implements TransportApiService {
103 private final DataDecodingEncodingService dataDecodingEncodingService; 101 private final DataDecodingEncodingService dataDecodingEncodingService;
104 private final DeviceProvisionService deviceProvisionService; 102 private final DeviceProvisionService deviceProvisionService;
105 103
106 -  
107 private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>(); 104 private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>();
108 105
109 - public DefaultTransportApiService(DeviceProfileService deviceProfileService, TenantService tenantService, 106 + public DefaultTransportApiService(TbDeviceProfileCache deviceProfileCache,
110 TbTenantProfileCache tenantProfileCache, DeviceService deviceService, 107 TbTenantProfileCache tenantProfileCache, DeviceService deviceService,
111 RelationService relationService, DeviceCredentialsService deviceCredentialsService, 108 RelationService relationService, DeviceCredentialsService deviceCredentialsService,
112 DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService, 109 DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService,
113 TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService, 110 TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService,
114 DeviceProvisionService deviceProvisionService) { 111 DeviceProvisionService deviceProvisionService) {
115 - this.deviceProfileService = deviceProfileService;  
116 - this.tenantService = tenantService; 112 + this.deviceProfileCache = deviceProfileCache;
117 this.tenantProfileCache = tenantProfileCache; 113 this.tenantProfileCache = tenantProfileCache;
118 this.deviceService = deviceService; 114 this.deviceService = deviceService;
119 this.relationService = relationService; 115 this.relationService = relationService;
@@ -143,11 +139,8 @@ public class DefaultTransportApiService implements TransportApiService { @@ -143,11 +139,8 @@ public class DefaultTransportApiService implements TransportApiService {
143 } else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) { 139 } else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) {
144 return Futures.transform(handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()), 140 return Futures.transform(handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()),
145 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 141 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
146 - } else if (transportApiRequestMsg.hasGetTenantRoutingInfoRequestMsg()) {  
147 - return Futures.transform(handle(transportApiRequestMsg.getGetTenantRoutingInfoRequestMsg()),  
148 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());  
149 - } else if (transportApiRequestMsg.hasGetDeviceProfileRequestMsg()) {  
150 - return Futures.transform(handle(transportApiRequestMsg.getGetDeviceProfileRequestMsg()), 142 + } else if (transportApiRequestMsg.hasEntityProfileRequestMsg()) {
  143 + return Futures.transform(handle(transportApiRequestMsg.getEntityProfileRequestMsg()),
151 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 144 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
152 } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) { 145 } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) {
153 return Futures.transform(handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()), 146 return Futures.transform(handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()),
@@ -238,7 +231,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -238,7 +231,7 @@ public class DefaultTransportApiService implements TransportApiService {
238 device.setName(requestMsg.getDeviceName()); 231 device.setName(requestMsg.getDeviceName());
239 device.setType(requestMsg.getDeviceType()); 232 device.setType(requestMsg.getDeviceType());
240 device.setCustomerId(gateway.getCustomerId()); 233 device.setCustomerId(gateway.getCustomerId());
241 - DeviceProfile deviceProfile = deviceProfileService.findOrCreateDeviceProfile(gateway.getTenantId(), requestMsg.getDeviceType()); 234 + DeviceProfile deviceProfile = deviceProfileCache.findOrCreateDeviceProfile(gateway.getTenantId(), requestMsg.getDeviceType());
242 device.setDeviceProfileId(deviceProfile.getId()); 235 device.setDeviceProfileId(deviceProfile.getId());
243 device = deviceService.saveDevice(device); 236 device = deviceService.saveDevice(device);
244 relationService.saveRelationAsync(TenantId.SYS_TENANT_ID, new EntityRelation(gateway.getId(), device.getId(), "Created")); 237 relationService.saveRelationAsync(TenantId.SYS_TENANT_ID, new EntityRelation(gateway.getId(), device.getId(), "Created"));
@@ -258,7 +251,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -258,7 +251,7 @@ public class DefaultTransportApiService implements TransportApiService {
258 } 251 }
259 GetOrCreateDeviceFromGatewayResponseMsg.Builder builder = GetOrCreateDeviceFromGatewayResponseMsg.newBuilder() 252 GetOrCreateDeviceFromGatewayResponseMsg.Builder builder = GetOrCreateDeviceFromGatewayResponseMsg.newBuilder()
260 .setDeviceInfo(getDeviceInfoProto(device)); 253 .setDeviceInfo(getDeviceInfoProto(device));
261 - DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); 254 + DeviceProfile deviceProfile = deviceProfileCache.get(device.getTenantId(), device.getDeviceProfileId());
262 if (deviceProfile != null) { 255 if (deviceProfile != null) {
263 builder.setProfileBody(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile))); 256 builder.setProfileBody(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile)));
264 } else { 257 } else {
@@ -320,23 +313,21 @@ public class DefaultTransportApiService implements TransportApiService { @@ -320,23 +313,21 @@ public class DefaultTransportApiService implements TransportApiService {
320 .build(); 313 .build();
321 } 314 }
322 315
323 - private ListenableFuture<TransportApiResponseMsg> handle(GetTenantRoutingInfoRequestMsg requestMsg) {  
324 - TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB()));  
325 -  
326 - ListenableFuture<TenantProfile> tenantProfileFuture = Futures.immediateFuture(tenantProfileCache.get(tenantId));  
327 - return Futures.transform(tenantProfileFuture, tenantProfile -> TransportApiResponseMsg.newBuilder()  
328 - .setGetTenantRoutingInfoResponseMsg(GetTenantRoutingInfoResponseMsg.newBuilder().setIsolatedTbCore(tenantProfile.isIsolatedTbCore())  
329 - .setIsolatedTbRuleEngine(tenantProfile.isIsolatedTbRuleEngine()).build()).build(), dbCallbackExecutorService);  
330 - }  
331 -  
332 - private ListenableFuture<TransportApiResponseMsg> handle(TransportProtos.GetDeviceProfileRequestMsg requestMsg) {  
333 - DeviceProfileId profileId = new DeviceProfileId(new UUID(requestMsg.getProfileIdMSB(), requestMsg.getProfileIdLSB()));  
334 - DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(TenantId.SYS_TENANT_ID, profileId);  
335 - return Futures.immediateFuture(TransportApiResponseMsg.newBuilder()  
336 - .setGetDeviceProfileResponseMsg(  
337 - TransportProtos.GetDeviceProfileResponseMsg.newBuilder()  
338 - .setData(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile)))  
339 - .build()).build()); 316 + private ListenableFuture<TransportApiResponseMsg> handle(GetEntityProfileRequestMsg requestMsg) {
  317 + EntityType entityType = EntityType.valueOf(requestMsg.getEntityType());
  318 + UUID entityUuid = new UUID(requestMsg.getEntityIdMSB(), requestMsg.getEntityIdLSB());
  319 + ByteString data;
  320 + if (entityType.equals(EntityType.DEVICE_PROFILE)) {
  321 + DeviceProfileId deviceProfileId = new DeviceProfileId(entityUuid);
  322 + DeviceProfile deviceProfile = deviceProfileCache.find(deviceProfileId);
  323 + data = ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile));
  324 + } else if (entityType.equals(EntityType.TENANT)) {
  325 + TenantProfile tenantProfile = tenantProfileCache.get(new TenantId(entityUuid));
  326 + data = ByteString.copyFrom(dataDecodingEncodingService.encode(tenantProfile));
  327 + } else {
  328 + throw new RuntimeException("Invalid entity profile request: " + entityType);
  329 + }
  330 + return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setEntityProfileResponseMsg(GetEntityProfileResponseMsg.newBuilder().setData(data).build()).build());
340 } 331 }
341 332
342 private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) { 333 private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) {
@@ -348,7 +339,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -348,7 +339,7 @@ public class DefaultTransportApiService implements TransportApiService {
348 try { 339 try {
349 ValidateDeviceCredentialsResponseMsg.Builder builder = ValidateDeviceCredentialsResponseMsg.newBuilder(); 340 ValidateDeviceCredentialsResponseMsg.Builder builder = ValidateDeviceCredentialsResponseMsg.newBuilder();
350 builder.setDeviceInfo(getDeviceInfoProto(device)); 341 builder.setDeviceInfo(getDeviceInfoProto(device));
351 - DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); 342 + DeviceProfile deviceProfile = deviceProfileCache.get(device.getTenantId(), device.getDeviceProfileId());
352 if (deviceProfile != null) { 343 if (deviceProfile != null) {
353 builder.setProfileBody(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile))); 344 builder.setProfileBody(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile)));
354 } else { 345 } else {
@@ -502,7 +502,7 @@ js: @@ -502,7 +502,7 @@ js:
502 remote: 502 remote:
503 # Maximum allowed JavaScript execution errors before JavaScript will be blacklisted 503 # Maximum allowed JavaScript execution errors before JavaScript will be blacklisted
504 max_errors: "${REMOTE_JS_SANDBOX_MAX_ERRORS:3}" 504 max_errors: "${REMOTE_JS_SANDBOX_MAX_ERRORS:3}"
505 - # Maximum time in seconds for black listed function to stay in the list. 505 + # Maximum time in seconds for black listed function to stay in 1:the list.
506 max_black_list_duration_sec: "${REMOTE_JS_SANDBOX_MAX_BLACKLIST_DURATION_SEC:60}" 506 max_black_list_duration_sec: "${REMOTE_JS_SANDBOX_MAX_BLACKLIST_DURATION_SEC:60}"
507 stats: 507 stats:
508 enabled: "${TB_JS_REMOTE_STATS_ENABLED:false}" 508 enabled: "${TB_JS_REMOTE_STATS_ENABLED:false}"
@@ -512,10 +512,6 @@ transport: @@ -512,10 +512,6 @@ transport:
512 sessions: 512 sessions:
513 inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" 513 inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
514 report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}" 514 report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
515 - rate_limits:  
516 - enabled: "${TB_TRANSPORT_RATE_LIMITS_ENABLED:false}"  
517 - tenant: "${TB_TRANSPORT_RATE_LIMITS_TENANT:1000:1,20000:60}"  
518 - device: "${TB_TRANSPORT_RATE_LIMITS_DEVICE:10:1,300:60}"  
519 json: 515 json:
520 # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON 516 # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON
521 type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}" 517 type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}"
@@ -177,32 +177,26 @@ message GetOrCreateDeviceFromGatewayResponseMsg { @@ -177,32 +177,26 @@ message GetOrCreateDeviceFromGatewayResponseMsg {
177 bytes profileBody = 2; 177 bytes profileBody = 2;
178 } 178 }
179 179
180 -message GetTenantRoutingInfoRequestMsg {  
181 - int64 tenantIdMSB = 1;  
182 - int64 tenantIdLSB = 2;  
183 -}  
184 -  
185 -message GetTenantRoutingInfoResponseMsg {  
186 - bool isolatedTbCore = 1;  
187 - bool isolatedTbRuleEngine = 2;  
188 -}  
189 -  
190 -message GetDeviceProfileRequestMsg {  
191 - int64 profileIdMSB = 1;  
192 - int64 profileIdLSB = 2; 180 +message GetEntityProfileRequestMsg {
  181 + string entityType = 1;
  182 + int64 entityIdMSB = 2;
  183 + int64 entityIdLSB = 3;
193 } 184 }
194 185
195 -message GetDeviceProfileResponseMsg {  
196 - bytes data = 1; 186 +message GetEntityProfileResponseMsg {
  187 + string entityType = 1;
  188 + bytes data = 2;
197 } 189 }
198 190
199 -message DeviceProfileUpdateMsg {  
200 - bytes data = 1; 191 +message EntityUpdateMsg {
  192 + string entityType = 1;
  193 + bytes data = 2;
201 } 194 }
202 195
203 -message DeviceProfileDeleteMsg {  
204 - int64 profileIdMSB = 1;  
205 - int64 profileIdLSB = 2; 196 +message EntityDeleteMsg {
  197 + string entityType = 1;
  198 + int64 entityIdMSB = 2;
  199 + int64 entityIdLSB = 3;
206 } 200 }
207 201
208 message SessionCloseNotificationProto { 202 message SessionCloseNotificationProto {
@@ -482,8 +476,7 @@ message TransportApiRequestMsg { @@ -482,8 +476,7 @@ message TransportApiRequestMsg {
482 ValidateDeviceTokenRequestMsg validateTokenRequestMsg = 1; 476 ValidateDeviceTokenRequestMsg validateTokenRequestMsg = 1;
483 ValidateDeviceX509CertRequestMsg validateX509CertRequestMsg = 2; 477 ValidateDeviceX509CertRequestMsg validateX509CertRequestMsg = 2;
484 GetOrCreateDeviceFromGatewayRequestMsg getOrCreateDeviceRequestMsg = 3; 478 GetOrCreateDeviceFromGatewayRequestMsg getOrCreateDeviceRequestMsg = 3;
485 - GetTenantRoutingInfoRequestMsg getTenantRoutingInfoRequestMsg = 4;  
486 - GetDeviceProfileRequestMsg getDeviceProfileRequestMsg = 5; 479 + GetEntityProfileRequestMsg entityProfileRequestMsg = 4;
487 ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 6; 480 ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 6;
488 ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7; 481 ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7;
489 } 482 }
@@ -492,9 +485,8 @@ message TransportApiRequestMsg { @@ -492,9 +485,8 @@ message TransportApiRequestMsg {
492 message TransportApiResponseMsg { 485 message TransportApiResponseMsg {
493 ValidateDeviceCredentialsResponseMsg validateCredResponseMsg = 1; 486 ValidateDeviceCredentialsResponseMsg validateCredResponseMsg = 1;
494 GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2; 487 GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2;
495 - GetTenantRoutingInfoResponseMsg getTenantRoutingInfoResponseMsg = 4;  
496 - GetDeviceProfileResponseMsg getDeviceProfileResponseMsg = 5;  
497 - ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 6; 488 + GetEntityProfileResponseMsg entityProfileResponseMsg = 3;
  489 + ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4;
498 } 490 }
499 491
500 /* Messages that are handled by ThingsBoard Core Service */ 492 /* Messages that are handled by ThingsBoard Core Service */
@@ -535,7 +527,8 @@ message ToTransportMsg { @@ -535,7 +527,8 @@ message ToTransportMsg {
535 AttributeUpdateNotificationMsg attributeUpdateNotification = 5; 527 AttributeUpdateNotificationMsg attributeUpdateNotification = 5;
536 ToDeviceRpcRequestMsg toDeviceRequest = 6; 528 ToDeviceRpcRequestMsg toDeviceRequest = 6;
537 ToServerRpcResponseMsg toServerResponse = 7; 529 ToServerRpcResponseMsg toServerResponse = 7;
538 - DeviceProfileUpdateMsg deviceProfileUpdateMsg = 8;  
539 - DeviceProfileDeleteMsg deviceProfileDeleteMsg = 9; 530 + /* For Tenant, TenantProfile and DeviceProfile */
  531 + EntityUpdateMsg entityUpdateMsg = 8;
  532 + EntityDeleteMsg entityDeleteMsg = 9;
540 ProvisionDeviceResponseMsg provisionResponse = 10; 533 ProvisionDeviceResponseMsg provisionResponse = 10;
541 } 534 }
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportDeviceProfileCache.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportProfileCache.java
@@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
21 21
22 import java.util.Optional; 22 import java.util.Optional;
23 23
24 -public interface TransportProfileCache { 24 +public interface TransportDeviceProfileCache {
25 25
26 DeviceProfile getOrCreate(DeviceProfileId id, ByteString profileBody); 26 DeviceProfile getOrCreate(DeviceProfileId id, ByteString profileBody);
27 27
@@ -20,11 +20,12 @@ import org.thingsboard.server.common.data.DeviceTransportType; @@ -20,11 +20,12 @@ import org.thingsboard.server.common.data.DeviceTransportType;
20 import org.thingsboard.server.common.data.id.DeviceProfileId; 20 import org.thingsboard.server.common.data.id.DeviceProfileId;
21 import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; 21 import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse;
22 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 22 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
  23 +import org.thingsboard.server.gen.transport.TransportProtos;
23 import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; 24 import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg;
24 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; 25 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg;
25 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; 26 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
26 -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoRequestMsg;  
27 -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoResponseMsg; 27 +import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg;
  28 +import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg;
28 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; 29 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
29 import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; 30 import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
30 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; 31 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
@@ -47,7 +48,7 @@ import java.util.concurrent.ScheduledExecutorService; @@ -47,7 +48,7 @@ import java.util.concurrent.ScheduledExecutorService;
47 */ 48 */
48 public interface TransportService { 49 public interface TransportService {
49 50
50 - GetTenantRoutingInfoResponseMsg getRoutingInfo(GetTenantRoutingInfoRequestMsg msg); 51 + GetEntityProfileResponseMsg getRoutingInfo(GetEntityProfileRequestMsg msg);
51 52
52 void process(DeviceTransportType transportType, ValidateDeviceTokenRequestMsg msg, 53 void process(DeviceTransportType transportType, ValidateDeviceTokenRequestMsg msg,
53 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback); 54 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
@@ -64,8 +65,6 @@ public interface TransportService { @@ -64,8 +65,6 @@ public interface TransportService {
64 void process(ProvisionDeviceRequestMsg msg, 65 void process(ProvisionDeviceRequestMsg msg,
65 TransportServiceCallback<ProvisionDeviceResponseMsg> callback); 66 TransportServiceCallback<ProvisionDeviceResponseMsg> callback);
66 67
67 - void getDeviceProfile(DeviceProfileId deviceProfileId, TransportServiceCallback<DeviceProfile> callback);  
68 -  
69 void onProfileUpdate(DeviceProfile deviceProfile); 68 void onProfileUpdate(DeviceProfile deviceProfile);
70 69
71 boolean checkLimits(SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<Void> callback); 70 boolean checkLimits(SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<Void> callback);
  1 +/**
  2 + * Copyright © 2016-2020 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.common.transport;
  17 +
  18 +import com.google.protobuf.ByteString;
  19 +import org.thingsboard.server.common.data.TenantProfile;
  20 +import org.thingsboard.server.common.data.id.TenantId;
  21 +import org.thingsboard.server.common.data.id.TenantProfileId;
  22 +import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult;
  23 +import org.thingsboard.server.queue.discovery.TenantRoutingInfo;
  24 +import org.thingsboard.server.queue.discovery.TenantRoutingInfoService;
  25 +
  26 +import java.util.Set;
  27 +
  28 +public interface TransportTenantProfileCache {
  29 +
  30 + TenantProfile get(TenantId tenantId);
  31 +
  32 + TenantProfileUpdateResult put(ByteString profileBody);
  33 +
  34 + boolean put(TenantId tenantId, TenantProfileId profileId);
  35 +
  36 + Set<TenantId> remove(TenantProfileId profileId);
  37 +
  38 +}
  1 +/**
  2 + * Copyright © 2016-2020 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.common.transport.limits;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.stereotype.Component;
  20 +import org.springframework.util.StringUtils;
  21 +import org.thingsboard.server.common.msg.tools.TbRateLimits;
  22 +
  23 +@Slf4j
  24 +@Component
  25 +public class DefaultTransportRateLimitFactory implements TransportRateLimitFactory {
  26 +
  27 + private static final DummyTransportRateLimit ALWAYS_TRUE = new DummyTransportRateLimit();
  28 +
  29 + @Override
  30 + public TransportRateLimit create(TransportRateLimitType type, Object configuration) {
  31 + if (!StringUtils.isEmpty(configuration)) {
  32 + try {
  33 + return new SimpleTransportRateLimit(new TbRateLimits(configuration.toString()), configuration.toString());
  34 + } catch (Exception e) {
  35 + log.warn("[{}] Failed to init rate limit with configuration: {}", type, configuration, e);
  36 + return ALWAYS_TRUE;
  37 + }
  38 + } else {
  39 + return ALWAYS_TRUE;
  40 + }
  41 + }
  42 +
  43 + @Override
  44 + public TransportRateLimit createDefault(TransportRateLimitType type) {
  45 + return ALWAYS_TRUE;
  46 + }
  47 +}
  1 +/**
  2 + * Copyright © 2016-2020 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.common.transport.limits;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.stereotype.Service;
  20 +import org.thingsboard.server.common.data.TenantProfile;
  21 +import org.thingsboard.server.common.data.TenantProfileData;
  22 +import org.thingsboard.server.common.data.id.DeviceId;
  23 +import org.thingsboard.server.common.data.id.TenantId;
  24 +import org.thingsboard.server.common.transport.TransportTenantProfileCache;
  25 +import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult;
  26 +
  27 +import java.util.concurrent.ConcurrentHashMap;
  28 +import java.util.concurrent.ConcurrentMap;
  29 +
  30 +@Service
  31 +@Slf4j
  32 +public class DefaultTransportRateLimitService implements TransportRateLimitService {
  33 +
  34 + private final ConcurrentMap<TenantId, TransportRateLimit[]> perTenantLimits = new ConcurrentHashMap<>();
  35 + private final ConcurrentMap<DeviceId, TransportRateLimit[]> perDeviceLimits = new ConcurrentHashMap<>();
  36 +
  37 + private final TransportRateLimitFactory rateLimitFactory;
  38 + private final TransportTenantProfileCache tenantProfileCache;
  39 +
  40 + public DefaultTransportRateLimitService(TransportRateLimitFactory rateLimitFactory, TransportTenantProfileCache tenantProfileCache) {
  41 + this.rateLimitFactory = rateLimitFactory;
  42 + this.tenantProfileCache = tenantProfileCache;
  43 + }
  44 +
  45 + @Override
  46 + public TransportRateLimit getRateLimit(TenantId tenantId, TransportRateLimitType limitType) {
  47 + TransportRateLimit[] limits = perTenantLimits.get(tenantId);
  48 + if (limits == null) {
  49 + limits = fetchProfileAndInit(tenantId);
  50 + perTenantLimits.put(tenantId, limits);
  51 + }
  52 + return limits[limitType.ordinal()];
  53 + }
  54 +
  55 + @Override
  56 + public TransportRateLimit getRateLimit(TenantId tenantId, DeviceId deviceId, TransportRateLimitType limitType) {
  57 + TransportRateLimit[] limits = perDeviceLimits.get(deviceId);
  58 + if (limits == null) {
  59 + limits = fetchProfileAndInit(tenantId);
  60 + perDeviceLimits.put(deviceId, limits);
  61 + }
  62 + return limits[limitType.ordinal()];
  63 + }
  64 +
  65 + @Override
  66 + public void update(TenantProfileUpdateResult update) {
  67 + TransportRateLimit[] newLimits = createTransportRateLimits(update.getProfile());
  68 + for (TenantId tenantId : update.getAffectedTenants()) {
  69 + mergeLimits(tenantId, newLimits);
  70 + }
  71 + }
  72 +
  73 + @Override
  74 + public void update(TenantId tenantId) {
  75 + mergeLimits(tenantId, fetchProfileAndInit(tenantId));
  76 + }
  77 +
  78 + public void mergeLimits(TenantId tenantId, TransportRateLimit[] newRateLimits) {
  79 + TransportRateLimit[] oldRateLimits = perTenantLimits.get(tenantId);
  80 + if (oldRateLimits == null) {
  81 + perTenantLimits.put(tenantId, newRateLimits);
  82 + } else {
  83 + for (int i = 0; i < TransportRateLimitType.values().length; i++) {
  84 + TransportRateLimit newLimit = newRateLimits[i];
  85 + TransportRateLimit oldLimit = oldRateLimits[i];
  86 + if (newLimit != null && (oldLimit == null || !oldLimit.getConfiguration().equals(newLimit.getConfiguration()))) {
  87 + oldRateLimits[i] = newLimit;
  88 + }
  89 + }
  90 + }
  91 + }
  92 +
  93 + @Override
  94 + public void remove(TenantId tenantId) {
  95 + perTenantLimits.remove(tenantId);
  96 + }
  97 +
  98 + @Override
  99 + public void remove(DeviceId deviceId) {
  100 + perDeviceLimits.remove(deviceId);
  101 + }
  102 +
  103 + private TransportRateLimit[] fetchProfileAndInit(TenantId tenantId) {
  104 + return perTenantLimits.computeIfAbsent(tenantId, tmp -> createTransportRateLimits(tenantProfileCache.get(tenantId)));
  105 + }
  106 +
  107 + private TransportRateLimit[] createTransportRateLimits(TenantProfile tenantProfile) {
  108 + TenantProfileData profileData = tenantProfile.getProfileData();
  109 + TransportRateLimit[] rateLimits = new TransportRateLimit[TransportRateLimitType.values().length];
  110 + for (TransportRateLimitType type : TransportRateLimitType.values()) {
  111 + rateLimits[type.ordinal()] = rateLimitFactory.create(type, profileData.getProperties().get(type.getConfigurationKey()));
  112 + }
  113 + return rateLimits;
  114 + }
  115 +}
  1 +/**
  2 + * Copyright © 2016-2020 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.common.transport.limits;
  17 +
  18 +public class DummyTransportRateLimit implements TransportRateLimit {
  19 +
  20 + @Override
  21 + public String getConfiguration() {
  22 + return "";
  23 + }
  24 +
  25 + @Override
  26 + public boolean tryConsume() {
  27 + return true;
  28 + }
  29 +
  30 +}
  1 +/**
  2 + * Copyright © 2016-2020 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.common.transport.limits;
  17 +
  18 +import lombok.Getter;
  19 +import lombok.RequiredArgsConstructor;
  20 +import org.thingsboard.server.common.msg.tools.TbRateLimits;
  21 +
  22 +@RequiredArgsConstructor
  23 +public class SimpleTransportRateLimit implements TransportRateLimit {
  24 +
  25 + private final TbRateLimits rateLimit;
  26 + @Getter
  27 + private final String configuration;
  28 +
  29 + @Override
  30 + public boolean tryConsume() {
  31 + return rateLimit.tryConsume();
  32 + }
  33 +
  34 +}
  1 +/**
  2 + * Copyright © 2016-2020 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.common.transport.limits;
  17 +
  18 +public interface TransportRateLimit {
  19 +
  20 + String getConfiguration();
  21 +
  22 + boolean tryConsume();
  23 +
  24 +}
  1 +/**
  2 + * Copyright © 2016-2020 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.common.transport.limits;
  17 +
  18 +public interface TransportRateLimitFactory {
  19 +
  20 + TransportRateLimit create(TransportRateLimitType type, Object config);
  21 +
  22 + TransportRateLimit createDefault(TransportRateLimitType type);
  23 +
  24 +}
  1 +/**
  2 + * Copyright © 2016-2020 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.common.transport.limits;
  17 +
  18 +import org.thingsboard.server.common.data.id.DeviceId;
  19 +import org.thingsboard.server.common.data.id.TenantId;
  20 +import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult;
  21 +
  22 +public interface TransportRateLimitService {
  23 +
  24 + TransportRateLimit getRateLimit(TenantId tenantId, TransportRateLimitType limit);
  25 +
  26 + TransportRateLimit getRateLimit(TenantId tenantId, DeviceId deviceId, TransportRateLimitType limit);
  27 +
  28 + void update(TenantProfileUpdateResult update);
  29 +
  30 + void update(TenantId tenantId);
  31 +
  32 + void remove(TenantId tenantId);
  33 +
  34 + void remove(DeviceId deviceId);
  35 +
  36 +}
  1 +/**
  2 + * Copyright © 2016-2020 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.common.transport.limits;
  17 +
  18 +import lombok.Getter;
  19 +
  20 +public enum TransportRateLimitType {
  21 +
  22 + TENANT_MAX_MSGS("transport.tenant.max.msg"),
  23 + TENANT_MAX_DATA_POINTS("transport.tenant.max.dataPoints"),
  24 + DEVICE_MAX_MSGS("transport.device.max.msg"),
  25 + DEVICE_MAX_DATA_POINTS("transport.device.max.dataPoints");
  26 +
  27 + @Getter
  28 + private final String configurationKey;
  29 +
  30 + TransportRateLimitType(String configurationKey) {
  31 + this.configurationKey = configurationKey;
  32 + }
  33 +}
  1 +/**
  2 + * Copyright © 2016-2020 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.common.transport.profile;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.TenantProfile;
  20 +import org.thingsboard.server.common.data.id.TenantId;
  21 +
  22 +import java.util.Set;
  23 +
  24 +@Data
  25 +public class TenantProfileUpdateResult {
  26 +
  27 + private final TenantProfile profile;
  28 + private final Set<TenantId> affectedTenants;
  29 +
  30 +}
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportProfileCache.java
@@ -21,7 +21,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; @@ -21,7 +21,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
21 import org.springframework.stereotype.Component; 21 import org.springframework.stereotype.Component;
22 import org.thingsboard.server.common.data.DeviceProfile; 22 import org.thingsboard.server.common.data.DeviceProfile;
23 import org.thingsboard.server.common.data.id.DeviceProfileId; 23 import org.thingsboard.server.common.data.id.DeviceProfileId;
24 -import org.thingsboard.server.common.transport.TransportProfileCache; 24 +import org.thingsboard.server.common.transport.TransportDeviceProfileCache;
25 import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; 25 import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
26 26
27 import java.util.Optional; 27 import java.util.Optional;
@@ -31,13 +31,13 @@ import java.util.concurrent.ConcurrentMap; @@ -31,13 +31,13 @@ import java.util.concurrent.ConcurrentMap;
31 @Slf4j 31 @Slf4j
32 @Component 32 @Component
33 @ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'") 33 @ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'")
34 -public class DefaultTransportProfileCache implements TransportProfileCache { 34 +public class DefaultTransportDeviceProfileCache implements TransportDeviceProfileCache {
35 35
36 private final ConcurrentMap<DeviceProfileId, DeviceProfile> deviceProfiles = new ConcurrentHashMap<>(); 36 private final ConcurrentMap<DeviceProfileId, DeviceProfile> deviceProfiles = new ConcurrentHashMap<>();
37 37
38 private final DataDecodingEncodingService dataDecodingEncodingService; 38 private final DataDecodingEncodingService dataDecodingEncodingService;
39 39
40 - public DefaultTransportProfileCache(DataDecodingEncodingService dataDecodingEncodingService) { 40 + public DefaultTransportDeviceProfileCache(DataDecodingEncodingService dataDecodingEncodingService) {
41 this.dataDecodingEncodingService = dataDecodingEncodingService; 41 this.dataDecodingEncodingService = dataDecodingEncodingService;
42 } 42 }
43 43
@@ -29,25 +29,35 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -29,25 +29,35 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory;
29 import org.thingsboard.server.common.data.DeviceProfile; 29 import org.thingsboard.server.common.data.DeviceProfile;
30 import org.thingsboard.server.common.data.DeviceTransportType; 30 import org.thingsboard.server.common.data.DeviceTransportType;
31 import org.thingsboard.server.common.data.EntityType; 31 import org.thingsboard.server.common.data.EntityType;
  32 +import org.thingsboard.server.common.data.Tenant;
32 import org.thingsboard.server.common.data.id.DeviceId; 33 import org.thingsboard.server.common.data.id.DeviceId;
33 import org.thingsboard.server.common.data.id.DeviceProfileId; 34 import org.thingsboard.server.common.data.id.DeviceProfileId;
34 import org.thingsboard.server.common.data.id.RuleChainId; 35 import org.thingsboard.server.common.data.id.RuleChainId;
35 import org.thingsboard.server.common.data.id.TenantId; 36 import org.thingsboard.server.common.data.id.TenantId;
  37 +import org.thingsboard.server.common.data.id.TenantProfileId;
36 import org.thingsboard.server.common.msg.TbMsg; 38 import org.thingsboard.server.common.msg.TbMsg;
37 import org.thingsboard.server.common.msg.TbMsgMetaData; 39 import org.thingsboard.server.common.msg.TbMsgMetaData;
38 import org.thingsboard.server.common.msg.queue.ServiceQueue; 40 import org.thingsboard.server.common.msg.queue.ServiceQueue;
39 import org.thingsboard.server.common.msg.queue.ServiceType; 41 import org.thingsboard.server.common.msg.queue.ServiceType;
40 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; 42 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
41 import org.thingsboard.server.common.msg.session.SessionMsgType; 43 import org.thingsboard.server.common.msg.session.SessionMsgType;
42 -import org.thingsboard.server.common.msg.tools.TbRateLimits;  
43 import org.thingsboard.server.common.msg.tools.TbRateLimitsException; 44 import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
  45 +import org.thingsboard.server.common.stats.MessagesStats;
  46 +import org.thingsboard.server.common.stats.StatsFactory;
  47 +import org.thingsboard.server.common.stats.StatsType;
44 import org.thingsboard.server.common.transport.SessionMsgListener; 48 import org.thingsboard.server.common.transport.SessionMsgListener;
45 -import org.thingsboard.server.common.transport.TransportProfileCache; 49 +import org.thingsboard.server.common.transport.TransportDeviceProfileCache;
46 import org.thingsboard.server.common.transport.TransportService; 50 import org.thingsboard.server.common.transport.TransportService;
47 import org.thingsboard.server.common.transport.TransportServiceCallback; 51 import org.thingsboard.server.common.transport.TransportServiceCallback;
  52 +import org.thingsboard.server.common.transport.TransportTenantProfileCache;
48 import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; 53 import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse;
49 import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; 54 import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
50 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 55 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
  56 +import org.thingsboard.server.common.transport.limits.TransportRateLimit;
  57 +import org.thingsboard.server.common.transport.limits.TransportRateLimitService;
  58 +import org.thingsboard.server.common.transport.limits.TransportRateLimitType;
  59 +import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult;
  60 +import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
51 import org.thingsboard.server.common.transport.util.JsonUtils; 61 import org.thingsboard.server.common.transport.util.JsonUtils;
52 import org.thingsboard.server.gen.transport.TransportProtos; 62 import org.thingsboard.server.gen.transport.TransportProtos;
53 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; 63 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
@@ -69,15 +79,13 @@ import org.thingsboard.server.queue.discovery.PartitionService; @@ -69,15 +79,13 @@ import org.thingsboard.server.queue.discovery.PartitionService;
69 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; 79 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
70 import org.thingsboard.server.queue.provider.TbQueueProducerProvider; 80 import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
71 import org.thingsboard.server.queue.provider.TbTransportQueueFactory; 81 import org.thingsboard.server.queue.provider.TbTransportQueueFactory;
72 -import org.thingsboard.server.common.stats.MessagesStats;  
73 -import org.thingsboard.server.common.stats.StatsFactory;  
74 -import org.thingsboard.server.common.stats.StatsType;  
75 82
76 import javax.annotation.PostConstruct; 83 import javax.annotation.PostConstruct;
77 import javax.annotation.PreDestroy; 84 import javax.annotation.PreDestroy;
78 import java.util.Collections; 85 import java.util.Collections;
79 import java.util.List; 86 import java.util.List;
80 import java.util.Map; 87 import java.util.Map;
  88 +import java.util.Optional;
81 import java.util.Random; 89 import java.util.Random;
82 import java.util.UUID; 90 import java.util.UUID;
83 import java.util.concurrent.ConcurrentHashMap; 91 import java.util.concurrent.ConcurrentHashMap;
@@ -98,12 +106,6 @@ import java.util.concurrent.atomic.AtomicInteger; @@ -98,12 +106,6 @@ import java.util.concurrent.atomic.AtomicInteger;
98 @ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'") 106 @ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'")
99 public class DefaultTransportService implements TransportService { 107 public class DefaultTransportService implements TransportService {
100 108
101 - @Value("${transport.rate_limits.enabled}")  
102 - private boolean rateLimitEnabled;  
103 - @Value("${transport.rate_limits.tenant}")  
104 - private String perTenantLimitsConf;  
105 - @Value("${transport.rate_limits.device}")  
106 - private String perDevicesLimitsConf;  
107 @Value("${transport.sessions.inactivity_timeout}") 109 @Value("${transport.sessions.inactivity_timeout}")
108 private long sessionInactivityTimeout; 110 private long sessionInactivityTimeout;
109 @Value("${transport.sessions.report_timeout}") 111 @Value("${transport.sessions.report_timeout}")
@@ -119,7 +121,10 @@ public class DefaultTransportService implements TransportService { @@ -119,7 +121,10 @@ public class DefaultTransportService implements TransportService {
119 private final PartitionService partitionService; 121 private final PartitionService partitionService;
120 private final TbServiceInfoProvider serviceInfoProvider; 122 private final TbServiceInfoProvider serviceInfoProvider;
121 private final StatsFactory statsFactory; 123 private final StatsFactory statsFactory;
122 - private final TransportProfileCache transportProfileCache; 124 + private final TransportDeviceProfileCache deviceProfileCache;
  125 + private final TransportTenantProfileCache tenantProfileCache;
  126 + private final TransportRateLimitService rateLimitService;
  127 + private final DataDecodingEncodingService dataDecodingEncodingService;
123 128
124 protected TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> transportApiRequestTemplate; 129 protected TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> transportApiRequestTemplate;
125 protected TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> ruleEngineMsgProducer; 130 protected TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> ruleEngineMsgProducer;
@@ -132,14 +137,11 @@ public class DefaultTransportService implements TransportService { @@ -132,14 +137,11 @@ public class DefaultTransportService implements TransportService {
132 137
133 protected ScheduledExecutorService schedulerExecutor; 138 protected ScheduledExecutorService schedulerExecutor;
134 protected ExecutorService transportCallbackExecutor; 139 protected ExecutorService transportCallbackExecutor;
  140 + private ExecutorService mainConsumerExecutor;
135 141
136 private final ConcurrentMap<UUID, SessionMetaData> sessions = new ConcurrentHashMap<>(); 142 private final ConcurrentMap<UUID, SessionMetaData> sessions = new ConcurrentHashMap<>();
137 private final Map<String, RpcRequestMetadata> toServerRpcPendingMap = new ConcurrentHashMap<>(); 143 private final Map<String, RpcRequestMetadata> toServerRpcPendingMap = new ConcurrentHashMap<>();
138 - //TODO 3.2: @ybondarenko Implement cleanup of this maps.  
139 - private final ConcurrentMap<TenantId, TbRateLimits> perTenantLimits = new ConcurrentHashMap<>();  
140 - private final ConcurrentMap<DeviceId, TbRateLimits> perDeviceLimits = new ConcurrentHashMap<>();  
141 144
142 - private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("transport-consumer"));  
143 private volatile boolean stopped = false; 145 private volatile boolean stopped = false;
144 146
145 public DefaultTransportService(TbServiceInfoProvider serviceInfoProvider, 147 public DefaultTransportService(TbServiceInfoProvider serviceInfoProvider,
@@ -147,22 +149,22 @@ public class DefaultTransportService implements TransportService { @@ -147,22 +149,22 @@ public class DefaultTransportService implements TransportService {
147 TbQueueProducerProvider producerProvider, 149 TbQueueProducerProvider producerProvider,
148 PartitionService partitionService, 150 PartitionService partitionService,
149 StatsFactory statsFactory, 151 StatsFactory statsFactory,
150 - TransportProfileCache transportProfileCache) { 152 + TransportDeviceProfileCache deviceProfileCache,
  153 + TransportTenantProfileCache tenantProfileCache,
  154 + TransportRateLimitService rateLimitService, DataDecodingEncodingService dataDecodingEncodingService) {
151 this.serviceInfoProvider = serviceInfoProvider; 155 this.serviceInfoProvider = serviceInfoProvider;
152 this.queueProvider = queueProvider; 156 this.queueProvider = queueProvider;
153 this.producerProvider = producerProvider; 157 this.producerProvider = producerProvider;
154 this.partitionService = partitionService; 158 this.partitionService = partitionService;
155 this.statsFactory = statsFactory; 159 this.statsFactory = statsFactory;
156 - this.transportProfileCache = transportProfileCache; 160 + this.deviceProfileCache = deviceProfileCache;
  161 + this.tenantProfileCache = tenantProfileCache;
  162 + this.rateLimitService = rateLimitService;
  163 + this.dataDecodingEncodingService = dataDecodingEncodingService;
157 } 164 }
158 165
159 @PostConstruct 166 @PostConstruct
160 public void init() { 167 public void init() {
161 - if (rateLimitEnabled) {  
162 - //Just checking the configuration parameters  
163 - new TbRateLimits(perTenantLimitsConf);  
164 - new TbRateLimits(perDevicesLimitsConf);  
165 - }  
166 this.ruleEngineProducerStats = statsFactory.createMessagesStats(StatsType.RULE_ENGINE.getName() + ".producer"); 168 this.ruleEngineProducerStats = statsFactory.createMessagesStats(StatsType.RULE_ENGINE.getName() + ".producer");
167 this.tbCoreProducerStats = statsFactory.createMessagesStats(StatsType.CORE.getName() + ".producer"); 169 this.tbCoreProducerStats = statsFactory.createMessagesStats(StatsType.CORE.getName() + ".producer");
168 this.transportApiStats = statsFactory.createMessagesStats(StatsType.TRANSPORT.getName() + ".producer"); 170 this.transportApiStats = statsFactory.createMessagesStats(StatsType.TRANSPORT.getName() + ".producer");
@@ -177,6 +179,7 @@ public class DefaultTransportService implements TransportService { @@ -177,6 +179,7 @@ public class DefaultTransportService implements TransportService {
177 TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_TRANSPORT, serviceInfoProvider.getServiceId()); 179 TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_TRANSPORT, serviceInfoProvider.getServiceId());
178 transportNotificationsConsumer.subscribe(Collections.singleton(tpi)); 180 transportNotificationsConsumer.subscribe(Collections.singleton(tpi));
179 transportApiRequestTemplate.init(); 181 transportApiRequestTemplate.init();
  182 + mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("transport-consumer"));
180 mainConsumerExecutor.execute(() -> { 183 mainConsumerExecutor.execute(() -> {
181 while (!stopped) { 184 while (!stopped) {
182 try { 185 try {
@@ -208,10 +211,6 @@ public class DefaultTransportService implements TransportService { @@ -208,10 +211,6 @@ public class DefaultTransportService implements TransportService {
208 211
209 @PreDestroy 212 @PreDestroy
210 public void destroy() { 213 public void destroy() {
211 - if (rateLimitEnabled) {  
212 - perTenantLimits.clear();  
213 - perDeviceLimits.clear();  
214 - }  
215 stopped = true; 214 stopped = true;
216 215
217 if (transportNotificationsConsumer != null) { 216 if (transportNotificationsConsumer != null) {
@@ -232,7 +231,7 @@ public class DefaultTransportService implements TransportService { @@ -232,7 +231,7 @@ public class DefaultTransportService implements TransportService {
232 } 231 }
233 232
234 @Override 233 @Override
235 - public ScheduledExecutorService getSchedulerExecutor(){ 234 + public ScheduledExecutorService getSchedulerExecutor() {
236 return this.schedulerExecutor; 235 return this.schedulerExecutor;
237 } 236 }
238 237
@@ -242,12 +241,12 @@ public class DefaultTransportService implements TransportService { @@ -242,12 +241,12 @@ public class DefaultTransportService implements TransportService {
242 } 241 }
243 242
244 @Override 243 @Override
245 - public TransportProtos.GetTenantRoutingInfoResponseMsg getRoutingInfo(TransportProtos.GetTenantRoutingInfoRequestMsg msg) { 244 + public TransportProtos.GetEntityProfileResponseMsg getRoutingInfo(TransportProtos.GetEntityProfileRequestMsg msg) {
246 TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg> protoMsg = 245 TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg> protoMsg =
247 - new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setGetTenantRoutingInfoRequestMsg(msg).build()); 246 + new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setEntityProfileRequestMsg(msg).build());
248 try { 247 try {
249 TbProtoQueueMsg<TransportApiResponseMsg> response = transportApiRequestTemplate.send(protoMsg).get(); 248 TbProtoQueueMsg<TransportApiResponseMsg> response = transportApiRequestTemplate.send(protoMsg).get();
250 - return response.getValue().getGetTenantRoutingInfoResponseMsg(); 249 + return response.getValue().getEntityProfileResponseMsg();
251 } catch (InterruptedException | ExecutionException e) { 250 } catch (InterruptedException | ExecutionException e) {
252 throw new RuntimeException(e); 251 throw new RuntimeException(e);
253 } 252 }
@@ -289,7 +288,7 @@ public class DefaultTransportService implements TransportService { @@ -289,7 +288,7 @@ public class DefaultTransportService implements TransportService {
289 result.deviceInfo(tdi); 288 result.deviceInfo(tdi);
290 ByteString profileBody = msg.getProfileBody(); 289 ByteString profileBody = msg.getProfileBody();
291 if (profileBody != null && !profileBody.isEmpty()) { 290 if (profileBody != null && !profileBody.isEmpty()) {
292 - DeviceProfile profile = transportProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody); 291 + DeviceProfile profile = deviceProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody);
293 if (transportType != DeviceTransportType.DEFAULT 292 if (transportType != DeviceTransportType.DEFAULT
294 && profile != null && profile.getTransportType() != DeviceTransportType.DEFAULT && profile.getTransportType() != transportType) { 293 && profile != null && profile.getTransportType() != DeviceTransportType.DEFAULT && profile.getTransportType() != transportType) {
295 log.debug("[{}] Device profile [{}] has different transport type: {}, expected: {}", tdi.getDeviceId(), tdi.getDeviceProfileId(), profile.getTransportType(), transportType); 294 log.debug("[{}] Device profile [{}] has different transport type: {}, expected: {}", tdi.getDeviceId(), tdi.getDeviceProfileId(), profile.getTransportType(), transportType);
@@ -315,7 +314,7 @@ public class DefaultTransportService implements TransportService { @@ -315,7 +314,7 @@ public class DefaultTransportService implements TransportService {
315 result.deviceInfo(tdi); 314 result.deviceInfo(tdi);
316 ByteString profileBody = msg.getProfileBody(); 315 ByteString profileBody = msg.getProfileBody();
317 if (profileBody != null && !profileBody.isEmpty()) { 316 if (profileBody != null && !profileBody.isEmpty()) {
318 - result.deviceProfile(transportProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody)); 317 + result.deviceProfile(deviceProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody));
319 } 318 }
320 } 319 }
321 return result.build(); 320 return result.build();
@@ -339,8 +338,8 @@ public class DefaultTransportService implements TransportService { @@ -339,8 +338,8 @@ public class DefaultTransportService implements TransportService {
339 log.trace("Processing msg: {}", requestMsg); 338 log.trace("Processing msg: {}", requestMsg);
340 TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setProvisionDeviceRequestMsg(requestMsg).build()); 339 TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setProvisionDeviceRequestMsg(requestMsg).build());
341 ListenableFuture<ProvisionDeviceResponseMsg> response = Futures.transform(transportApiRequestTemplate.send(protoMsg), tmp -> 340 ListenableFuture<ProvisionDeviceResponseMsg> response = Futures.transform(transportApiRequestTemplate.send(protoMsg), tmp ->
342 - tmp.getValue().getProvisionDeviceResponseMsg()  
343 - , MoreExecutors.directExecutor()); 341 + tmp.getValue().getProvisionDeviceResponseMsg()
  342 + , MoreExecutors.directExecutor());
344 AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor); 343 AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor);
345 } 344 }
346 345
@@ -580,12 +579,11 @@ public class DefaultTransportService implements TransportService { @@ -580,12 +579,11 @@ public class DefaultTransportService implements TransportService {
580 if (log.isTraceEnabled()) { 579 if (log.isTraceEnabled()) {
581 log.trace("[{}] Processing msg: {}", toSessionId(sessionInfo), msg); 580 log.trace("[{}] Processing msg: {}", toSessionId(sessionInfo), msg);
582 } 581 }
583 - if (!rateLimitEnabled) {  
584 - return true;  
585 - }  
586 TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); 582 TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB()));
587 - TbRateLimits rateLimits = perTenantLimits.computeIfAbsent(tenantId, id -> new TbRateLimits(perTenantLimitsConf));  
588 - if (!rateLimits.tryConsume()) { 583 +
  584 + TransportRateLimit tenantRateLimit = rateLimitService.getRateLimit(tenantId, TransportRateLimitType.TENANT_MAX_MSGS);
  585 +
  586 + if (!tenantRateLimit.tryConsume()) {
589 if (callback != null) { 587 if (callback != null) {
590 callback.onError(new TbRateLimitsException(EntityType.TENANT)); 588 callback.onError(new TbRateLimitsException(EntityType.TENANT));
591 } 589 }
@@ -595,8 +593,8 @@ public class DefaultTransportService implements TransportService { @@ -595,8 +593,8 @@ public class DefaultTransportService implements TransportService {
595 return false; 593 return false;
596 } 594 }
597 DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); 595 DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()));
598 - rateLimits = perDeviceLimits.computeIfAbsent(deviceId, id -> new TbRateLimits(perDevicesLimitsConf));  
599 - if (!rateLimits.tryConsume()) { 596 + TransportRateLimit deviceRateLimit = rateLimitService.getRateLimit(tenantId, deviceId, TransportRateLimitType.DEVICE_MAX_MSGS);
  597 + if (!deviceRateLimit.tryConsume()) {
600 if (callback != null) { 598 if (callback != null) {
601 callback.onError(new TbRateLimitsException(EntityType.DEVICE)); 599 callback.onError(new TbRateLimitsException(EntityType.DEVICE));
602 } 600 }
@@ -637,16 +635,40 @@ public class DefaultTransportService implements TransportService { @@ -637,16 +635,40 @@ public class DefaultTransportService implements TransportService {
637 deregisterSession(md.getSessionInfo()); 635 deregisterSession(md.getSessionInfo());
638 } 636 }
639 } else { 637 } else {
640 - if (toSessionMsg.hasDeviceProfileUpdateMsg()) {  
641 - DeviceProfile deviceProfile = transportProfileCache.put(toSessionMsg.getDeviceProfileUpdateMsg().getData());  
642 - if (deviceProfile != null) {  
643 - onProfileUpdate(deviceProfile); 638 + if (toSessionMsg.hasEntityUpdateMsg()) {
  639 + TransportProtos.EntityUpdateMsg msg = toSessionMsg.getEntityUpdateMsg();
  640 + EntityType entityType = EntityType.valueOf(msg.getEntityType());
  641 + if (EntityType.DEVICE_PROFILE.equals(entityType)) {
  642 + DeviceProfile deviceProfile = deviceProfileCache.put(msg.getData());
  643 + if (deviceProfile != null) {
  644 + onProfileUpdate(deviceProfile);
  645 + }
  646 + } else if (EntityType.TENANT_PROFILE.equals(entityType)) {
  647 + TenantProfileUpdateResult update = tenantProfileCache.put(msg.getData());
  648 + rateLimitService.update(update);
  649 + } else if (EntityType.TENANT.equals(entityType)) {
  650 + Optional<Tenant> profileOpt = dataDecodingEncodingService.decode(msg.getData().toByteArray());
  651 + if (profileOpt.isPresent()) {
  652 + Tenant tenant = profileOpt.get();
  653 + boolean updated = tenantProfileCache.put(tenant.getId(), tenant.getTenantProfileId());
  654 + if (updated) {
  655 + rateLimitService.update(tenant.getId());
  656 + }
  657 + }
  658 + }
  659 + } else if (toSessionMsg.hasEntityDeleteMsg()) {
  660 + TransportProtos.EntityDeleteMsg msg = toSessionMsg.getEntityDeleteMsg();
  661 + EntityType entityType = EntityType.valueOf(msg.getEntityType());
  662 + UUID entityUuid = new UUID(msg.getEntityIdMSB(), msg.getEntityIdLSB());
  663 + if (EntityType.DEVICE_PROFILE.equals(entityType)) {
  664 + deviceProfileCache.evict(new DeviceProfileId(new UUID(msg.getEntityIdMSB(), msg.getEntityIdLSB())));
  665 + } else if (EntityType.TENANT_PROFILE.equals(entityType)) {
  666 + tenantProfileCache.remove(new TenantProfileId(entityUuid));
  667 + } else if (EntityType.TENANT.equals(entityType)) {
  668 + rateLimitService.remove(new TenantId(entityUuid));
  669 + } else if (EntityType.DEVICE.equals(entityType)) {
  670 + rateLimitService.remove(new DeviceId(entityUuid));
644 } 671 }
645 - } else if (toSessionMsg.hasDeviceProfileDeleteMsg()) {  
646 - transportProfileCache.evict(new DeviceProfileId(new UUID(  
647 - toSessionMsg.getDeviceProfileDeleteMsg().getProfileIdMSB(),  
648 - toSessionMsg.getDeviceProfileDeleteMsg().getProfileIdLSB()  
649 - )));  
650 } else { 672 } else {
651 //TODO: should we notify the device actor about missed session? 673 //TODO: should we notify the device actor about missed session?
652 log.debug("[{}] Missing session.", sessionId); 674 log.debug("[{}] Missing session.", sessionId);
@@ -655,38 +677,6 @@ public class DefaultTransportService implements TransportService { @@ -655,38 +677,6 @@ public class DefaultTransportService implements TransportService {
655 } 677 }
656 678
657 @Override 679 @Override
658 - public void getDeviceProfile(DeviceProfileId deviceProfileId, TransportServiceCallback<DeviceProfile> callback) {  
659 - DeviceProfile deviceProfile = transportProfileCache.get(deviceProfileId);  
660 - if (deviceProfile != null) {  
661 - callback.onSuccess(deviceProfile);  
662 - } else {  
663 - log.trace("Processing device profile request: [{}]", deviceProfileId);  
664 - TransportProtos.GetDeviceProfileRequestMsg msg = TransportProtos.GetDeviceProfileRequestMsg.newBuilder()  
665 - .setProfileIdMSB(deviceProfileId.getId().getMostSignificantBits())  
666 - .setProfileIdLSB(deviceProfileId.getId().getLeastSignificantBits())  
667 - .build();  
668 - TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(),  
669 - TransportApiRequestMsg.newBuilder().setGetDeviceProfileRequestMsg(msg).build());  
670 - AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg),  
671 - response -> {  
672 - ByteString devProfileBody = response.getValue().getGetDeviceProfileResponseMsg().getData();  
673 - if (devProfileBody != null && !devProfileBody.isEmpty()) {  
674 - DeviceProfile profile = transportProfileCache.put(devProfileBody);  
675 - if (profile != null) {  
676 - callback.onSuccess(profile);  
677 - } else {  
678 - log.warn("Failed to decode device profile: {}", devProfileBody);  
679 - callback.onError(new IllegalArgumentException("Failed to decode device profile!"));  
680 - }  
681 - } else {  
682 - log.warn("Failed to find device profile: [{}]", deviceProfileId);  
683 - callback.onError(new IllegalArgumentException("Failed to find device profile!"));  
684 - }  
685 - }, callback::onError, transportCallbackExecutor);  
686 - }  
687 - }  
688 -  
689 - @Override  
690 public void onProfileUpdate(DeviceProfile deviceProfile) { 680 public void onProfileUpdate(DeviceProfile deviceProfile) {
691 long deviceProfileIdMSB = deviceProfile.getId().getId().getMostSignificantBits(); 681 long deviceProfileIdMSB = deviceProfile.getId().getId().getMostSignificantBits();
692 long deviceProfileIdLSB = deviceProfile.getId().getId().getLeastSignificantBits(); 682 long deviceProfileIdLSB = deviceProfile.getId().getId().getLeastSignificantBits();
@@ -750,7 +740,7 @@ public class DefaultTransportService implements TransportService { @@ -750,7 +740,7 @@ public class DefaultTransportService implements TransportService {
750 740
751 private RuleChainId resolveRuleChainId(TransportProtos.SessionInfoProto sessionInfo) { 741 private RuleChainId resolveRuleChainId(TransportProtos.SessionInfoProto sessionInfo) {
752 DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); 742 DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
753 - DeviceProfile deviceProfile = transportProfileCache.get(deviceProfileId); 743 + DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId);
754 RuleChainId ruleChainId; 744 RuleChainId ruleChainId;
755 if (deviceProfile == null) { 745 if (deviceProfile == null) {
756 log.warn("[{}] Device profile is null!", deviceProfileId); 746 log.warn("[{}] Device profile is null!", deviceProfileId);
@@ -779,7 +769,7 @@ public class DefaultTransportService implements TransportService { @@ -779,7 +769,7 @@ public class DefaultTransportService implements TransportService {
779 } 769 }
780 } 770 }
781 771
782 - private class StatsCallback implements TbQueueCallback { 772 + private static class StatsCallback implements TbQueueCallback {
783 private final TbQueueCallback callback; 773 private final TbQueueCallback callback;
784 private final MessagesStats stats; 774 private final MessagesStats stats;
785 775
  1 +/**
  2 + * Copyright © 2016-2020 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.common.transport.service;
  17 +
  18 +import com.google.protobuf.ByteString;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.beans.factory.annotation.Autowired;
  21 +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
  22 +import org.springframework.context.annotation.Lazy;
  23 +import org.springframework.stereotype.Component;
  24 +import org.thingsboard.server.common.data.DeviceProfile;
  25 +import org.thingsboard.server.common.data.EntityType;
  26 +import org.thingsboard.server.common.data.TenantProfile;
  27 +import org.thingsboard.server.common.data.id.TenantId;
  28 +import org.thingsboard.server.common.data.id.TenantProfileId;
  29 +import org.thingsboard.server.common.transport.TransportService;
  30 +import org.thingsboard.server.common.transport.TransportTenantProfileCache;
  31 +import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult;
  32 +import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
  33 +import org.thingsboard.server.gen.transport.TransportProtos;
  34 +import org.thingsboard.server.queue.discovery.TenantRoutingInfo;
  35 +import org.thingsboard.server.queue.discovery.TenantRoutingInfoService;
  36 +
  37 +import java.util.Collections;
  38 +import java.util.Optional;
  39 +import java.util.Set;
  40 +import java.util.concurrent.ConcurrentHashMap;
  41 +import java.util.concurrent.ConcurrentMap;
  42 +import java.util.concurrent.locks.Lock;
  43 +import java.util.concurrent.locks.ReentrantLock;
  44 +
  45 +@Component
  46 +@ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'")
  47 +@Slf4j
  48 +public class DefaultTransportTenantProfileCache implements TransportTenantProfileCache {
  49 +
  50 + private final Lock tenantProfileFetchLock = new ReentrantLock();
  51 + private final ConcurrentMap<TenantProfileId, TenantProfile> profiles = new ConcurrentHashMap<>();
  52 + private final ConcurrentMap<TenantId, TenantProfileId> tenantIds = new ConcurrentHashMap<>();
  53 + private final ConcurrentMap<TenantProfileId, Set<TenantId>> tenantProfileIds = new ConcurrentHashMap<>();
  54 + private final DataDecodingEncodingService dataDecodingEncodingService;
  55 +
  56 + private TransportService transportService;
  57 +
  58 + @Lazy
  59 + @Autowired
  60 + public void setTransportService(TransportService transportService) {
  61 + this.transportService = transportService;
  62 + }
  63 +
  64 + public DefaultTransportTenantProfileCache(DataDecodingEncodingService dataDecodingEncodingService) {
  65 + this.dataDecodingEncodingService = dataDecodingEncodingService;
  66 + }
  67 +
  68 + @Override
  69 + public TenantProfile get(TenantId tenantId) {
  70 + return getTenantProfile(tenantId);
  71 + }
  72 +
  73 + @Override
  74 + public TenantProfileUpdateResult put(ByteString profileBody) {
  75 + Optional<TenantProfile> profileOpt = dataDecodingEncodingService.decode(profileBody.toByteArray());
  76 + if (profileOpt.isPresent()) {
  77 + TenantProfile newProfile = profileOpt.get();
  78 + log.trace("[{}] put: {}", newProfile.getId(), newProfile);
  79 + return new TenantProfileUpdateResult(newProfile, tenantProfileIds.get(newProfile.getId()));
  80 + } else {
  81 + log.warn("Failed to decode profile: {}", profileBody.toString());
  82 + return new TenantProfileUpdateResult(null, Collections.emptySet());
  83 + }
  84 + }
  85 +
  86 + @Override
  87 + public boolean put(TenantId tenantId, TenantProfileId profileId) {
  88 + log.trace("[{}] put: {}", tenantId, profileId);
  89 + TenantProfileId oldProfileId = tenantIds.get(tenantId);
  90 + if (oldProfileId != null && !oldProfileId.equals(profileId)) {
  91 + tenantProfileIds.computeIfAbsent(oldProfileId, id -> ConcurrentHashMap.newKeySet()).remove(tenantId);
  92 + tenantIds.put(tenantId, profileId);
  93 + tenantProfileIds.computeIfAbsent(profileId, id -> ConcurrentHashMap.newKeySet()).add(tenantId);
  94 + return true;
  95 + } else {
  96 + return false;
  97 + }
  98 + }
  99 +
  100 + @Override
  101 + public Set<TenantId> remove(TenantProfileId profileId) {
  102 + Set<TenantId> tenants = tenantProfileIds.remove(profileId);
  103 + if (tenants != null) {
  104 + tenants.forEach(tenantIds::remove);
  105 + }
  106 + profiles.remove(profileId);
  107 + return tenants;
  108 + }
  109 +
  110 + private TenantProfile getTenantProfile(TenantId tenantId) {
  111 + TenantProfile profile = null;
  112 + TenantProfileId tenantProfileId = tenantIds.get(tenantId);
  113 + if (tenantProfileId != null) {
  114 + profile = profiles.get(tenantProfileId);
  115 + }
  116 + if (profile == null) {
  117 + tenantProfileFetchLock.lock();
  118 + try {
  119 + tenantProfileId = tenantIds.get(tenantId);
  120 + if (tenantProfileId != null) {
  121 + profile = profiles.get(tenantProfileId);
  122 + }
  123 + if (profile == null) {
  124 + TransportProtos.GetEntityProfileRequestMsg msg = TransportProtos.GetEntityProfileRequestMsg.newBuilder()
  125 + .setEntityType(EntityType.TENANT.name())
  126 + .setEntityIdMSB(tenantId.getId().getMostSignificantBits())
  127 + .setEntityIdLSB(tenantId.getId().getLeastSignificantBits())
  128 + .build();
  129 + TransportProtos.GetEntityProfileResponseMsg routingInfo = transportService.getRoutingInfo(msg);
  130 + Optional<TenantProfile> profileOpt = dataDecodingEncodingService.decode(routingInfo.getData().toByteArray());
  131 + if (profileOpt.isPresent()) {
  132 + profile = profileOpt.get();
  133 + TenantProfile existingProfile = profiles.get(profile.getId());
  134 + if (existingProfile != null) {
  135 + profile = existingProfile;
  136 + } else {
  137 + profiles.put(profile.getId(), profile);
  138 + }
  139 + tenantProfileIds.computeIfAbsent(profile.getId(), id -> ConcurrentHashMap.newKeySet()).add(tenantId);
  140 + tenantIds.put(tenantId, profile.getId());
  141 + } else {
  142 + log.warn("[{}] Can't decode tenant profile: {}", tenantId, routingInfo.getData());
  143 + throw new RuntimeException("Can't decode tenant profile!");
  144 + }
  145 + }
  146 + } finally {
  147 + tenantProfileFetchLock.unlock();
  148 + }
  149 + }
  150 + return profile;
  151 + }
  152 +
  153 +
  154 +}
@@ -16,14 +16,11 @@ @@ -16,14 +16,11 @@
16 package org.thingsboard.server.common.transport.service; 16 package org.thingsboard.server.common.transport.service;
17 17
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 -import org.springframework.beans.factory.annotation.Autowired;  
20 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 19 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
21 -import org.springframework.context.annotation.Lazy;  
22 import org.springframework.stereotype.Service; 20 import org.springframework.stereotype.Service;
  21 +import org.thingsboard.server.common.data.TenantProfile;
23 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
24 -import org.thingsboard.server.common.transport.TransportService;  
25 -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoRequestMsg;  
26 -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoResponseMsg; 23 +import org.thingsboard.server.common.transport.TransportTenantProfileCache;
27 import org.thingsboard.server.queue.discovery.TenantRoutingInfo; 24 import org.thingsboard.server.queue.discovery.TenantRoutingInfo;
28 import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; 25 import org.thingsboard.server.queue.discovery.TenantRoutingInfoService;
29 26
@@ -32,21 +29,16 @@ import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; @@ -32,21 +29,16 @@ import org.thingsboard.server.queue.discovery.TenantRoutingInfoService;
32 @ConditionalOnExpression("'${service.type:null}'=='tb-transport'") 29 @ConditionalOnExpression("'${service.type:null}'=='tb-transport'")
33 public class TransportTenantRoutingInfoService implements TenantRoutingInfoService { 30 public class TransportTenantRoutingInfoService implements TenantRoutingInfoService {
34 31
35 - private TransportService transportService; 32 + private TransportTenantProfileCache tenantProfileCache;
36 33
37 - @Lazy  
38 - @Autowired  
39 - public void setTransportService(TransportService transportService) {  
40 - this.transportService = transportService; 34 + public TransportTenantRoutingInfoService(TransportTenantProfileCache tenantProfileCache) {
  35 + this.tenantProfileCache = tenantProfileCache;
41 } 36 }
42 37
43 @Override 38 @Override
44 public TenantRoutingInfo getRoutingInfo(TenantId tenantId) { 39 public TenantRoutingInfo getRoutingInfo(TenantId tenantId) {
45 - GetTenantRoutingInfoRequestMsg msg = GetTenantRoutingInfoRequestMsg.newBuilder()  
46 - .setTenantIdMSB(tenantId.getId().getMostSignificantBits())  
47 - .setTenantIdLSB(tenantId.getId().getLeastSignificantBits())  
48 - .build();  
49 - GetTenantRoutingInfoResponseMsg routingInfo = transportService.getRoutingInfo(msg);  
50 - return new TenantRoutingInfo(tenantId, routingInfo.getIsolatedTbCore(), routingInfo.getIsolatedTbRuleEngine()); 40 + TenantProfile profile = tenantProfileCache.get(tenantId);
  41 + return new TenantRoutingInfo(tenantId, profile.isIsolatedTbCore(), profile.isIsolatedTbRuleEngine());
51 } 42 }
  43 +
52 } 44 }
@@ -15,8 +15,6 @@ @@ -15,8 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.common.transport.util; 16 package org.thingsboard.server.common.transport.util;
17 17
18 -import org.thingsboard.server.common.msg.TbActorMsg;  
19 -  
20 import java.util.Optional; 18 import java.util.Optional;
21 19
22 public interface DataDecodingEncodingService { 20 public interface DataDecodingEncodingService {
@@ -49,10 +49,6 @@ transport: @@ -49,10 +49,6 @@ transport:
49 sessions: 49 sessions:
50 inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" 50 inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
51 report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}" 51 report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
52 - rate_limits:  
53 - enabled: "${TB_TRANSPORT_RATE_LIMITS_ENABLED:false}"  
54 - tenant: "${TB_TRANSPORT_RATE_LIMITS_TENANT:1000:1,20000:60}"  
55 - device: "${TB_TRANSPORT_RATE_LIMITS_DEVICE:10:1,300:60}"  
56 json: 52 json:
57 # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON 53 # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON
58 type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}" 54 type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}"
@@ -42,10 +42,6 @@ transport: @@ -42,10 +42,6 @@ transport:
42 sessions: 42 sessions:
43 inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" 43 inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
44 report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}" 44 report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
45 - rate_limits:  
46 - enabled: "${TB_TRANSPORT_RATE_LIMITS_ENABLED:false}"  
47 - tenant: "${TB_TRANSPORT_RATE_LIMITS_TENANT:1000:1,20000:60}"  
48 - device: "${TB_TRANSPORT_RATE_LIMITS_DEVICE:10:1,300:60}"  
49 json: 45 json:
50 # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON 46 # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON
51 type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}" 47 type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}"
@@ -71,10 +71,6 @@ transport: @@ -71,10 +71,6 @@ transport:
71 sessions: 71 sessions:
72 inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" 72 inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
73 report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}" 73 report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
74 - rate_limits:  
75 - enabled: "${TB_TRANSPORT_RATE_LIMITS_ENABLED:false}"  
76 - tenant: "${TB_TRANSPORT_RATE_LIMITS_TENANT:1000:1,20000:60}"  
77 - device: "${TB_TRANSPORT_RATE_LIMITS_DEVICE:10:1,300:60}"  
78 json: 74 json:
79 # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON 75 # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON
80 type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}" 76 type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}"