Commit 356d4ff26cc6101b66df347e8516857dc42716f7

Authored by Andrii Shvaika
1 parent d3f519a2

Profile Node improvements in cluster mode

@@ -544,7 +544,11 @@ public class ActorSystemContext { @@ -544,7 +544,11 @@ public class ActorSystemContext {
544 544
545 public void scheduleMsgWithDelay(TbActorRef ctx, TbActorMsg msg, long delayInMs) { 545 public void scheduleMsgWithDelay(TbActorRef ctx, TbActorMsg msg, long delayInMs) {
546 log.debug("Scheduling msg {} with delay {} ms", msg, delayInMs); 546 log.debug("Scheduling msg {} with delay {} ms", msg, delayInMs);
547 - getScheduler().schedule(() -> ctx.tell(msg), delayInMs, TimeUnit.MILLISECONDS); 547 + if (delayInMs > 0) {
  548 + getScheduler().schedule(() -> ctx.tell(msg), delayInMs, TimeUnit.MILLISECONDS);
  549 + } else {
  550 + ctx.tell(msg);
  551 + }
548 } 552 }
549 553
550 } 554 }
@@ -35,6 +35,7 @@ import org.thingsboard.server.actors.TbActorRef; @@ -35,6 +35,7 @@ import org.thingsboard.server.actors.TbActorRef;
35 import org.thingsboard.server.common.data.Customer; 35 import org.thingsboard.server.common.data.Customer;
36 import org.thingsboard.server.common.data.DataConstants; 36 import org.thingsboard.server.common.data.DataConstants;
37 import org.thingsboard.server.common.data.Device; 37 import org.thingsboard.server.common.data.Device;
  38 +import org.thingsboard.server.common.data.DeviceProfile;
38 import org.thingsboard.server.common.data.alarm.Alarm; 39 import org.thingsboard.server.common.data.alarm.Alarm;
39 import org.thingsboard.server.common.data.asset.Asset; 40 import org.thingsboard.server.common.data.asset.Asset;
40 import org.thingsboard.server.common.data.id.EntityId; 41 import org.thingsboard.server.common.data.id.EntityId;
@@ -477,6 +478,16 @@ class DefaultTbContext implements TbContext { @@ -477,6 +478,16 @@ class DefaultTbContext implements TbContext {
477 mainCtx.getRuleNodeStateService().removeByRuleNodeId(getTenantId(), getSelfId()); 478 mainCtx.getRuleNodeStateService().removeByRuleNodeId(getTenantId(), getSelfId());
478 } 479 }
479 480
  481 + @Override
  482 + public void addProfileListener(Consumer<DeviceProfile> listener) {
  483 + mainCtx.getDeviceProfileCache().addListener(getTenantId(), getSelfId(), listener);
  484 + }
  485 +
  486 + @Override
  487 + public void removeProfileListener() {
  488 + mainCtx.getDeviceProfileCache().removeListener(getTenantId(), getSelfId());
  489 + }
  490 +
