Browse Source

Added push to edge/cloud functionality

pull/2818/head
Volodymyr Babak 7 years ago
parent
commit
c99cf51ca6
  1. 6
      application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
  2. 14
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
  3. 37
      application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
  4. 10
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java
  5. 289
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  6. 7
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java
  7. 1
      common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java
  8. 15
      common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainType.java
  9. 44
      common/edge-api/src/main/proto/edge.proto
  10. 4
      common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java
  11. 194
      dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java
  12. 2
      dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEntity.java
  13. 2
      dao/src/main/java/org/thingsboard/server/dao/model/type/RuleChainTypeCodec.java
  14. 3
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
  15. 41
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/PushToEdgeNodeCallback.java
  16. 58
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToCloudNode.java
  17. 58
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java

6
application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java

@ -59,6 +59,7 @@ import org.thingsboard.server.dao.cassandra.CassandraCluster;
import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.nosql.CassandraBufferedRateExecutor; import org.thingsboard.server.dao.nosql.CassandraBufferedRateExecutor;
import org.thingsboard.server.dao.nosql.CassandraStatementTask; import org.thingsboard.server.dao.nosql.CassandraStatementTask;
@ -304,6 +305,11 @@ class DefaultTbContext implements TbContext {
return mainCtx.getRuleChainTransactionService(); return mainCtx.getRuleChainTransactionService();
} }
@Override
public EdgeService getEdgeService() {
return mainCtx.getEdgeService();
}
@Override @Override
public EventLoopGroup getSharedEventLoop() { public EventLoopGroup getSharedEventLoop() {
return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup(); return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup();

14
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java

@ -23,6 +23,7 @@ import com.datastax.driver.core.utils.UUIDs;
import java.util.Optional; import java.util.Optional;
import com.google.common.util.concurrent.FutureCallback;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg;
@ -49,6 +50,7 @@ import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -348,7 +350,17 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
case DataConstants.ENTITY_DELETED: case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_ASSIGNED_TO_EDGE: case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
edgeService.pushEventToEdge(tenantId, msg); edgeService.pushEventToEdge(tenantId, msg, new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void aVoid) {
log.debug("Event saved successfully!");
}
@Override
public void onFailure(Throwable t) {
log.debug("Failure during event save", t);
}
});
} }
} }

37
application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java

@ -17,13 +17,50 @@ package org.thingsboard.server.service.edge;
import lombok.Data; import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.actors.service.ActorService;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.relation.RelationService;
@Component @Component
@Data @Data
public class EdgeContextComponent { public class EdgeContextComponent {
@Lazy
@Autowired @Autowired
private EdgeService edgeService; private EdgeService edgeService;
@Lazy
@Autowired
private AssetService assetService;
@Lazy
@Autowired
private DeviceService deviceService;
@Lazy
@Autowired
private EntityViewService entityViewService;
@Lazy
@Autowired
private AttributesService attributesService;
@Lazy
@Autowired
private CustomerService customerService;
@Lazy
@Autowired
private RelationService relationService;
@Lazy
@Autowired
private ActorService actorService;
} }

10
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java

