Commit cd2e89e834d2283ebc0145abe5393772812bf393

Authored by deaflynx
2 parents b5d99e50 6ffaca25

Merge branch 'feature/edge' of github.com:volodymyr-babak/thingsboard into feature/edge

Showing 79 changed files with 1179 additions and 917 deletions
... ... @@ -35,6 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
35 35 import org.thingsboard.rule.engine.api.MailService;
36 36 import org.thingsboard.server.common.data.User;
37 37 import org.thingsboard.server.common.data.audit.ActionType;
  38 +import org.thingsboard.server.common.data.edge.EdgeEventType;
38 39 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
39 40 import org.thingsboard.server.common.data.exception.ThingsboardException;
40 41 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -124,6 +125,9 @@ public class AuthController extends BaseController {
124 125 }
125 126 userCredentials.setPassword(passwordEncoder.encode(newPassword));
126 127 userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials);
  128 +
  129 + sendNotificationMsgToEdgeService(getTenantId(), null, userCredentials.getUserId(), EdgeEventType.USER, ActionType.CREDENTIALS_UPDATED);
  130 +
127 131 } catch (Exception e) {
128 132 throw handleException(e);
129 133 }
... ...
... ... @@ -26,12 +26,12 @@ import org.springframework.beans.factory.annotation.Value;
26 26 import org.springframework.security.core.Authentication;
27 27 import org.springframework.security.core.context.SecurityContextHolder;
28 28 import org.springframework.web.bind.annotation.ExceptionHandler;
29   -import org.thingsboard.server.common.data.BaseData;
30 29 import org.thingsboard.server.common.data.Customer;
31 30 import org.thingsboard.server.common.data.Dashboard;
32 31 import org.thingsboard.server.common.data.DashboardInfo;
33 32 import org.thingsboard.server.common.data.DataConstants;
34 33 import org.thingsboard.server.common.data.Device;
  34 +import org.thingsboard.server.common.data.EdgeUtils;
35 35 import org.thingsboard.server.common.data.EntityType;
36 36 import org.thingsboard.server.common.data.EntityView;
37 37 import org.thingsboard.server.common.data.HasName;
... ... @@ -39,14 +39,14 @@ import org.thingsboard.server.common.data.HasTenantId;
39 39 import org.thingsboard.server.common.data.Tenant;
40 40 import org.thingsboard.server.common.data.User;
41 41 import org.thingsboard.server.common.data.alarm.Alarm;
42   -import org.thingsboard.server.common.data.edge.EdgeEventType;
43   -import org.thingsboard.server.common.data.id.AlarmId;
44 42 import org.thingsboard.server.common.data.alarm.AlarmInfo;
45 43 import org.thingsboard.server.common.data.asset.Asset;
46 44 import org.thingsboard.server.common.data.audit.ActionType;
47 45 import org.thingsboard.server.common.data.edge.Edge;
  46 +import org.thingsboard.server.common.data.edge.EdgeEventType;
48 47 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
49 48 import org.thingsboard.server.common.data.exception.ThingsboardException;
  49 +import org.thingsboard.server.common.data.id.AlarmId;
50 50 import org.thingsboard.server.common.data.id.AssetId;
51 51 import org.thingsboard.server.common.data.id.CustomerId;
52 52 import org.thingsboard.server.common.data.id.DashboardId;
... ... @@ -85,7 +85,6 @@ import org.thingsboard.server.dao.dashboard.DashboardService;
85 85 import org.thingsboard.server.dao.device.ClaimDevicesService;
86 86 import org.thingsboard.server.dao.device.DeviceCredentialsService;
87 87 import org.thingsboard.server.dao.device.DeviceService;
88   -import org.thingsboard.server.dao.edge.EdgeEventService;
89 88 import org.thingsboard.server.dao.edge.EdgeService;
90 89 import org.thingsboard.server.dao.entityview.EntityViewService;
91 90 import org.thingsboard.server.dao.exception.DataValidationException;
... ... @@ -113,7 +112,6 @@ import org.thingsboard.server.service.state.DeviceStateService;
113 112 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
114 113
115 114 import javax.mail.MessagingException;
116   -import javax.management.relation.Relation;
117 115 import javax.servlet.http.HttpServletResponse;
118 116 import java.util.List;
119 117 import java.util.Optional;
... ... @@ -209,9 +207,6 @@ public abstract class BaseController {
209 207 @Autowired
210 208 protected EdgeNotificationService edgeNotificationService;
211 209
212   - @Autowired
213   - protected EdgeEventService edgeEventService;
214   -
215 210 @Value("${server.log_controller_error_stack_trace}")
216 211 @Getter
217 212 private boolean logControllerErrorStackTrace;
... ... @@ -725,14 +720,17 @@ public abstract class BaseController {
725 720
726 721 protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityRelation relation, ActionType edgeEventAction) {
727 722 try {
728   - sendNotificationMsgToEdgeService(tenantId, null, null, json.writeValueAsString(relation), EdgeEventType.RELATION, edgeEventAction);
  723 + if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
  724 + !relation.getTo().getEntityType().equals(EntityType.EDGE)) {
  725 + sendNotificationMsgToEdgeService(tenantId, null, null, json.writeValueAsString(relation), EdgeEventType.RELATION, edgeEventAction);
  726 + }
729 727 } catch (Exception e) {
730 728 log.warn("Failed to push relation to core: {}", relation, e);
731 729 }
732 730 }
733 731
734 732 protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityId entityId, ActionType edgeEventAction) {
735   - EdgeEventType edgeEventType = edgeEventService.getEdgeEventTypeByEntityType(entityId.getEntityType());
  733 + EdgeEventType edgeEventType = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType());
736 734 if (edgeEventType != null) {
737 735 sendNotificationMsgToEdgeService(tenantId, null, entityId, null, edgeEventType, edgeEventAction);
738 736 }
... ...
... ... @@ -35,17 +35,14 @@ import org.thingsboard.rule.engine.api.MailService;
35 35 import org.thingsboard.server.common.data.EntityType;
36 36 import org.thingsboard.server.common.data.User;
37 37 import org.thingsboard.server.common.data.audit.ActionType;
38   -import org.thingsboard.server.common.data.edge.Edge;
  38 +import org.thingsboard.server.common.data.edge.EdgeEventType;