480 private TbMsgMetaData getActionMetaData(RuleNodeId ruleNodeId) { 491 private TbMsgMetaData getActionMetaData(RuleNodeId ruleNodeId) {
481 TbMsgMetaData metaData = new TbMsgMetaData(); 492 TbMsgMetaData metaData = new TbMsgMetaData();
482 metaData.putValue("ruleNodeId", ruleNodeId.toString()); 493 metaData.putValue("ruleNodeId", ruleNodeId.toString());
@@ -94,7 +94,6 @@ public class DeviceProfileController extends BaseController { @@ -94,7 +94,6 @@ public class DeviceProfileController extends BaseController {
94 94
95 DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile)); 95 DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile));
96 96
97 - deviceProfileCache.put(savedDeviceProfile);  
98 tbClusterService.onDeviceProfileChange(savedDeviceProfile, null); 97 tbClusterService.onDeviceProfileChange(savedDeviceProfile, null);
99 tbClusterService.onEntityStateChange(deviceProfile.getTenantId(), savedDeviceProfile.getId(), 98 tbClusterService.onEntityStateChange(deviceProfile.getTenantId(), savedDeviceProfile.getId(),
100 created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); 99 created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
@@ -120,7 +119,6 @@ public class DeviceProfileController extends BaseController { @@ -120,7 +119,6 @@ public class DeviceProfileController extends BaseController {
120 DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); 119 DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
121 DeviceProfile deviceProfile = checkDeviceProfileId(deviceProfileId, Operation.DELETE); 120 DeviceProfile deviceProfile = checkDeviceProfileId(deviceProfileId, Operation.DELETE);
122 deviceProfileService.deleteDeviceProfile(getTenantId(), deviceProfileId); 121 deviceProfileService.deleteDeviceProfile(getTenantId(), deviceProfileId);
123 - deviceProfileCache.evict(deviceProfileId);  
124 122
125 tbClusterService.onDeviceProfileDelete(deviceProfile, null); 123 tbClusterService.onDeviceProfileDelete(deviceProfile, null);
126 tbClusterService.onEntityStateChange(deviceProfile.getTenantId(), deviceProfile.getId(), ComponentLifecycleEvent.DELETED); 124 tbClusterService.onEntityStateChange(deviceProfile.getTenantId(), deviceProfile.getId(), ComponentLifecycleEvent.DELETED);
@@ -21,14 +21,17 @@ import org.thingsboard.server.common.data.Device; @@ -21,14 +21,17 @@ import org.thingsboard.server.common.data.Device;
21 import org.thingsboard.server.common.data.DeviceProfile; 21 import org.thingsboard.server.common.data.DeviceProfile;
22 import org.thingsboard.server.common.data.id.DeviceId; 22 import org.thingsboard.server.common.data.id.DeviceId;
23 import org.thingsboard.server.common.data.id.DeviceProfileId; 23 import org.thingsboard.server.common.data.id.DeviceProfileId;
  24 +import org.thingsboard.server.common.data.id.EntityId;
24 import org.thingsboard.server.common.data.id.TenantId; 25 import org.thingsboard.server.common.data.id.TenantId;
25 import org.thingsboard.server.dao.device.DeviceProfileService; 26 import org.thingsboard.server.dao.device.DeviceProfileService;
26 import org.thingsboard.server.dao.device.DeviceService; 27 import org.thingsboard.server.dao.device.DeviceService;
27 28
  29 +import java.util.Map;
28 import java.util.concurrent.ConcurrentHashMap; 30 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap; 31 import java.util.concurrent.ConcurrentMap;
30 import java.util.concurrent.locks.Lock; 32 import java.util.concurrent.locks.Lock;
31 import java.util.concurrent.locks.ReentrantLock; 33 import java.util.concurrent.locks.ReentrantLock;
  34 +import java.util.function.Consumer;
32 35
33 @Service 36 @Service
34 @Slf4j 37 @Slf4j
@@ -40,6 +43,7 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { @@ -40,6 +43,7 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache {
40 43
41 private final ConcurrentMap<DeviceProfileId, DeviceProfile> deviceProfilesMap = new ConcurrentHashMap<>(); 44 private final ConcurrentMap<DeviceProfileId, DeviceProfile> deviceProfilesMap = new ConcurrentHashMap<>();
42 private final ConcurrentMap<DeviceId, DeviceProfileId> devicesMap = new ConcurrentHashMap<>(); 45 private final ConcurrentMap<DeviceId, DeviceProfileId> devicesMap = new ConcurrentHashMap<>();
  46 + private final ConcurrentMap<TenantId, ConcurrentMap<EntityId, Consumer<DeviceProfile>>> listeners = new ConcurrentHashMap<>();
43 47
44 public DefaultTbDeviceProfileCache(DeviceProfileService deviceProfileService, DeviceService deviceService) { 48 public DefaultTbDeviceProfileCache(DeviceProfileService deviceProfileService, DeviceService deviceService) {
45 this.deviceProfileService = deviceProfileService; 49 this.deviceProfileService = deviceProfileService;
@@ -50,19 +54,21 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { @@ -50,19 +54,21 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache {
50 public DeviceProfile get(TenantId tenantId, DeviceProfileId deviceProfileId) { 54 public DeviceProfile get(TenantId tenantId, DeviceProfileId deviceProfileId) {
51 DeviceProfile profile = deviceProfilesMap.get(deviceProfileId); 55 DeviceProfile profile = deviceProfilesMap.get(deviceProfileId);
52 if (profile == null) { 56 if (profile == null) {
53 - profile = deviceProfilesMap.get(deviceProfileId);  
54 - if (profile == null) {  
55 - deviceProfileFetchLock.lock();  
56 - try { 57 + deviceProfileFetchLock.lock();
  58 + try {
  59 + profile = deviceProfilesMap.get(deviceProfileId);
  60 + if (profile == null) {
57 profile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId); 61 profile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
58 if (profile != null) { 62 if (profile != null) {
59 deviceProfilesMap.put(deviceProfileId, profile); 63 deviceProfilesMap.put(deviceProfileId, profile);
  64 + log.info("[{}] Fetch device profile into cache: {}", profile.getId(), profile);
60 } 65 }
61 - } finally {  
62 - deviceProfileFetchLock.unlock();  
63 } 66 }
  67 + } finally {
  68 + deviceProfileFetchLock.unlock();
64 } 69 }
65 } 70 }
  71 + log.trace("[{}] Found device profile in cache: {}", deviceProfileId, profile);
66 return profile; 72 return profile;
67 } 73 }
68 74
@@ -85,12 +91,19 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { @@ -85,12 +91,19 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache {
85 public void put(DeviceProfile profile) { 91 public void put(DeviceProfile profile) {
86 if (profile.getId() != null) { 92 if (profile.getId() != null) {
87 deviceProfilesMap.put(profile.getId(), profile); 93 deviceProfilesMap.put(profile.getId(), profile);
  94 + log.info("[{}] pushed device profile to cache: {}", profile.getId(), profile);
  95 + notifyListeners(profile);
88 } 96 }
89 } 97 }
90 98
91 @Override 99 @Override
92 - public void evict(DeviceProfileId profileId) {  
93 - deviceProfilesMap.remove(profileId); 100 + public void evict(TenantId tenantId, DeviceProfileId profileId) {
  101 + DeviceProfile oldProfile = deviceProfilesMap.remove(profileId);
  102 + log.info("[{}] evict device profile from cache: {}", profileId, oldProfile);
  103 + DeviceProfile newProfile = get(tenantId, profileId);
  104 + if (newProfile != null) {
  105 + notifyListeners(newProfile);
  106 + }
94 } 107 }
95 108
96 @Override 109 @Override
@@ -98,4 +111,24 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { @@ -98,4 +111,24 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache {
98 devicesMap.remove(deviceId); 111 devicesMap.remove(deviceId);
99 } 112 }
100 113
  114 + @Override
  115 + public void addListener(TenantId tenantId, EntityId listenerId, Consumer<DeviceProfile> listener) {
  116 + listeners.computeIfAbsent(tenantId, id -> new ConcurrentHashMap<>()).put(listenerId, listener);
  117 + }
  118 +
  119 + @Override
  120 + public void removeListener(TenantId tenantId, EntityId listenerId) {
  121 + ConcurrentMap<EntityId, Consumer<DeviceProfile>> tenantListeners = listeners.get(tenantId);
  122 + if (tenantListeners != null) {
  123 + tenantListeners.remove(listenerId);
  124 + }
  125 + }
  126 +
  127 + private void notifyListeners(DeviceProfile profile) {
  128 + ConcurrentMap<EntityId, Consumer<DeviceProfile>> tenantListeners = listeners.get(profile.getTenantId());
  129 + if (tenantListeners != null) {
  130 + tenantListeners.forEach((id, listener) -> listener.accept(profile));
  131 + }
  132 + }
  133 +
101 } 134 }
@@ -55,17 +55,17 @@ public class DefaultTbTenantProfileCache implements TbTenantProfileCache { @@ -55,17 +55,17 @@ public class DefaultTbTenantProfileCache implements TbTenantProfileCache {
55 public TenantProfile get(TenantProfileId tenantProfileId) { 55 public TenantProfile get(TenantProfileId tenantProfileId) {
56 TenantProfile profile = tenantProfilesMap.get(tenantProfileId); 56 TenantProfile profile = tenantProfilesMap.get(tenantProfileId);
57 if (profile == null) { 57 if (profile == null) {
58 - profile = tenantProfilesMap.get(tenantProfileId);  
59 - if (profile == null) {  
60 - tenantProfileFetchLock.lock();  
61 - try { 58 + tenantProfileFetchLock.lock();
  59 + try {
  60 + profile = tenantProfilesMap.get(tenantProfileId);
  61 + if (profile == null) {
62 profile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, tenantProfileId); 62 profile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, tenantProfileId);
63 if (profile != null) { 63 if (profile != null) {
64 tenantProfilesMap.put(tenantProfileId, profile); 64 tenantProfilesMap.put(tenantProfileId, profile);
65 } 65 }
66 - } finally {  
67 - tenantProfileFetchLock.unlock();  
68 } 66 }
  67 + } finally {
  68 + tenantProfileFetchLock.unlock();
69 } 69 }
70 } 70 }
71 return profile; 71 return profile;
@@ -19,12 +19,13 @@ import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache; @@ -19,12 +19,13 @@ import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache;
19 import org.thingsboard.server.common.data.DeviceProfile; 19 import org.thingsboard.server.common.data.DeviceProfile;
20 import org.thingsboard.server.common.data.id.DeviceId; 20 import org.thingsboard.server.common.data.id.DeviceId;
21 import org.thingsboard.server.common.data.id.DeviceProfileId; 21 import org.thingsboard.server.common.data.id.DeviceProfileId;
  22 +import org.thingsboard.server.common.data.id.TenantId;
22 23
23 public interface TbDeviceProfileCache extends RuleEngineDeviceProfileCache { 24 public interface TbDeviceProfileCache extends RuleEngineDeviceProfileCache {
24 25
25 void put(DeviceProfile profile); 26 void put(DeviceProfile profile);
26 27
27 - void evict(DeviceProfileId id); 28 + void evict(TenantId tenantId, DeviceProfileId id);
28 29
29 void evict(DeviceId id); 30 void evict(DeviceId id);
30 31
@@ -15,11 +15,7 @@ @@ -15,11 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.service.profile; 16 package org.thingsboard.server.service.profile;
17 17
18 -import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache;  
19 -import org.thingsboard.server.common.data.DeviceProfile;  
20 import org.thingsboard.server.common.data.TenantProfile; 18 import org.thingsboard.server.common.data.TenantProfile;
21 -import org.thingsboard.server.common.data.id.DeviceId;  
22 -import org.thingsboard.server.common.data.id.DeviceProfileId;  
23 import org.thingsboard.server.common.data.id.TenantId; 19 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.common.data.id.TenantProfileId; 20 import org.thingsboard.server.common.data.id.TenantProfileId;
25 21
@@ -221,7 +221,8 @@ public class DefaultTbClusterService implements TbClusterService { @@ -221,7 +221,8 @@ public class DefaultTbClusterService implements TbClusterService {
221 byte[] msgBytes = encodingService.encode(msg); 221 byte[] msgBytes = encodingService.encode(msg);
222 TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> toRuleEngineProducer = producerProvider.getRuleEngineNotificationsMsgProducer(); 222 TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> toRuleEngineProducer = producerProvider.getRuleEngineNotificationsMsgProducer();
223 Set<String> tbRuleEngineServices = new HashSet<>(partitionService.getAllServiceIds(ServiceType.TB_RULE_ENGINE)); 223 Set<String> tbRuleEngineServices = new HashSet<>(partitionService.getAllServiceIds(ServiceType.TB_RULE_ENGINE));
224 - if (msg.getEntityId().getEntityType().equals(EntityType.TENANT)) { 224 + if (msg.getEntityId().getEntityType().equals(EntityType.TENANT)
  225 + || msg.getEntityId().getEntityType().equals(EntityType.DEVICE_PROFILE)) {
225 TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> toCoreNfProducer = producerProvider.getTbCoreNotificationsMsgProducer(); 226 TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> toCoreNfProducer = producerProvider.getTbCoreNotificationsMsgProducer();
226 Set<String> tbCoreServices = partitionService.getAllServiceIds(ServiceType.TB_CORE); 227 Set<String> tbCoreServices = partitionService.getAllServiceIds(ServiceType.TB_CORE);
227 for (String serviceId : tbCoreServices) { 228 for (String serviceId : tbCoreServices) {
@@ -144,7 +144,7 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene @@ -144,7 +144,7 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
144 if (actorMsg instanceof ComponentLifecycleMsg) { 144 if (actorMsg instanceof ComponentLifecycleMsg) {
145 ComponentLifecycleMsg componentLifecycleMsg = (ComponentLifecycleMsg) actorMsg; 145 ComponentLifecycleMsg componentLifecycleMsg = (ComponentLifecycleMsg) actorMsg;
146 if (EntityType.DEVICE_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { 146 if (EntityType.DEVICE_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
147 - deviceProfileCache.evict(new DeviceProfileId(componentLifecycleMsg.getEntityId().getId())); 147 + deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceProfileId(componentLifecycleMsg.getEntityId().getId()));
148 } else if (EntityType.DEVICE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { 148 } else if (EntityType.DEVICE.equals(componentLifecycleMsg.getEntityId().getEntityType())) {
149 deviceProfileCache.evict(new DeviceId(componentLifecycleMsg.getEntityId().getId())); 149 deviceProfileCache.evict(new DeviceId(componentLifecycleMsg.getEntityId().getId()));
150 } 150 }
@@ -18,8 +18,11 @@ package org.thingsboard.rule.engine.api; @@ -18,8 +18,11 @@ package org.thingsboard.rule.engine.api;
18 import org.thingsboard.server.common.data.DeviceProfile; 18 import org.thingsboard.server.common.data.DeviceProfile;
19 import org.thingsboard.server.common.data.id.DeviceId; 19 import org.thingsboard.server.common.data.id.DeviceId;
20 import org.thingsboard.server.common.data.id.DeviceProfileId; 20 import org.thingsboard.server.common.data.id.DeviceProfileId;
  21 +import org.thingsboard.server.common.data.id.EntityId;
21 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
22 23
  24 +import java.util.function.Consumer;
  25 +
23 /** 26 /**
24 * Created by ashvayka on 02.04.18. 27 * Created by ashvayka on 02.04.18.
25 */ 28 */
@@ -29,4 +32,8 @@ public interface RuleEngineDeviceProfileCache { @@ -29,4 +32,8 @@ public interface RuleEngineDeviceProfileCache {
29 32
30 DeviceProfile get(TenantId tenantId, DeviceId deviceId); 33 DeviceProfile get(TenantId tenantId, DeviceId deviceId);
31 34
  35 + void addListener(TenantId tenantId, EntityId listenerId, Consumer<DeviceProfile> listener);
  36 +
  37 + void removeListener(TenantId tenantId, EntityId listenerId);
  38 +
32 } 39 }
@@ -20,6 +20,7 @@ import org.springframework.data.redis.core.RedisTemplate; @@ -20,6 +20,7 @@ import org.springframework.data.redis.core.RedisTemplate;
20 import org.thingsboard.common.util.ListeningExecutor; 20 import org.thingsboard.common.util.ListeningExecutor;
21 import org.thingsboard.server.common.data.Customer; 21 import org.thingsboard.server.common.data.Customer;
22 import org.thingsboard.server.common.data.Device; 22 import org.thingsboard.server.common.data.Device;
  23 +import org.thingsboard.server.common.data.DeviceProfile;
23 import org.thingsboard.server.common.data.alarm.Alarm; 24 import org.thingsboard.server.common.data.alarm.Alarm;
24 import org.thingsboard.server.common.data.asset.Asset; 25 import org.thingsboard.server.common.data.asset.Asset;
25 import org.thingsboard.server.common.data.id.EntityId; 26 import org.thingsboard.server.common.data.id.EntityId;
@@ -223,4 +224,8 @@ public interface TbContext { @@ -223,4 +224,8 @@ public interface TbContext {
223 RuleNodeState saveRuleNodeState(RuleNodeState state); 224 RuleNodeState saveRuleNodeState(RuleNodeState state);
224 225
225 void clearRuleNodeStates(); 226 void clearRuleNodeStates();
  227 +
  228 + void addProfileListener(Consumer<DeviceProfile> listener);
  229 +
  230 + void removeProfileListener();
226 } 231 }
@@ -39,6 +39,7 @@ import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; @@ -39,6 +39,7 @@ import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
39 import org.thingsboard.server.dao.util.mapping.JacksonUtil; 39 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
40 40
41 import java.util.Map; 41 import java.util.Map;
  42 +import java.util.UUID;
42 import java.util.concurrent.ConcurrentHashMap; 43 import java.util.concurrent.ConcurrentHashMap;
43 import java.util.concurrent.ExecutionException; 44 import java.util.concurrent.ExecutionException;
44 import java.util.concurrent.TimeUnit; 45 import java.util.concurrent.TimeUnit;
@@ -57,16 +58,20 @@ import java.util.concurrent.TimeUnit; @@ -57,16 +58,20 @@ import java.util.concurrent.TimeUnit;
57 ) 58 )
58 public class TbDeviceProfileNode implements TbNode { 59 public class TbDeviceProfileNode implements TbNode {
59 private static final String PERIODIC_MSG_TYPE = "TbDeviceProfilePeriodicMsg"; 60 private static final String PERIODIC_MSG_TYPE = "TbDeviceProfilePeriodicMsg";
  61 + private static final String PROFILE_UPDATE_MSG_TYPE = "TbDeviceProfileUpdateMsg";
60 62
61 private TbDeviceProfileNodeConfiguration config; 63 private TbDeviceProfileNodeConfiguration config;
62 private RuleEngineDeviceProfileCache cache; 64 private RuleEngineDeviceProfileCache cache;
  65 + private TbContext ctx;
63 private final Map<DeviceId, DeviceState> deviceStates = new ConcurrentHashMap<>(); 66 private final Map<DeviceId, DeviceState> deviceStates = new ConcurrentHashMap<>();
64 67
65 @Override 68 @Override
66 public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { 69 public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
67 this.config = TbNodeUtils.convert(configuration, TbDeviceProfileNodeConfiguration.class); 70 this.config = TbNodeUtils.convert(configuration, TbDeviceProfileNodeConfiguration.class);
68 this.cache = ctx.getDeviceProfileCache(); 71 this.cache = ctx.getDeviceProfileCache();
  72 + this.ctx = ctx;
69 scheduleAlarmHarvesting(ctx); 73 scheduleAlarmHarvesting(ctx);
  74 + ctx.addProfileListener(this::onProfileUpdate);
70 if (config.isFetchAlarmRulesStateOnStart()) { 75 if (config.isFetchAlarmRulesStateOnStart()) {
71 log.info("[{}] Fetching alarm rule state", ctx.getSelfId()); 76 log.info("[{}] Fetching alarm rule state", ctx.getSelfId());
72 int fetchCount = 0; 77 int fetchCount = 0;
@@ -95,15 +100,14 @@ public class TbDeviceProfileNode implements TbNode { @@ -95,15 +100,14 @@ public class TbDeviceProfileNode implements TbNode {
95 } 100 }
96 } 101 }
97 102
98 - /**  
99 - * TODO: Dynamic values evaluation;  
100 - */  
101 @Override 103 @Override
102 public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { 104 public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException {
103 EntityType originatorType = msg.getOriginator().getEntityType(); 105 EntityType originatorType = msg.getOriginator().getEntityType();
104 if (msg.getType().equals(PERIODIC_MSG_TYPE)) { 106 if (msg.getType().equals(PERIODIC_MSG_TYPE)) {
105 scheduleAlarmHarvesting(ctx); 107 scheduleAlarmHarvesting(ctx);
106 harvestAlarms(ctx, System.currentTimeMillis()); 108 harvestAlarms(ctx, System.currentTimeMillis());
  109 + } else if (msg.getType().equals(PROFILE_UPDATE_MSG_TYPE)) {
  110 + updateProfile(ctx, new DeviceProfileId(UUID.fromString(msg.getData())));
107 } else { 111 } else {
108 if (EntityType.DEVICE.equals(originatorType)) { 112 if (EntityType.DEVICE.equals(originatorType)) {
109 DeviceId deviceId = new DeviceId(msg.getOriginator().getId()); 113 DeviceId deviceId = new DeviceId(msg.getOriginator().getId());
@@ -119,36 +123,12 @@ public class TbDeviceProfileNode implements TbNode { @@ -119,36 +123,12 @@ public class TbDeviceProfileNode implements TbNode {
119 ctx.tellFailure(msg, new IllegalStateException("Device profile for device [" + deviceId + "] not found!")); 123 ctx.tellFailure(msg, new IllegalStateException("Device profile for device [" + deviceId + "] not found!"));
120 } 124 }
121 } 125 }
122 - } else if (EntityType.DEVICE_PROFILE.equals(originatorType)) {  
123 - log.info("[{}] Received device profile update notification: {}", ctx.getSelfId(), msg.getData());  
124 - if (msg.getType().equals("ENTITY_UPDATED")) {  
125 - DeviceProfile deviceProfile = JacksonUtil.fromString(msg.getData(), DeviceProfile.class);  
126 - if (deviceProfile != null) {  
127 - for (DeviceState state : deviceStates.values()) {  
128 - if (deviceProfile.getId().equals(state.getProfileId())) {  
129 - state.updateProfile(ctx, deviceProfile);  
130 - }  
131 - }  
132 - }  
133 - }  
134 - ctx.tellSuccess(msg);  
135 } else { 126 } else {
136 ctx.tellSuccess(msg); 127 ctx.tellSuccess(msg);
137 } 128 }
138 } 129 }
139 } 130 }
140 131
141 - public void invalidateDeviceProfileCache(DeviceId deviceId, String deviceJson) {  
142 - DeviceState deviceState = deviceStates.get(deviceId);  
143 - if (deviceState != null) {  
144 - DeviceProfileId currentProfileId = deviceState.getProfileId();  
145 - Device device = JacksonUtil.fromString(deviceJson, Device.class);  
146 - if (!currentProfileId.equals(device.getDeviceProfileId())) {  
147 - deviceStates.remove(deviceId);  
148 - }  
149 - }  
150 - }  
151 -  
152 @Override 132 @Override
153 public void onPartitionChangeMsg(TbContext ctx, PartitionChangeMsg msg) { 133 public void onPartitionChangeMsg(TbContext ctx, PartitionChangeMsg msg) {
154 // Cleanup the cache for all entities that are no longer assigned to current server partitions 134 // Cleanup the cache for all entities that are no longer assigned to current server partitions
@@ -157,6 +137,7 @@ public class TbDeviceProfileNode implements TbNode { @@ -157,6 +137,7 @@ public class TbDeviceProfileNode implements TbNode {
157 137
158 @Override 138 @Override
159 public void destroy() { 139 public void destroy() {
  140 + ctx.removeProfileListener();
160 deviceStates.clear(); 141 deviceStates.clear();
161 } 142 }
162 143
@@ -183,4 +164,33 @@ public class TbDeviceProfileNode implements TbNode { @@ -183,4 +164,33 @@ public class TbDeviceProfileNode implements TbNode {
183 } 164 }
184 } 165 }
185 166
  167 + protected void updateProfile(TbContext ctx, DeviceProfileId deviceProfileId) throws ExecutionException, InterruptedException {
  168 + DeviceProfile deviceProfile = cache.get(ctx.getTenantId(), deviceProfileId);
  169 + if (deviceProfile != null) {
  170 + log.info("[{}] Received device profile update notification: {}", ctx.getSelfId(), deviceProfile);
  171 + for (DeviceState state : deviceStates.values()) {
  172 + if (deviceProfile.getId().equals(state.getProfileId())) {
  173 + state.updateProfile(ctx, deviceProfile);
  174 + }
  175 + }
  176 + } else {
  177 + log.info("[{}] Received stale profile update notification: [{}]", ctx.getSelfId(), deviceProfileId);
  178 + }
  179 + }
  180 +
  181 + protected void onProfileUpdate(DeviceProfile profile) {
  182 + ctx.tellSelf(TbMsg.newMsg(PROFILE_UPDATE_MSG_TYPE, ctx.getTenantId(), TbMsgMetaData.EMPTY, profile.getId().getId().toString()), 0L);
  183 + }
  184 +
  185 + protected void invalidateDeviceProfileCache(DeviceId deviceId, String deviceJson) {
  186 + DeviceState deviceState = deviceStates.get(deviceId);
  187 + if (deviceState != null) {
  188 + DeviceProfileId currentProfileId = deviceState.getProfileId();
  189 + Device device = JacksonUtil.fromString(deviceJson, Device.class);
  190 + if (!currentProfileId.equals(device.getDeviceProfileId())) {
  191 + deviceStates.remove(deviceId);
  192 + }
  193 + }
  194 + }
  195 +
186 } 196 }