@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.actors.service.ActorService;
import org.thingsboard.server.common.data.Event; import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
@ -36,6 +37,7 @@ import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.gen.edge.EdgeRpcServiceGrpc; import org.thingsboard.server.gen.edge.EdgeRpcServiceGrpc;
import org.thingsboard.server.gen.edge.RequestMsg; import org.thingsboard.server.gen.edge.RequestMsg;
@ -81,9 +83,15 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase {
@Autowired @Autowired
private DeviceService deviceService; private DeviceService deviceService;
@Autowired
private EntityViewService entityViewService;
@Autowired @Autowired
private AttributesService attributesService; private AttributesService attributesService;
@Autowired
private ActorService actorService;
private Server server; private Server server;
private ExecutorService executor; private ExecutorService executor;
@ -124,7 +132,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase {
@Override @Override
public StreamObserver<RequestMsg> handleMsgs(StreamObserver<ResponseMsg> outputStream) { public StreamObserver<RequestMsg> handleMsgs(StreamObserver<ResponseMsg> outputStream) {
return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, edgeService, assetService, deviceService, attributesService, objectMapper).getInputStream(); return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, objectMapper).getInputStream();
} }
private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) { private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) {

289
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java

@ -18,8 +18,10 @@ package org.thingsboard.server.service.edge.rpc;
import com.datastax.driver.core.utils.UUIDs; import com.datastax.driver.core.utils.UUIDs;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.protobuf.ByteString;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -33,23 +35,29 @@ import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeQueueEntry; import org.thingsboard.server.common.data.edge.EdgeQueueEntry;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.page.TimePageData; import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo; import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.dao.util.mapping.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.AssetUpdateMsg; import org.thingsboard.server.gen.edge.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.ConnectRequestMsg; import org.thingsboard.server.gen.edge.ConnectRequestMsg;
@ -57,7 +65,9 @@ import org.thingsboard.server.gen.edge.ConnectResponseCode;
import org.thingsboard.server.gen.edge.ConnectResponseMsg; import org.thingsboard.server.gen.edge.ConnectResponseMsg;
import org.thingsboard.server.gen.edge.DashboardUpdateMsg; import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.DownlinkMsg;
import org.thingsboard.server.gen.edge.EdgeConfiguration; import org.thingsboard.server.gen.edge.EdgeConfiguration;
import org.thingsboard.server.gen.edge.EntityDataProto;
import org.thingsboard.server.gen.edge.EntityViewUpdateMsg; import org.thingsboard.server.gen.edge.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.NodeConnectionInfoProto; import org.thingsboard.server.gen.edge.NodeConnectionInfoProto;
import org.thingsboard.server.gen.edge.RequestMsg; import org.thingsboard.server.gen.edge.RequestMsg;
@ -72,12 +82,14 @@ import org.thingsboard.server.gen.edge.UplinkMsg;
import org.thingsboard.server.gen.edge.UplinkResponseMsg; import org.thingsboard.server.gen.edge.UplinkResponseMsg;
import org.thingsboard.server.service.edge.EdgeContextComponent; import org.thingsboard.server.service.edge.EdgeContextComponent;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -85,6 +97,8 @@ import java.util.function.Consumer;
@Data @Data
public final class EdgeGrpcSession implements Cloneable { public final class EdgeGrpcSession implements Cloneable {
private static final ReentrantLock entityCreationLock = new ReentrantLock();
private final UUID sessionId; private final UUID sessionId;
private final BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener; private final BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener;
private final Consumer<EdgeId> sessionCloseListener; private final Consumer<EdgeId> sessionCloseListener;
@ -96,24 +110,14 @@ public final class EdgeGrpcSession implements Cloneable {
private StreamObserver<ResponseMsg> outputStream; private StreamObserver<ResponseMsg> outputStream;
private boolean connected; private boolean connected;
private EdgeService edgeService; EdgeGrpcSession(EdgeContextComponent ctx, StreamObserver<ResponseMsg> outputStream, BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener,
private AssetService assetService; Consumer<EdgeId> sessionCloseListener, ObjectMapper objectMapper) {
private DeviceService deviceService;
private AttributesService attributesService;
EdgeGrpcSession(EdgeContextComponent ctx, StreamObserver<ResponseMsg> outputStream,
BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener, Consumer<EdgeId> sessionCloseListener,
EdgeService edgeService, AssetService assetService, DeviceService deviceService, AttributesService attributesService, ObjectMapper objectMapper) {
this.sessionId = UUID.randomUUID(); this.sessionId = UUID.randomUUID();
this.ctx = ctx; this.ctx = ctx;
this.outputStream = outputStream; this.outputStream = outputStream;
this.sessionOpenListener = sessionOpenListener; this.sessionOpenListener = sessionOpenListener;
this.sessionCloseListener = sessionCloseListener; this.sessionCloseListener = sessionCloseListener;
this.objectMapper = objectMapper; this.objectMapper = objectMapper;
this.edgeService = edgeService;
this.assetService = assetService;
this.deviceService = deviceService;
this.attributesService = attributesService;
initInputStream(); initInputStream();
} }
@ -136,6 +140,11 @@ public final class EdgeGrpcSession implements Cloneable {
.setUplinkResponseMsg(processUplinkMsg(requestMsg.getUplinkMsg())) .setUplinkResponseMsg(processUplinkMsg(requestMsg.getUplinkMsg()))
.build()); .build());
} }
if (requestMsg.getMsgType().equals(RequestMsgType.DEVICE_UPDATE_RPC_MESSAGE) && requestMsg.hasDeviceUpdateMsg()) {
outputStream.onNext(ResponseMsg.newBuilder()
.setUplinkResponseMsg(processUplinkMsg(requestMsg.getUplinkMsg()))
.build());
}
} }
} }
@ -159,37 +168,23 @@ public final class EdgeGrpcSession implements Cloneable {
TimePageData<Event> pageData; TimePageData<Event> pageData;
UUID ifOffset = null; UUID ifOffset = null;
do { do {
pageData = edgeService.findQueueEvents(edge.getTenantId(), edge.getId(), pageLink); pageData = ctx.getEdgeService().findQueueEvents(edge.getTenantId(), edge.getId(), pageLink);
if (!pageData.getData().isEmpty()) { if (!pageData.getData().isEmpty()) {
edge = ctx.getEdgeService().findEdgeById(edge.getTenantId(), edge.getId());
for (Event event : pageData.getData()) { for (Event event : pageData.getData()) {
EdgeQueueEntry entry; EdgeQueueEntry entry;
try { try {
entry = objectMapper.treeToValue(event.getBody(), EdgeQueueEntry.class); entry = objectMapper.treeToValue(event.getBody(), EdgeQueueEntry.class);
UpdateMsgType msgType = getResponseMsgType(entry.getType()); UpdateMsgType msgType = getResponseMsgType(entry.getType());
switch (entry.getEntityType()) { switch (msgType) {
case DEVICE: case ENTITY_DELETED_RPC_MESSAGE:
Device device = objectMapper.readValue(entry.getData(), Device.class); case ENTITY_UPDATED_RPC_MESSAGE:
onDeviceUpdated(msgType, device); case ENTITY_CREATED_RPC_MESSAGE:
processEntityCRUDMessage(entry, msgType);
break; break;
case ASSET: case RULE_CHAIN_CUSTOM_MESSAGE:
Asset asset = objectMapper.readValue(entry.getData(), Asset.class); processCustomDownlinkMessage(entry);
onAssetUpdated(msgType, asset);
break;
case ENTITY_VIEW:
EntityView entityView = objectMapper.readValue(entry.getData(), EntityView.class);
onEntityViewUpdated(msgType, entityView);
break;
case DASHBOARD:
Dashboard dashboard = objectMapper.readValue(entry.getData(), Dashboard.class);
onDashboardUpdated(msgType, dashboard);
break;
case RULE_CHAIN:
RuleChain ruleChain = objectMapper.readValue(entry.getData(), RuleChain.class);
onRuleChainUpdated(msgType, ruleChain);
break;
case RULE_CHAIN_METADATA:
RuleChainMetaData ruleChainMetaData = objectMapper.readValue(entry.getData(), RuleChainMetaData.class);
onRuleChainMetadataUpdated(msgType, ruleChainMetaData);
break; break;
} }
} catch (Exception e) { } catch (Exception e) {
@ -214,14 +209,71 @@ public final class EdgeGrpcSession implements Cloneable {
} }
} }
private void processCustomDownlinkMessage(EdgeQueueEntry entry) throws IOException {
log.trace("Executing processCustomDownlinkMessage, entry [{}], msgType [{}]", entry);
TbMsg tbMsg = objectMapper.readValue(entry.getData(), TbMsg.class);
String entityName = null;
switch (entry.getEntityType()) {
case DEVICE:
Device device = ctx.getDeviceService().findDeviceById(edge.getTenantId(), new DeviceId(tbMsg.getOriginator().getId()));
entityName = device.getName();
break;
case ASSET:
Asset asset = ctx.getAssetService().findAssetById(edge.getTenantId(), new AssetId(tbMsg.getOriginator().getId()));
entityName = asset.getName();
break;
case ENTITY_VIEW:
EntityView entityView = ctx.getEntityViewService().findEntityViewById(edge.getTenantId(), new EntityViewId(tbMsg.getOriginator().getId()));
entityName = entityView.getName();
break;
}
if (entityName != null) {
log.debug("Sending donwlink entity data msg, entityName [{}], tbMsg [{}]", entityName, tbMsg);
outputStream.onNext(ResponseMsg.newBuilder()
.setDownlinkMsg(constructDownlinkEntityDataMsg(entityName, tbMsg))
.build());
}
}
private void processEntityCRUDMessage(EdgeQueueEntry entry, UpdateMsgType msgType) throws java.io.IOException {
log.trace("Executing processEntityCRUDMessage, entry [{}], msgType [{}]", entry, msgType);
switch (entry.getEntityType()) {
case DEVICE:
Device device = objectMapper.readValue(entry.getData(), Device.class);
onDeviceUpdated(msgType, device);
break;
case ASSET:
Asset asset = objectMapper.readValue(entry.getData(), Asset.class);
onAssetUpdated(msgType, asset);
break;
case ENTITY_VIEW:
EntityView entityView = objectMapper.readValue(entry.getData(), EntityView.class);
onEntityViewUpdated(msgType, entityView);
break;
case DASHBOARD:
Dashboard dashboard = objectMapper.readValue(entry.getData(), Dashboard.class);
onDashboardUpdated(msgType, dashboard);
break;
case RULE_CHAIN:
RuleChain ruleChain = objectMapper.readValue(entry.getData(), RuleChain.class);
onRuleChainUpdated(msgType, ruleChain);
break;
case RULE_CHAIN_METADATA:
RuleChainMetaData ruleChainMetaData = objectMapper.readValue(entry.getData(), RuleChainMetaData.class);
onRuleChainMetadataUpdated(msgType, ruleChainMetaData);
break;
}
}
private void updateQueueStartTs(Long newStartTs) { private void updateQueueStartTs(Long newStartTs) {
List<AttributeKvEntry> attributes = Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry("queueStartTs", newStartTs), System.currentTimeMillis())); List<AttributeKvEntry> attributes = Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry("queueStartTs", newStartTs), System.currentTimeMillis()));
attributesService.save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes); ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes);
} }
private ListenableFuture<Long> getQueueStartTs() { private ListenableFuture<Long> getQueueStartTs() {
ListenableFuture<Optional<AttributeKvEntry>> future = ListenableFuture<Optional<AttributeKvEntry>> future =
attributesService.find(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, "queueStartTs"); ctx.getAttributesService().find(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, "queueStartTs");
return Futures.transform(future, attributeKvEntryOpt -> { return Futures.transform(future, attributeKvEntryOpt -> {
if (attributeKvEntryOpt != null && attributeKvEntryOpt.isPresent()) { if (attributeKvEntryOpt != null && attributeKvEntryOpt.isPresent()) {
AttributeKvEntry attributeKvEntry = attributeKvEntryOpt.get(); AttributeKvEntry attributeKvEntry = attributeKvEntryOpt.get();
@ -272,17 +324,24 @@ public final class EdgeGrpcSession implements Cloneable {
} }
private UpdateMsgType getResponseMsgType(String msgType) { private UpdateMsgType getResponseMsgType(String msgType) {
switch (msgType) { if (msgType.equals(SessionMsgType.POST_TELEMETRY_REQUEST.name()) ||
case DataConstants.ENTITY_UPDATED: msgType.equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ||
return UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE; msgType.equals(DataConstants.ATTRIBUTES_UPDATED) ||
case DataConstants.ENTITY_CREATED: msgType.equals(DataConstants.ATTRIBUTES_DELETED)) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE: return UpdateMsgType.RULE_CHAIN_CUSTOM_MESSAGE;
return UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE; } else {
case DataConstants.ENTITY_DELETED: switch (msgType) {
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: case DataConstants.ENTITY_UPDATED:
return UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE; return UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE;
default: case DataConstants.ENTITY_CREATED:
throw new RuntimeException("Unsupported mstType [" + msgType + "]"); case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
return UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE;
case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
return UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE;
default:
throw new RuntimeException("Unsupported msgType [" + msgType + "]");
}
} }
} }
@ -292,7 +351,7 @@ public final class EdgeGrpcSession implements Cloneable {
.setIdMSB(ruleChain.getId().getId().getMostSignificantBits()) .setIdMSB(ruleChain.getId().getId().getMostSignificantBits())
.setIdLSB(ruleChain.getId().getId().getLeastSignificantBits()) .setIdLSB(ruleChain.getId().getId().getLeastSignificantBits())
.setName(ruleChain.getName()) .setName(ruleChain.getName())
.setRoot(ruleChain.isRoot()) .setRoot(ruleChain.getId().equals(edge.getRootRuleChainId()))
.setDebugMode(ruleChain.isDebugMode()) .setDebugMode(ruleChain.isDebugMode())
.setConfiguration(JacksonUtil.toString(ruleChain.getConfiguration())); .setConfiguration(JacksonUtil.toString(ruleChain.getConfiguration()));
if (ruleChain.getFirstRuleNodeId() != null) { if (ruleChain.getFirstRuleNodeId() != null) {
@ -302,6 +361,17 @@ public final class EdgeGrpcSession implements Cloneable {
return builder.build(); return builder.build();
} }
private DownlinkMsg constructDownlinkEntityDataMsg(String entityName, TbMsg tbMsg) {
EntityDataProto entityData = EntityDataProto.newBuilder()
.setEntityName(entityName)
.setTbMsg(ByteString.copyFrom(TbMsg.toBytes(tbMsg))).build();
DownlinkMsg.Builder builder = DownlinkMsg.newBuilder()
.addAllEntityData(Collections.singletonList(entityData));
return builder.build();
}
private RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(UpdateMsgType msgType, RuleChainMetaData ruleChainMetaData) { private RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(UpdateMsgType msgType, RuleChainMetaData ruleChainMetaData) {
try { try {
RuleChainMetadataUpdateMsg.Builder builder = RuleChainMetadataUpdateMsg.newBuilder() RuleChainMetadataUpdateMsg.Builder builder = RuleChainMetadataUpdateMsg.newBuilder()
@ -409,12 +479,12 @@ public final class EdgeGrpcSession implements Cloneable {
String relatedType; String relatedType;
org.thingsboard.server.gen.edge.EntityType relatedEntityType; org.thingsboard.server.gen.edge.EntityType relatedEntityType;
if (entityView.getEntityId().getEntityType().equals(EntityType.DEVICE)) { if (entityView.getEntityId().getEntityType().equals(EntityType.DEVICE)) {
Device device = deviceService.findDeviceById(entityView.getTenantId(), new DeviceId(entityView.getEntityId().getId())); Device device = ctx.getDeviceService().findDeviceById(entityView.getTenantId(), new DeviceId(entityView.getEntityId().getId()));
relatedName = device.getName(); relatedName = device.getName();
relatedType = device.getType(); relatedType = device.getType();
relatedEntityType = org.thingsboard.server.gen.edge.EntityType.DEVICE; relatedEntityType = org.thingsboard.server.gen.edge.EntityType.DEVICE;
} else { } else {
Asset asset = assetService.findAssetById(entityView.getTenantId(), new AssetId(entityView.getEntityId().getId())); Asset asset = ctx.getAssetService().findAssetById(entityView.getTenantId(), new AssetId(entityView.getEntityId().getId()));
relatedName = asset.getName(); relatedName = asset.getName();
relatedType = asset.getType(); relatedType = asset.getType();
relatedEntityType = org.thingsboard.server.gen.edge.EntityType.ASSET; relatedEntityType = org.thingsboard.server.gen.edge.EntityType.ASSET;
@ -430,7 +500,103 @@ public final class EdgeGrpcSession implements Cloneable {
} }
private UplinkResponseMsg processUplinkMsg(UplinkMsg uplinkMsg) { private UplinkResponseMsg processUplinkMsg(UplinkMsg uplinkMsg) {
return null; try {
if (uplinkMsg.getEntityDataList() != null && !uplinkMsg.getEntityDataList().isEmpty()) {
for (EntityDataProto entityData : uplinkMsg.getEntityDataList()) {
TbMsg tbMsg = null;
TbMsg tmp = TbMsg.fromBytes(entityData.getTbMsg().toByteArray());
switch (tmp.getOriginator().getEntityType()) {
case DEVICE:
String deviceName = entityData.getEntityName();
String deviceType = entityData.getEntityType();
Device device = getOrCreateDevice(deviceName, deviceType);
if (device != null) {
tbMsg = new TbMsg(UUIDs.timeBased(), tmp.getType(), device.getId(), tmp.getMetaData().copy(),
tmp.getDataType(), tmp.getData(), null, null, 0L);
}
break;
case ASSET:
String assetName = entityData.getEntityName();
Asset asset = ctx.getAssetService().findAssetByTenantIdAndName(edge.getTenantId(), assetName);
if (asset != null) {
tbMsg = new TbMsg(UUIDs.timeBased(), tmp.getType(), asset.getId(), tmp.getMetaData().copy(),
tmp.getDataType(), tmp.getData(), null, null, 0L);
}
break;
case ENTITY_VIEW:
String entityViewName = entityData.getEntityName();
EntityView entityView = ctx.getEntityViewService().findEntityViewByTenantIdAndName(edge.getTenantId(), entityViewName);
if (entityView != null) {
tbMsg = new TbMsg(UUIDs.timeBased(), tmp.getType(), entityView.getId(), tmp.getMetaData().copy(),
tmp.getDataType(), tmp.getData(), null, null, 0L);
}
break;
}
if (tbMsg != null) {
ctx.getActorService().onMsg(new SendToClusterMsg(tbMsg.getOriginator(), new ServiceToRuleEngineMsg(edge.getTenantId(), tbMsg)));
}
}
}
} catch (Exception e) {
return UplinkResponseMsg.newBuilder().setSuccess(false).setErrorMsg(e.getMessage()).build();
}
return UplinkResponseMsg.newBuilder().setSuccess(true).build();
}
private Device getOrCreateDevice(String deviceName, String deviceType) {
Device device = ctx.getDeviceService().findDeviceByTenantIdAndName(edge.getTenantId(), deviceName);
if (device == null) {
entityCreationLock.lock();
try {
return processGetOrCreateDevice(deviceName, deviceType);
} finally {
entityCreationLock.unlock();
}
}
return device;
}
private Device processGetOrCreateDevice(String deviceName, String deviceType) {
Device device = ctx.getDeviceService().findDeviceByTenantIdAndName(edge.getTenantId(), deviceName);
if (device == null) {
device = new Device();
device.setName(deviceName);
device.setType(deviceType);
device.setTenantId(edge.getTenantId());
device.setCustomerId(edge.getCustomerId());
device = ctx.getDeviceService().saveDevice(device);
createRelationFromEdge(device.getId());
ctx.getActorService().onDeviceAdded(device);
pushDeviceCreatedEventToRuleEngine(device);
}
return device;
}
private void pushDeviceCreatedEventToRuleEngine(Device device) {
try {
ObjectNode entityNode = objectMapper.valueToTree(device);
TbMsg msg = new TbMsg(UUIDs.timeBased(), DataConstants.ENTITY_CREATED, device.getId(), deviceActionTbMsgMetaData(device), objectMapper.writeValueAsString(entityNode), null, null, 0L);
ctx.getActorService().onMsg(new SendToClusterMsg(device.getId(), new ServiceToRuleEngineMsg(edge.getTenantId(), msg)));
} catch (JsonProcessingException | IllegalArgumentException e) {
log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), DataConstants.ENTITY_CREATED, e);
}
}
private TbMsgMetaData deviceActionTbMsgMetaData(Device device) {
TbMsgMetaData metaData = getTbMsgMetaData();
CustomerId customerId = device.getCustomerId();
if (customerId != null && !customerId.isNullUid()) {
metaData.putValue("customerId", customerId.toString());
}
return metaData;
}
private TbMsgMetaData getTbMsgMetaData() {
TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue("edgeId", edge.getId().toString());
metaData.putValue("edgeName", edge.getName());
return metaData;
} }
private ConnectResponseMsg processConnect(ConnectRequestMsg request) { private ConnectResponseMsg processConnect(ConnectRequestMsg request) {
@ -464,6 +630,15 @@ public final class EdgeGrpcSession implements Cloneable {
.setConfiguration(EdgeConfiguration.getDefaultInstance()).build(); .setConfiguration(EdgeConfiguration.getDefaultInstance()).build();
} }
private void createRelationFromEdge(EntityId entityId) {
EntityRelation relation = new EntityRelation();
relation.setFrom(edge.getId());
relation.setTo(entityId);
relation.setTypeGroup(RelationTypeGroup.COMMON);
relation.setType(EntityRelation.EDGE_TYPE);
ctx.getRelationService().saveRelation(edge.getTenantId(), relation);
}
private EdgeConfiguration constructEdgeConfigProto(Edge edge) throws JsonProcessingException { private EdgeConfiguration constructEdgeConfigProto(Edge edge) throws JsonProcessingException {
return EdgeConfiguration.newBuilder() return EdgeConfiguration.newBuilder()
.setTenantIdMSB(edge.getTenantId().getId().getMostSignificantBits()) .setTenantIdMSB(edge.getTenantId().getId().getMostSignificantBits())

7
common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java

@ -15,6 +15,8 @@
*/ */
package org.thingsboard.server.dao.edge; package org.thingsboard.server.dao.edge;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.Event; import org.thingsboard.server.common.data.Event;
@ -31,6 +33,7 @@ import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -72,11 +75,11 @@ public interface EdgeService {
ListenableFuture<List<EntitySubtype>> findEdgeTypesByTenantId(TenantId tenantId); ListenableFuture<List<EntitySubtype>> findEdgeTypesByTenantId(TenantId tenantId);
void pushEventToEdge(TenantId tenantId, TbMsg tbMsg); void pushEventToEdge(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback);
TimePageData<Event> findQueueEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); TimePageData<Event> findQueueEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
Edge setRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId); Edge setRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException;
} }

1
common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java

@ -32,6 +32,7 @@ public class EntityRelation implements Serializable {
private static final long serialVersionUID = 2807343040519543363L; private static final long serialVersionUID = 2807343040519543363L;
public static final String EDGE_TYPE = "ManagedByEdge";
public static final String CONTAINS_TYPE = "Contains"; public static final String CONTAINS_TYPE = "Contains";
public static final String MANAGES_TYPE = "Manages"; public static final String MANAGES_TYPE = "Manages";

15
common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainType.java

@ -1,3 +1,18 @@
/**
* Copyright © 2016-2019 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.rule; package org.thingsboard.server.common.data.rule;
public enum RuleChainType { public enum RuleChainType {

44
common/edge-api/src/main/proto/edge.proto

@ -53,6 +53,7 @@ message ResponseMsg {
enum RequestMsgType { enum RequestMsgType {
CONNECT_RPC_MESSAGE = 0; CONNECT_RPC_MESSAGE = 0;
UPLINK_RPC_MESSAGE = 1; UPLINK_RPC_MESSAGE = 1;
DEVICE_UPDATE_RPC_MESSAGE = 2;
} }
message ConnectRequestMsg { message ConnectRequestMsg {
@ -84,35 +85,12 @@ enum UpdateMsgType {
ENTITY_CREATED_RPC_MESSAGE = 0; ENTITY_CREATED_RPC_MESSAGE = 0;
ENTITY_UPDATED_RPC_MESSAGE = 1; ENTITY_UPDATED_RPC_MESSAGE = 1;
ENTITY_DELETED_RPC_MESSAGE = 2; ENTITY_DELETED_RPC_MESSAGE = 2;
RULE_CHAIN_CUSTOM_MESSAGE = 3;
} }
message DeviceData { message EntityDataProto {
string deviceName = 1; string entityName = 1;
string deviceType = 2; string entityType = 2;
bytes tbMsg = 3;
}
message AssetData {
string assetName = 1;
string assetType = 2;
bytes tbMsg = 3;
}
message EntityViewData {
string entityViewName = 1;
string entityViewType = 2;
bytes tbMsg = 3;
}
message RuleChainData {
string ruleChainName = 1;
string ruleChainType = 2;
bytes tbMsg = 3;
}
message DashboardData {
string dashboardName = 1;
string dashboardType = 2;
bytes tbMsg = 3; bytes tbMsg = 3;
} }
@ -199,11 +177,7 @@ enum EntityType {
message UplinkMsg { message UplinkMsg {
int32 uplinkMsgId = 1; int32 uplinkMsgId = 1;
repeated DeviceData deviceData = 2; repeated EntityDataProto entityData = 2;
repeated AssetData assetData = 3;
repeated EntityViewData entityViewData = 4;
repeated RuleChainData ruleChainData = 5;
repeated DashboardData dashboardData = 6;
} }
message UplinkResponseMsg { message UplinkResponseMsg {
@ -213,10 +187,6 @@ message UplinkResponseMsg {
message DownlinkMsg { message DownlinkMsg {
int32 downlinkMsgId = 1; int32 downlinkMsgId = 1;
repeated DeviceData deviceData = 2; repeated EntityDataProto entityData = 2;
repeated AssetData assetData = 3;
repeated EntityViewData entityViewData = 4;
repeated RuleChainData ruleChainData = 5;
repeated DashboardData dashboardData = 6;
} }

4
common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java

@ -105,6 +105,10 @@ public final class TbMsg implements Serializable {
return ByteBuffer.wrap(bytes); return ByteBuffer.wrap(bytes);
} }
public static TbMsg fromBytes(byte[] data) {
return fromBytes(ByteBuffer.wrap(data));
}
public static TbMsg fromBytes(ByteBuffer buffer) { public static TbMsg fromBytes(ByteBuffer buffer) {
try { try {
MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(buffer.array()); MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(buffer.array());

194
dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java

@ -17,6 +17,7 @@ package org.thingsboard.server.dao.edge;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -41,9 +42,12 @@ import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeQueueEntityType; import org.thingsboard.server.common.data.edge.EdgeQueueEntityType;
import org.thingsboard.server.common.data.edge.EdgeQueueEntry; import org.thingsboard.server.common.data.edge.EdgeQueueEntry;
import org.thingsboard.server.common.data.edge.EdgeSearchQuery; import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageData;
@ -55,9 +59,13 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.customer.CustomerDao;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
@ -67,6 +75,8 @@ import org.thingsboard.server.dao.service.Validator;
import org.thingsboard.server.dao.tenant.TenantDao; import org.thingsboard.server.dao.tenant.TenantDao;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -74,6 +84,8 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.CacheConstants.EDGE_CACHE; import static org.thingsboard.server.common.data.CacheConstants.EDGE_CACHE;
@ -116,6 +128,30 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
@Autowired @Autowired
private RuleChainService ruleChainService; private RuleChainService ruleChainService;
@Autowired
private DeviceService deviceService;
@Autowired
private AssetService assetService;
@Autowired
private EntityViewService entityViewService;
private ExecutorService tsCallBackExecutor;
@PostConstruct
public void initExecutor() {
tsCallBackExecutor = Executors.newSingleThreadExecutor();
}
@PreDestroy
public void shutdownExecutor() {
if (tsCallBackExecutor != null) {
tsCallBackExecutor.shutdownNow();
}
}
@Override @Override
public Edge findEdgeById(TenantId tenantId, EdgeId edgeId) { public Edge findEdgeById(TenantId tenantId, EdgeId edgeId) {
log.trace("Executing findEdgeById [{}]", edgeId); log.trace("Executing findEdgeById [{}]", edgeId);
@ -304,46 +340,80 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
} }
@Override @Override
public void pushEventToEdge(TenantId tenantId, TbMsg tbMsg) { public void pushEventToEdge(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) {
try { if (tbMsg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name()) ||
switch (tbMsg.getOriginator().getEntityType()) { tbMsg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ||
case ASSET: tbMsg.getType().equals(DataConstants.ATTRIBUTES_UPDATED) ||
processAsset(tenantId, tbMsg); tbMsg.getType().equals(DataConstants.ATTRIBUTES_DELETED)) {
break; processCustomTbMsg(tenantId, tbMsg, callback);
case DEVICE: } else {
processDevice(tenantId, tbMsg); try {
break; switch (tbMsg.getOriginator().getEntityType()) {
case DASHBOARD: case ASSET:
processDashboard(tenantId, tbMsg); processAsset(tenantId, tbMsg, callback);
break; break;
case RULE_CHAIN: case DEVICE:
processRuleChain(tenantId, tbMsg); processDevice(tenantId, tbMsg, callback);
break; break;
case ENTITY_VIEW: case DASHBOARD:
processEntityView(tenantId, tbMsg); processDashboard(tenantId, tbMsg, callback);
break; break;
default: case RULE_CHAIN:
log.debug("Entity type [{}] is not designed to be pushed to edge", tbMsg.getOriginator().getEntityType()); processRuleChain(tenantId, tbMsg, callback);
break;
case ENTITY_VIEW:
processEntityView(tenantId, tbMsg, callback);
break;
default:
log.debug("Entity type [{}] is not designed to be pushed to edge", tbMsg.getOriginator().getEntityType());
}
} catch (IOException e) {
log.error("Can't push to edge updates, entity type [{}], data [{}]", tbMsg.getOriginator().getEntityType(), tbMsg.getData(), e);
} }
} catch (IOException e) {
log.error("Can't push to edge updates, entity type [{}], data [{}]", tbMsg.getOriginator().getEntityType(), tbMsg.getData(), e);
} }
}
private void processCustomTbMsg(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) {
EdgeId edgeId = null;
EdgeQueueEntityType edgeQueueEntityType = null;
switch (tbMsg.getOriginator().getEntityType()) {
case DEVICE:
edgeQueueEntityType = EdgeQueueEntityType.DEVICE;
Device device = deviceService.findDeviceById(tenantId, new DeviceId(tbMsg.getOriginator().getId()));
edgeId = device.getEdgeId();
break;
case ASSET:
edgeQueueEntityType = EdgeQueueEntityType.ASSET;
Asset asset = assetService.findAssetById(tenantId, new AssetId(tbMsg.getOriginator().getId()));
edgeId = asset.getEdgeId();
break;
case ENTITY_VIEW:
edgeQueueEntityType = EdgeQueueEntityType.ENTITY_VIEW;
EntityView entityView = entityViewService.findEntityViewById(tenantId, new EntityViewId(tbMsg.getOriginator().getId()));
edgeId = entityView.getEdgeId();
break;
}
if (edgeId != null) {
try {
saveEventToEdgeQueue(tenantId, edgeId, edgeQueueEntityType, tbMsg.getType(), mapper.writeValueAsString(tbMsg), callback);
} catch (IOException e) {
log.error("Error while saving custom tbMsg into Edge Queue", e);
}
}
} }
private void processDevice(TenantId tenantId, TbMsg tbMsg) throws IOException { private void processDevice(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException {
switch (tbMsg.getType()) { switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE: case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.DEVICE); processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.DEVICE, callback);
break; break;
case DataConstants.ENTITY_DELETED: case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_CREATED: case DataConstants.ENTITY_CREATED:
case DataConstants.ENTITY_UPDATED: case DataConstants.ENTITY_UPDATED:
Device device = mapper.readValue(tbMsg.getData(), Device.class); Device device = mapper.readValue(tbMsg.getData(), Device.class);
if (device.getEdgeId() != null) { if (device.getEdgeId() != null) {
pushEventsToEdge(tenantId, device.getEdgeId(), EdgeQueueEntityType.DEVICE, tbMsg); pushEventToEdge(tenantId, device.getEdgeId(), EdgeQueueEntityType.DEVICE, tbMsg, callback);
} }
break; break;
default: default:
@ -351,18 +421,18 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
} }
} }
private void processAsset(TenantId tenantId, TbMsg tbMsg) throws IOException { private void processAsset(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException {
switch (tbMsg.getType()) { switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE: case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.ASSET); processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.ASSET, callback);
break; break;
case DataConstants.ENTITY_DELETED: case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_CREATED: case DataConstants.ENTITY_CREATED:
case DataConstants.ENTITY_UPDATED: case DataConstants.ENTITY_UPDATED:
Asset asset = mapper.readValue(tbMsg.getData(), Asset.class); Asset asset = mapper.readValue(tbMsg.getData(), Asset.class);
if (asset.getEdgeId() != null) { if (asset.getEdgeId() != null) {
pushEventsToEdge(tenantId, asset.getEdgeId(), EdgeQueueEntityType.ASSET, tbMsg); pushEventToEdge(tenantId, asset.getEdgeId(), EdgeQueueEntityType.ASSET, tbMsg, callback);
} }
break; break;
default: default:
@ -370,18 +440,18 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
} }
} }
private void processEntityView(TenantId tenantId, TbMsg tbMsg) throws IOException { private void processEntityView(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException {
switch (tbMsg.getType()) { switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE: case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.ENTITY_VIEW); processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.ENTITY_VIEW, callback);
break; break;
case DataConstants.ENTITY_DELETED: case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_CREATED: case DataConstants.ENTITY_CREATED:
case DataConstants.ENTITY_UPDATED: case DataConstants.ENTITY_UPDATED:
EntityView entityView = mapper.readValue(tbMsg.getData(), EntityView.class); EntityView entityView = mapper.readValue(tbMsg.getData(), EntityView.class);
if (entityView.getEdgeId() != null) { if (entityView.getEdgeId() != null) {
pushEventsToEdge(tenantId, entityView.getEdgeId(), EdgeQueueEntityType.ENTITY_VIEW, tbMsg); pushEventToEdge(tenantId, entityView.getEdgeId(), EdgeQueueEntityType.ENTITY_VIEW, tbMsg, callback);
} }
break; break;
default: default:
@ -389,15 +459,15 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
} }
} }
private void processDashboard(TenantId tenantId, TbMsg tbMsg) throws IOException { private void processDashboard(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException {
processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.DASHBOARD); processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.DASHBOARD, callback);
} }
private void processRuleChain(TenantId tenantId, TbMsg tbMsg) throws IOException { private void processRuleChain(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException {
switch (tbMsg.getType()) { switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE: case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.RULE_CHAIN); processAssignedEntity(tenantId, tbMsg, EdgeQueueEntityType.RULE_CHAIN, callback);
break; break;
case DataConstants.ENTITY_DELETED: case DataConstants.ENTITY_DELETED:
case DataConstants.ENTITY_CREATED: case DataConstants.ENTITY_CREATED:
@ -405,7 +475,7 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
RuleChain ruleChain = mapper.readValue(tbMsg.getData(), RuleChain.class); RuleChain ruleChain = mapper.readValue(tbMsg.getData(), RuleChain.class);
if (ruleChain.getAssignedEdges() != null && !ruleChain.getAssignedEdges().isEmpty()) { if (ruleChain.getAssignedEdges() != null && !ruleChain.getAssignedEdges().isEmpty()) {
for (ShortEdgeInfo assignedEdge : ruleChain.getAssignedEdges()) { for (ShortEdgeInfo assignedEdge : ruleChain.getAssignedEdges()) {
pushEventsToEdge(tenantId, assignedEdge.getEdgeId(), EdgeQueueEntityType.RULE_CHAIN, tbMsg); pushEventToEdge(tenantId, assignedEdge.getEdgeId(), EdgeQueueEntityType.RULE_CHAIN, tbMsg, callback);
} }
} }
break; break;
@ -414,31 +484,31 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
} }
} }
private void processAssignedEntity(TenantId tenantId, TbMsg tbMsg, EdgeQueueEntityType entityType) throws IOException { private void processAssignedEntity(TenantId tenantId, TbMsg tbMsg, EdgeQueueEntityType entityType, FutureCallback<Void> callback) throws IOException {
EdgeId edgeId; EdgeId edgeId;
switch (tbMsg.getType()) { switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE: case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
edgeId = new EdgeId(UUID.fromString(tbMsg.getMetaData().getValue("assignedEdgeId"))); edgeId = new EdgeId(UUID.fromString(tbMsg.getMetaData().getValue("assignedEdgeId")));
pushEventsToEdge(tenantId, edgeId, entityType, tbMsg); pushEventToEdge(tenantId, edgeId, entityType, tbMsg, callback);
break; break;
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
edgeId = new EdgeId(UUID.fromString(tbMsg.getMetaData().getValue("unassignedEdgeId"))); edgeId = new EdgeId(UUID.fromString(tbMsg.getMetaData().getValue("unassignedEdgeId")));
pushEventsToEdge(tenantId, edgeId, entityType, tbMsg); pushEventToEdge(tenantId, edgeId, entityType, tbMsg, callback);
break; break;
} }
} }
private void pushEventsToEdge(TenantId tenantId, EdgeId edgeId, EdgeQueueEntityType entityType, TbMsg tbMsg) throws IOException { private void pushEventToEdge(TenantId tenantId, EdgeId edgeId, EdgeQueueEntityType entityType, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException {
log.debug("Pushing event(s) to edge queue. tenantId [{}], edgeId [{}], entityType [{}], tbMsg [{}]", tenantId, edgeId, entityType, tbMsg); log.debug("Pushing event(s) to edge queue. tenantId [{}], edgeId [{}], entityType [{}], tbMsg [{}]", tenantId, edgeId, entityType, tbMsg);
pushEventsToEdge(tenantId, edgeId, entityType, tbMsg.getType(), tbMsg.getData()); saveEventToEdgeQueue(tenantId, edgeId, entityType, tbMsg.getType(), tbMsg.getData(), callback);
if (entityType.equals(EdgeQueueEntityType.RULE_CHAIN)) { if (entityType.equals(EdgeQueueEntityType.RULE_CHAIN)) {
pushRuleChainMetadataToEdge(tenantId, edgeId, tbMsg); pushRuleChainMetadataToEdge(tenantId, edgeId, tbMsg, callback);
} }
} }
private void pushEventsToEdge(TenantId tenantId, EdgeId edgeId, EdgeQueueEntityType entityType, String type, String data) throws IOException { private void saveEventToEdgeQueue(TenantId tenantId, EdgeId edgeId, EdgeQueueEntityType entityType, String type, String data, FutureCallback<Void> callback) throws IOException {
log.debug("Pushing single event to edge queue. tenantId [{}], edgeId [{}], entityType [{}], type[{}], data [{}]", tenantId, edgeId, entityType, type, data); log.debug("Pushing single event to edge queue. tenantId [{}], edgeId [{}], entityType [{}], type[{}], data [{}]", tenantId, edgeId, entityType, type, data);
EdgeQueueEntry queueEntry = new EdgeQueueEntry(); EdgeQueueEntry queueEntry = new EdgeQueueEntry();
@ -451,17 +521,33 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
event.setTenantId(tenantId); event.setTenantId(tenantId);
event.setType(DataConstants.EDGE_QUEUE_EVENT_TYPE); event.setType(DataConstants.EDGE_QUEUE_EVENT_TYPE);
event.setBody(mapper.valueToTree(queueEntry)); event.setBody(mapper.valueToTree(queueEntry));
eventService.saveAsync(event); ListenableFuture<Event> saveFuture = eventService.saveAsync(event);
addMainCallback(saveFuture, callback);
}
private void addMainCallback(ListenableFuture<Event> saveFuture, final FutureCallback<Void> callback) {
Futures.addCallback(saveFuture, new FutureCallback<Event>() {
@Override
public void onSuccess(@Nullable Event result) {
callback.onSuccess(null);
}
@Override
public void onFailure(Throwable t) {
callback.onFailure(t);
}
}, tsCallBackExecutor);
} }
private void pushRuleChainMetadataToEdge(TenantId tenantId, EdgeId edgeId, TbMsg tbMsg) throws IOException { private void pushRuleChainMetadataToEdge(TenantId tenantId, EdgeId edgeId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException {
RuleChain ruleChain = mapper.readValue(tbMsg.getData(), RuleChain.class); RuleChain ruleChain = mapper.readValue(tbMsg.getData(), RuleChain.class);
switch (tbMsg.getType()) { switch (tbMsg.getType()) {
case DataConstants.ENTITY_ASSIGNED_TO_EDGE: case DataConstants.ENTITY_ASSIGNED_TO_EDGE:
case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE:
case DataConstants.ENTITY_UPDATED: case DataConstants.ENTITY_UPDATED:
RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(tenantId, ruleChain.getId()); RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(tenantId, ruleChain.getId());
pushEventsToEdge(tenantId, edgeId, EdgeQueueEntityType.RULE_CHAIN_METADATA, tbMsg.getType(), mapper.writeValueAsString(ruleChainMetaData)); saveEventToEdgeQueue(tenantId, edgeId, EdgeQueueEntityType.RULE_CHAIN_METADATA, tbMsg.getType(), mapper.writeValueAsString(ruleChainMetaData), callback);
break; break;
default: default:
log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg);
@ -474,10 +560,22 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
} }
@Override @Override
public Edge setRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) { public Edge setRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException {
edge.setRootRuleChainId(ruleChainId); edge.setRootRuleChainId(ruleChainId);
Edge saveEdge = saveEdge(edge); Edge saveEdge = saveEdge(edge);
ruleChainService.updateEdgeRuleChains(tenantId, saveEdge.getId()); ruleChainService.updateEdgeRuleChains(tenantId, saveEdge.getId());
RuleChain ruleChain = ruleChainService.findRuleChainById(tenantId, ruleChainId);
saveEventToEdgeQueue(tenantId, edge.getId(), EdgeQueueEntityType.RULE_CHAIN, DataConstants.ENTITY_UPDATED, mapper.writeValueAsString(ruleChain), new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void aVoid) {
log.debug("Event saved successfully!");
}
@Override
public void onFailure(Throwable t) {
log.debug("Failure during event save", t);
}
});
return saveEdge; return saveEdge;
} }

2
dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEntity.java

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,

2
dao/src/main/java/org/thingsboard/server/dao/model/type/RuleChainTypeCodec.java

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,

3
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java

@ -33,6 +33,7 @@ import org.thingsboard.server.dao.cassandra.CassandraCluster;
import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.nosql.CassandraStatementTask; import org.thingsboard.server.dao.nosql.CassandraStatementTask;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
@ -110,6 +111,8 @@ public interface TbContext {
EntityViewService getEntityViewService(); EntityViewService getEntityViewService();
EdgeService getEdgeService();
ListeningExecutor getJsExecutor(); ListeningExecutor getJsExecutor();
ListeningExecutor getMailExecutor(); ListeningExecutor getMailExecutor();

41
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/PushToEdgeNodeCallback.java

@ -0,0 +1,41 @@
/**
* Copyright © 2016-2019 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.rule.engine.edge;
import com.google.common.util.concurrent.FutureCallback;
import lombok.Data;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.server.common.msg.TbMsg;
import javax.annotation.Nullable;
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
@Data
class PushToEdgeNodeCallback implements FutureCallback<Void> {
private final TbContext ctx;
private final TbMsg msg;
@Override
public void onSuccess(@Nullable Void result) {
ctx.tellNext(msg, SUCCESS);
}
@Override
public void onFailure(Throwable t) {
ctx.tellFailure(msg, t);
}
}

58
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToCloudNode.java

@ -0,0 +1,58 @@
/**
* Copyright © 2016-2019 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.rule.engine.edge;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "push to cloud",
configClazz = EmptyNodeConfiguration.class,
nodeDescription = "Pushes messages to cloud",
nodeDetails = "Pushes messages to cloud. This node is used only on Edge instances to push messages from Edge to Cloud.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbNodeEmptyConfig",
icon = "cloud_upload"
)
public class TbMsgPushToCloudNode implements TbNode {
private EmptyNodeConfiguration config;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class);
}
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
// Implementation of this node is done on the Edge
}
@Override
public void destroy() {
}
}

58
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java

@ -0,0 +1,58 @@
/**
* Copyright © 2016-2019 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.rule.engine.edge;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
@Slf4j
@RuleNode(
type = ComponentType.ACTION,
name = "push to edge",
configClazz = EmptyNodeConfiguration.class,
nodeDescription = "Pushes messages to edge",
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).",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbNodeEmptyConfig",
icon = "cloud_download"
)
public class TbMsgPushToEdgeNode implements TbNode {
private EmptyNodeConfiguration config;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class);
}
@Override
public void onMsg(TbContext ctx, TbMsg msg) {
ctx.getEdgeService().pushEventToEdge(ctx.getTenantId(), msg, new PushToEdgeNodeCallback(ctx, msg));
}
@Override
public void destroy() {
}
}
Loading…
Cancel
Save