39 39 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
40 40 import org.thingsboard.server.common.data.exception.ThingsboardException;
41 41 import org.thingsboard.server.common.data.id.CustomerId;
42   -import org.thingsboard.server.common.data.id.EdgeId;
43 42 import org.thingsboard.server.common.data.id.TenantId;
44 43 import org.thingsboard.server.common.data.id.UserId;
45 44 import org.thingsboard.server.common.data.page.TextPageData;
46 45 import org.thingsboard.server.common.data.page.TextPageLink;
47   -import org.thingsboard.server.common.data.page.TimePageData;
48   -import org.thingsboard.server.common.data.page.TimePageLink;
49 46 import org.thingsboard.server.common.data.security.Authority;
50 47 import org.thingsboard.server.common.data.security.UserCredentials;
51 48 import org.thingsboard.server.queue.util.TbCoreComponent;
... ... @@ -60,8 +57,6 @@ import org.thingsboard.server.utils.MiscUtils;
60 57
61 58 import javax.servlet.http.HttpServletRequest;
62 59
63   -import static org.thingsboard.server.controller.EdgeController.EDGE_ID;
64   -
65 60 @RestController
66 61 @TbCoreComponent
67 62 @RequestMapping("/api")
... ... @@ -167,6 +162,8 @@ public class UserController extends BaseController {
167 162 savedUser.getCustomerId(),
168 163 user.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
169 164
  165 + sendNotificationMsgToEdgeService(getTenantId(), null, user.getId(), EdgeEventType.USER, user.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
  166 +
170 167 return savedUser;
171 168 } catch (Exception e) {
172 169
... ... @@ -242,6 +239,8 @@ public class UserController extends BaseController {
242 239 user.getCustomerId(),
243 240 ActionType.DELETED, null, strUserId);
244 241
  242 + sendNotificationMsgToEdgeService(getTenantId(), null, user.getId(), EdgeEventType.USER, ActionType.DELETED);
  243 +
245 244 } catch (Exception e) {
246 245 logEntityAction(emptyId(EntityType.USER),
247 246 null,
... ...
... ... @@ -23,12 +23,14 @@ import lombok.extern.slf4j.Slf4j;
23 23 import org.springframework.beans.factory.annotation.Autowired;
24 24 import org.springframework.stereotype.Service;
25 25 import org.thingsboard.server.common.data.EntityType;
  26 +import org.thingsboard.server.common.data.User;
26 27 import org.thingsboard.server.common.data.alarm.Alarm;
27 28 import org.thingsboard.server.common.data.audit.ActionType;
28 29 import org.thingsboard.server.common.data.edge.Edge;
29 30 import org.thingsboard.server.common.data.edge.EdgeEvent;
30 31 import org.thingsboard.server.common.data.edge.EdgeEventType;
31 32 import org.thingsboard.server.common.data.id.AlarmId;
  33 +import org.thingsboard.server.common.data.id.CustomerId;
32 34 import org.thingsboard.server.common.data.id.DashboardId;
33 35 import org.thingsboard.server.common.data.id.EdgeId;
34 36 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -36,19 +38,20 @@ import org.thingsboard.server.common.data.id.EntityIdFactory;
36 38 import org.thingsboard.server.common.data.id.IdBased;
37 39 import org.thingsboard.server.common.data.id.RuleChainId;
38 40 import org.thingsboard.server.common.data.id.TenantId;
  41 +import org.thingsboard.server.common.data.id.UserId;
39 42 import org.thingsboard.server.common.data.page.TextPageData;
40 43 import org.thingsboard.server.common.data.page.TextPageLink;
41 44 import org.thingsboard.server.common.data.page.TimePageData;
42 45 import org.thingsboard.server.common.data.page.TimePageLink;
43 46 import org.thingsboard.server.common.data.relation.EntityRelation;
44 47 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
45   -import org.thingsboard.server.common.data.rule.RuleChainMetaData;
46 48 import org.thingsboard.server.common.msg.queue.TbCallback;
47 49 import org.thingsboard.server.dao.alarm.AlarmService;
48 50 import org.thingsboard.server.dao.edge.EdgeEventService;
49 51 import org.thingsboard.server.dao.edge.EdgeService;
  52 +import org.thingsboard.server.dao.model.ModelConstants;
50 53 import org.thingsboard.server.dao.relation.RelationService;
51   -import org.thingsboard.server.dao.rule.RuleChainService;
  54 +import org.thingsboard.server.dao.user.UserService;
52 55 import org.thingsboard.server.gen.transport.TransportProtos;
53 56 import org.thingsboard.server.queue.util.TbCoreComponent;
54 57 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
... ... @@ -77,10 +80,10 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
77 80 private EdgeService edgeService;
78 81
79 82 @Autowired
80   - private RuleChainService ruleChainService;
  83 + private AlarmService alarmService;
81 84
82 85 @Autowired
83   - private AlarmService alarmService;
  86 + private UserService userService;
84 87
85 88 @Autowired
86 89 private RelationService relationService;
... ... @@ -147,12 +150,13 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
147 150 switch (edgeEventType) {
148 151 // TODO: voba - handle edge updates
149 152 // case EDGE:
  153 + case USER:
150 154 case ASSET:
151 155 case DEVICE:
152 156 case ENTITY_VIEW:
153 157 case DASHBOARD:
154 158 case RULE_CHAIN:
155   - processEntities(tenantId, edgeNotificationMsg);
  159 + processEntity(tenantId, edgeNotificationMsg);
156 160 break;
157 161 case ALARM:
158 162 processAlarm(tenantId, edgeNotificationMsg);
... ... @@ -171,7 +175,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
171 175 }
172 176 }
173 177
174   - private void processEntities(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
  178 + private void processEntity(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
175 179 ActionType edgeEventActionType = ActionType.valueOf(edgeNotificationMsg.getEdgeEventAction());
176 180 EdgeEventType edgeEventType = EdgeEventType.valueOf(edgeNotificationMsg.getEdgeEventType());
177 181 EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(edgeEventType, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
... ... @@ -179,16 +183,13 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
179 183 // TODO: voba - ADDED is not required for CE version ?
180 184 // case ADDED:
181 185 case UPDATED:
  186 + case CREDENTIALS_UPDATED:
182 187 ListenableFuture<List<EdgeId>> edgeIdsFuture = findRelatedEdgeIdsByEntityId(tenantId, entityId);
183 188 Futures.transform(edgeIdsFuture, edgeIds -> {
184 189 if (edgeIds != null && !edgeIds.isEmpty()) {
185 190 for (EdgeId edgeId : edgeIds) {
186 191 try {
187 192 saveEdgeEvent(tenantId, edgeId, edgeEventType, edgeEventActionType, entityId, null);
188   - if (edgeEventType.equals(EdgeEventType.RULE_CHAIN)) {
189   - RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(tenantId, new RuleChainId(entityId.getId()));
190   - saveEdgeEvent(tenantId, edgeId, EdgeEventType.RULE_CHAIN_METADATA, edgeEventActionType, ruleChainMetaData.getRuleChainId(), null);
191   - }
192 193 } catch (Exception e) {
193 194 log.error("[{}] Failed to push event to edge, edgeId [{}], edgeEventType [{}], edgeEventActionType [{}], entityId [{}]",
194 195 tenantId, edgeId, edgeEventType, edgeEventActionType, entityId, e);
... ... @@ -245,32 +246,35 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
245 246 }
246 247
247 248 private void processRelation(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
248   - EntityRelation entityRelation = mapper.convertValue(edgeNotificationMsg.getEntityBody(), EntityRelation.class);
249   - List<ListenableFuture<List<EdgeId>>> futures = new ArrayList<>();
250   - futures.add(findRelatedEdgeIdsByEntityId(tenantId, entityRelation.getTo()));
251   - futures.add(findRelatedEdgeIdsByEntityId(tenantId, entityRelation.getFrom()));
252   - ListenableFuture<List<List<EdgeId>>> combinedFuture = Futures.allAsList(futures);
253   - Futures.transform(combinedFuture, listOfListsEdgeIds -> {
254   - Set<EdgeId> uniqueEdgeIds = new HashSet<>();
255   - if (listOfListsEdgeIds != null && !listOfListsEdgeIds.isEmpty()) {
256   - for (List<EdgeId> listOfListsEdgeId : listOfListsEdgeIds) {
257   - if (listOfListsEdgeId != null) {
258   - uniqueEdgeIds.addAll(listOfListsEdgeId);
  249 + EntityRelation relation = mapper.convertValue(edgeNotificationMsg.getEntityBody(), EntityRelation.class);
  250 + if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
  251 + !relation.getTo().getEntityType().equals(EntityType.EDGE)) {
  252 + List<ListenableFuture<List<EdgeId>>> futures = new ArrayList<>();
  253 + futures.add(findRelatedEdgeIdsByEntityId(tenantId, relation.getTo()));
  254 + futures.add(findRelatedEdgeIdsByEntityId(tenantId, relation.getFrom()));
  255 + ListenableFuture<List<List<EdgeId>>> combinedFuture = Futures.allAsList(futures);
  256 + Futures.transform(combinedFuture, listOfListsEdgeIds -> {
  257 + Set<EdgeId> uniqueEdgeIds = new HashSet<>();
  258 + if (listOfListsEdgeIds != null && !listOfListsEdgeIds.isEmpty()) {
  259 + for (List<EdgeId> listOfListsEdgeId : listOfListsEdgeIds) {
  260 + if (listOfListsEdgeId != null) {
  261 + uniqueEdgeIds.addAll(listOfListsEdgeId);
  262 + }
259 263 }
260 264 }
261   - }
262   - if (!uniqueEdgeIds.isEmpty()) {
263   - for (EdgeId edgeId : uniqueEdgeIds) {
264   - saveEdgeEvent(tenantId,
265   - edgeId,
266   - EdgeEventType.RELATION,
267   - ActionType.valueOf(edgeNotificationMsg.getEdgeEventAction()),
268   - null,
269   - mapper.valueToTree(entityRelation));
  265 + if (!uniqueEdgeIds.isEmpty()) {
  266 + for (EdgeId edgeId : uniqueEdgeIds) {
  267 + saveEdgeEvent(tenantId,
  268 + edgeId,
  269 + EdgeEventType.RELATION,
  270 + ActionType.valueOf(edgeNotificationMsg.getEdgeEventAction()),
  271 + null,
  272 + mapper.valueToTree(relation));
  273 + }
270 274 }
271   - }
272   - return null;
273   - }, dbCallbackExecutorService);
  275 + return null;
  276 + }, dbCallbackExecutorService);
  277 + }
274 278 }
275 279
276 280 private ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) {
... ... @@ -278,7 +282,8 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
278 282 case DEVICE:
279 283 case ASSET:
280 284 case ENTITY_VIEW:
281   - ListenableFuture<List<EntityRelation>> originatorEdgeRelationsFuture = relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
  285 + ListenableFuture<List<EntityRelation>> originatorEdgeRelationsFuture =
  286 + relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
282 287 return Futures.transform(originatorEdgeRelationsFuture, originatorEdgeRelations -> {
283 288 if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) {
284 289 return Collections.singletonList(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId()));
... ... @@ -290,6 +295,15 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
290 295 return convertToEdgeIds(edgeService.findEdgesByTenantIdAndDashboardId(tenantId, new DashboardId(entityId.getId())));
291 296 case RULE_CHAIN:
292 297 return convertToEdgeIds(edgeService.findEdgesByTenantIdAndRuleChainId(tenantId, new RuleChainId(entityId.getId())));
  298 + case USER:
  299 + User userById = userService.findUserById(tenantId, new UserId(entityId.getId()));
  300 + TextPageData<Edge> edges;
  301 + if (userById.getCustomerId() == null || userById.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
  302 + edges = edgeService.findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE));
  303 + } else {
  304 + edges = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, new CustomerId(entityId.getId()), new TextPageLink(Integer.MAX_VALUE));
  305 + }
  306 + return convertToEdgeIds(Futures.immediateFuture(edges.getData()));
293 307 default:
294 308 return Futures.immediateFuture(Collections.emptyList());
295 309 }
... ... @@ -314,7 +328,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
314 328 case ENTITY_VIEW:
315 329 return EdgeEventType.ENTITY_VIEW;
316 330 default:
317   - log.info("Unsupported entity type: [{}]", entityType);
  331 + log.debug("Unsupported entity type: [{}]", entityType);
318 332 return null;
319 333 }
320 334 }
... ...
... ... @@ -33,6 +33,9 @@ import org.thingsboard.server.dao.entityview.EntityViewService;
33 33 import org.thingsboard.server.dao.relation.RelationService;
34 34 import org.thingsboard.server.dao.rule.RuleChainService;
35 35 import org.thingsboard.server.dao.user.UserService;
  36 +import org.thingsboard.server.queue.discovery.PartitionService;
  37 +import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
  38 +import org.thingsboard.server.queue.util.TbCoreComponent;
36 39 import org.thingsboard.server.service.edge.rpc.EdgeEventStorageSettings;
37 40 import org.thingsboard.server.service.edge.rpc.constructor.AlarmUpdateMsgConstructor;
38 41 import org.thingsboard.server.service.edge.rpc.constructor.AssetUpdateMsgConstructor;
... ... @@ -49,6 +52,7 @@ import org.thingsboard.server.service.queue.TbClusterService;
49 52 import org.thingsboard.server.service.state.DeviceStateService;
50 53
51 54 @Component
  55 +@TbCoreComponent
52 56 @Data
53 57 public class EdgeContextComponent {
54 58
... ... @@ -56,6 +60,13 @@ public class EdgeContextComponent {
56 60 @Autowired
57 61 private EdgeService edgeService;
58 62
  63 + @Autowired
  64 + private PartitionService partitionService;
  65 +
  66 + @Autowired
  67 + @Lazy
  68 + private TbQueueProducerProvider producerProvider;
  69 +
59 70 @Lazy
60 71 @Autowired
61 72 private EdgeNotificationService edgeNotificationService;
... ...
... ... @@ -26,8 +26,6 @@ import org.springframework.beans.factory.annotation.Value;
26 26 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
27 27 import org.springframework.stereotype.Service;
28 28 import org.thingsboard.server.common.data.id.EdgeId;
29   -import org.thingsboard.server.common.data.id.RuleChainId;
30   -import org.thingsboard.server.common.data.id.TenantId;
31 29 import org.thingsboard.server.gen.edge.EdgeRpcServiceGrpc;
32 30 import org.thingsboard.server.gen.edge.RequestMsg;
33 31 import org.thingsboard.server.gen.edge.ResponseMsg;
... ... @@ -48,7 +46,7 @@ import java.util.concurrent.Executors;
48 46 public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase {
49 47
50 48 private final Map<EdgeId, EdgeGrpcSession> sessions = new ConcurrentHashMap<>();
51   - private static final ObjectMapper objectMapper = new ObjectMapper();
  49 + private static final ObjectMapper mapper = new ObjectMapper();
52 50
53 51 @Value("${edges.rpc.port}")
54 52 private int rpcPort;
... ... @@ -102,7 +100,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase {
102 100
103 101 @Override
104 102 public StreamObserver<RequestMsg> handleMsgs(StreamObserver<ResponseMsg> outputStream) {
105   - return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, objectMapper).getInputStream();
  103 + return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, mapper).getInputStream();
106 104 }
107 105
108 106 private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) {
... ...
... ... @@ -22,13 +22,13 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
22 22 import com.google.common.util.concurrent.FutureCallback;
23 23 import com.google.common.util.concurrent.Futures;
24 24 import com.google.common.util.concurrent.ListenableFuture;
25   -import com.google.common.util.concurrent.MoreExecutors;
26 25 import com.google.gson.Gson;
27 26 import com.google.gson.JsonElement;
28 27 import com.google.gson.JsonObject;
29 28 import io.grpc.stub.StreamObserver;
30 29 import lombok.Data;
31 30 import lombok.extern.slf4j.Slf4j;
  31 +import org.apache.commons.lang.RandomStringUtils;
32 32 import org.checkerframework.checker.nullness.qual.Nullable;
33 33 import org.thingsboard.server.common.data.Dashboard;
34 34 import org.thingsboard.server.common.data.DataConstants;
... ... @@ -45,6 +45,7 @@ import org.thingsboard.server.common.data.edge.Edge;
45 45 import org.thingsboard.server.common.data.edge.EdgeEvent;
46 46 import org.thingsboard.server.common.data.id.AlarmId;
47 47 import org.thingsboard.server.common.data.id.AssetId;
  48 +import org.thingsboard.server.common.data.id.CustomerId;
48 49 import org.thingsboard.server.common.data.id.DashboardId;
49 50 import org.thingsboard.server.common.data.id.DeviceId;
50 51 import org.thingsboard.server.common.data.id.EdgeId;
... ... @@ -55,7 +56,6 @@ import org.thingsboard.server.common.data.id.TenantId;
55 56 import org.thingsboard.server.common.data.id.UserId;
56 57 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
57 58 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
58   -import org.thingsboard.server.common.data.kv.DataType;
59 59 import org.thingsboard.server.common.data.kv.LongDataEntry;
60 60 import org.thingsboard.server.common.data.page.TimePageData;
61 61 import org.thingsboard.server.common.data.page.TimePageLink;
... ... @@ -65,28 +65,45 @@ import org.thingsboard.server.common.data.rule.RuleChain;
65 65 import org.thingsboard.server.common.data.rule.RuleChainMetaData;
66 66 import org.thingsboard.server.common.data.security.DeviceCredentials;
67 67 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
  68 +import org.thingsboard.server.common.data.security.UserCredentials;
68 69 import org.thingsboard.server.common.msg.TbMsg;
69 70 import org.thingsboard.server.common.msg.TbMsgMetaData;
  71 +import org.thingsboard.server.common.msg.queue.ServiceType;
  72 +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
70 73 import org.thingsboard.server.common.msg.session.SessionMsgType;
71 74 import org.thingsboard.server.common.transport.util.JsonUtils;
72 75 import org.thingsboard.server.gen.edge.AlarmUpdateMsg;
  76 +import org.thingsboard.server.gen.edge.AssetUpdateMsg;
  77 +import org.thingsboard.server.gen.edge.AttributesRequestMsg;
73 78 import org.thingsboard.server.gen.edge.ConnectRequestMsg;
74 79 import org.thingsboard.server.gen.edge.ConnectResponseCode;
75 80 import org.thingsboard.server.gen.edge.ConnectResponseMsg;
  81 +import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
  82 +import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
  83 +import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
76 84 import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
77 85 import org.thingsboard.server.gen.edge.DownlinkMsg;
78 86 import org.thingsboard.server.gen.edge.EdgeConfiguration;
79 87 import org.thingsboard.server.gen.edge.EntityDataProto;
80 88 import org.thingsboard.server.gen.edge.EntityUpdateMsg;
  89 +import org.thingsboard.server.gen.edge.EntityViewUpdateMsg;
  90 +import org.thingsboard.server.gen.edge.RelationRequestMsg;
81 91 import org.thingsboard.server.gen.edge.RequestMsg;
82 92 import org.thingsboard.server.gen.edge.RequestMsgType;
83 93 import org.thingsboard.server.gen.edge.ResponseMsg;
84 94 import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg;
85 95 import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg;
  96 +import org.thingsboard.server.gen.edge.RuleChainUpdateMsg;
86 97 import org.thingsboard.server.gen.edge.UpdateMsgType;
87 98 import org.thingsboard.server.gen.edge.UplinkMsg;
88 99 import org.thingsboard.server.gen.edge.UplinkResponseMsg;
  100 +import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg;
  101 +import org.thingsboard.server.gen.edge.UserCredentialsUpdateMsg;
89 102 import org.thingsboard.server.gen.transport.TransportProtos;
  103 +import org.thingsboard.server.queue.TbQueueCallback;
  104 +import org.thingsboard.server.queue.TbQueueMsgMetadata;
  105 +import org.thingsboard.server.queue.TbQueueProducer;
  106 +import org.thingsboard.server.queue.common.TbProtoQueueMsg;
90 107 import org.thingsboard.server.service.edge.EdgeContextComponent;
91 108
92 109 import java.io.Closeable;
... ... @@ -115,7 +132,7 @@ public final class EdgeGrpcSession implements Closeable {
115 132 private final UUID sessionId;
116 133 private final BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener;
117 134 private final Consumer<EdgeId> sessionCloseListener;
118   - private final ObjectMapper objectMapper;
  135 + private final ObjectMapper mapper;
119 136
120 137 private EdgeContextComponent ctx;
121 138 private Edge edge;
... ... @@ -123,14 +140,17 @@ public final class EdgeGrpcSession implements Closeable {
123 140 private StreamObserver<ResponseMsg> outputStream;
124 141 private boolean connected;
125 142
  143 + private TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> ruleEngineMsgProducer;
  144 +
126 145 EdgeGrpcSession(EdgeContextComponent ctx, StreamObserver<ResponseMsg> outputStream, BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener,
127   - Consumer<EdgeId> sessionCloseListener, ObjectMapper objectMapper) {
  146 + Consumer<EdgeId> sessionCloseListener, ObjectMapper mapper) {
128 147 this.sessionId = UUID.randomUUID();
129 148 this.ctx = ctx;
130 149 this.outputStream = outputStream;
131 150 this.sessionOpenListener = sessionOpenListener;
132 151 this.sessionCloseListener = sessionCloseListener;
133   - this.objectMapper = objectMapper;
  152 + this.mapper = mapper;
  153 + this.ruleEngineMsgProducer = ctx.getProducerProvider().getRuleEngineMsgProducer();
134 154 initInputStream();
135 155 }
136 156
... ... @@ -147,7 +167,7 @@ public final class EdgeGrpcSession implements Closeable {
147 167 outputStream.onError(new RuntimeException(responseMsg.getErrorMsg()));
148 168 }
149 169 if (ConnectResponseCode.ACCEPTED == responseMsg.getResponseCode()) {
150   - ctx.getSyncEdgeService().sync(ctx, edge, outputStream);
  170 + ctx.getSyncEdgeService().sync(edge);
151 171 }
152 172 }
153 173 if (connected) {
... ... @@ -184,14 +204,23 @@ public final class EdgeGrpcSession implements Closeable {
184 204 for (EdgeEvent edgeEvent : pageData.getData()) {
185 205 log.trace("[{}] Processing edge event [{}]", this.sessionId, edgeEvent);
186 206 try {
187   - UpdateMsgType msgType = getResponseMsgType(ActionType.valueOf(edgeEvent.getEdgeEventAction()));
188   - if (msgType == null) {
189   - processTelemetryMessage(edgeEvent);
190   - } else {
191   - processEntityCRUDMessage(edgeEvent, msgType);
192   - if (ENTITY_CREATED_RPC_MESSAGE.equals(msgType)) {
193   - pushEntityAttributesToEdge(edgeEvent);
194   - }
  207 + ActionType edgeEventAction = ActionType.valueOf(edgeEvent.getEdgeEventAction());
  208 + switch (edgeEventAction) {
  209 + case UPDATED:
  210 + case ADDED:
  211 + case ASSIGNED_TO_EDGE:
  212 + case DELETED:
  213 + case UNASSIGNED_FROM_EDGE:
  214 + case ALARM_ACK:
  215 + case ALARM_CLEAR:
  216 + case CREDENTIALS_UPDATED:
  217 + processEntityMessage(edgeEvent, edgeEventAction);
  218 + break;
  219 + case ATTRIBUTES_UPDATED:
  220 + case ATTRIBUTES_DELETED:
  221 + case TIMESERIES_UPDATED:
  222 + processTelemetryMessage(edgeEvent);
  223 + break;
195 224 }
196 225 } catch (Exception e) {
197 226 log.error("Exception during processing records from queue", e);
... ... @@ -230,7 +259,7 @@ public final class EdgeGrpcSession implements Closeable {
230 259 } else {
231 260 return 0L;
232 261 }
233   - }, MoreExecutors.directExecutor());
  262 + }, ctx.getDbCallbackExecutor());
234 263 }
235 264
236 265 private void updateQueueStartTs(Long newStartTs) {
... ... @@ -239,12 +268,10 @@ public final class EdgeGrpcSession implements Closeable {
239 268 ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes);
240 269 }
241 270
242   - private void pushEntityAttributesToEdge(EdgeEvent edgeEvent) throws IOException {
  271 + private void processTelemetryMessage(EdgeEvent edgeEvent) throws IOException {
  272 + log.trace("Executing processTelemetryMessage, edgeEvent [{}]", edgeEvent);
243 273 EntityId entityId = null;
244 274 switch (edgeEvent.getEdgeEventType()) {
245   - case EDGE:
246   - entityId = edge.getId();
247   - break;
248 275 case DEVICE:
249 276 entityId = new DeviceId(edgeEvent.getEntityId());
250 277 break;
... ... @@ -259,59 +286,11 @@ public final class EdgeGrpcSession implements Closeable {
259 286 break;
260 287 }
261 288 if (entityId != null) {
262   - final EntityId finalEntityId = entityId;
263   - ListenableFuture<List<AttributeKvEntry>> ssAttrFuture = ctx.getAttributesService().findAll(edge.getTenantId(), entityId, DataConstants.SERVER_SCOPE);
264   - Futures.transform(ssAttrFuture, ssAttributes -> {
265   - if (ssAttributes != null && !ssAttributes.isEmpty()) {
266   - try {
267   - ObjectNode entityNode = objectMapper.createObjectNode();
268   - for (AttributeKvEntry attr : ssAttributes) {
269   - if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) {
270   - entityNode.put(attr.getKey(), attr.getBooleanValue().get());
271   - } else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) {
272   - entityNode.put(attr.getKey(), attr.getDoubleValue().get());
273   - } else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) {
274   - entityNode.put(attr.getKey(), attr.getLongValue().get());
275   - } else {
276   - entityNode.put(attr.getKey(), attr.getValueAsString());
277   - }
278   - }
279   - log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", finalEntityId, entityNode);
280   - DownlinkMsg value = constructEntityDataProtoMsg(finalEntityId, ActionType.ATTRIBUTES_UPDATED, JsonUtils.parse(objectMapper.writeValueAsString(entityNode)));
281   - outputStream.onNext(ResponseMsg.newBuilder()
282   - .setDownlinkMsg(value).build());
283   - } catch (Exception e) {
284   - log.error("[{}] Failed to send attribute updates to the edge", edge.getName(), e);
285   - }
286   - }
287   - return null;
288   - }, MoreExecutors.directExecutor());
289   - ListenableFuture<List<AttributeKvEntry>> shAttrFuture = ctx.getAttributesService().findAll(edge.getTenantId(), entityId, DataConstants.SHARED_SCOPE);
290   - ListenableFuture<List<AttributeKvEntry>> clAttrFuture = ctx.getAttributesService().findAll(edge.getTenantId(), entityId, DataConstants.CLIENT_SCOPE);
291   - }
292   - }
293   -
294   - private void processTelemetryMessage(EdgeEvent edgeEvent) throws IOException {
295   - log.trace("Executing processTelemetryMessage, edgeEvent [{}]", edgeEvent);
296   - EntityId entityId = null;
297   - switch (edgeEvent.getEdgeEventType()) {
298   - case DEVICE:
299   - entityId = new DeviceId(edgeEvent.getEntityId());
300   - break;
301   - case ASSET:
302   - entityId = new AssetId(edgeEvent.getEntityId());
303   - break;
304   - case ENTITY_VIEW:
305   - entityId = new EntityViewId(edgeEvent.getEntityId());
306   - break;
307   -
308   - }
309   - if (entityId != null) {
310 289 log.debug("Sending telemetry data msg, entityId [{}], body [{}]", edgeEvent.getEntityId(), edgeEvent.getEntityBody());
311 290 DownlinkMsg downlinkMsg;
312 291 try {
313 292 ActionType actionType = ActionType.valueOf(edgeEvent.getEdgeEventAction());
314   - downlinkMsg = constructEntityDataProtoMsg(entityId, actionType, JsonUtils.parse(objectMapper.writeValueAsString(edgeEvent.getEntityBody())));
  293 + downlinkMsg = constructEntityDataProtoMsg(entityId, actionType, JsonUtils.parse(mapper.writeValueAsString(edgeEvent.getEntityBody())));
315 294 outputStream.onNext(ResponseMsg.newBuilder()
316 295 .setDownlinkMsg(downlinkMsg)
317 296 .build());
... ... @@ -322,302 +301,268 @@ public final class EdgeGrpcSession implements Closeable {
322 301 }
323 302 }
324 303
325   - private void processEntityCRUDMessage(EdgeEvent edgeEvent, UpdateMsgType msgType) {
326   - log.trace("Executing processEntityCRUDMessage, edgeEvent [{}], msgType [{}]", edgeEvent, msgType);
  304 + private void processEntityMessage(EdgeEvent edgeEvent, ActionType edgeEventAction) {
  305 + UpdateMsgType msgType = getResponseMsgType(ActionType.valueOf(edgeEvent.getEdgeEventAction()));
  306 + log.trace("Executing processEntityMessage, edgeEvent [{}], edgeEventAction [{}], msgType [{}]", edgeEvent, edgeEventAction, msgType);
327 307 switch (edgeEvent.getEdgeEventType()) {
328 308 case EDGE:
329 309 // TODO: voba - add edge update logic
330 310 break;
331 311 case DEVICE:
332   - processDeviceCRUD(edgeEvent, msgType);
  312 + processDevice(edgeEvent, msgType, edgeEventAction);
333 313 break;
334 314 case ASSET:
335   - processAssetCRUD(edgeEvent, msgType);
  315 + processAsset(edgeEvent, msgType, edgeEventAction);
336 316 break;
337 317 case ENTITY_VIEW:
338   - processEntityViewCRUD(edgeEvent, msgType);
  318 + processEntityView(edgeEvent, msgType, edgeEventAction);
339 319 break;
340 320 case DASHBOARD:
341   - processDashboardCRUD(edgeEvent, msgType);
  321 + processDashboard(edgeEvent, msgType, edgeEventAction);
342 322 break;
343 323 case RULE_CHAIN:
344   - processRuleChainCRUD(edgeEvent, msgType);
  324 + processRuleChain(edgeEvent, msgType, edgeEventAction);
345 325 break;
346 326 case RULE_CHAIN_METADATA:
347   - processRuleChainMetadataCRUD(edgeEvent, msgType);
  327 + processRuleChainMetadata(edgeEvent, msgType);
348 328 break;
349 329 case ALARM:
350   - processAlarmCRUD(edgeEvent, msgType);
  330 + processAlarm(edgeEvent, msgType);
351 331 break;
352 332 case USER:
353   - processUserCRUD(edgeEvent, msgType);
  333 + processUser(edgeEvent, msgType, edgeEventAction);
354 334 break;
355 335 case RELATION:
356   - processRelationCRUD(edgeEvent, msgType);
  336 + processRelation(edgeEvent, msgType);
357 337 break;
358 338 }
359 339 }
360 340
361   - private void processDeviceCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  341 + private void processDevice(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeActionType) {
362 342 DeviceId deviceId = new DeviceId(edgeEvent.getEntityId());
363   - switch (msgType) {
364   - case ENTITY_CREATED_RPC_MESSAGE:
365   - case ENTITY_UPDATED_RPC_MESSAGE:
366   - case DEVICE_CONFLICT_RPC_MESSAGE:
367   - ListenableFuture<Device> deviceFuture = ctx.getDeviceService().findDeviceByIdAsync(edgeEvent.getTenantId(), deviceId);
368   - Futures.addCallback(deviceFuture,
369   - new FutureCallback<Device>() {
370   - @Override
371   - public void onSuccess(@Nullable Device device) {
372   - if (device != null) {
373   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
374   - .setDeviceUpdateMsg(ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(msgType, device))
375   - .build();
376   - outputStream.onNext(ResponseMsg.newBuilder()
377   - .setEntityUpdateMsg(entityUpdateMsg)
378   - .build());
379   - }
380   - }
381   -
382   - @Override
383   - public void onFailure(Throwable t) {
384   - log.warn("Can't processDeviceCRUD, edgeEvent [{}]", edgeEvent, t);
385   - }
386   - }, ctx.getDbCallbackExecutor());
  343 + EntityUpdateMsg entityUpdateMsg = null;
  344 + switch (edgeActionType) {
  345 + case ADDED:
  346 + case UPDATED:
  347 + case ASSIGNED_TO_EDGE:
  348 + Device device = ctx.getDeviceService().findDeviceById(edgeEvent.getTenantId(), deviceId);
  349 + if (device != null) {
  350 + DeviceUpdateMsg deviceUpdateMsg =
  351 + ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(msgType, device);
  352 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  353 + .setDeviceUpdateMsg(deviceUpdateMsg)
  354 + .build();
  355 + }
387 356 break;
388   - case ENTITY_DELETED_RPC_MESSAGE:
389   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
390   - .setDeviceUpdateMsg(ctx.getDeviceUpdateMsgConstructor().constructDeviceDeleteMsg(deviceId))
  357 + case DELETED:
  358 + case UNASSIGNED_FROM_EDGE:
  359 + DeviceUpdateMsg deviceUpdateMsg =
  360 + ctx.getDeviceUpdateMsgConstructor().constructDeviceDeleteMsg(deviceId);
  361 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  362 + .setDeviceUpdateMsg(deviceUpdateMsg)
391 363 .build();
392   - outputStream.onNext(ResponseMsg.newBuilder()
393   - .setEntityUpdateMsg(entityUpdateMsg)
394   - .build());
  364 + break;
  365 + case CREDENTIALS_UPDATED:
  366 + DeviceCredentials deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(edge.getTenantId(), deviceId);
  367 + if (deviceCredentials != null) {
  368 + DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg =
  369 + ctx.getDeviceUpdateMsgConstructor().constructDeviceCredentialsUpdatedMsg(deviceCredentials);
  370 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  371 + .setDeviceCredentialsUpdateMsg(deviceCredentialsUpdateMsg)
  372 + .build();
  373 + }
  374 + break;
  375 + }
  376 + if (entityUpdateMsg != null) {
  377 + outputStream.onNext(ResponseMsg.newBuilder()
  378 + .setEntityUpdateMsg(entityUpdateMsg)
  379 + .build());
395 380 }
396   -
397   -
398 381 }
399 382
400   - private void processAssetCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  383 + private void processAsset(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
401 384 AssetId assetId = new AssetId(edgeEvent.getEntityId());
402   - switch (msgType) {
403   - case ENTITY_CREATED_RPC_MESSAGE:
404   - case ENTITY_UPDATED_RPC_MESSAGE:
405   - case DEVICE_CONFLICT_RPC_MESSAGE:
406   - ListenableFuture<Asset> assetFuture = ctx.getAssetService().findAssetByIdAsync(edgeEvent.getTenantId(), assetId);
407   - Futures.addCallback(assetFuture,
408   - new FutureCallback<Asset>() {
409   - @Override
410   - public void onSuccess(@Nullable Asset asset) {
411   - if (asset != null) {
412   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
413   - .setAssetUpdateMsg(ctx.getAssetUpdateMsgConstructor().constructAssetUpdatedMsg(msgType, asset))
414   - .build();
415   - outputStream.onNext(ResponseMsg.newBuilder()
416   - .setEntityUpdateMsg(entityUpdateMsg)
417   - .build());
418   - }
419   - }
420   -
421   - @Override
422   - public void onFailure(Throwable t) {
423   - log.warn("Can't processAssetCRUD, edgeEvent [{}]", edgeEvent, t);
424   - }
425   - }, ctx.getDbCallbackExecutor());
  385 + EntityUpdateMsg entityUpdateMsg = null;
  386 + switch (edgeEventAction) {
  387 + case ADDED:
  388 + case UPDATED:
  389 + case ASSIGNED_TO_EDGE:
  390 + Asset asset = ctx.getAssetService().findAssetById(edgeEvent.getTenantId(), assetId);
  391 + if (asset != null) {
  392 + AssetUpdateMsg assetUpdateMsg =
  393 + ctx.getAssetUpdateMsgConstructor().constructAssetUpdatedMsg(msgType, asset);
  394 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  395 + .setAssetUpdateMsg(assetUpdateMsg)
  396 + .build();
  397 + }
426 398 break;
427   - case ENTITY_DELETED_RPC_MESSAGE:
428   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
429   - .setAssetUpdateMsg(ctx.getAssetUpdateMsgConstructor().constructAssetDeleteMsg(assetId))
  399 + case DELETED:
  400 + case UNASSIGNED_FROM_EDGE:
  401 + AssetUpdateMsg assetUpdateMsg =
  402 + ctx.getAssetUpdateMsgConstructor().constructAssetDeleteMsg(assetId);
  403 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  404 + .setAssetUpdateMsg(assetUpdateMsg)
430 405 .build();
431   - outputStream.onNext(ResponseMsg.newBuilder()
432   - .setEntityUpdateMsg(entityUpdateMsg)
433   - .build());
434 406 break;
435 407 }
  408 + if (entityUpdateMsg != null) {
  409 + outputStream.onNext(ResponseMsg.newBuilder()
  410 + .setEntityUpdateMsg(entityUpdateMsg)
  411 + .build());
  412 + }
436 413 }
437 414
438   - private void processEntityViewCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  415 + private void processEntityView(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
439 416 EntityViewId entityViewId = new EntityViewId(edgeEvent.getEntityId());
440   - switch (msgType) {
441   - case ENTITY_CREATED_RPC_MESSAGE:
442   - case ENTITY_UPDATED_RPC_MESSAGE:
443   - case DEVICE_CONFLICT_RPC_MESSAGE:
444   - ListenableFuture<EntityView> entityViewFuture = ctx.getEntityViewService().findEntityViewByIdAsync(edgeEvent.getTenantId(), entityViewId);
445   - Futures.addCallback(entityViewFuture,
446   - new FutureCallback<EntityView>() {
447   - @Override
448   - public void onSuccess(@Nullable EntityView entityView) {
449   - if (entityView != null) {
450   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
451   - .setEntityViewUpdateMsg(ctx.getEntityViewUpdateMsgConstructor().constructEntityViewUpdatedMsg(msgType, entityView))
452   - .build();
453   - outputStream.onNext(ResponseMsg.newBuilder()
454   - .setEntityUpdateMsg(entityUpdateMsg)
455   - .build());
456   - }
457   - }
458   -
459   - @Override
460   - public void onFailure(Throwable t) {
461   - log.warn("Can't processEntityViewCRUD, edgeEvent [{}]", edgeEvent, t);
462   - }
463   - }, ctx.getDbCallbackExecutor());
  417 + EntityUpdateMsg entityUpdateMsg = null;
  418 + switch (edgeEventAction) {
  419 + case ADDED:
  420 + case UPDATED:
  421 + case ASSIGNED_TO_EDGE:
  422 + EntityView entityView = ctx.getEntityViewService().findEntityViewById(edgeEvent.getTenantId(), entityViewId);
  423 + if (entityView != null) {
  424 + EntityViewUpdateMsg entityViewUpdateMsg =
  425 + ctx.getEntityViewUpdateMsgConstructor().constructEntityViewUpdatedMsg(msgType, entityView);
  426 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  427 + .setEntityViewUpdateMsg(entityViewUpdateMsg)
  428 + .build();
  429 + }
464 430 break;
465   - case ENTITY_DELETED_RPC_MESSAGE:
466   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
467   - .setEntityViewUpdateMsg(ctx.getEntityViewUpdateMsgConstructor().constructEntityViewDeleteMsg(entityViewId))
  431 + case DELETED:
  432 + case UNASSIGNED_FROM_EDGE:
  433 + EntityViewUpdateMsg entityViewUpdateMsg =
  434 + ctx.getEntityViewUpdateMsgConstructor().constructEntityViewDeleteMsg(entityViewId);
  435 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  436 + .setEntityViewUpdateMsg(entityViewUpdateMsg)
468 437 .build();
469   - outputStream.onNext(ResponseMsg.newBuilder()
470   - .setEntityUpdateMsg(entityUpdateMsg)
471   - .build());
472 438 break;
473 439 }
  440 + if (entityUpdateMsg != null) {
  441 + outputStream.onNext(ResponseMsg.newBuilder()
  442 + .setEntityUpdateMsg(entityUpdateMsg)
  443 + .build());
  444 + }
474 445 }
475 446
476   - private void processDashboardCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  447 + private void processDashboard(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
477 448 DashboardId dashboardId = new DashboardId(edgeEvent.getEntityId());
478   - switch (msgType) {
479   - case ENTITY_CREATED_RPC_MESSAGE:
480   - case ENTITY_UPDATED_RPC_MESSAGE:
481   - case DEVICE_CONFLICT_RPC_MESSAGE:
482   - ListenableFuture<Dashboard> dashboardFuture = ctx.getDashboardService().findDashboardByIdAsync(edgeEvent.getTenantId(), dashboardId);
483   - Futures.addCallback(dashboardFuture,
484   - new FutureCallback<Dashboard>() {
485   - @Override
486   - public void onSuccess(@Nullable Dashboard dashboard) {
487   - if (dashboard != null) {
488   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
489   - .setDashboardUpdateMsg(ctx.getDashboardUpdateMsgConstructor().constructDashboardUpdatedMsg(msgType, dashboard))
490   - .build();
491   - outputStream.onNext(ResponseMsg.newBuilder()
492   - .setEntityUpdateMsg(entityUpdateMsg)
493   - .build());
494   - }
495   - }
496   -
497   - @Override
498   - public void onFailure(Throwable t) {
499   - log.warn("Can't processDashboardCRUD, edgeEvent [{}]", edgeEvent, t);
500   - }
501   - }, ctx.getDbCallbackExecutor());
  449 + EntityUpdateMsg entityUpdateMsg = null;
  450 + switch (edgeEventAction) {
  451 + case ADDED:
  452 + case UPDATED:
  453 + case ASSIGNED_TO_EDGE:
  454 + Dashboard dashboard = ctx.getDashboardService().findDashboardById(edgeEvent.getTenantId(), dashboardId);
  455 + if (dashboard != null) {
  456 + DashboardUpdateMsg dashboardUpdateMsg =
  457 + ctx.getDashboardUpdateMsgConstructor().constructDashboardUpdatedMsg(msgType, dashboard);
  458 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  459 + .setDashboardUpdateMsg(dashboardUpdateMsg)
  460 + .build();
  461 + }
502 462 break;
503   - case ENTITY_DELETED_RPC_MESSAGE:
504   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
505   - .setDashboardUpdateMsg(ctx.getDashboardUpdateMsgConstructor().constructDashboardDeleteMsg(dashboardId))
  463 + case DELETED:
  464 + case UNASSIGNED_FROM_EDGE:
  465 + DashboardUpdateMsg dashboardUpdateMsg =
  466 + ctx.getDashboardUpdateMsgConstructor().constructDashboardDeleteMsg(dashboardId);
  467 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  468 + .setDashboardUpdateMsg(dashboardUpdateMsg)
506 469 .build();
507   - outputStream.onNext(ResponseMsg.newBuilder()
508   - .setEntityUpdateMsg(entityUpdateMsg)
509   - .build());
510 470 break;
511 471 }
  472 + if (entityUpdateMsg != null) {
  473 + outputStream.onNext(ResponseMsg.newBuilder()
  474 + .setEntityUpdateMsg(entityUpdateMsg)
  475 + .build());
  476 + }
512 477 }
513 478
514   - private void processRuleChainCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  479 + private void processRuleChain(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
515 480 RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId());
516   - switch (msgType) {
517   - case ENTITY_CREATED_RPC_MESSAGE:
518   - case ENTITY_UPDATED_RPC_MESSAGE:
519   - case DEVICE_CONFLICT_RPC_MESSAGE:
520   - ListenableFuture<RuleChain> ruleChainFuture = ctx.getRuleChainService().findRuleChainByIdAsync(edgeEvent.getTenantId(), ruleChainId);
521   - Futures.addCallback(ruleChainFuture,
522   - new FutureCallback<RuleChain>() {
523   - @Override
524   - public void onSuccess(@Nullable RuleChain ruleChain) {
525   - if (ruleChain != null) {
526   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
527   - .setRuleChainUpdateMsg(ctx.getRuleChainUpdateMsgConstructor().constructRuleChainUpdatedMsg(edge.getRootRuleChainId(), msgType, ruleChain))
528   - .build();
529   - outputStream.onNext(ResponseMsg.newBuilder()
530   - .setEntityUpdateMsg(entityUpdateMsg)
531   - .build());
532   - }
533   - }
534   -
535   - @Override
536   - public void onFailure(Throwable t) {
537   - log.warn("Can't processRuleChainCRUD, edgeEvent [{}]", edgeEvent, t);
538   - }
539   - }, ctx.getDbCallbackExecutor());
  481 + EntityUpdateMsg entityUpdateMsg = null;
  482 + switch (edgeEventAction) {
  483 + case ADDED:
  484 + case UPDATED:
  485 + case ASSIGNED_TO_EDGE:
  486 + RuleChain ruleChain = ctx.getRuleChainService().findRuleChainById(edgeEvent.getTenantId(), ruleChainId);
  487 + if (ruleChain != null) {
  488 + RuleChainUpdateMsg ruleChainUpdateMsg =
  489 + ctx.getRuleChainUpdateMsgConstructor().constructRuleChainUpdatedMsg(edge.getRootRuleChainId(), msgType, ruleChain);
  490 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  491 + .setRuleChainUpdateMsg(ruleChainUpdateMsg)
  492 + .build();
  493 + }
540 494 break;
541   - case ENTITY_DELETED_RPC_MESSAGE:
542   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  495 + case DELETED:
  496 + case UNASSIGNED_FROM_EDGE:
  497 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
543 498 .setRuleChainUpdateMsg(ctx.getRuleChainUpdateMsgConstructor().constructRuleChainDeleteMsg(ruleChainId))
544 499 .build();
545   - outputStream.onNext(ResponseMsg.newBuilder()
546   - .setEntityUpdateMsg(entityUpdateMsg)
547   - .build());
548 500 break;
549 501 }
  502 + if (entityUpdateMsg != null) {
  503 + outputStream.onNext(ResponseMsg.newBuilder()
  504 + .setEntityUpdateMsg(entityUpdateMsg)
  505 + .build());
  506 + }
550 507 }
551 508
552   - private void processRuleChainMetadataCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  509 + private void processRuleChainMetadata(EdgeEvent edgeEvent, UpdateMsgType msgType) {
553 510 RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId());
554   - ListenableFuture<RuleChain> ruleChainFuture = ctx.getRuleChainService().findRuleChainByIdAsync(edgeEvent.getTenantId(), ruleChainId);
555   - Futures.addCallback(ruleChainFuture,
556   - new FutureCallback<RuleChain>() {
557   - @Override
558   - public void onSuccess(@Nullable RuleChain ruleChain) {
559   - if (ruleChain != null) {
560   - RuleChainMetaData ruleChainMetaData = ctx.getRuleChainService().loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId);
561   - RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg =
562   - ctx.getRuleChainUpdateMsgConstructor().constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData);
563   - if (ruleChainMetadataUpdateMsg != null) {
564   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
565   - .setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg)
566   - .build();
567   - outputStream.onNext(ResponseMsg.newBuilder()
568   - .setEntityUpdateMsg(entityUpdateMsg)
569   - .build());
570   - }
571   - }
572   - }
573   -
574   - @Override
575   - public void onFailure(Throwable t) {
576   - log.warn("Can't processRuleChainMetadataCRUD, edgeEvent [{}]", edgeEvent, t);
577   - }
578   - }, ctx.getDbCallbackExecutor());
  511 + RuleChain ruleChain = ctx.getRuleChainService().findRuleChainById(edgeEvent.getTenantId(), ruleChainId);
  512 + if (ruleChain != null) {
  513 + RuleChainMetaData ruleChainMetaData = ctx.getRuleChainService().loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId);
  514 + RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg =
  515 + ctx.getRuleChainUpdateMsgConstructor().constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData);
  516 + if (ruleChainMetadataUpdateMsg != null) {
  517 + EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  518 + .setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg)
  519 + .build();
  520 + outputStream.onNext(ResponseMsg.newBuilder()
  521 + .setEntityUpdateMsg(entityUpdateMsg)
  522 + .build());
  523 + }
  524 + }
579 525 }
580 526
581   - private void processUserCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  527 + private void processUser(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeActionType) {
582 528 UserId userId = new UserId(edgeEvent.getEntityId());
583   - switch (msgType) {
584   - case ENTITY_CREATED_RPC_MESSAGE:
585   - case ENTITY_UPDATED_RPC_MESSAGE:
586   - case DEVICE_CONFLICT_RPC_MESSAGE:
587   - ListenableFuture<User> userFuture = ctx.getUserService().findUserByIdAsync(edgeEvent.getTenantId(), userId);
588   - Futures.addCallback(userFuture,
589   - new FutureCallback<User>() {
590   - @Override
591   - public void onSuccess(@Nullable User user) {
592   - if (user != null) {
593   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
594   - .setUserUpdateMsg(ctx.getUserUpdateMsgConstructor().constructUserUpdatedMsg(msgType, user))
595   - .build();
596   - outputStream.onNext(ResponseMsg.newBuilder()
597   - .setEntityUpdateMsg(entityUpdateMsg)
598   - .build());
599   - }
600   - }
601   -
602   - @Override
603   - public void onFailure(Throwable t) {
604   - log.warn("Can't processUserCRUD, edgeEvent [{}]", edgeEvent, t);
605   - }
606   - }, ctx.getDbCallbackExecutor());
  529 + EntityUpdateMsg entityUpdateMsg = null;
  530 + switch (edgeActionType) {
  531 + case ADDED:
  532 + case UPDATED:
  533 + case ASSIGNED_TO_EDGE:
  534 + User user = ctx.getUserService().findUserById(edgeEvent.getTenantId(), userId);
  535 + if (user != null) {
  536 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  537 + .setUserUpdateMsg(ctx.getUserUpdateMsgConstructor().constructUserUpdatedMsg(msgType, user))
  538 + .build();
  539 + }
607 540 break;
608   - case ENTITY_DELETED_RPC_MESSAGE:
609   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  541 + case DELETED:
  542 + case UNASSIGNED_FROM_EDGE:
  543 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
610 544 .setUserUpdateMsg(ctx.getUserUpdateMsgConstructor().constructUserDeleteMsg(userId))
611 545 .build();
612   - outputStream.onNext(ResponseMsg.newBuilder()
613   - .setEntityUpdateMsg(entityUpdateMsg)
614   - .build());
615 546 break;
  547 + case CREDENTIALS_UPDATED:
  548 + UserCredentials userCredentialsByUserId = ctx.getUserService().findUserCredentialsByUserId(edge.getTenantId(), userId);
  549 + if (userCredentialsByUserId != null) {
  550 + UserCredentialsUpdateMsg userCredentialsUpdateMsg =
  551 + ctx.getUserUpdateMsgConstructor().constructUserCredentialsUpdatedMsg(userCredentialsByUserId);
  552 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
  553 + .setUserCredentialsUpdateMsg(userCredentialsUpdateMsg)
  554 + .build();
  555 + }
  556 + }
  557 + if (entityUpdateMsg != null) {
  558 + outputStream.onNext(ResponseMsg.newBuilder()
  559 + .setEntityUpdateMsg(entityUpdateMsg)
  560 + .build());
616 561 }
617 562 }
618 563
619   - private void processRelationCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
620   - EntityRelation entityRelation = objectMapper.convertValue(edgeEvent.getEntityBody(), EntityRelation.class);
  564 + private void processRelation(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  565 + EntityRelation entityRelation = mapper.convertValue(edgeEvent.getEntityBody(), EntityRelation.class);
621 566 EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
622 567 .setRelationUpdateMsg(ctx.getRelationUpdateMsgConstructor().constructRelationUpdatedMsg(msgType, entityRelation))
623 568 .build();
... ... @@ -626,33 +571,27 @@ public final class EdgeGrpcSession implements Closeable {
626 571 .build());
627 572 }
628 573
629   - private void processAlarmCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
630   - AlarmId alarmId = new AlarmId(edgeEvent.getEntityId());
631   - ListenableFuture<Alarm> alarmFuture = ctx.getAlarmService().findAlarmByIdAsync(edgeEvent.getTenantId(), alarmId);
632   - Futures.addCallback(alarmFuture,
633   - new FutureCallback<Alarm>() {
634   - @Override
635   - public void onSuccess(@Nullable Alarm alarm) {
636   - if (alarm != null) {
637   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
638   - .setAlarmUpdateMsg(ctx.getAlarmUpdateMsgConstructor().constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm))
639   - .build();
640   - outputStream.onNext(ResponseMsg.newBuilder()
641   - .setEntityUpdateMsg(entityUpdateMsg)
642   - .build());
643   - }
644   - }
645   -
646   - @Override
647   - public void onFailure(Throwable t) {
648   - log.warn("Can't processAlarmCRUD, edgeEvent [{}]", edgeEvent, t);
649   - }
650   - }, ctx.getDbCallbackExecutor());
  574 + private void processAlarm(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  575 + try {
  576 + AlarmId alarmId = new AlarmId(edgeEvent.getEntityId());
  577 + Alarm alarm = ctx.getAlarmService().findAlarmByIdAsync(edgeEvent.getTenantId(), alarmId).get();
  578 + if (alarm != null) {
  579 + EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  580 + .setAlarmUpdateMsg(ctx.getAlarmUpdateMsgConstructor().constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm))
  581 + .build();
  582 + outputStream.onNext(ResponseMsg.newBuilder()
  583 + .setEntityUpdateMsg(entityUpdateMsg)
  584 + .build());
  585 + }
  586 + } catch (Exception e) {
  587 + log.error("Can't process alarm msg [{}] [{}]", edgeEvent, msgType, e);
  588 + }
651 589 }
652 590
653 591 private UpdateMsgType getResponseMsgType(ActionType actionType) {
654 592 switch (actionType) {
655 593 case UPDATED:
  594 + case CREDENTIALS_UPDATED:
656 595 return UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE;
657 596 case ADDED:
658 597 case ASSIGNED_TO_EDGE:
... ... @@ -664,10 +603,6 @@ public final class EdgeGrpcSession implements Closeable {
664 603 return UpdateMsgType.ALARM_ACK_RPC_MESSAGE;
665 604 case ALARM_CLEAR:
666 605 return UpdateMsgType.ALARM_CLEAR_RPC_MESSAGE;
667   - case ATTRIBUTES_UPDATED:
668   - case ATTRIBUTES_DELETED:
669   - case TIMESERIES_DELETED:
670   - return null;
671 606 default:
672 607 throw new RuntimeException("Unsupported actionType [" + actionType + "]");
673 608 }
... ... @@ -702,11 +637,17 @@ public final class EdgeGrpcSession implements Closeable {
702 637 }
703 638 }
704 639 }
  640 +
705 641 if (uplinkMsg.getDeviceUpdateMsgList() != null && !uplinkMsg.getDeviceUpdateMsgList().isEmpty()) {
706 642 for (DeviceUpdateMsg deviceUpdateMsg : uplinkMsg.getDeviceUpdateMsgList()) {
707 643 onDeviceUpdate(deviceUpdateMsg);
708 644 }
709 645 }
  646 + if (uplinkMsg.getDeviceCredentialsUpdateMsgList() != null && !uplinkMsg.getDeviceCredentialsUpdateMsgList().isEmpty()) {
  647 + for (DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg : uplinkMsg.getDeviceCredentialsUpdateMsgList()) {
  648 + onDeviceCredentialsUpdate(deviceCredentialsUpdateMsg);
  649 + }
  650 + }
710 651 if (uplinkMsg.getAlarmUpdateMsgList() != null && !uplinkMsg.getAlarmUpdateMsgList().isEmpty()) {
711 652 for (AlarmUpdateMsg alarmUpdateMsg : uplinkMsg.getAlarmUpdateMsgList()) {
712 653 onAlarmUpdate(alarmUpdateMsg);
... ... @@ -714,7 +655,27 @@ public final class EdgeGrpcSession implements Closeable {
714 655 }
715 656 if (uplinkMsg.getRuleChainMetadataRequestMsgList() != null && !uplinkMsg.getRuleChainMetadataRequestMsgList().isEmpty()) {
716 657 for (RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg : uplinkMsg.getRuleChainMetadataRequestMsgList()) {
717   - ctx.getSyncEdgeService().syncRuleChainMetadata(edge, ruleChainMetadataRequestMsg, outputStream);
  658 + ctx.getSyncEdgeService().processRuleChainMetadataRequestMsg(edge, ruleChainMetadataRequestMsg);
  659 + }
  660 + }
  661 + if (uplinkMsg.getAttributesRequestMsgList() != null && !uplinkMsg.getAttributesRequestMsgList().isEmpty()) {
  662 + for (AttributesRequestMsg attributesRequestMsg : uplinkMsg.getAttributesRequestMsgList()) {
  663 + ctx.getSyncEdgeService().processAttributesRequestMsg(edge, attributesRequestMsg);
  664 + }
  665 + }
  666 + if (uplinkMsg.getRelationRequestMsgList() != null && !uplinkMsg.getRelationRequestMsgList().isEmpty()) {
  667 + for (RelationRequestMsg relationRequestMsg : uplinkMsg.getRelationRequestMsgList()) {
  668 + ctx.getSyncEdgeService().processRelationRequestMsg(edge, relationRequestMsg);
  669 + }
  670 + }
  671 + if (uplinkMsg.getUserCredentialsRequestMsgList() != null && !uplinkMsg.getUserCredentialsRequestMsgList().isEmpty()) {
  672 + for (UserCredentialsRequestMsg userCredentialsRequestMsg : uplinkMsg.getUserCredentialsRequestMsgList()) {
  673 + ctx.getSyncEdgeService().processUserCredentialsRequestMsg(edge, userCredentialsRequestMsg);
  674 + }
  675 + }
  676 + if (uplinkMsg.getDeviceCredentialsRequestMsgList() != null && !uplinkMsg.getDeviceCredentialsRequestMsgList().isEmpty()) {
  677 + for (DeviceCredentialsRequestMsg deviceCredentialsRequestMsg : uplinkMsg.getDeviceCredentialsRequestMsgList()) {
  678 + ctx.getSyncEdgeService().processDeviceCredentialsRequestMsg(edge, deviceCredentialsRequestMsg);
718 679 }
719 680 }
720 681 } catch (Exception e) {
... ... @@ -817,17 +778,19 @@ public final class EdgeGrpcSession implements Closeable {
817 778 Device deviceById = ctx.getDeviceService().findDeviceById(edge.getTenantId(), edgeDeviceId);
818 779 if (deviceById != null) {
819 780 // this ID already used by other device - create new device and update ID on the edge
820   - Device savedDevice = createDevice(deviceUpdateMsg);
  781 + device = createDevice(deviceUpdateMsg);
821 782 EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
822   - .setDeviceUpdateMsg(ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(UpdateMsgType.DEVICE_CONFLICT_RPC_MESSAGE, savedDevice))
  783 + .setDeviceUpdateMsg(ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(UpdateMsgType.DEVICE_CONFLICT_RPC_MESSAGE, device))
823 784 .build();
824 785 outputStream.onNext(ResponseMsg.newBuilder()
825 786 .setEntityUpdateMsg(entityUpdateMsg)
826 787 .build());
827 788 } else {
828   - createDevice(deviceUpdateMsg);
  789 + device = createDevice(deviceUpdateMsg);
829 790 }
830 791 }
  792 + // TODO: voba - assign device only in case device is not assigned yet. Missing functionality to check this relation prior assignment
  793 + ctx.getDeviceService().assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId());
831 794 break;
832 795 case ENTITY_UPDATED_RPC_MESSAGE:
833 796 updateDevice(deviceUpdateMsg);
... ... @@ -850,21 +813,57 @@ public final class EdgeGrpcSession implements Closeable {
850 813 device.setType(deviceUpdateMsg.getType());
851 814 device.setLabel(deviceUpdateMsg.getLabel());
852 815 device = ctx.getDeviceService().saveDevice(device);
853   - updateDeviceCredentials(deviceUpdateMsg, device);
  816 +
  817 + requestDeviceCredentialsFromEdge(device);
854 818 }
855 819
856   - private void updateDeviceCredentials(DeviceUpdateMsg deviceUpdateMsg, Device device) {
857   - log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]",
858   - device.getName(), deviceUpdateMsg.getCredentialsId(), deviceUpdateMsg.getCredentialsValue());
  820 + private void onDeviceCredentialsUpdate(DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg) {
  821 + log.debug("Executing onDeviceCredentialsUpdate, deviceCredentialsUpdateMsg [{}]", deviceCredentialsUpdateMsg);
  822 + DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsUpdateMsg.getDeviceIdMSB(), deviceCredentialsUpdateMsg.getDeviceIdLSB()));
  823 + ListenableFuture<Device> deviceFuture = ctx.getDeviceService().findDeviceByIdAsync(edge.getTenantId(), deviceId);
859 824
860   - DeviceCredentials deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(edge.getTenantId(), device.getId());
861   - deviceCredentials.setCredentialsType(DeviceCredentialsType.valueOf(deviceUpdateMsg.getCredentialsType()));
862   - deviceCredentials.setCredentialsId(deviceUpdateMsg.getCredentialsId());
863   - deviceCredentials.setCredentialsValue(deviceUpdateMsg.getCredentialsValue());
864   - ctx.getDeviceCredentialsService().updateDeviceCredentials(edge.getTenantId(), deviceCredentials);
865   - log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]",
866   - device.getName(), deviceUpdateMsg.getCredentialsId(), deviceUpdateMsg.getCredentialsValue());
  825 + Futures.addCallback(deviceFuture, new FutureCallback<Device>() {
  826 + @Override
  827 + public void onSuccess(@Nullable Device device) {
  828 + if (device != null) {
  829 + log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]",
  830 + device.getName(), deviceCredentialsUpdateMsg.getCredentialsId(), deviceCredentialsUpdateMsg.getCredentialsValue());
  831 + try {
  832 + DeviceCredentials deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(edge.getTenantId(), device.getId());
  833 + deviceCredentials.setCredentialsType(DeviceCredentialsType.valueOf(deviceCredentialsUpdateMsg.getCredentialsType()));
  834 + deviceCredentials.setCredentialsId(deviceCredentialsUpdateMsg.getCredentialsId());
  835 + deviceCredentials.setCredentialsValue(deviceCredentialsUpdateMsg.getCredentialsValue());
  836 + ctx.getDeviceCredentialsService().updateDeviceCredentials(edge.getTenantId(), deviceCredentials);
  837 + } catch (Exception e) {
  838 + log.error("Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]", device.getName(), deviceCredentialsUpdateMsg, e);
  839 + }
  840 + }
  841 + }
867 842
  843 + @Override
  844 + public void onFailure(Throwable t) {
  845 + log.error("Can't update device credentials for deviceCredentialsUpdateMsg [{}]", deviceCredentialsUpdateMsg, t);
  846 + }
  847 + }, ctx.getDbCallbackExecutor());
  848 + }
  849 +
  850 + private void requestDeviceCredentialsFromEdge(Device device) {
  851 + log.debug("Executing requestDeviceCredentialsFromEdge device [{}]", device);
  852 +
  853 + DownlinkMsg downlinkMsg = constructDeviceCredentialsRequestMsg(device.getId());
  854 + outputStream.onNext(ResponseMsg.newBuilder()
  855 + .setDownlinkMsg(downlinkMsg)
  856 + .build());
  857 + }
  858 +
  859 + private DownlinkMsg constructDeviceCredentialsRequestMsg(DeviceId deviceId) {
  860 + DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = DeviceCredentialsRequestMsg.newBuilder()
  861 + .setDeviceIdMSB(deviceId.getId().getMostSignificantBits())
  862 + .setDeviceIdLSB(deviceId.getId().getLeastSignificantBits())
  863 + .build();
  864 + DownlinkMsg.Builder builder = DownlinkMsg.newBuilder()
  865 + .addAllDeviceCredentialsRequestMsg(Collections.singletonList(deviceCredentialsRequestMsg));
  866 + return builder.build();
868 867 }
869 868
870 869 private Device createDevice(DeviceUpdateMsg deviceUpdateMsg) {
... ... @@ -880,17 +879,68 @@ public final class EdgeGrpcSession implements Closeable {
880 879 device.setType(deviceUpdateMsg.getType());
881 880 device.setLabel(deviceUpdateMsg.getLabel());
882 881 device = ctx.getDeviceService().saveDevice(device);
883   - device = ctx.getDeviceService().assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId());
  882 + createDeviceCredentials(device);
884 883 createRelationFromEdge(device.getId());
885   - ctx.getRelationService().saveRelationAsync(TenantId.SYS_TENANT_ID, new EntityRelation(edge.getId(), device.getId(), "Created"));
886 884 ctx.getDeviceStateService().onDeviceAdded(device);
887   - updateDeviceCredentials(deviceUpdateMsg, device);
  885 + pushDeviceCreatedEventToRuleEngine(device);
  886 + requestDeviceCredentialsFromEdge(device);
888 887 } finally {
889 888 deviceCreationLock.unlock();
890 889 }
891 890 return device;
892 891 }
893 892
  893 + private void createDeviceCredentials(Device device) {
  894 + DeviceCredentials deviceCredentials = new DeviceCredentials();
  895 + deviceCredentials.setDeviceId(device.getId());
  896 + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
  897 + deviceCredentials.setCredentialsId(RandomStringUtils.randomAlphanumeric(20));
  898 + ctx.getDeviceCredentialsService().createDeviceCredentials(device.getTenantId(), deviceCredentials);
  899 + }
  900 +
  901 + private void pushDeviceCreatedEventToRuleEngine(Device device) {
  902 + try {
  903 + ObjectNode entityNode = mapper.valueToTree(device);
  904 + TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, device.getId(), getActionTbMsgMetaData(device.getCustomerId()), mapper.writeValueAsString(entityNode));
  905 + sendToRuleEngine(edge.getTenantId(), tbMsg, new TbQueueCallback() {
  906 + @Override
  907 + public void onSuccess(TbQueueMsgMetadata metadata) {
  908 + // TODO: voba - handle success
  909 + }
  910 +
  911 + @Override
  912 + public void onFailure(Throwable t) {
  913 + // TODO: voba - handle failure
  914 + }
  915 + });
  916 + } catch (JsonProcessingException | IllegalArgumentException e) {
  917 + log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), DataConstants.ENTITY_CREATED, e);
  918 + }
  919 + }
  920 +
  921 + protected void sendToRuleEngine(TenantId tenantId, TbMsg tbMsg, TbQueueCallback callback) {
  922 + TopicPartitionInfo tpi = ctx.getPartitionService().resolve(ServiceType.TB_RULE_ENGINE, tenantId, tbMsg.getOriginator());
  923 + TransportProtos.ToRuleEngineMsg msg = TransportProtos.ToRuleEngineMsg.newBuilder().setTbMsg(TbMsg.toByteString(tbMsg))
  924 + .setTenantIdMSB(tenantId.getId().getMostSignificantBits())
  925 + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()).build();
  926 + ruleEngineMsgProducer.send(tpi, new TbProtoQueueMsg<>(tbMsg.getId(), msg), callback);
  927 + }
  928 +
  929 + private TbMsgMetaData getActionTbMsgMetaData(CustomerId customerId) {
  930 + TbMsgMetaData metaData = getTbMsgMetaData(edge);
  931 + if (customerId != null && !customerId.isNullUid()) {
  932 + metaData.putValue("customerId", customerId.toString());
  933 + }
  934 + return metaData;
  935 + }
  936 +
  937 + private TbMsgMetaData getTbMsgMetaData(Edge edge) {
  938 + TbMsgMetaData metaData = new TbMsgMetaData();
  939 + metaData.putValue("edgeId", edge.getId().toString());
  940 + metaData.putValue("edgeName", edge.getName());
  941 + return metaData;
  942 + }
  943 +
894 944 private EntityId getAlarmOriginator(String entityName, org.thingsboard.server.common.data.EntityType entityType) {
895 945 switch (entityType) {
896 946 case DEVICE:
... ... @@ -925,7 +975,7 @@ public final class EdgeGrpcSession implements Closeable {
925 975 existentAlarm.setPropagate(alarmUpdateMsg.getPropagate());
926 976 }
927 977 existentAlarm.setEndTs(alarmUpdateMsg.getEndTs());
928   - existentAlarm.setDetails(objectMapper.readTree(alarmUpdateMsg.getDetails()));
  978 + existentAlarm.setDetails(mapper.readTree(alarmUpdateMsg.getDetails()));
929 979 ctx.getAlarmService().createOrUpdateAlarm(existentAlarm);
930 980 break;
931 981 case ALARM_ACK_RPC_MESSAGE:
... ... @@ -935,7 +985,7 @@ public final class EdgeGrpcSession implements Closeable {
935 985 break;
936 986 case ALARM_CLEAR_RPC_MESSAGE:
937 987 if (existentAlarm != null) {
938   - ctx.getAlarmService().clearAlarm(edge.getTenantId(), existentAlarm.getId(), objectMapper.readTree(alarmUpdateMsg.getDetails()), alarmUpdateMsg.getAckTs());
  988 + ctx.getAlarmService().clearAlarm(edge.getTenantId(), existentAlarm.getId(), mapper.readTree(alarmUpdateMsg.getDetails()), alarmUpdateMsg.getAckTs());
939 989 }
940 990 break;
941 991 case ENTITY_DELETED_RPC_MESSAGE:
... ...
... ... @@ -16,11 +16,9 @@
16 16 package org.thingsboard.server.service.edge.rpc.constructor;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19   -import org.springframework.beans.factory.annotation.Autowired;
20 19 import org.springframework.stereotype.Component;
21 20 import org.thingsboard.server.common.data.Dashboard;
22 21 import org.thingsboard.server.common.data.id.DashboardId;
23   -import org.thingsboard.server.dao.dashboard.DashboardService;
24 22 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
25 23 import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
26 24 import org.thingsboard.server.gen.edge.UpdateMsgType;
... ... @@ -29,11 +27,7 @@ import org.thingsboard.server.gen.edge.UpdateMsgType;
29 27 @Slf4j
30 28 public class DashboardUpdateMsgConstructor {
31 29
32   - @Autowired
33   - private DashboardService dashboardService;
34   -
35 30 public DashboardUpdateMsg constructDashboardUpdatedMsg(UpdateMsgType msgType, Dashboard dashboard) {
36   - dashboard = dashboardService.findDashboardById(dashboard.getTenantId(), dashboard.getId());
37 31 DashboardUpdateMsg.Builder builder = DashboardUpdateMsg.newBuilder()
38 32 .setMsgType(msgType)
39 33 .setIdMSB(dashboard.getId().getId().getMostSignificantBits())
... ...
... ... @@ -16,12 +16,11 @@
16 16 package org.thingsboard.server.service.edge.rpc.constructor;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19   -import org.springframework.beans.factory.annotation.Autowired;
20 19 import org.springframework.stereotype.Component;
21 20 import org.thingsboard.server.common.data.Device;
22 21 import org.thingsboard.server.common.data.id.DeviceId;
23 22 import org.thingsboard.server.common.data.security.DeviceCredentials;
24   -import org.thingsboard.server.dao.device.DeviceCredentialsService;
  23 +import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
25 24 import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
26 25 import org.thingsboard.server.gen.edge.UpdateMsgType;
27 26
... ... @@ -29,9 +28,6 @@ import org.thingsboard.server.gen.edge.UpdateMsgType;
29 28 @Slf4j
30 29 public class DeviceUpdateMsgConstructor {
31 30
32   - @Autowired
33   - private DeviceCredentialsService deviceCredentialsService;
34   -
35 31 public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device) {
36 32 DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder()
37 33 .setMsgType(msgType)
... ... @@ -42,20 +38,19 @@ public class DeviceUpdateMsgConstructor {
42 38 if (device.getLabel() != null) {
43 39 builder.setLabel(device.getLabel());
44 40 }
45   - if (msgType.equals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE) ||
46   - msgType.equals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE) ||
47   - msgType.equals(UpdateMsgType.DEVICE_CONFLICT_RPC_MESSAGE)) {
48   - DeviceCredentials deviceCredentials
49   - = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), device.getId());
50   - if (deviceCredentials != null) {
51   - if (deviceCredentials.getCredentialsType() != null) {
52   - builder.setCredentialsType(deviceCredentials.getCredentialsType().name())
53   - .setCredentialsId(deviceCredentials.getCredentialsId());
54   - }
55   - if (deviceCredentials.getCredentialsValue() != null) {
56   - builder.setCredentialsValue(deviceCredentials.getCredentialsValue());
57   - }
58   - }
  41 + return builder.build();
  42 + }
  43 +
  44 + public DeviceCredentialsUpdateMsg constructDeviceCredentialsUpdatedMsg(DeviceCredentials deviceCredentials) {
  45 + DeviceCredentialsUpdateMsg.Builder builder = DeviceCredentialsUpdateMsg.newBuilder()
  46 + .setDeviceIdMSB(deviceCredentials.getDeviceId().getId().getMostSignificantBits())
  47 + .setDeviceIdLSB(deviceCredentials.getDeviceId().getId().getLeastSignificantBits());
  48 + if (deviceCredentials.getCredentialsType() != null) {
  49 + builder.setCredentialsType(deviceCredentials.getCredentialsType().name())
  50 + .setCredentialsId(deviceCredentials.getCredentialsId());
  51 + }
  52 + if (deviceCredentials.getCredentialsValue() != null) {
  53 + builder.setCredentialsValue(deviceCredentials.getCredentialsValue());
59 54 }
60 55 return builder.build();
61 56 }
... ...
... ... @@ -16,31 +16,26 @@
16 16 package org.thingsboard.server.service.edge.rpc.constructor;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19   -import org.springframework.beans.factory.annotation.Autowired;
20 19 import org.springframework.stereotype.Component;
21 20 import org.thingsboard.server.common.data.User;
22 21 import org.thingsboard.server.common.data.id.UserId;
23 22 import org.thingsboard.server.common.data.security.UserCredentials;
24   -import org.thingsboard.server.dao.user.UserService;
25 23 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
26 24 import org.thingsboard.server.gen.edge.UpdateMsgType;
  25 +import org.thingsboard.server.gen.edge.UserCredentialsUpdateMsg;
27 26 import org.thingsboard.server.gen.edge.UserUpdateMsg;
28 27
29 28 @Component
30 29 @Slf4j
31 30 public class UserUpdateMsgConstructor {
32 31
33   - @Autowired
34   - private UserService userService;
35   -
36 32 public UserUpdateMsg constructUserUpdatedMsg(UpdateMsgType msgType, User user) {
37 33 UserUpdateMsg.Builder builder = UserUpdateMsg.newBuilder()
38 34 .setMsgType(msgType)
39 35 .setIdMSB(user.getId().getId().getMostSignificantBits())
40 36 .setIdLSB(user.getId().getId().getLeastSignificantBits())
41 37 .setEmail(user.getEmail())
42   - .setAuthority(user.getAuthority().name())
43   - .setEnabled(false);
  38 + .setAuthority(user.getAuthority().name());
44 39 if (user.getFirstName() != null) {
45 40 builder.setFirstName(user.getFirstName());
46 41 }
... ... @@ -53,13 +48,6 @@ public class UserUpdateMsgConstructor {
53 48 if (user.getAdditionalInfo() != null) {
54 49 builder.setAdditionalInfo(JacksonUtil.toString(user.getAdditionalInfo()));
55 50 }
56   - if (msgType.equals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE) ||
57   - msgType.equals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE)) {
58   - UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
59   - if (userCredentials != null) {
60   - builder.setEnabled(userCredentials.isEnabled()).setPassword(userCredentials.getPassword());
61   - }
62   - }
63 51 return builder.build();
64 52 }
65 53
... ... @@ -69,4 +57,13 @@ public class UserUpdateMsgConstructor {
69 57 .setIdMSB(userId.getId().getMostSignificantBits())
70 58 .setIdLSB(userId.getId().getLeastSignificantBits()).build();
71 59 }
  60 +
  61 + public UserCredentialsUpdateMsg constructUserCredentialsUpdatedMsg(UserCredentials userCredentials) {
  62 + UserCredentialsUpdateMsg.Builder builder = UserCredentialsUpdateMsg.newBuilder()
  63 + .setUserIdMSB(userCredentials.getUserId().getId().getMostSignificantBits())
  64 + .setUserIdLSB(userCredentials.getUserId().getId().getLeastSignificantBits())
  65 + .setEnabled(userCredentials.isEnabled())
  66 + .setPassword(userCredentials.getPassword());
  67 + return builder.build();
  68 + }
72 69 }
... ...
... ... @@ -15,22 +15,36 @@
15 15 */
16 16 package org.thingsboard.server.service.edge.rpc.init;
17 17
  18 +import com.fasterxml.jackson.databind.JsonNode;
  19 +import com.fasterxml.jackson.databind.ObjectMapper;
  20 +import com.fasterxml.jackson.databind.node.ObjectNode;
  21 +import com.google.common.util.concurrent.FutureCallback;
18 22 import com.google.common.util.concurrent.Futures;
19 23 import com.google.common.util.concurrent.ListenableFuture;
20   -import com.google.common.util.concurrent.MoreExecutors;
21   -import io.grpc.stub.StreamObserver;
22 24 import lombok.extern.slf4j.Slf4j;
  25 +import org.checkerframework.checker.nullness.qual.Nullable;
23 26 import org.springframework.beans.factory.annotation.Autowired;
24 27 import org.springframework.stereotype.Service;
25   -import org.thingsboard.server.common.data.Dashboard;
26 28 import org.thingsboard.server.common.data.DashboardInfo;
  29 +import org.thingsboard.server.common.data.DataConstants;
27 30 import org.thingsboard.server.common.data.Device;
  31 +import org.thingsboard.server.common.data.EntityType;
28 32 import org.thingsboard.server.common.data.EntityView;
29 33 import org.thingsboard.server.common.data.User;
30 34 import org.thingsboard.server.common.data.asset.Asset;
  35 +import org.thingsboard.server.common.data.audit.ActionType;
31 36 import org.thingsboard.server.common.data.edge.Edge;
  37 +import org.thingsboard.server.common.data.edge.EdgeEvent;
  38 +import org.thingsboard.server.common.data.edge.EdgeEventType;
  39 +import org.thingsboard.server.common.data.id.DeviceId;
  40 +import org.thingsboard.server.common.data.id.EdgeId;
32 41 import org.thingsboard.server.common.data.id.EntityId;
  42 +import org.thingsboard.server.common.data.id.EntityIdFactory;
33 43 import org.thingsboard.server.common.data.id.RuleChainId;
  44 +import org.thingsboard.server.common.data.id.TenantId;
  45 +import org.thingsboard.server.common.data.id.UserId;
  46 +import org.thingsboard.server.common.data.kv.AttributeKvEntry;
  47 +import org.thingsboard.server.common.data.kv.DataType;
34 48 import org.thingsboard.server.common.data.page.TextPageData;
35 49 import org.thingsboard.server.common.data.page.TextPageLink;
36 50 import org.thingsboard.server.common.data.page.TimePageData;
... ... @@ -40,45 +54,38 @@ import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
40 54 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
41 55 import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
42 56 import org.thingsboard.server.common.data.rule.RuleChain;
43   -import org.thingsboard.server.common.data.rule.RuleChainMetaData;
44 57 import org.thingsboard.server.dao.asset.AssetService;
  58 +import org.thingsboard.server.dao.attributes.AttributesService;
45 59 import org.thingsboard.server.dao.dashboard.DashboardService;
46 60 import org.thingsboard.server.dao.device.DeviceService;
  61 +import org.thingsboard.server.dao.edge.EdgeEventService;
47 62 import org.thingsboard.server.dao.entityview.EntityViewService;
48 63 import org.thingsboard.server.dao.relation.RelationService;
49 64 import org.thingsboard.server.dao.rule.RuleChainService;
50 65 import org.thingsboard.server.dao.user.UserService;
51   -import org.thingsboard.server.gen.edge.AssetUpdateMsg;
52   -import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
53   -import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
54   -import org.thingsboard.server.gen.edge.EntityUpdateMsg;
55   -import org.thingsboard.server.gen.edge.EntityViewUpdateMsg;
56   -import org.thingsboard.server.gen.edge.RelationUpdateMsg;
57   -import org.thingsboard.server.gen.edge.ResponseMsg;
  66 +import org.thingsboard.server.gen.edge.AttributesRequestMsg;
  67 +import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
  68 +import org.thingsboard.server.gen.edge.RelationRequestMsg;
58 69 import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg;
59   -import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg;
60   -import org.thingsboard.server.gen.edge.RuleChainUpdateMsg;
61   -import org.thingsboard.server.gen.edge.UpdateMsgType;
62   -import org.thingsboard.server.gen.edge.UserUpdateMsg;
63   -import org.thingsboard.server.service.edge.EdgeContextComponent;
64   -import org.thingsboard.server.service.edge.rpc.constructor.AssetUpdateMsgConstructor;
65   -import org.thingsboard.server.service.edge.rpc.constructor.DashboardUpdateMsgConstructor;
66   -import org.thingsboard.server.service.edge.rpc.constructor.DeviceUpdateMsgConstructor;
67   -import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgConstructor;
68   -import org.thingsboard.server.service.edge.rpc.constructor.RelationUpdateMsgConstructor;
69   -import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor;
70   -import org.thingsboard.server.service.edge.rpc.constructor.UserUpdateMsgConstructor;
  70 +import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg;
  71 +import org.thingsboard.server.service.executors.DbCallbackExecutorService;
71 72
72 73 import java.util.ArrayList;
73   -import java.util.HashSet;
74 74 import java.util.List;
75   -import java.util.Set;
76 75 import java.util.UUID;
77 76
78 77 @Service
79 78 @Slf4j
80 79 public class DefaultSyncEdgeService implements SyncEdgeService {
81 80
  81 + private static final ObjectMapper mapper = new ObjectMapper();
  82 +
  83 + @Autowired
  84 + private EdgeEventService edgeEventService;
  85 +
  86 + @Autowired
  87 + private AttributesService attributesService;
  88 +
82 89 @Autowired
83 90 private RuleChainService ruleChainService;
84 91
... ... @@ -101,299 +108,323 @@ public class DefaultSyncEdgeService implements SyncEdgeService {
101 108 private UserService userService;
102 109
103 110 @Autowired
104   - private RuleChainUpdateMsgConstructor ruleChainUpdateMsgConstructor;
105   -
106   - @Autowired
107   - private DeviceUpdateMsgConstructor deviceUpdateMsgConstructor;
108   -
109   - @Autowired
110   - private AssetUpdateMsgConstructor assetUpdateMsgConstructor;
111   -
112   - @Autowired
113   - private EntityViewUpdateMsgConstructor entityViewUpdateMsgConstructor;
114   -
115   - @Autowired
116   - private DashboardUpdateMsgConstructor dashboardUpdateMsgConstructor;
117   -
118   - @Autowired
119   - private UserUpdateMsgConstructor userUpdateMsgConstructor;
120   -
121   - @Autowired
122   - private RelationUpdateMsgConstructor relationUpdateMsgConstructor;
  111 + private DbCallbackExecutorService dbCallbackExecutorService;
123 112
124 113 @Override
125   - public void sync(EdgeContextComponent ctx, Edge edge, StreamObserver<ResponseMsg> outputStream) {
126   - Set<EntityId> pushedEntityIds = new HashSet<>();
127   - syncUsers(ctx, edge, pushedEntityIds, outputStream);
128   - List<ListenableFuture<Void>> futures = new ArrayList<>();
129   - futures.add(syncRuleChains(ctx, edge, pushedEntityIds, outputStream));
130   - futures.add(syncDevices(ctx, edge, pushedEntityIds, outputStream));
131   - futures.add(syncAssets(ctx, edge, pushedEntityIds, outputStream));
132   - futures.add(syncEntityViews(ctx, edge, pushedEntityIds, outputStream));
133   - futures.add(syncDashboards(ctx, edge, pushedEntityIds, outputStream));
134   - ListenableFuture<List<Void>> joinFuture = Futures.allAsList(futures);
135   - Futures.transform(joinFuture, result -> {
136   - syncRelations(ctx, edge, pushedEntityIds, outputStream);
137   - return null;
138   - }, MoreExecutors.directExecutor());
  114 + public void sync(Edge edge) {
  115 + try {
  116 + syncUsers(edge);
  117 + syncRuleChains(edge);
  118 + syncDevices(edge);
  119 + syncAssets(edge);
  120 + syncEntityViews(edge);
  121 + syncDashboards(edge);
  122 + } catch (Exception e) {
  123 + log.error("Exception during sync process", e);
  124 + }
139 125 }
140 126
141   - private ListenableFuture<Void> syncRuleChains(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
  127 + private void syncRuleChains(Edge edge) {
142 128 try {
143   - ListenableFuture<TimePageData<RuleChain>> future = ruleChainService.findRuleChainsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
144   - return Futures.transform(future, pageData -> {
145   - try {
  129 + ListenableFuture<TimePageData<RuleChain>> future =
  130 + ruleChainService.findRuleChainsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
  131 + Futures.addCallback(future, new FutureCallback<TimePageData<RuleChain>>() {
  132 + @Override
  133 + public void onSuccess(@Nullable TimePageData<RuleChain> pageData) {
146 134 if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
147 135 log.trace("[{}] [{}] rule chains(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
148 136 for (RuleChain ruleChain : pageData.getData()) {
149   - RuleChainUpdateMsg ruleChainUpdateMsg =
150   - ruleChainUpdateMsgConstructor.constructRuleChainUpdatedMsg(
151   - edge.getRootRuleChainId(),
152   - UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE,
153   - ruleChain);
154   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
155   - .setRuleChainUpdateMsg(ruleChainUpdateMsg)
156   - .build();
157   - outputStream.onNext(ResponseMsg.newBuilder()
158   - .setEntityUpdateMsg(entityUpdateMsg)
159   - .build());
160   - pushedEntityIds.add(ruleChain.getId());
  137 + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.RULE_CHAIN, ActionType.ADDED, ruleChain.getId(), null);
161 138 }
162 139 }
163   - } catch (Exception e) {
164   - log.error("Exception during loading edge rule chain(s) on sync!", e);
165 140 }
166   - return null;
167   - }, ctx.getDbCallbackExecutor());
  141 +
  142 + @Override
  143 + public void onFailure(Throwable t) {
  144 + log.error("Exception during loading edge rule chain(s) on sync!", t);
  145 + }
  146 + }, dbCallbackExecutorService);
168 147 } catch (Exception e) {
169 148 log.error("Exception during loading edge rule chain(s) on sync!", e);
170   - return Futures.immediateFuture(null);
171 149 }
172 150 }
173 151
174   - private ListenableFuture<Void> syncDevices(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
  152 + private void syncDevices(Edge edge) {
175 153 try {
176   - ListenableFuture<TimePageData<Device>> future = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
177   - return Futures.transform(future, pageData -> {
178   - if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
179   - log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
180   - for (Device device : pageData.getData()) {
181   - DeviceUpdateMsg deviceUpdateMsg =
182   - deviceUpdateMsgConstructor.constructDeviceUpdatedMsg(
183   - UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
184   - device);
185   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
186   - .setDeviceUpdateMsg(deviceUpdateMsg)
187   - .build();
188   - outputStream.onNext(ResponseMsg.newBuilder()
189   - .setEntityUpdateMsg(entityUpdateMsg)
190   - .build());
191   - pushedEntityIds.add(device.getId());
  154 + ListenableFuture<TimePageData<Device>> future =
  155 + deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
  156 + Futures.addCallback(future, new FutureCallback<TimePageData<Device>>() {
  157 + @Override
  158 + public void onSuccess(@Nullable TimePageData<Device> pageData) {
  159 + if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
  160 + log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
  161 + for (Device device : pageData.getData()) {
  162 + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.DEVICE, ActionType.ADDED, device.getId(), null);
  163 + }
192 164 }
193 165 }
194   - return null;
195   - }, ctx.getDbCallbackExecutor());
  166 +
  167 + @Override
  168 + public void onFailure(Throwable t) {
  169 + log.error("Exception during loading edge device(s) on sync!", t);
  170 + }
  171 + }, dbCallbackExecutorService);
196 172 } catch (Exception e) {
197 173 log.error("Exception during loading edge device(s) on sync!", e);
198   - return Futures.immediateFuture(null);
199 174 }
200 175 }
201 176
202   - private ListenableFuture<Void> syncAssets(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
  177 + private void syncAssets(Edge edge) {
203 178 try {
204 179 ListenableFuture<TimePageData<Asset>> future = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
205   - return Futures.transform(future, pageData -> {
206   - if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
207   - log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
208   - for (Asset asset : pageData.getData()) {
209   - AssetUpdateMsg assetUpdateMsg =
210   - assetUpdateMsgConstructor.constructAssetUpdatedMsg(
211   - UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
212   - asset);
213   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
214   - .setAssetUpdateMsg(assetUpdateMsg)
215   - .build();
216   - outputStream.onNext(ResponseMsg.newBuilder()
217   - .setEntityUpdateMsg(entityUpdateMsg)
218   - .build());
219   - pushedEntityIds.add(asset.getId());
  180 + Futures.addCallback(future, new FutureCallback<TimePageData<Asset>>() {
  181 + @Override
  182 + public void onSuccess(@Nullable TimePageData<Asset> pageData) {
  183 + if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
  184 + log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
  185 + for (Asset asset : pageData.getData()) {
  186 + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.ASSET, ActionType.ADDED, asset.getId(), null);
  187 + }
220 188 }
221 189 }
222   - return null;
223   - }, ctx.getDbCallbackExecutor());
  190 +
  191 + @Override
  192 + public void onFailure(Throwable t) {
  193 + log.error("Exception during loading edge asset(s) on sync!", t);
  194 + }
  195 + }, dbCallbackExecutorService);
224 196 } catch (Exception e) {
225 197 log.error("Exception during loading edge asset(s) on sync!", e);
226   - return Futures.immediateFuture(null);
227 198 }
228 199 }
229 200
230   - private ListenableFuture<Void> syncEntityViews(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
  201 + private void syncEntityViews(Edge edge) {
231 202 try {
232 203 ListenableFuture<TimePageData<EntityView>> future = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
233   - return Futures.transform(future, pageData -> {
234   - try {
  204 + Futures.addCallback(future, new FutureCallback<TimePageData<EntityView>>() {
  205 + @Override
  206 + public void onSuccess(@Nullable TimePageData<EntityView> pageData) {
235 207 if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
236 208 log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
237 209 for (EntityView entityView : pageData.getData()) {
238   - EntityViewUpdateMsg entityViewUpdateMsg =
239   - entityViewUpdateMsgConstructor.constructEntityViewUpdatedMsg(
240   - UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
241   - entityView);
242   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
243   - .setEntityViewUpdateMsg(entityViewUpdateMsg)
244   - .build();
245   - outputStream.onNext(ResponseMsg.newBuilder()
246   - .setEntityUpdateMsg(entityUpdateMsg)
247   - .build());
248   - pushedEntityIds.add(entityView.getId());
  210 + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.ENTITY_VIEW, ActionType.ADDED, entityView.getId(), null);
249 211 }
250 212 }
251   - } catch (Exception e) {
252   - log.error("Exception during loading edge entity view(s) on sync!", e);
253 213 }
254   - return null;
255   - }, ctx.getDbCallbackExecutor());
  214 +
  215 + @Override
  216 + public void onFailure(Throwable t) {
  217 + log.error("Exception during loading edge entity view(s) on sync!", t);
  218 + }
  219 + }, dbCallbackExecutorService);
256 220 } catch (Exception e) {
257 221 log.error("Exception during loading edge entity view(s) on sync!", e);
258   - return Futures.immediateFuture(null);
259 222 }
260 223 }
261 224
262   - private ListenableFuture<Void> syncDashboards(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
  225 + private void syncDashboards(Edge edge) {
263 226 try {
264 227 ListenableFuture<TimePageData<DashboardInfo>> future = dashboardService.findDashboardsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
265   - return Futures.transform(future, pageData -> {
266   - try {
  228 + Futures.addCallback(future, new FutureCallback<TimePageData<DashboardInfo>>() {
  229 + @Override
  230 + public void onSuccess(@Nullable TimePageData<DashboardInfo> pageData) {
267 231 if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
268 232 log.trace("[{}] [{}] dashboard(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
269 233 for (DashboardInfo dashboardInfo : pageData.getData()) {
270   - Dashboard dashboard = dashboardService.findDashboardById(edge.getTenantId(), dashboardInfo.getId());
271   - DashboardUpdateMsg dashboardUpdateMsg =
272   - dashboardUpdateMsgConstructor.constructDashboardUpdatedMsg(
273   - UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
274   - dashboard);
275   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
276   - .setDashboardUpdateMsg(dashboardUpdateMsg)
277   - .build();
278   - outputStream.onNext(ResponseMsg.newBuilder()
279   - .setEntityUpdateMsg(entityUpdateMsg)
280   - .build());
281   - pushedEntityIds.add(dashboard.getId());
  234 + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.DASHBOARD, ActionType.ADDED, dashboardInfo.getId(), null);
282 235 }
283 236 }
284   - } catch (Exception e) {
285   - log.error("Exception during loading edge dashboard(s) on sync!", e);
286 237 }
287   - return null;
288   - }, ctx.getDbCallbackExecutor());
  238 +
  239 + @Override
  240 + public void onFailure(Throwable t) {
  241 + log.error("Exception during loading edge dashboard(s) on sync!", t);
  242 + }
  243 + }, dbCallbackExecutorService);
289 244 } catch (Exception e) {
290 245 log.error("Exception during loading edge dashboard(s) on sync!", e);
291   - return Futures.immediateFuture(null);
292 246 }
293 247 }
294 248
295   - private void syncUsers(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
  249 + private void syncUsers(Edge edge) {
296 250 try {
297 251 TextPageData<User> pageData = userService.findTenantAdmins(edge.getTenantId(), new TextPageLink(Integer.MAX_VALUE));
298   - pushUsersToEdge(pageData, edge, pushedEntityIds, outputStream);
  252 + pushUsersToEdge(pageData, edge);
299 253 if (edge.getCustomerId() != null && !EntityId.NULL_UUID.equals(edge.getCustomerId().getId())) {
300 254 pageData = userService.findCustomerUsers(edge.getTenantId(), edge.getCustomerId(), new TextPageLink(Integer.MAX_VALUE));
301   - pushUsersToEdge(pageData, edge, pushedEntityIds, outputStream);
  255 + pushUsersToEdge(pageData, edge);
302 256 }
303 257 } catch (Exception e) {
304 258 log.error("Exception during loading edge user(s) on sync!", e);
305 259 }
306 260 }
307 261
308   - private void pushUsersToEdge(TextPageData<User> pageData, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
  262 + private void pushUsersToEdge(TextPageData<User> pageData, Edge edge) {
309 263 if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
310 264 log.trace("[{}] [{}] user(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
311 265 for (User user : pageData.getData()) {
312   - UserUpdateMsg userUpdateMsg =
313   - userUpdateMsgConstructor.constructUserUpdatedMsg(
314   - UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
315   - user);
316   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
317   - .setUserUpdateMsg(userUpdateMsg)
318   - .build();
319   - outputStream.onNext(ResponseMsg.newBuilder()
320   - .setEntityUpdateMsg(entityUpdateMsg)
321   - .build());
322   - pushedEntityIds.add(user.getId());
  266 + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, ActionType.ADDED, user.getId(), null);
323 267 }
324 268 }
325 269 }
326 270
327   - private ListenableFuture<Void> syncRelations(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) {
328   - if (!pushedEntityIds.isEmpty()) {
329   - List<ListenableFuture<List<EntityRelation>>> futures = new ArrayList<>();
330   - for (EntityId entityId : pushedEntityIds) {
331   - futures.add(syncRelations(edge, entityId, EntitySearchDirection.FROM));
332   - futures.add(syncRelations(edge, entityId, EntitySearchDirection.TO));
333   - }
334   - ListenableFuture<List<List<EntityRelation>>> relationsListFuture = Futures.allAsList(futures);
335   - return Futures.transform(relationsListFuture, relationsList -> {
336   - try {
337   - Set<EntityRelation> uniqueEntityRelations = new HashSet<>();
338   - if (!relationsList.isEmpty()) {
339   - for (List<EntityRelation> entityRelations : relationsList) {
340   - if (!entityRelations.isEmpty()) {
341   - uniqueEntityRelations.addAll(entityRelations);
  271 + @Override
  272 + public void processRuleChainMetadataRequestMsg(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg) {
  273 + if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) {
  274 + RuleChainId ruleChainId = new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB()));
  275 + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.RULE_CHAIN_METADATA, ActionType.ADDED, ruleChainId, null);
  276 + }
  277 + }
  278 +
  279 + @Override
  280 + public void processAttributesRequestMsg(Edge edge, AttributesRequestMsg attributesRequestMsg) {
  281 + EntityId entityId = EntityIdFactory.getByTypeAndUuid(
  282 + EntityType.valueOf(attributesRequestMsg.getEntityType()),
  283 + new UUID(attributesRequestMsg.getEntityIdMSB(), attributesRequestMsg.getEntityIdLSB()));
  284 + final EdgeEventType edgeEventType = getEdgeQueueTypeByEntityType(entityId.getEntityType());
  285 + if (edgeEventType != null) {
  286 + ListenableFuture<List<AttributeKvEntry>> ssAttrFuture = attributesService.findAll(edge.getTenantId(), entityId, DataConstants.SERVER_SCOPE);
  287 + Futures.addCallback(ssAttrFuture, new FutureCallback<List<AttributeKvEntry>>() {
  288 + @Override
  289 + public void onSuccess(@Nullable List<AttributeKvEntry> ssAttributes) {
  290 + if (ssAttributes != null && !ssAttributes.isEmpty()) {
  291 + try {
  292 + ObjectNode entityNode = mapper.createObjectNode();
  293 + for (AttributeKvEntry attr : ssAttributes) {
  294 + if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) {
  295 + entityNode.put(attr.getKey(), attr.getBooleanValue().get());
  296 + } else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) {
  297 + entityNode.put(attr.getKey(), attr.getDoubleValue().get());
  298 + } else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) {
  299 + entityNode.put(attr.getKey(), attr.getLongValue().get());
  300 + } else {
  301 + entityNode.put(attr.getKey(), attr.getValueAsString());
  302 + }
342 303 }
  304 + log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, entityNode);
  305 + saveEdgeEvent(edge.getTenantId(),
  306 + edge.getId(),
  307 + edgeEventType,
  308 + ActionType.ATTRIBUTES_UPDATED,
  309 + entityId,
  310 + entityNode);
  311 + } catch (Exception e) {
  312 + log.error("[{}] Failed to send attribute updates to the edge", edge.getName(), e);
343 313 }
344 314 }
345   - if (!uniqueEntityRelations.isEmpty()) {
346   - log.trace("[{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), uniqueEntityRelations.size());
347   - for (EntityRelation relation : uniqueEntityRelations) {
348   - try {
349   - RelationUpdateMsg relationUpdateMsg =
350   - relationUpdateMsgConstructor.constructRelationUpdatedMsg(
351   - UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
352   - relation);
353   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
354   - .setRelationUpdateMsg(relationUpdateMsg)
355   - .build();
356   - outputStream.onNext(ResponseMsg.newBuilder()
357   - .setEntityUpdateMsg(entityUpdateMsg)
358   - .build());
359   - } catch (Exception e) {
360   - log.error("Exception during loading relation [{}] to edge on sync!", relation, e);
  315 + }
  316 +
  317 + @Override
  318 + public void onFailure(Throwable t) {
  319 +
  320 + }
  321 + }, dbCallbackExecutorService);
  322 +
  323 + // TODO: voba - push shared attributes to edge?
  324 + ListenableFuture<List<AttributeKvEntry>> shAttrFuture = attributesService.findAll(edge.getTenantId(), entityId, DataConstants.SHARED_SCOPE);
  325 + ListenableFuture<List<AttributeKvEntry>> clAttrFuture = attributesService.findAll(edge.getTenantId(), entityId, DataConstants.CLIENT_SCOPE);
  326 + }
  327 + }
  328 +
  329 + private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) {
  330 + switch (entityType) {
  331 + case DEVICE:
  332 + return EdgeEventType.DEVICE;
  333 + case ASSET:
  334 + return EdgeEventType.ASSET;
  335 + case ENTITY_VIEW:
  336 + return EdgeEventType.ENTITY_VIEW;
  337 + default:
  338 + return null;
  339 + }
  340 + }
  341 +
  342 + @Override
  343 + public void processRelationRequestMsg(Edge edge, RelationRequestMsg relationRequestMsg) {
  344 + EntityId entityId = EntityIdFactory.getByTypeAndUuid(
  345 + EntityType.valueOf(relationRequestMsg.getEntityType()),
  346 + new UUID(relationRequestMsg.getEntityIdMSB(), relationRequestMsg.getEntityIdLSB()));
  347 +
  348 + List<ListenableFuture<List<EntityRelation>>> futures = new ArrayList<>();
  349 + futures.add(findRelationByQuery(edge, entityId, EntitySearchDirection.FROM));
  350 + futures.add(findRelationByQuery(edge, entityId, EntitySearchDirection.TO));
  351 + ListenableFuture<List<List<EntityRelation>>> relationsListFuture = Futures.allAsList(futures);
  352 + Futures.addCallback(relationsListFuture, new FutureCallback<List<List<EntityRelation>>>() {
  353 + @Override
  354 + public void onSuccess(@Nullable List<List<EntityRelation>> relationsList) {
  355 + try {
  356 + if (!relationsList.isEmpty()) {
  357 + for (List<EntityRelation> entityRelations : relationsList) {
  358 + log.trace("[{}] [{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), entityId, entityRelations.size());
  359 + for (EntityRelation relation : entityRelations) {
  360 + try {
  361 + if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
  362 + !relation.getTo().getEntityType().equals(EntityType.EDGE)) {
  363 + saveEdgeEvent(edge.getTenantId(),
  364 + edge.getId(),
  365 + EdgeEventType.RELATION,
  366 + ActionType.ADDED,
  367 + null,
  368 + mapper.valueToTree(relation));
  369 + }
  370 + } catch (Exception e) {
  371 + log.error("Exception during loading relation [{}] to edge on sync!", relation, e);
  372 + }
361 373 }
362 374 }
363 375 }
364 376 } catch (Exception e) {
365 377 log.error("Exception during loading relation(s) to edge on sync!", e);
366 378 }
367   - return null;
368   - }, ctx.getDbCallbackExecutor());
369   - } else {
370   - return Futures.immediateFuture(null);
371   - }
  379 + }
  380 +
  381 + @Override
  382 + public void onFailure(Throwable t) {
  383 + log.error("Exception during loading relation(s) to edge on sync!", t);
  384 + }
  385 + }, dbCallbackExecutorService);
372 386 }
373 387
374   - private ListenableFuture<List<EntityRelation>> syncRelations(Edge edge, EntityId entityId, EntitySearchDirection direction) {
  388 + private ListenableFuture<List<EntityRelation>> findRelationByQuery(Edge edge, EntityId entityId, EntitySearchDirection direction) {
375 389 EntityRelationsQuery query = new EntityRelationsQuery();
376 390 query.setParameters(new RelationsSearchParameters(entityId, direction, -1, false));
377 391 return relationService.findByQuery(edge.getTenantId(), query);
378 392 }
379 393
380 394 @Override
381   - public void syncRuleChainMetadata(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg, StreamObserver<ResponseMsg> outputStream) {
382   - if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) {
383   - RuleChainId ruleChainId = new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB()));
384   - RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(edge.getTenantId(), ruleChainId);
385   - RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg =
386   - ruleChainUpdateMsgConstructor.constructRuleChainMetadataUpdatedMsg(
387   - UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE,
388   - ruleChainMetaData);
389   - if (ruleChainMetadataUpdateMsg != null) {
390   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
391   - .setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg)
392   - .build();
393   - outputStream.onNext(ResponseMsg.newBuilder()
394   - .setEntityUpdateMsg(entityUpdateMsg)
395   - .build());
396   - }
  395 + public void processDeviceCredentialsRequestMsg(Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg) {
  396 + if (deviceCredentialsRequestMsg.getDeviceIdMSB() != 0 && deviceCredentialsRequestMsg.getDeviceIdLSB() != 0) {
  397 + DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsRequestMsg.getDeviceIdMSB(), deviceCredentialsRequestMsg.getDeviceIdLSB()));
  398 + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.DEVICE, ActionType.CREDENTIALS_UPDATED, deviceId, null);
  399 + }
  400 + }
  401 +
  402 + @Override
  403 + public void processUserCredentialsRequestMsg(Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg) {
  404 + if (userCredentialsRequestMsg.getUserIdMSB() != 0 && userCredentialsRequestMsg.getUserIdLSB() != 0) {
  405 + UserId userId = new UserId(new UUID(userCredentialsRequestMsg.getUserIdMSB(), userCredentialsRequestMsg.getUserIdLSB()));
  406 + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, ActionType.CREDENTIALS_UPDATED, userId, null);
  407 + }
  408 + }
  409 +
  410 + private void saveEdgeEvent(TenantId tenantId,
  411 + EdgeId edgeId,
  412 + EdgeEventType edgeEventType,
  413 + ActionType edgeEventAction,
  414 + EntityId entityId,
  415 + JsonNode entityBody) {
  416 + log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], edgeEventType [{}], edgeEventAction[{}], entityId [{}], entityBody [{}]",
  417 + tenantId, edgeId, edgeEventType, edgeEventAction, entityId, entityBody);
  418 +
  419 + EdgeEvent edgeEvent = new EdgeEvent();
  420 + edgeEvent.setTenantId(tenantId);
  421 + edgeEvent.setEdgeId(edgeId);
  422 + edgeEvent.setEdgeEventType(edgeEventType);
  423 + edgeEvent.setEdgeEventAction(edgeEventAction.name());
  424 + if (entityId != null) {
  425 + edgeEvent.setEntityId(entityId.getId());
397 426 }
  427 + edgeEvent.setEntityBody(entityBody);
  428 + edgeEventService.saveAsync(edgeEvent);
398 429 }
399 430 }
... ...
... ... @@ -15,15 +15,24 @@
15 15 */
16 16 package org.thingsboard.server.service.edge.rpc.init;
17 17
18   -import io.grpc.stub.StreamObserver;
19 18 import org.thingsboard.server.common.data.edge.Edge;
20   -import org.thingsboard.server.gen.edge.ResponseMsg;
  19 +import org.thingsboard.server.gen.edge.AttributesRequestMsg;
  20 +import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
  21 +import org.thingsboard.server.gen.edge.RelationRequestMsg;
21 22 import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg;
22   -import org.thingsboard.server.service.edge.EdgeContextComponent;
  23 +import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg;
23 24
24 25 public interface SyncEdgeService {
25 26
26   - void sync(EdgeContextComponent ctx, Edge edge, StreamObserver<ResponseMsg> outputStream);
  27 + void sync(Edge edge);
27 28
28   - void syncRuleChainMetadata(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg, StreamObserver<ResponseMsg> outputStream);
  29 + void processRuleChainMetadataRequestMsg(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg);
  30 +
  31 + void processAttributesRequestMsg(Edge edge, AttributesRequestMsg attributesRequestMsg);
  32 +
  33 + void processRelationRequestMsg(Edge edge, RelationRequestMsg relationRequestMsg);
  34 +
  35 + void processDeviceCredentialsRequestMsg(Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg);
  36 +
  37 + void processUserCredentialsRequestMsg(Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg);
29 38 }
... ...
... ... @@ -33,9 +33,9 @@ public class TbCoreConsumerStats {
33 33 private final AtomicInteger claimDeviceCounter = new AtomicInteger(0);
34 34
35 35 private final AtomicInteger deviceStateCounter = new AtomicInteger(0);
36   - private final AtomicInteger edgeNotificationCounter = new AtomicInteger(0);
37 36 private final AtomicInteger subscriptionMsgCounter = new AtomicInteger(0);
38 37 private final AtomicInteger toCoreNotificationsCounter = new AtomicInteger(0);
  38 + private final AtomicInteger edgeNotificationMsgCounter = new AtomicInteger(0);
39 39
40 40 public void log(TransportProtos.TransportToDeviceActorMsg msg) {
41 41 totalCounter.incrementAndGet();
... ... @@ -69,7 +69,7 @@ public class TbCoreConsumerStats {
69 69
70 70 public void log(TransportProtos.EdgeNotificationMsgProto msg) {
71 71 totalCounter.incrementAndGet();
72   - edgeNotificationCounter.incrementAndGet();
  72 + edgeNotificationMsgCounter.incrementAndGet();
73 73 }
74 74
75 75 public void log(TransportProtos.SubscriptionMgrMsgProto msg) {
... ... @@ -86,12 +86,13 @@ public class TbCoreConsumerStats {
86 86 int total = totalCounter.getAndSet(0);
87 87 if (total > 0) {
88 88 log.info("Total [{}] sessionEvents [{}] getAttr [{}] subToAttr [{}] subToRpc [{}] toDevRpc [{}] subInfo [{}] claimDevice [{}]" +
89   - " deviceState [{}] subMgr [{}] coreNfs [{}]",
  89 + " deviceState [{}] subMgr [{}] coreNfs [{}] edgeNfs [{}]",
90 90 total, sessionEventCounter.getAndSet(0),
91 91 getAttributesCounter.getAndSet(0), subscribeToAttributesCounter.getAndSet(0),
92 92 subscribeToRPCCounter.getAndSet(0), toDeviceRPCCallResponseCounter.getAndSet(0),
93 93 subscriptionInfoCounter.getAndSet(0), claimDeviceCounter.getAndSet(0)
94   - , deviceStateCounter.getAndSet(0), subscriptionMsgCounter.getAndSet(0), toCoreNotificationsCounter.getAndSet(0));
  94 + , deviceStateCounter.getAndSet(0), subscriptionMsgCounter.getAndSet(0), toCoreNotificationsCounter.getAndSet(0),
  95 + edgeNotificationMsgCounter.getAndSet(0));
95 96 }
96 97 }
97 98
... ...
... ... @@ -26,8 +26,6 @@ import org.thingsboard.server.common.data.page.TimePageLink;
26 26
27 27 public interface EdgeEventService {
28 28
29   - EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType);
30   -
31 29 ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent);
32 30
33 31 TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.common.data;
17 17
  18 +import org.thingsboard.server.common.data.edge.EdgeEventType;
18 19 import org.thingsboard.server.common.data.id.EdgeId;
19 20
20 21 import java.util.Set;
... ... @@ -24,50 +25,22 @@ public final class EdgeUtils {
24 25 private EdgeUtils() {
25 26 }
26 27
27   - public static boolean isAssignedToEdge(Set<ShortEdgeInfo> assignedEdges, EdgeId edgeId) {
28   - return assignedEdges != null && assignedEdges.contains(new ShortEdgeInfo(edgeId, null, null));
29   - }
30   -
31   - public static ShortEdgeInfo getAssignedEdgeInfo(Set<ShortEdgeInfo> assignedEdges, EdgeId edgeId) {
32   - if (assignedEdges != null) {
33   - for (ShortEdgeInfo edgeInfo : assignedEdges) {
34   - if (edgeInfo.getEdgeId().equals(edgeId)) {
35   - return edgeInfo;
36   - }
37   - }
38   - }
39   - return null;
40   - }
41   -
42   - public static boolean addAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) {
43   - if (assignedEdges != null && assignedEdges.contains(edgeInfo)) {
44   - return false;
45   - } else {
46   - if (assignedEdges != null) {
47   - assignedEdges.add(edgeInfo);
48   - return true;
49   - } else {
50   - return false;
51   - }
52   - }
53   - }
54   -
55   - public static boolean updateAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) {
56   - if (assignedEdges != null && assignedEdges.contains(edgeInfo)) {
57   - assignedEdges.remove(edgeInfo);
58   - assignedEdges.add(edgeInfo);
59   - return true;
60   - } else {
61   - return false;
62   - }
63   - }
64   -
65   - public static boolean removeAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) {
66   - if (assignedEdges != null && assignedEdges.contains(edgeInfo)) {
67   - assignedEdges.remove(edgeInfo);
68   - return true;
69   - } else {
70   - return false;
  28 + public static EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType) {
  29 + switch (entityType) {
  30 + case DEVICE:
  31 + return EdgeEventType.DEVICE;
  32 + case ASSET:
  33 + return EdgeEventType.ASSET;
  34 + case ENTITY_VIEW:
  35 + return EdgeEventType.ENTITY_VIEW;
  36 + case DASHBOARD:
  37 + return EdgeEventType.DASHBOARD;
  38 + case USER:
  39 + return EdgeEventType.USER;
  40 + case ALARM:
  41 + return EdgeEventType.ALARM;
  42 + default:
  43 + return null;
71 44 }
72 45 }
73 46 }
... ...
... ... @@ -43,7 +43,8 @@ public enum ActionType {
43 43 LOGOUT(false),
44 44 LOCKOUT(false),
45 45 ASSIGNED_TO_EDGE(false), // log edge name
46   - UNASSIGNED_FROM_EDGE(false); // log edge name
  46 + UNASSIGNED_FROM_EDGE(false), // log edge name
  47 + CREDENTIALS_REQUEST(false); // request credentials from edge
47 48
48 49 private final boolean isRead;
49 50
... ...
... ... @@ -20,7 +20,6 @@ import lombok.Data;
20 20 import org.thingsboard.server.common.data.BaseData;
21 21 import org.thingsboard.server.common.data.id.EdgeEventId;
22 22 import org.thingsboard.server.common.data.id.EdgeId;
23   -import org.thingsboard.server.common.data.id.EntityId;
24 23 import org.thingsboard.server.common.data.id.TenantId;
25 24
26 25 import java.util.UUID;
... ...
... ... @@ -16,5 +16,15 @@
16 16 package org.thingsboard.server.common.data.edge;
17 17
18 18 public enum EdgeEventType {
19   - DASHBOARD, ASSET, DEVICE, ENTITY_VIEW, ALARM, RULE_CHAIN, RULE_CHAIN_METADATA, EDGE, USER, CUSTOMER, RELATION
  19 + DASHBOARD,
  20 + ASSET,
  21 + DEVICE,
  22 + ENTITY_VIEW,
  23 + ALARM,
  24 + RULE_CHAIN,
  25 + RULE_CHAIN_METADATA,
  26 + EDGE,
  27 + USER,
  28 + CUSTOMER,
  29 + RELATION
20 30 }
... ...
... ... @@ -48,15 +48,17 @@ message ResponseMsg {
48 48
49 49 message EntityUpdateMsg {
50 50 DeviceUpdateMsg deviceUpdateMsg = 1;
51   - RuleChainUpdateMsg ruleChainUpdateMsg = 2;
52   - RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = 3;
53   - DashboardUpdateMsg dashboardUpdateMsg = 4;
54   - AssetUpdateMsg assetUpdateMsg = 5;
55   - EntityViewUpdateMsg entityViewUpdateMsg = 6;
56   - AlarmUpdateMsg alarmUpdateMsg = 7;
57   - UserUpdateMsg userUpdateMsg = 8;
58   - CustomerUpdateMsg customerUpdateMsg = 9;
59   - RelationUpdateMsg relationUpdateMsg = 10;
  51 + DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg = 2;
  52 + RuleChainUpdateMsg ruleChainUpdateMsg = 3;
  53 + RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = 4;
  54 + DashboardUpdateMsg dashboardUpdateMsg = 5;
  55 + AssetUpdateMsg assetUpdateMsg = 6;
  56 + EntityViewUpdateMsg entityViewUpdateMsg = 7;
  57 + AlarmUpdateMsg alarmUpdateMsg = 8;
  58 + UserUpdateMsg userUpdateMsg = 9;
  59 + UserCredentialsUpdateMsg userCredentialsUpdateMsg = 10;
  60 + CustomerUpdateMsg customerUpdateMsg = 11;
  61 + RelationUpdateMsg relationUpdateMsg = 12;
60 62 }
61 63
62 64 enum RequestMsgType {
... ... @@ -169,9 +171,14 @@ message DeviceUpdateMsg {
169 171 string name = 4;
170 172 string type = 5;
171 173 string label = 6;
172   - string credentialsType = 7;
173   - string credentialsId = 8;
174   - string credentialsValue = 9;
  174 +}
  175 +
  176 +message DeviceCredentialsUpdateMsg {
  177 + int64 deviceIdMSB = 1;
  178 + int64 deviceIdLSB = 2;
  179 + string credentialsType = 3;
  180 + string credentialsId = 4;
  181 + string credentialsValue = 5;
175 182 }
176 183
177 184 message AssetUpdateMsg {
... ... @@ -248,8 +255,13 @@ message UserUpdateMsg {
248 255 string firstName = 6;
249 256 string lastName = 7;
250 257 string additionalInfo = 8;
251   - bool enabled = 9;
252   - string password = 10;
  258 +}
  259 +
  260 +message UserCredentialsUpdateMsg {
  261 + int64 userIdMSB = 1;
  262 + int64 userIdLSB = 2;
  263 + bool enabled = 3;
  264 + string password = 4;
253 265 }
254 266
255 267 message RuleChainMetadataRequestMsg {
... ... @@ -257,6 +269,28 @@ message RuleChainMetadataRequestMsg {
257 269 int64 ruleChainIdLSB = 2;
258 270 }
259 271
  272 +message AttributesRequestMsg {
  273 + int64 entityIdMSB = 1;
  274 + int64 entityIdLSB = 2;
  275 + string entityType = 3;
  276 +}
  277 +
  278 +message RelationRequestMsg {
  279 + int64 entityIdMSB = 1;
  280 + int64 entityIdLSB = 2;
  281 + string entityType = 3;
  282 +}
  283 +
  284 +message UserCredentialsRequestMsg {
  285 + int64 userIdMSB = 1;
  286 + int64 userIdLSB = 2;
  287 +}
  288 +
  289 +message DeviceCredentialsRequestMsg {
  290 + int64 deviceIdMSB = 1;
  291 + int64 deviceIdLSB = 2;
  292 +}
  293 +
260 294 enum EdgeEntityType {
261 295 DEVICE = 0;
262 296 ASSET = 1;
... ... @@ -270,8 +304,13 @@ message UplinkMsg {
270 304 int32 uplinkMsgId = 1;
271 305 repeated EntityDataProto entityData = 2;
272 306 repeated DeviceUpdateMsg deviceUpdateMsg = 3;
273   - repeated AlarmUpdateMsg alarmUpdateMsg = 4;
274   - repeated RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg = 5;
  307 + repeated DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg = 4;
  308 + repeated AlarmUpdateMsg alarmUpdateMsg = 5;
  309 + repeated RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg = 6;
  310 + repeated AttributesRequestMsg attributesRequestMsg = 7;
  311 + repeated RelationRequestMsg relationRequestMsg = 8;
  312 + repeated UserCredentialsRequestMsg userCredentialsRequestMsg = 9;
  313 + repeated DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 10;
275 314 }
276 315
277 316 message UplinkResponseMsg {
... ... @@ -282,5 +321,6 @@ message UplinkResponseMsg {
282 321 message DownlinkMsg {
283 322 int32 downlinkMsgId = 1;
284 323 repeated EntityDataProto entityData = 2;
  324 + repeated DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 3;
285 325 }
286 326
... ...
... ... @@ -232,7 +232,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
232 232 if (edge == null) {
233 233 throw new DataValidationException("Can't assign dashboard to non-existent edge!");
234 234 }
235   - if (!edge.getTenantId().getId().equals(dashboard.getTenantId().getId())) {
  235 + if (!edge.getTenantId().equals(dashboard.getTenantId())) {
236 236 throw new DataValidationException("Can't assign dashboard to edge from different tenant!");
237 237 }
238 238 try {
... ...
... ... @@ -20,9 +20,7 @@ import lombok.extern.slf4j.Slf4j;
20 20 import org.apache.commons.lang3.StringUtils;
21 21 import org.springframework.beans.factory.annotation.Autowired;
22 22 import org.springframework.stereotype.Service;
23   -import org.thingsboard.server.common.data.EntityType;
24 23 import org.thingsboard.server.common.data.edge.EdgeEvent;
25   -import org.thingsboard.server.common.data.edge.EdgeEventType;
26 24 import org.thingsboard.server.common.data.id.EdgeId;
27 25 import org.thingsboard.server.common.data.id.TenantId;
28 26 import org.thingsboard.server.common.data.page.TimePageData;
... ... @@ -40,27 +38,6 @@ public class BaseEdgeEventService implements EdgeEventService {
40 38 public EdgeEventDao edgeEventDao;
41 39
42 40 @Override
43   - public EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType) {
44   - switch (entityType) {
45   - case DEVICE:
46   - return EdgeEventType.DEVICE;
47   - case ASSET:
48   - return EdgeEventType.ASSET;
49   - case ENTITY_VIEW:
50   - return EdgeEventType.ENTITY_VIEW;
51   - case DASHBOARD:
52   - return EdgeEventType.DASHBOARD;
53   - case USER:
54   - return EdgeEventType.USER;
55   - case ALARM:
56   - return EdgeEventType.ALARM;
57   - default:
58   - log.warn("Failed to push notification to edge service. Unsupported entity type [{}]", entityType);
59   - return null;
60   - }
61   - }
62   -
63   - @Override
64 41 public ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent) {
65 42 edgeEventValidator.validate(edgeEvent, EdgeEvent::getTenantId);
66 43 return edgeEventDao.saveAsync(edgeEvent);
... ...
... ... @@ -22,17 +22,13 @@ import lombok.extern.slf4j.Slf4j;
22 22 import org.springframework.beans.factory.annotation.Autowired;
23 23 import org.springframework.stereotype.Component;
24 24 import org.thingsboard.server.common.data.EntitySubtype;
25   -import org.thingsboard.server.common.data.EntityType;
26 25 import org.thingsboard.server.common.data.edge.Edge;
27 26 import org.thingsboard.server.common.data.id.DashboardId;
28   -import org.thingsboard.server.common.data.id.EdgeId;
29 27 import org.thingsboard.server.common.data.id.RuleChainId;
30 28 import org.thingsboard.server.common.data.id.TenantId;
31 29 import org.thingsboard.server.common.data.page.TextPageLink;
32   -import org.thingsboard.server.common.data.page.TimePageLink;
33 30 import org.thingsboard.server.common.data.relation.EntityRelation;
34 31 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
35   -import org.thingsboard.server.common.data.rule.RuleChain;
36 32 import org.thingsboard.server.dao.model.nosql.EdgeEntity;
37 33 import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao;
38 34 import org.thingsboard.server.dao.relation.RelationDao;
... ... @@ -113,19 +109,17 @@ public class CassandraEdgeDao extends CassandraAbstractSearchTextDao<EdgeEntity,
113 109 public ListenableFuture<List<Edge>> findEdgesByTenantIdAndRuleChainId(UUID tenantId, UUID ruleChainId) {
114 110 log.debug("Try to find edges by tenantId [{}], ruleChainId [{}]", tenantId, ruleChainId);
115 111 ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new RuleChainId(ruleChainId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
116   - return Futures.transformAsync(relations, input -> {
117   - List<ListenableFuture<Edge>> edgeFutures = new ArrayList<>(input.size());
118   - for (EntityRelation relation : input) {
119   - edgeFutures.add(findByIdAsync(new TenantId(tenantId), relation.getFrom().getId()));
120   - }
121   - return Futures.successfulAsList(edgeFutures);
122   - }, MoreExecutors.directExecutor());
  112 + return transformFromRelationToEdge(tenantId, relations);
123 113 }
124 114
125 115 @Override
126 116 public ListenableFuture<List<Edge>> findEdgesByTenantIdAndDashboardId(UUID tenantId, UUID dashboardId) {
127 117 log.debug("Try to find edges by tenantId [{}], dashboardId [{}]", tenantId, dashboardId);
128 118 ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new DashboardId(dashboardId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
  119 + return transformFromRelationToEdge(tenantId, relations);
  120 + }
  121 +
  122 + private ListenableFuture<List<Edge>> transformFromRelationToEdge(UUID tenantId, ListenableFuture<List<EntityRelation>> relations) {
129 123 return Futures.transformAsync(relations, input -> {
130 124 List<ListenableFuture<Edge>> edgeFutures = new ArrayList<>(input.size());
131 125 for (EntityRelation relation : input) {
... ...
... ... @@ -414,7 +414,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
414 414 if (edge == null) {
415 415 throw new DataValidationException("Can't assign ruleChain to non-existent edge!");
416 416 }
417   - if (!edge.getTenantId().getId().equals(ruleChain.getTenantId().getId())) {
  417 + if (!edge.getTenantId().equals(ruleChain.getTenantId())) {
418 418 throw new DataValidationException("Can't assign ruleChain to edge from different tenant!");
419 419 }
420 420 try {
... ...
... ... @@ -151,19 +151,17 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple
151 151 public ListenableFuture<List<Edge>> findEdgesByTenantIdAndRuleChainId(UUID tenantId, UUID ruleChainId) {
152 152 log.debug("Try to find edges by tenantId [{}], ruleChainId [{}]", tenantId, ruleChainId);
153 153 ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new RuleChainId(ruleChainId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
154   - return Futures.transformAsync(relations, input -> {
155   - List<ListenableFuture<Edge>> edgeFutures = new ArrayList<>(input.size());
156   - for (EntityRelation relation : input) {
157   - edgeFutures.add(findByIdAsync(new TenantId(tenantId), relation.getFrom().getId()));
158   - }
159   - return Futures.successfulAsList(edgeFutures);
160   - }, MoreExecutors.directExecutor());
  154 + return transformFromRelationToEdge(tenantId, relations);
161 155 }
162 156
163 157 @Override
164 158 public ListenableFuture<List<Edge>> findEdgesByTenantIdAndDashboardId(UUID tenantId, UUID dashboardId) {
165 159 log.debug("Try to find edges by tenantId [{}], dashboardId [{}]", tenantId, dashboardId);
166 160 ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByToAndType(new TenantId(tenantId), new DashboardId(dashboardId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
  161 + return transformFromRelationToEdge(tenantId, relations);
  162 + }
  163 +
  164 + private ListenableFuture<List<Edge>> transformFromRelationToEdge(UUID tenantId, ListenableFuture<List<EntityRelation>> relations) {
167 165 return Futures.transformAsync(relations, input -> {
168 166 List<ListenableFuture<Edge>> edgeFutures = new ArrayList<>(input.size());
169 167 for (EntityRelation relation : input) {
... ...
... ... @@ -332,6 +332,21 @@ public abstract class BaseRuleChainServiceTest extends AbstractServiceTest {
332 332 Assert.assertEquals(1, result.size());
333 333 }
334 334
  335 + @Test
  336 + public void setDefaultRootEdgeRuleChain() throws Exception {
  337 + RuleChainId ruleChainId1 = saveRuleChainAndSetDefaultEdge("Default Edge Rule Chain 1");
  338 + RuleChainId ruleChainId2 = saveRuleChainAndSetDefaultEdge("Default Edge Rule Chain 2");
  339 +
  340 + ruleChainService.setDefaultRootEdgeRuleChain(tenantId, ruleChainId1);
  341 + ruleChainService.setDefaultRootEdgeRuleChain(tenantId, ruleChainId2);
  342 +
  343 + RuleChain ruleChainById = ruleChainService.findRuleChainById(tenantId, ruleChainId1);
  344 + Assert.assertFalse(ruleChainById.isRoot());
  345 +
  346 + ruleChainById = ruleChainService.findRuleChainById(tenantId, ruleChainId2);
  347 + Assert.assertTrue(ruleChainById.isRoot());
  348 + }
  349 +
335 350 private RuleChainId saveRuleChainAndSetDefaultEdge(String name) {
336 351 RuleChain edgeRuleChain = new RuleChain();
337 352 edgeRuleChain.setTenantId(tenantId);
... ...
... ... @@ -45,7 +45,8 @@ import org.thingsboard.server.common.data.Tenant;
45 45 import org.thingsboard.server.common.data.UpdateMessage;
46 46 import org.thingsboard.server.common.data.User;
47 47 import org.thingsboard.server.common.data.alarm.Alarm;
48   -import org.thingsboard.server.common.data.id.AlarmId;
  48 +import org.thingsboard.server.common.data.edge.Edge;
  49 +import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
49 50 import org.thingsboard.server.common.data.alarm.AlarmInfo;
50 51 import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
51 52 import org.thingsboard.server.common.data.alarm.AlarmSeverity;
... ... @@ -56,10 +57,12 @@ import org.thingsboard.server.common.data.audit.ActionType;
56 57 import org.thingsboard.server.common.data.audit.AuditLog;
57 58 import org.thingsboard.server.common.data.device.DeviceSearchQuery;
58 59 import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
  60 +import org.thingsboard.server.common.data.id.AlarmId;
59 61 import org.thingsboard.server.common.data.id.AssetId;
60 62 import org.thingsboard.server.common.data.id.CustomerId;
61 63 import org.thingsboard.server.common.data.id.DashboardId;
62 64 import org.thingsboard.server.common.data.id.DeviceId;
  65 +import org.thingsboard.server.common.data.id.EdgeId;
63 66 import org.thingsboard.server.common.data.id.EntityId;
64 67 import org.thingsboard.server.common.data.id.EntityViewId;
65 68 import org.thingsboard.server.common.data.id.RuleChainId;
... ... @@ -1978,6 +1981,190 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
1978 1981 }
1979 1982 }
1980 1983
  1984 + public Edge saveEdge(Edge edge) {
  1985 + return restTemplate.postForEntity(baseURL + "/api/edge", edge, Edge.class).getBody();
  1986 + }
  1987 +
  1988 + public void deleteEdge(EdgeId edgeId) {
  1989 + restTemplate.delete(baseURL + "/api/edge/{edgeId}", edgeId.getId());
  1990 + }
  1991 +
  1992 + public Optional<Edge> getEdgeById(EdgeId edgeId) {
  1993 + try {
  1994 + ResponseEntity<Edge> edge = restTemplate.getForEntity(baseURL + "/api/edge/{edgeId}", Edge.class, edgeId.getId());
  1995 + return Optional.ofNullable(edge.getBody());
  1996 + } catch (HttpClientErrorException exception) {
  1997 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  1998 + return Optional.empty();
  1999 + } else {
  2000 + throw exception;
  2001 + }
  2002 + }
  2003 + }
  2004 +
  2005 + public Optional<Edge> assignEdgeToCustomer(CustomerId customerId, EdgeId edgeId) {
  2006 + try {
  2007 + ResponseEntity<Edge> edge = restTemplate.postForEntity(baseURL + "/api/customer/{customerId}/edge/{edgeId}", null, Edge.class, customerId.getId(), edgeId.getId());
  2008 + return Optional.ofNullable(edge.getBody());
  2009 + } catch (HttpClientErrorException exception) {
  2010 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2011 + return Optional.empty();
  2012 + } else {
  2013 + throw exception;
  2014 + }
  2015 + }
  2016 + }
  2017 +
  2018 + public Optional<Edge> unassignEdgeFromCustomer(EdgeId edgeId) {
  2019 + try {
  2020 + ResponseEntity<Edge> edge = restTemplate.exchange(baseURL + "/api/customer/edge/{edgeId}", HttpMethod.DELETE, HttpEntity.EMPTY, Edge.class, edgeId.getId());
  2021 + return Optional.ofNullable(edge.getBody());
  2022 + } catch (HttpClientErrorException exception) {
  2023 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2024 + return Optional.empty();
  2025 + } else {
  2026 + throw exception;
  2027 + }
  2028 + }
  2029 + }
  2030 +
  2031 + public Optional<Device> assignDeviceToEdge(EdgeId edgeId, DeviceId deviceId) {
  2032 + try {
  2033 + ResponseEntity<Device> device = restTemplate.postForEntity(baseURL + "/api/edge/{edgeId}/device/{deviceId}", null, Device.class, edgeId.getId(), deviceId.getId());
  2034 + return Optional.ofNullable(device.getBody());
  2035 + } catch (HttpClientErrorException exception) {
  2036 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2037 + return Optional.empty();
  2038 + } else {
  2039 + throw exception;
  2040 + }
  2041 + }
  2042 + }
  2043 +
  2044 + public Optional<Device> unassignDeviceFromEdge(DeviceId deviceId) {
  2045 + try {
  2046 + ResponseEntity<Device> device = restTemplate.exchange(baseURL + "/api/edge/device/{deviceId}", HttpMethod.DELETE, HttpEntity.EMPTY, Device.class, deviceId.getId());
  2047 + return Optional.ofNullable(device.getBody());
  2048 + } catch (HttpClientErrorException exception) {
  2049 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2050 + return Optional.empty();
  2051 + } else {
  2052 + throw exception;
  2053 + }
  2054 + }
  2055 + }
  2056 +
  2057 + public TextPageData<Device> getEdgeDevices(EdgeId edgeId, String deviceType, TextPageLink pageLink) {
  2058 + Map<String, String> params = new HashMap<>();
  2059 + params.put("edgeId", edgeId.getId().toString());
  2060 + params.put("type", deviceType);
  2061 + addPageLinkToParam(params, pageLink);
  2062 + return restTemplate.exchange(
  2063 + baseURL + "/api/edge/{edgeId}/devices?type={type}&" + getUrlParams(pageLink),
  2064 + HttpMethod.GET, HttpEntity.EMPTY,
  2065 + new ParameterizedTypeReference<TextPageData<Device>>() {
  2066 + }, params).getBody();
  2067 + }
  2068 +
  2069 + public Optional<Asset> assignAssetToEdge(EdgeId edgeId, AssetId assetId) {
  2070 + try {
  2071 + ResponseEntity<Asset> asset = restTemplate.postForEntity(baseURL + "/api/edge/{edgeId}/asset/{assetId}", null, Asset.class, edgeId.getId(), assetId.getId());
  2072 + return Optional.ofNullable(asset.getBody());
  2073 + } catch (HttpClientErrorException exception) {
  2074 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2075 + return Optional.empty();
  2076 + } else {
  2077 + throw exception;
  2078 + }
  2079 + }
  2080 + }
  2081 +
  2082 + public Optional<Asset> unassignAssetFromEdge(AssetId assetId) {
  2083 + try {
  2084 + ResponseEntity<Asset> asset = restTemplate.exchange(baseURL + "/api/edge/asset/{assetId}", HttpMethod.DELETE, HttpEntity.EMPTY, Asset.class, assetId.getId());
  2085 + return Optional.ofNullable(asset.getBody());
  2086 + } catch (HttpClientErrorException exception) {
  2087 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2088 + return Optional.empty();
  2089 + } else {
  2090 + throw exception;
  2091 + }
  2092 + }
  2093 + }
  2094 +
  2095 + public TextPageData<Asset> getEdgeAssets(EdgeId edgeId, String assetType, TextPageLink pageLink) {
  2096 + Map<String, String> params = new HashMap<>();
  2097 + params.put("edgeId", edgeId.getId().toString());
  2098 + params.put("type", assetType);
  2099 + addPageLinkToParam(params, pageLink);
  2100 + return restTemplate.exchange(
  2101 + baseURL + "/api/edge/{edgeId}/assets?type={type}&" + getUrlParams(pageLink),
  2102 + HttpMethod.GET, HttpEntity.EMPTY,
  2103 + new ParameterizedTypeReference<TextPageData<Asset>>() {
  2104 + }, params).getBody();
  2105 + }
  2106 +
  2107 + public TextPageData<Edge> getTenantEdges(String type, TextPageLink pageLink) {
  2108 + Map<String, String> params = new HashMap<>();
  2109 + params.put("type", type);
  2110 + addPageLinkToParam(params, pageLink);
  2111 + return restTemplate.exchange(
  2112 + baseURL + "/api/tenant/edges?type={type}&" + getUrlParams(pageLink),
  2113 + HttpMethod.GET, HttpEntity.EMPTY,
  2114 + new ParameterizedTypeReference<TextPageData<Edge>>() {
  2115 + }, params).getBody();
  2116 + }
  2117 +
  2118 + public Optional<Edge> getTenantEdge(String edgeName) {
  2119 + try {
  2120 + ResponseEntity<Edge> edge = restTemplate.getForEntity(baseURL + "/api/tenant/edges?edgeName={edgeName}", Edge.class, edgeName);
  2121 + return Optional.ofNullable(edge.getBody());
  2122 + } catch (HttpClientErrorException exception) {
  2123 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2124 + return Optional.empty();
  2125 + } else {
  2126 + throw exception;
  2127 + }
  2128 + }
  2129 + }
  2130 +
  2131 + public TextPageData<Edge> getCustomerEdges(CustomerId customerId, String edgeType, TextPageLink pageLink) {
  2132 + Map<String, String> params = new HashMap<>();
  2133 + params.put("customerId", customerId.getId().toString());
  2134 + params.put("type", edgeType);
  2135 + addPageLinkToParam(params, pageLink);
  2136 + return restTemplate.exchange(
  2137 + baseURL + "/api/customer/{customerId}/edges?type={type}&" + getUrlParams(pageLink),
  2138 + HttpMethod.GET, HttpEntity.EMPTY,
  2139 + new ParameterizedTypeReference<TextPageData<Edge>>() {
  2140 + }, params).getBody();
  2141 + }
  2142 +
  2143 + public List<Edge> getEdgesByIds(List<EdgeId> edgeIds) {
  2144 + return restTemplate.exchange(baseURL + "/api/edges?edgeIds={edgeIds}",
  2145 + HttpMethod.GET,
  2146 + HttpEntity.EMPTY, new ParameterizedTypeReference<List<Edge>>() {
  2147 + }, listIdsToString(edgeIds)).getBody();
  2148 + }
  2149 +
  2150 + public List<Edge> findByQuery(EdgeSearchQuery query) {
  2151 + return restTemplate.exchange(
  2152 + baseURL + "/api/edges",
  2153 + HttpMethod.POST,
  2154 + new HttpEntity<>(query),
  2155 + new ParameterizedTypeReference<List<Edge>>() {
  2156 + }).getBody();
  2157 + }
  2158 +
  2159 + public List<EntitySubtype> getEdgeTypes() {
  2160 + return restTemplate.exchange(
  2161 + baseURL + "/api/edge/types",
  2162 + HttpMethod.GET,
  2163 + HttpEntity.EMPTY,
  2164 + new ParameterizedTypeReference<List<EntitySubtype>>() {
  2165 + }).getBody();
  2166 + }
  2167 +
1981 2168 @Deprecated
1982 2169 public Optional<JsonNode> getAttributes(String accessToken, String clientKeys, String sharedKeys) {
1983 2170 Map<String, String> params = new HashMap<>();
... ...
... ... @@ -58,6 +58,6 @@ public @interface RuleNode {
58 58
59 59 boolean customRelations() default false;
60 60
61   - RuleChainType[] ruleChainTypes() default RuleChainType.CORE;
  61 + RuleChainType[] ruleChainTypes() default {RuleChainType.CORE, RuleChainType.EDGE};
62 62
63 63 }
... ...
... ... @@ -37,9 +37,7 @@ import org.thingsboard.server.common.msg.TbMsg;
37 37 "Will create new Customer if it doesn't exists and 'Create new Customer if not exists' is set to true.",
38 38 uiResources = {"static/rulenode/rulenode-core-config.js"},
39 39 configDirective = "tbActionNodeAssignToCustomerConfig",
40   - icon = "add_circle",
41   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
42   -)
  40 + icon = "add_circle")
43 41 public class TbAssignToCustomerNode extends TbAbstractCustomerActionNode<TbAssignToCustomerNodeConfiguration> {
44 42
45 43 @Override
... ...
... ... @@ -45,9 +45,7 @@ import org.thingsboard.server.common.msg.TbMsg;
45 45 "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
46 46 uiResources = {"static/rulenode/rulenode-core-config.js"},
47 47 configDirective = "tbActionNodeClearAlarmConfig",
48   - icon = "notifications_off",
49   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
50   -)
  48 + icon = "notifications_off")
51 49 public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfiguration> {
52 50
53 51 @Override
... ...
... ... @@ -57,9 +57,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
57 57 "Changes message originator to related entity view and produces new messages according to count of updated entity views",
58 58 uiResources = {"static/rulenode/rulenode-core-config.js"},
59 59 configDirective = "tbNodeEmptyConfig",
60   - icon = "content_copy",
61   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
62   -)
  60 + icon = "content_copy")
63 61 public class TbCopyAttributesToEntityViewNode implements TbNode {
64 62
65 63 EmptyNodeConfiguration config;
... ...
... ... @@ -51,9 +51,7 @@ import java.util.List;
51 51 "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
52 52 uiResources = {"static/rulenode/rulenode-core-config.js"},
53 53 configDirective = "tbActionNodeCreateAlarmConfig",
54   - icon = "notifications_active",
55   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
56   -)
  54 + icon = "notifications_active")
57 55 public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConfiguration> {
58 56
59 57 private static ObjectMapper mapper = new ObjectMapper();
... ...
... ... @@ -54,9 +54,7 @@ import java.util.List;
54 54 nodeDetails = "If the relation already exists or successfully created - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.",
55 55 uiResources = {"static/rulenode/rulenode-core-config.js"},
56 56 configDirective = "tbActionNodeCreateRelationConfig",
57   - icon = "add_circle",
58   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
59   -)
  57 + icon = "add_circle")
60 58 public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateRelationNodeConfiguration> {
61 59
62 60 @Override
... ...
... ... @@ -44,9 +44,7 @@ import java.util.List;
44 44 nodeDetails = "If the relation(s) successfully deleted - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.",
45 45 uiResources = {"static/rulenode/rulenode-core-config.js"},
46 46 configDirective = "tbActionNodeDeleteRelationConfig",
47   - icon = "remove_circle",
48   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
49   -)
  47 + icon = "remove_circle")
50 48 public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> {
51 49
52 50 @Override
... ...
... ... @@ -37,10 +37,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
37 37 "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
38 38 uiResources = {"static/rulenode/rulenode-core-config.js"},
39 39 configDirective = "tbActionNodeLogConfig",
40   - icon = "menu",
41   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
42   -)
43   -
  40 + icon = "menu")
44 41 public class TbLogNode implements TbNode {
45 42
46 43 private TbLogNodeConfiguration config;
... ...
... ... @@ -44,9 +44,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
44 44 nodeDetails = "Count incoming messages for specified interval and produces POST_TELEMETRY_REQUEST msg with messages count",
45 45 icon = "functions",
46 46 uiResources = {"static/rulenode/rulenode-core-config.js"},
47   - configDirective = "tbActionNodeMsgCountConfig",
48   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
49   -)
  47 + configDirective = "tbActionNodeMsgCountConfig")
50 48 public class TbMsgCountNode implements TbNode {
51 49
52 50 private static final String TB_MSG_COUNT_NODE_MSG = "TbMsgCountNodeMsg";
... ...
... ... @@ -78,7 +78,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
78 78 " otherwise, the message will be routed via <b>success</b> chain.",
79 79 uiResources = {"static/rulenode/rulenode-core-config.js"},
80 80 configDirective = "tbActionNodeCustomTableConfig",
81   - icon = "file_upload"
  81 + icon = "file_upload",
  82 + ruleChainTypes = RuleChainType.CORE
82 83 )
83 84 public class TbSaveToCustomCassandraTableNode implements TbNode {
84 85
... ...
... ... @@ -21,9 +21,13 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
21 21 import org.thingsboard.rule.engine.api.TbNodeException;
22 22 import org.thingsboard.rule.engine.api.util.TbNodeUtils;
23 23 import org.thingsboard.server.common.data.EntityType;
24   -import org.thingsboard.server.common.data.id.*;
  24 +import org.thingsboard.server.common.data.id.AssetId;
  25 +import org.thingsboard.server.common.data.id.CustomerId;
  26 +import org.thingsboard.server.common.data.id.DashboardId;
  27 +import org.thingsboard.server.common.data.id.DeviceId;
  28 +import org.thingsboard.server.common.data.id.EdgeId;
  29 +import org.thingsboard.server.common.data.id.EntityViewId;
25 30 import org.thingsboard.server.common.data.plugin.ComponentType;
26   -import org.thingsboard.server.common.data.rule.RuleChainType;
27 31 import org.thingsboard.server.common.msg.TbMsg;
28 32
29 33 @RuleNode(
... ... @@ -34,8 +38,7 @@ import org.thingsboard.server.common.msg.TbMsg;
34 38 nodeDetails = "Finds target Entity Customer by Customer name pattern and then unassign Originator Entity from this customer.",
35 39 uiResources = {"static/rulenode/rulenode-core-config.js"},
36 40 configDirective = "tbActionNodeUnAssignToCustomerConfig",
37   - icon = "remove_circle",
38   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  41 + icon = "remove_circle"
39 42 )
40 43 public class TbUnassignFromCustomerNode extends TbAbstractCustomerActionNode<TbUnassignFromCustomerNodeConfiguration> {
41 44
... ...
... ... @@ -46,8 +46,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
46 46 "For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.",
47 47 uiResources = {"static/rulenode/rulenode-core-config.js"},
48 48 configDirective = "tbActionNodeSnsConfig",
49   - iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+",
50   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  49 + iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"
51 50 )
52 51 public class TbSnsNode implements TbNode {
53 52
... ...
... ... @@ -51,8 +51,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
51 51 " For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.",
52 52 uiResources = {"static/rulenode/rulenode-core-config.js"},
53 53 configDirective = "tbActionNodeSqsConfig",
54   - iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+",
55   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  54 + iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"
56 55 )
57 56 public class TbSqsNode implements TbNode {
58 57
... ...
... ... @@ -45,8 +45,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
45 45 inEnabled = false,
46 46 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
47 47 configDirective = "tbActionNodeGeneratorConfig",
48   - icon = "repeat",
49   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  48 + icon = "repeat"
50 49 )
51 50
52 51 public class TbMsgGeneratorNode implements TbNode {
... ...
... ... @@ -46,8 +46,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
46 46 nodeDetails = "Delays messages for configurable period. Please note, this node acknowledges the message from the current queue (message will be removed from queue)",
47 47 icon = "pause",
48 48 uiResources = {"static/rulenode/rulenode-core-config.js"},
49   - configDirective = "tbActionNodeMsgDelayConfig",
50   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  49 + configDirective = "tbActionNodeMsgDelayConfig"
51 50 )
52 51
53 52 public class TbMsgDelayNode implements TbNode {
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.rule.engine.edge;
17 17
  18 +import com.fasterxml.jackson.core.JsonProcessingException;
18 19 import com.fasterxml.jackson.databind.ObjectMapper;
19 20 import com.google.common.util.concurrent.FutureCallback;
20 21 import com.google.common.util.concurrent.Futures;
... ... @@ -28,6 +29,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
28 29 import org.thingsboard.rule.engine.api.TbNodeException;
29 30 import org.thingsboard.rule.engine.api.util.TbNodeUtils;
30 31 import org.thingsboard.server.common.data.DataConstants;
  32 +import org.thingsboard.server.common.data.EdgeUtils;
31 33 import org.thingsboard.server.common.data.EntityType;
32 34 import org.thingsboard.server.common.data.audit.ActionType;
33 35 import org.thingsboard.server.common.data.edge.EdgeEvent;
... ... @@ -38,6 +40,7 @@ import org.thingsboard.server.common.data.id.TenantId;
38 40 import org.thingsboard.server.common.data.plugin.ComponentType;
39 41 import org.thingsboard.server.common.data.relation.EntityRelation;
40 42 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
  43 +import org.thingsboard.server.common.data.rule.RuleChainType;
41 44 import org.thingsboard.server.common.msg.TbMsg;
42 45 import org.thingsboard.server.common.msg.session.SessionMsgType;
43 46
... ... @@ -55,7 +58,8 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
55 58 nodeDetails = "Pushes messages to edge, if Message Originator assigned to particular edge or is EDGE entity. This node is used only on Cloud instances to push messages from Cloud to Edge. Supports only DEVICE, ENTITY_VIEW, ASSET and EDGE Message Originator(s).",
56 59 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
57 60 configDirective = "tbNodeEmptyConfig",
58   - icon = "cloud_download"
  61 + icon = "cloud_download",
  62 + ruleChainTypes = RuleChainType.CORE
59 63 )
60 64 public class TbMsgPushToEdgeNode implements TbNode {
61 65
... ... @@ -77,33 +81,38 @@ public class TbMsgPushToEdgeNode implements TbNode {
77 81 if (isSupportedOriginator(msg.getOriginator().getEntityType())) {
78 82 if (isSupportedMsgType(msg.getType())) {
79 83 ListenableFuture<EdgeId> getEdgeIdFuture = getEdgeIdByOriginatorId(ctx, ctx.getTenantId(), msg.getOriginator());
80   - Futures.transform(getEdgeIdFuture, edgeId -> {
81   - EdgeEventType edgeEventTypeByEntityType = ctx.getEdgeEventService().getEdgeEventTypeByEntityType(msg.getOriginator().getEntityType());
82   - if (edgeEventTypeByEntityType == null) {
83   - log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType());
84   - ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '" + msg.getOriginator().getEntityType() + "'"));
85   - }
86   - EdgeEvent edgeEvent = new EdgeEvent();
87   - edgeEvent.setTenantId(ctx.getTenantId());
88   - edgeEvent.setEdgeId(edgeId);
89   - edgeEvent.setEdgeEventAction(getActionTypeByMsgType(msg.getType()).name());
90   - edgeEvent.setEntityId(msg.getOriginator().getId());
91   - edgeEvent.setEdgeEventType(edgeEventTypeByEntityType);
92   - edgeEvent.setEntityBody(json.valueToTree(msg.getData()));
93   - ListenableFuture<EdgeEvent> saveFuture = ctx.getEdgeEventService().saveAsync(edgeEvent);
94   - Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() {
95   - @Override
96   - public void onSuccess(@Nullable EdgeEvent event) {
97   - ctx.tellNext(msg, SUCCESS);
  84 + Futures.addCallback(getEdgeIdFuture, new FutureCallback<EdgeId>() {
  85 + @Override
  86 + public void onSuccess(@Nullable EdgeId edgeId) {
  87 + EdgeEventType edgeEventTypeByEntityType = EdgeUtils.getEdgeEventTypeByEntityType(msg.getOriginator().getEntityType());
  88 + if (edgeEventTypeByEntityType == null) {
  89 + log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType());
  90 + ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '" + msg.getOriginator().getEntityType() + "'"));
98 91 }
99   -
100   - @Override
101   - public void onFailure(Throwable th) {
102   - log.error("Could not save edge event", th);
103   - ctx.tellFailure(msg, th);
  92 + EdgeEvent edgeEvent = null;
  93 + try {
  94 + edgeEvent = buildEdgeEvent(ctx, msg, edgeId, edgeEventTypeByEntityType);
  95 + } catch (JsonProcessingException e) {
  96 + log.error("Failed to build edge event", e);
104 97 }
105   - }, ctx.getDbCallbackExecutor());
106   - return null;
  98 + ListenableFuture<EdgeEvent> saveFuture = ctx.getEdgeEventService().saveAsync(edgeEvent);
  99 + Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() {
  100 + @Override
  101 + public void onSuccess(@Nullable EdgeEvent event) {
  102 + ctx.tellNext(msg, SUCCESS);
  103 + }
  104 + @Override
  105 + public void onFailure(Throwable th) {
  106 + log.error("Could not save edge event", th);
  107 + ctx.tellFailure(msg, th);
  108 + }
  109 + }, ctx.getDbCallbackExecutor());
  110 + }
  111 + @Override
  112 + public void onFailure(Throwable t) {
  113 + ctx.tellFailure(msg, t);
  114 + }
  115 +
107 116 }, ctx.getDbCallbackExecutor());
108 117 } else {
109 118 log.debug("Unsupported msg type {}", msg.getType());
... ... @@ -115,6 +124,17 @@ public class TbMsgPushToEdgeNode implements TbNode {
115 124 }
116 125 }
117 126
  127 + private EdgeEvent buildEdgeEvent(TbContext ctx, TbMsg msg, EdgeId edgeId, EdgeEventType edgeEventTypeByEntityType) throws JsonProcessingException {
  128 + EdgeEvent edgeEvent = new EdgeEvent();
  129 + edgeEvent.setTenantId(ctx.getTenantId());
  130 + edgeEvent.setEdgeId(edgeId);
  131 + edgeEvent.setEdgeEventAction(getActionTypeByMsgType(msg.getType()).name());
  132 + edgeEvent.setEntityId(msg.getOriginator().getId());
  133 + edgeEvent.setEdgeEventType(edgeEventTypeByEntityType);
  134 + edgeEvent.setEntityBody(json.readTree(msg.getData()));
  135 + return edgeEvent;
  136 + }
  137 +
118 138 private ActionType getActionTypeByMsgType(String msgType) {
119 139 ActionType actionType;
120 140 if (SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msgType)) {
... ...
... ... @@ -40,8 +40,7 @@ import java.util.Map;
40 40 nodeDetails = "If selected checkbox 'Check that all selected keys are present'\" and all keys in message data and metadata are exist - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.\n" +
41 41 "Else if the checkbox is not selected, and at least one of the keys from data or metadata of the message exists - send Message via <b>True</b> chain, otherwise, <b>False</b> chain is used. ",
42 42 uiResources = {"static/rulenode/rulenode-core-config.js"},
43   - configDirective = "tbFilterNodeCheckMessageConfig",
44   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  43 + configDirective = "tbFilterNodeCheckMessageConfig"
45 44 )
46 45 public class TbCheckMessageNode implements TbNode {
47 46
... ...
... ... @@ -52,8 +52,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
52 52 " any relation to the originator of the message by type and direction.",
53 53 nodeDetails = "If at least one relation exists - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
54 54 uiResources = {"static/rulenode/rulenode-core-config.js"},
55   - configDirective = "tbFilterNodeCheckRelationConfig",
56   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  55 + configDirective = "tbFilterNodeCheckRelationConfig"
57 56 )
58 57 public class TbCheckRelationNode implements TbNode {
59 58
... ...
... ... @@ -37,8 +37,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
37 37 "Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
38 38 "Message type can be accessed via <code>msgType</code> property.",
39 39 uiResources = {"static/rulenode/rulenode-core-config.js"},
40   - configDirective = "tbFilterNodeScriptConfig",
41   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  40 + configDirective = "tbFilterNodeScriptConfig"
42 41 )
43 42
44 43 public class TbJsFilterNode implements TbNode {
... ...
... ... @@ -40,8 +40,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
40 40 "Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
41 41 "Message type can be accessed via <code>msgType</code> property.",
42 42 uiResources = {"static/rulenode/rulenode-core-config.js"},
43   - configDirective = "tbFilterNodeSwitchConfig",
44   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  43 + configDirective = "tbFilterNodeSwitchConfig"
45 44 )
46 45 public class TbJsSwitchNode implements TbNode {
47 46
... ...
... ... @@ -34,8 +34,7 @@ import org.thingsboard.server.common.msg.TbMsg;
34 34 nodeDescription = "Filter incoming messages by Message Type",
35 35 nodeDetails = "If incoming MessageType is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
36 36 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
37   - configDirective = "tbFilterNodeMessageTypeConfig",
38   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  37 + configDirective = "tbFilterNodeMessageTypeConfig"
39 38 )
40 39 public class TbMsgTypeFilterNode implements TbNode {
41 40
... ...
... ... @@ -35,8 +35,7 @@ import org.thingsboard.server.common.msg.session.SessionMsgType;
35 35 nodeDescription = "Route incoming messages by Message Type",
36 36 nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.",
37 37 uiResources = {"static/rulenode/rulenode-core-config.js"},
38   - configDirective = "tbNodeEmptyConfig",
39   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  38 + configDirective = "tbNodeEmptyConfig"
40 39 )
41 40 public class TbMsgTypeSwitchNode implements TbNode {
42 41
... ...
... ... @@ -32,8 +32,7 @@ import org.thingsboard.server.common.msg.TbMsg;
32 32 nodeDescription = "Filter incoming messages by message Originator Type",
33 33 nodeDetails = "If Originator Type of incoming message is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
34 34 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
35   - configDirective = "tbFilterNodeOriginatorTypeConfig",
36   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  35 + configDirective = "tbFilterNodeOriginatorTypeConfig"
37 36 )
38 37 public class TbOriginatorTypeFilterNode implements TbNode {
39 38
... ...
... ... @@ -32,8 +32,7 @@ import org.thingsboard.server.common.msg.TbMsg;
32 32 nodeDescription = "Route incoming messages by Message Originator Type",
33 33 nodeDetails = "Routes messages to chain according to the originator type ('Device', 'Asset', etc.).",
34 34 uiResources = {"static/rulenode/rulenode-core-config.js"},
35   - configDirective = "tbNodeEmptyConfig",
36   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  35 + configDirective = "tbNodeEmptyConfig"
37 36 )
38 37 public class TbOriginatorTypeSwitchNode implements TbNode {
39 38
... ...
... ... @@ -50,8 +50,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
50 50 "<b>messageId</b> field can be accessed with <code>metadata.messageId</code>.",
51 51 uiResources = {"static/rulenode/rulenode-core-config.js"},
52 52 configDirective = "tbActionNodePubSubConfig",
53   - iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo=",
54   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  53 + iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo="
55 54 )
56 55 public class TbPubSubNode implements TbNode {
57 56
... ...
... ... @@ -52,8 +52,7 @@ import java.util.concurrent.TimeoutException;
52 52 nodeDescription = "Produces incoming messages using GPS based geofencing",
53 53 nodeDetails = "Extracts latitude and longitude parameters from incoming message and returns different events based on configuration parameters",
54 54 uiResources = {"static/rulenode/rulenode-core-config.js"},
55   - configDirective = "tbActionNodeGpsGeofencingConfig",
56   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  55 + configDirective = "tbActionNodeGpsGeofencingConfig"
57 56 )
58 57 public class TbGpsGeofencingActionNode extends AbstractGeofencingNode<TbGpsGeofencingActionNodeConfiguration> {
59 58
... ...
... ... @@ -53,8 +53,7 @@ import java.util.List;
53 53 nodeDescription = "Filter incoming messages by GPS based geofencing",
54 54 nodeDetails = "Extracts latitude and longitude parameters from incoming message and returns 'True' if they are inside configured perimeters, 'False' otherwise.",
55 55 uiResources = {"static/rulenode/rulenode-core-config.js"},
56   - configDirective = "tbFilterNodeGpsGeofencingConfig",
57   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  56 + configDirective = "tbFilterNodeGpsGeofencingConfig"
58 57 )
59 58 public class TbGpsGeofencingFilterNode extends AbstractGeofencingNode<TbGpsGeofencingFilterNodeConfiguration> {
60 59
... ...
... ... @@ -52,8 +52,7 @@ import java.util.Properties;
52 52 " from the Kafka in the Message Metadata. For example <b>partition</b> field can be accessed with <code>metadata.partition</code>.",
53 53 uiResources = {"static/rulenode/rulenode-core-config.js"},
54 54 configDirective = "tbActionNodeKafkaConfig",
55   - iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg==",
56   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  55 + iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg=="
57 56 )
58 57 public class TbKafkaNode implements TbNode {
59 58
... ...
... ... @@ -41,8 +41,7 @@ import static org.thingsboard.rule.engine.mail.TbSendEmailNode.SEND_EMAIL_TYPE;
41 41 "Set 'SEND_EMAIL' output message type.",
42 42 uiResources = {"static/rulenode/rulenode-core-config.js"},
43 43 configDirective = "tbTransformationNodeToEmailConfig",
44   - icon = "email",
45   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  44 + icon = "email"
46 45 )
47 46 public class TbMsgToEmailNode implements TbNode {
48 47
... ...
... ... @@ -47,8 +47,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
47 47 "with <code>to Email</code> Node using <code>Successful</code> chain.",
48 48 uiResources = {"static/rulenode/rulenode-core-config.js"},
49 49 configDirective = "tbActionNodeSendEmailConfig",
50   - icon = "send",
51   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  50 + icon = "send"
52 51 )
53 52 public class TbSendEmailNode implements TbNode {
54 53
... ...
... ... @@ -41,8 +41,7 @@ import org.thingsboard.server.common.msg.TbMsg;
41 41 "To access those attributes in other nodes this template can be used " +
42 42 "<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ",
43 43 uiResources = {"static/rulenode/rulenode-core-config.js"},
44   - configDirective = "tbEnrichmentNodeOriginatorAttributesConfig",
45   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  44 + configDirective = "tbEnrichmentNodeOriginatorAttributesConfig"
46 45 )
47 46 public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttributesNodeConfiguration, EntityId> {
48 47
... ...
... ... @@ -34,8 +34,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
34 34 "To access those attributes in other nodes this template can be used " +
35 35 "<code>metadata.temperature</code>.",
36 36 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
37   - configDirective = "tbEnrichmentNodeCustomerAttributesConfig",
38   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  37 + configDirective = "tbEnrichmentNodeCustomerAttributesConfig"
39 38 )
40 39 public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode<CustomerId> {
41 40
... ...
... ... @@ -43,8 +43,7 @@ import org.thingsboard.server.common.msg.TbMsg;
43 43 "<b>Note:</b> only Device, Asset, and Entity View type are allowed.<br><br>" +
44 44 "If the originator of the message is not assigned to Customer, or originator type is not supported - Message will be forwarded to <b>Failure</b> chain, otherwise, <b>Success</b> chain will be used.",
45 45 uiResources = {"static/rulenode/rulenode-core-config.js"},
46   - configDirective = "tbEnrichmentNodeEntityDetailsConfig",
47   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  46 + configDirective = "tbEnrichmentNodeEntityDetailsConfig"
48 47 )
49 48 public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetCustomerDetailsNodeConfiguration> {
50 49
... ...
... ... @@ -39,8 +39,7 @@ import org.thingsboard.server.common.msg.TbMsg;
39 39 "To access those attributes in other nodes this template can be used " +
40 40 "<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ",
41 41 uiResources = {"static/rulenode/rulenode-core-config.js"},
42   - configDirective = "tbEnrichmentNodeDeviceAttributesConfig",
43   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  42 + configDirective = "tbEnrichmentNodeDeviceAttributesConfig"
44 43 )
45 44 public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode<TbGetDeviceAttrNodeConfiguration, DeviceId> {
46 45
... ...
... ... @@ -44,8 +44,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
44 44 nodeDescription = "Add Message Originator fields values into Message Metadata",
45 45 nodeDetails = "Will fetch fields values specified in mapping. If specified field is not part of originator fields it will be ignored.",
46 46 uiResources = {"static/rulenode/rulenode-core-config.js"},
47   - configDirective = "tbEnrichmentNodeOriginatorFieldsConfig",
48   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  47 + configDirective = "tbEnrichmentNodeOriginatorFieldsConfig"
49 48 )
50 49 public class TbGetOriginatorFieldsNode implements TbNode {
51 50
... ...
... ... @@ -36,8 +36,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
36 36 "To access those attributes in other nodes this template can be used " +
37 37 "<code>metadata.temperature</code>.",
38 38 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
39   - configDirective = "tbEnrichmentNodeRelatedAttributesConfig",
40   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  39 + configDirective = "tbEnrichmentNodeRelatedAttributesConfig"
41 40 )
42 41
43 42 public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> {
... ...
... ... @@ -67,8 +67,7 @@ import static org.thingsboard.server.common.data.kv.Aggregation.NONE;
67 67 "Also, the rule node allows you to select telemetry sampling order: <b>ASC</b> or <b>DESC</b>. </br>" +
68 68 "<b>Note</b>: The maximum size of the fetched array is 1000 records.\n ",
69 69 uiResources = {"static/rulenode/rulenode-core-config.js"},
70   - configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase",
71   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  70 + configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase"
72 71 )
73 72 public class TbGetTelemetryNode implements TbNode {
74 73
... ...
... ... @@ -36,8 +36,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
36 36 "To access those attributes in other nodes this template can be used " +
37 37 "<code>metadata.temperature</code>.",
38 38 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
39   - configDirective = "tbEnrichmentNodeTenantAttributesConfig",
40   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  39 + configDirective = "tbEnrichmentNodeTenantAttributesConfig"
41 40 )
42 41 public class TbGetTenantAttributeNode extends TbEntityGetAttrNode<TenantId> {
43 42
... ...
... ... @@ -38,8 +38,7 @@ import org.thingsboard.server.common.msg.TbMsg;
38 38 "<b>Note:</b> only Device, Asset, and Entity View type are allowed.<br><br>" +
39 39 "If the originator of the message is not assigned to Tenant, or originator type is not supported - Message will be forwarded to <b>Failure</b> chain, otherwise, <b>Success</b> chain will be used.",
40 40 uiResources = {"static/rulenode/rulenode-core-config.js"},
41   - configDirective = "tbEnrichmentNodeEntityDetailsConfig",
42   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  41 + configDirective = "tbEnrichmentNodeEntityDetailsConfig"
43 42 )
44 43 public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetTenantDetailsNodeConfiguration> {
45 44
... ...
... ... @@ -50,8 +50,7 @@ import java.util.concurrent.TimeoutException;
50 50 nodeDetails = "Will publish message payload to the MQTT broker with QoS <b>AT_LEAST_ONCE</b>.",
51 51 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
52 52 configDirective = "tbActionNodeMqttConfig",
53   - icon = "call_split",
54   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  53 + icon = "call_split"
55 54 )
56 55 public class TbMqttNode implements TbNode {
57 56
... ...
... ... @@ -40,8 +40,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
40 40 nodeDetails = "Will publish message payload to RabbitMQ queue.",
41 41 uiResources = {"static/rulenode/rulenode-core-config.js"},
42 42 configDirective = "tbActionNodeRabbitMqConfig",
43   - iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4=",
44   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  43 + iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4="
45 44 )
46 45 public class TbRabbitMqNode implements TbNode {
47 46
... ...
... ... @@ -42,8 +42,7 @@ import org.thingsboard.server.common.msg.TbMsg;
42 42 "and if your proxy with auth, the next ones should be added: \"tb.proxy.user\" and \"tb.proxy.password\" to the thingsboard.conf file.",
43 43 uiResources = {"static/rulenode/rulenode-core-config.js"},
44 44 configDirective = "tbActionNodeRestApiCallConfig",
45   - iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+",
46   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  45 + iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+"
47 46 )
48 47 public class TbRestApiCallNode implements TbNode {
49 48
... ...
... ... @@ -40,8 +40,7 @@ import java.util.UUID;
40 40 nodeDetails = "Expects messages with any message type. Will forward message body to the device.",
41 41 uiResources = {"static/rulenode/rulenode-core-config.js"},
42 42 configDirective = "tbActionNodeRpcReplyConfig",
43   - icon = "call_merge",
44   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  43 + icon = "call_merge"
45 44 )
46 45 public class TbSendRPCReplyNode implements TbNode {
47 46
... ...
... ... @@ -51,8 +51,7 @@ import java.util.concurrent.TimeUnit;
51 51 "If the RPC call request is originated by REST API call from user, will forward the response to user immediately.",
52 52 uiResources = {"static/rulenode/rulenode-core-config.js"},
53 53 configDirective = "tbActionNodeRpcRequestConfig",
54   - icon = "call_made",
55   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  54 + icon = "call_made"
56 55 )
57 56 public class TbSendRPCRequestNode implements TbNode {
58 57
... ...
... ... @@ -45,8 +45,7 @@ import java.util.Set;
45 45 nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type",
46 46 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
47 47 configDirective = "tbActionNodeAttributesConfig",
48   - icon = "file_upload",
49   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  48 + icon = "file_upload"
50 49 )
51 50 public class TbMsgAttributesNode implements TbNode {
52 51
... ...
... ... @@ -46,8 +46,7 @@ import java.util.Map;
46 46 nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type",
47 47 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
48 48 configDirective = "tbActionNodeTimeseriesConfig",
49   - icon = "file_upload",
50   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  49 + icon = "file_upload"
51 50 )
52 51 public class TbMsgTimeseriesNode implements TbNode {
53 52
... ...
... ... @@ -39,8 +39,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
39 39 "Subsequent messages will not be processed until the previous message processing is completed or timeout event occurs.\n" +
40 40 "Size of the queue per originator and timeout values are configurable on a system level",
41 41 uiResources = {"static/rulenode/rulenode-core-config.js"},
42   - configDirective = "tbNodeEmptyConfig",
43   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  42 + configDirective = "tbNodeEmptyConfig"
44 43 )
45 44 @Deprecated
46 45 public class TbSynchronizationBeginNode implements TbNode {
... ...
... ... @@ -39,8 +39,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
39 39 nodeDescription = "This Node is now deprecated. Use \"Checkpoint\" instead.",
40 40 nodeDetails = "",
41 41 uiResources = {"static/rulenode/rulenode-core-config.js"},
42   - configDirective = ("tbNodeEmptyConfig"),
43   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  42 + configDirective = ("tbNodeEmptyConfig")
44 43 )
45 44 @Deprecated
46 45 public class TbSynchronizationEndNode implements TbNode {
... ...
... ... @@ -47,8 +47,7 @@ import java.util.HashSet;
47 47 "Alarm Originator found only in case original Originator is <code>Alarm</code> entity.",
48 48 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
49 49 configDirective = "tbTransformationNodeChangeOriginatorConfig",
50   - icon = "find_replace",
51   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  50 + icon = "find_replace"
52 51 )
53 52 public class TbChangeOriginatorNode extends TbAbstractTransformNode {
54 53
... ...
... ... @@ -38,8 +38,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
38 38 "<code>{ msg: <i style=\"color: #666;\">new payload</i>,<br/>&nbsp&nbsp&nbspmetadata: <i style=\"color: #666;\">new metadata</i>,<br/>&nbsp&nbsp&nbspmsgType: <i style=\"color: #666;\">new msgType</i> }</code><br/>" +
39 39 "All fields in resulting object are optional and will be taken from original message if not specified.",
40 40 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
41   - configDirective = "tbTransformationNodeScriptConfig",
42   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  41 + configDirective = "tbTransformationNodeScriptConfig"
43 42 )
44 43 public class TbTransformMsgNode extends TbAbstractTransformNode {
45 44
... ...
... ... @@ -1180,7 +1180,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
1180 1180 var saveRuleChainPromise;
1181 1181 if (vm.isImport) {
1182 1182 if (angular.isUndefined(vm.ruleChain.type)) {
1183   - vm.ruleChain.type = types.systemRuleChainType;
  1183 + vm.ruleChain.type = types.coreRuleChainType;
1184 1184 }
1185 1185 saveRuleChainPromise = ruleChainService.saveRuleChain(vm.ruleChain);
1186 1186 } else {
... ... @@ -1269,7 +1269,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
1269 1269 vm.isDirty = false;
1270 1270 vm.isImport = false;
1271 1271 $mdUtil.nextTick(() => {
1272   - if (vm.ruleChain.type === vm.types.systemRuleChainType) {
  1272 + if (vm.ruleChain.type === vm.types.coreRuleChainType) {
1273 1273 $state.go('home.ruleChains.core.ruleChain', {ruleChainId: vm.ruleChain.id.id});
1274 1274 } else {
1275 1275 $state.go('home.ruleChains.edge.ruleChain', {ruleChainId: vm.ruleChain.id.id});
... ... @@ -1293,7 +1293,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
1293 1293 ruleNode.configuration = angular.copy(ruleNode.component.configurationDescriptor.nodeDefinition.defaultConfiguration);
1294 1294
1295 1295 var ruleChainId = vm.ruleChain.id ? vm.ruleChain.id.id : null;
1296   - var ruleChainType = vm.ruleChain.type ? vm.ruleChain.type : types.systemRuleChainType;
  1296 + var ruleChainType = vm.ruleChain.type ? vm.ruleChain.type : types.coreRuleChainType;
1297 1297
1298 1298 vm.enableHotKeys = false;
1299 1299
... ...
... ... @@ -82,7 +82,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
82 82 ruleNodeComponents:
83 83 /*@ngInject*/
84 84 function($stateParams, ruleChainService) {
85   - return ruleChainService.getRuleNodeComponents(types.systemRuleChainType);
  85 + return ruleChainService.getRuleNodeComponents(types.coreRuleChainType);
86 86 }
87 87 },
88 88 data: {
... ...
... ... @@ -114,7 +114,7 @@ export default function RuleChainsController(ruleChainService, userService, edge
114 114
115 115 if (vm.ruleChainsScope === 'tenant') {
116 116 fetchRuleChainsFunction = function (pageLink) {
117   - return fetchRuleChains(pageLink, types.systemRuleChainType);
  117 + return fetchRuleChains(pageLink, types.coreRuleChainType);
118 118 };
119 119 deleteRuleChainFunction = function (ruleChainId) {
120 120 return deleteRuleChain(ruleChainId);
... ... @@ -162,9 +162,9 @@ export default function RuleChainsController(ruleChainService, userService, edge
162 162 });
163 163 vm.ruleChainGridConfig.addItemActions.push({
164 164 onAction: function ($event) {
165   - importExport.importRuleChain($event, types.systemRuleChainType).then(
  165 + importExport.importRuleChain($event, types.coreRuleChainType).then(
166 166 function(ruleChainImport) {
167   - $state.go('home.ruleChains.importRuleChain', {ruleChainImport:ruleChainImport, ruleChainType: types.systemRuleChainType});
  167 + $state.go('home.ruleChains.importRuleChain', {ruleChainImport:ruleChainImport, ruleChainType: types.coreRuleChainType});
168 168 }
169 169 );
170 170 },
... ... @@ -385,7 +385,7 @@ export default function RuleChainsController(ruleChainService, userService, edge
385 385 if (vm.ruleChainsScope === 'edges') {
386 386 ruleChain.type = types.edgeRuleChainType;
387 387 } else {
388   - ruleChain.type = types.systemRuleChainType;
  388 + ruleChain.type = types.coreRuleChainType;
389 389 }
390 390 }
391 391 return ruleChainService.saveRuleChain(ruleChain);
... ...