Browse Source

Merge remote-tracking branch 'origin/feature/edge' into feature/3.0-edge

pull/3811/head
Volodymyr Babak 6 years ago
parent
commit
95786f858c
  1. 1
      .gitignore
  2. 1
      application/src/main/data/json/demo/rule_chains/root_rule_chain.json
  3. 68
      application/src/main/data/upgrade/2.6.0/schema_update.cql
  4. 18
      application/src/main/data/upgrade/2.6.0/schema_update.sql
  5. 32
      application/src/main/data/upgrade/2.6.0/schema_update_ttl.sql
  6. 21
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  7. 17
      application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java
  8. 2
      application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
  9. 3
      application/src/main/java/org/thingsboard/server/controller/AlarmController.java
  10. 22
      application/src/main/java/org/thingsboard/server/controller/AssetController.java
  11. 6
      application/src/main/java/org/thingsboard/server/controller/AuthController.java
  12. 88
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  13. 5
      application/src/main/java/org/thingsboard/server/controller/CustomerController.java
  14. 24
      application/src/main/java/org/thingsboard/server/controller/DashboardController.java
  15. 20
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  16. 63
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  17. 71
      application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java
  18. 4
      application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
  19. 21
      application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
  20. 19
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  21. 5
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  22. 12
      application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
  23. 11
      application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
  24. 13
      application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java
  25. 12
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  26. 353
      application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java
  27. 88
      application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
  28. 117
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java
  29. 1280
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  30. 26
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeRpcService.java
  31. 38
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AdminSettingsMsgConstructor.java
  32. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java
  33. 13
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AssetMsgConstructor.java
  34. 72
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/CustomerMsgConstructor.java
  35. 16
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java
  36. 97
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceMsgConstructor.java
  37. 69
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceUpdateMsgConstructor.java
  38. 40
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java
  39. 17
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityViewMsgConstructor.java
  40. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RelationMsgConstructor.java
  41. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java
  42. 37
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/UserMsgConstructor.java
  43. 61
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java
  44. 54
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetsBundleMsgConstructor.java
  45. 549
      application/src/main/java/org/thingsboard/server/service/edge/rpc/init/DefaultSyncEdgeService.java
  46. 20
      application/src/main/java/org/thingsboard/server/service/edge/rpc/init/SyncEdgeService.java
  47. 98
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/AlarmProcessor.java
  48. 113
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseProcessor.java
  49. 252
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceProcessor.java
  50. 104
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationProcessor.java
  51. 244
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryProcessor.java
  52. 2
      application/src/main/java/org/thingsboard/server/service/install/AbstractSqlTsDatabaseUpgradeService.java
  53. 2
      application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseUpgradeService.java
  54. 1
      application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java
  55. 9
      application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java
  56. 20
      application/src/main/java/org/thingsboard/server/service/install/PsqlTsDatabaseUpgradeService.java
  57. 2
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  58. 10
      application/src/main/java/org/thingsboard/server/service/install/TimescaleTsDatabaseUpgradeService.java
  59. 5
      application/src/main/java/org/thingsboard/server/service/install/cql/CassandraDbHelper.java
  60. 33
      application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
  61. 11
      application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java
  62. 3
      application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbRuleEngineRpcService.java
  63. 9
      application/src/main/java/org/thingsboard/server/service/rpc/TbRuleEngineDeviceRpcService.java
  64. 2
      application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java
  65. 56
      application/src/main/java/org/thingsboard/server/service/ttl/edge/EdgeEventsCleanUpService.java
  66. 12
      application/src/main/resources/thingsboard.yml
  67. 16
      application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
  68. 27
      application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java
  69. 57
      application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java
  70. 37
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
  71. 73
      application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java
  72. 125
      application/src/test/java/org/thingsboard/server/controller/BaseEdgeEventControllerTest.java
  73. 36
      application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java
  74. 23
      application/src/test/java/org/thingsboard/server/controller/nosql/EdgeEventControllerNoSqlTest.java
  75. 23
      application/src/test/java/org/thingsboard/server/controller/sql/EdgeEventControllerSqlTest.java
  76. 1090
      application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java
  77. 47
      application/src/test/java/org/thingsboard/server/edge/EdgeNoSqlTestSuite.java
  78. 41
      application/src/test/java/org/thingsboard/server/edge/EdgeSqlTestSuite.java
  79. 268
      application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java
  80. 23
      application/src/test/java/org/thingsboard/server/edge/nosql/EdgeNoSqlTest.java
  81. 23
      application/src/test/java/org/thingsboard/server/edge/sql/EdgeSqlTest.java
  82. 3
      application/src/test/java/org/thingsboard/server/mqtt/MqttNoSqlTestSuite.java
  83. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java
  84. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java
  85. 6
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeEventService.java
  86. 7
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java
  87. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
  88. 5
      common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java
  89. 7
      common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java
  90. 76
      common/data/src/main/java/org/thingsboard/server/common/data/EdgeUtils.java
  91. 50
      common/data/src/main/java/org/thingsboard/server/common/data/ShortEdgeInfo.java
  92. 4
      common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java
  93. 12
      common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java
  94. 8
      common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEvent.java
  95. 16
      common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java
  96. 3
      common/data/src/main/java/org/thingsboard/server/common/data/exception/ThingsboardErrorCode.java
  97. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java
  98. 109
      common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java
  99. 11
      common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeRpcClient.java
  100. 220
      common/edge-api/src/main/proto/edge.proto

1
.gitignore

@ -33,3 +33,4 @@ pom.xml.versionsBackup
**/.env **/.env
.instance_id .instance_id
rebuild-docker.sh rebuild-docker.sh
.run/

1
application/src/main/data/json/demo/rule_chains/root_rule_chain.json

@ -2,6 +2,7 @@
"ruleChain": { "ruleChain": {
"additionalInfo": null, "additionalInfo": null,
"name": "Root Rule Chain", "name": "Root Rule Chain",
"type": "CORE",
"firstRuleNodeId": null, "firstRuleNodeId": null,
"root": true, "root": true,
"debugMode": false, "debugMode": false,

68
application/src/main/data/upgrade/2.6.0/schema_update.cql

@ -14,15 +14,54 @@
-- limitations under the License. -- limitations under the License.
-- --
DROP MATERIALIZED VIEW IF EXISTS thingsboard.rule_chain_by_tenant_and_search_text;
DROP TABLE IF EXISTS thingsboard.rule_chain;
CREATE TABLE IF NOT EXISTS thingsboard.rule_chain (
id uuid,
tenant_id uuid,
name text,
type text,
search_text text,
first_rule_node_id uuid,
root boolean,
debug_mode boolean,
configuration text,
additional_info text,
PRIMARY KEY (id, tenant_id, type)
);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.rule_chain_by_tenant_and_search_text AS
SELECT *
from thingsboard.rule_chain
WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL AND type IS NOT NULL
PRIMARY KEY ( tenant_id, search_text, id, type )
WITH CLUSTERING ORDER BY ( search_text ASC, id DESC );
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.rule_chain_by_tenant_by_type_and_search_text AS
SELECT *
from thingsboard.rule_chain
WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL AND type IS NOT NULL
PRIMARY KEY ( tenant_id, type, search_text, id )
WITH CLUSTERING ORDER BY ( type ASC, search_text ASC, id DESC );
CREATE TABLE IF NOT EXISTS thingsboard.edge ( CREATE TABLE IF NOT EXISTS thingsboard.edge (
id timeuuid, id timeuuid,
tenant_id timeuuid, tenant_id timeuuid,
customer_id timeuuid, customer_id timeuuid,
root_rule_chain_id timeuuid,
type text,
name text, name text,
label text,
search_text text, search_text text,
routing_key text,
secret text,
edge_license_key text,
cloud_endpoint text,
configuration text, configuration text,
additional_info text, additional_info text,
PRIMARY KEY (id, tenant_id) PRIMARY KEY (id, tenant_id, customer_id, type)
); );
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_and_name AS CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_and_name AS
@ -32,6 +71,13 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_and_name AS
PRIMARY KEY ( tenant_id, name, id, customer_id, type) PRIMARY KEY ( tenant_id, name, id, customer_id, type)
WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC); WITH CLUSTERING ORDER BY ( name ASC, id DESC, customer_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_routing_key AS
SELECT *
from thingsboard.edge
WHERE tenant_id IS NOT NULL AND customer_id IS NOT NULL AND type IS NOT NULL AND routing_key IS NOT NULL AND id IS NOT NULL
PRIMARY KEY ( routing_key, tenant_id, id, customer_id, type)
WITH CLUSTERING ORDER BY ( tenant_id DESC, id DESC, customer_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_and_search_text AS CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_tenant_and_search_text AS
SELECT * SELECT *
from thingsboard.edge from thingsboard.edge
@ -60,4 +106,22 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_by_customer_by_type_and_
PRIMARY KEY ( customer_id, tenant_id, type, search_text, id ) PRIMARY KEY ( customer_id, tenant_id, type, search_text, id )
WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC ); WITH CLUSTERING ORDER BY ( tenant_id DESC, type ASC, search_text ASC, id DESC );
-- VOBA ADD changes for the MATERIALIZED view for DEVICE ASSET ENTITY_VIEW RULE_CHAIN CREATE TABLE IF NOT EXISTS thingsboard.edge_event (
id timeuuid,
tenant_id timeuuid,
edge_id timeuuid,
edge_event_type text,
edge_event_action text,
edge_event_uid text,
entity_id timeuuid,
body text,
PRIMARY KEY ((tenant_id, edge_id), edge_event_type, edge_event_uid)
);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.edge_event_by_id AS
SELECT *
FROM thingsboard.edge_event
WHERE tenant_id IS NOT NULL AND edge_id IS NOT NULL AND edge_event_type IS NOT NULL
AND id IS NOT NULL AND edge_event_uid IS NOT NULL
PRIMARY KEY ((tenant_id, edge_id), id, edge_event_type, edge_event_uid)
WITH CLUSTERING ORDER BY (id ASC);

18
application/src/main/data/upgrade/2.6.0/schema_update.sql

@ -25,6 +25,22 @@ CREATE TABLE IF NOT EXISTS edge (
label varchar(255), label varchar(255),
routing_key varchar(255), routing_key varchar(255),
secret varchar(255), secret varchar(255),
edge_license_key varchar(30),
cloud_endpoint varchar(255),
search_text varchar(255), search_text varchar(255),
tenant_id varchar(31) tenant_id varchar(31),
CONSTRAINT edge_name_unq_key UNIQUE (tenant_id, name),
CONSTRAINT edge_routing_key_unq_key UNIQUE (routing_key)
);
CREATE TABLE IF NOT EXISTS edge_event (
id varchar(31) NOT NULL CONSTRAINT edge_event_pkey PRIMARY KEY,
edge_id varchar(31),
edge_event_type varchar(255),
edge_event_uid varchar(255),
entity_id varchar(31),
edge_event_action varchar(255),
body varchar(10000000),
tenant_id varchar(31),
ts bigint NOT NULL
); );

32
application/src/main/data/upgrade/2.6.0/schema_update_ttl.sql

@ -0,0 +1,32 @@
--
-- Copyright © 2016-2020 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.
--
CREATE OR REPLACE PROCEDURE cleanup_edge_events_by_ttl(IN ttl bigint, INOUT deleted bigint)
LANGUAGE plpgsql AS
$$
DECLARE
ttl_ts bigint;
ttl_deleted_count bigint DEFAULT 0;
BEGIN
IF ttl > 0 THEN
ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - ttl::bigint * 1000)::bigint;
EXECUTE format(
'WITH deleted AS (DELETE FROM edge_event WHERE ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', ttl_ts) into ttl_deleted_count;
END IF;
RAISE NOTICE 'Edge events removed by ttl: %', ttl_deleted_count;
deleted := ttl_deleted_count;
END
$$;

21
application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java

@ -32,7 +32,6 @@ import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache;
import org.thingsboard.server.actors.service.ActorService; import org.thingsboard.server.actors.service.ActorService;
import org.thingsboard.server.actors.tenant.DebugTbRateLimits; import org.thingsboard.server.actors.tenant.DebugTbRateLimits;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
@ -45,6 +44,7 @@ import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.common.msg.tools.TbRateLimits; import org.thingsboard.server.common.msg.tools.TbRateLimits;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;
import org.thingsboard.server.dao.asset.AssetService; 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.audit.AuditLogService; import org.thingsboard.server.dao.audit.AuditLogService;
@ -68,7 +68,7 @@ import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.executors.ExternalCallExecutorService; import org.thingsboard.server.service.executors.ExternalCallExecutorService;
import org.thingsboard.server.service.executors.SharedEventLoopGroupService; import org.thingsboard.server.service.executors.SharedEventLoopGroupService;
@ -196,10 +196,6 @@ public class ActorSystemContext {
@Getter @Getter
private EntityViewService entityViewService; private EntityViewService entityViewService;
@Autowired
@Getter
private EdgeService edgeService;
@Autowired @Autowired
@Getter @Getter
private TelemetrySubscriptionService tsSubService; private TelemetrySubscriptionService tsSubService;
@ -274,9 +270,16 @@ public class ActorSystemContext {
private TbCoreDeviceRpcService tbCoreDeviceRpcService; private TbCoreDeviceRpcService tbCoreDeviceRpcService;
@Lazy @Lazy
@Autowired @Autowired(required = false)
@Getter @Getter private EdgeService edgeService;
private EdgeEventService edgeEventService;
@Lazy
@Autowired(required = false)
@Getter private EdgeEventService edgeEventService;
@Lazy
@Autowired(required = false)
@Getter private EdgeRpcService edgeRpcService;
@Value("${actors.session.max_concurrent_sessions_per_device:1}") @Value("${actors.session.max_concurrent_sessions_per_device:1}")
@Getter @Getter

17
application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java

@ -32,10 +32,13 @@ import org.thingsboard.server.actors.service.DefaultActorService;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.edge.Edge;
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.EntityId; import org.thingsboard.server.common.data.id.EntityId;
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.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.MsgType; import org.thingsboard.server.common.msg.MsgType;
@ -48,6 +51,7 @@ import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
import org.thingsboard.server.common.msg.queue.RuleEngineException; import org.thingsboard.server.common.msg.queue.RuleEngineException;
import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
import java.util.List; import java.util.List;
@ -211,7 +215,18 @@ public class TenantActor extends RuleChainManagerActor {
} }
private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
if (isRuleEngineForCurrentTenant) { if (msg.getEntityId().getEntityType() == EntityType.EDGE) {
EdgeId edgeId = new EdgeId(msg.getEntityId().getId());
EdgeRpcService edgeRpcService = systemContext.getEdgeRpcService();
if (msg.getEvent() == ComponentLifecycleEvent.DELETED) {
edgeRpcService.deleteEdge(edgeId);
} else {
Edge edge = systemContext.getEdgeService().findEdgeById(tenantId, edgeId);
if (msg.getEvent() == ComponentLifecycleEvent.UPDATED) {
edgeRpcService.updateEdge(edge);
}
}
} else if (isRuleEngineForCurrentTenant) {
TbActorRef target = getEntityActorRef(msg.getEntityId()); TbActorRef target = getEntityActorRef(msg.getEntityId());
if (target != null) { if (target != null) {
if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) {

2
application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java

@ -69,7 +69,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login"; public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login";
public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public"; public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public";
public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token"; public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token";
protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**"}; protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**", "/api/license/**"};
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**"; public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**";
public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**";

3
application/src/main/java/org/thingsboard/server/controller/AlarmController.java

@ -94,7 +94,8 @@ public class AlarmController extends BaseController {
getCurrentUser().getCustomerId(), getCurrentUser().getCustomerId(),
alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
sendNotificationMsgToEdgeService(getTenantId(), savedAlarm.getId(), alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED); sendNotificationMsgToEdgeService(getTenantId(), savedAlarm.getId(),
alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
return savedAlarm; return savedAlarm;
} catch (Exception e) { } catch (Exception e) {

22
application/src/main/java/org/thingsboard/server/controller/AssetController.java

@ -97,17 +97,18 @@ public class AssetController extends BaseController {
try { try {
asset.setTenantId(getCurrentUser().getTenantId()); asset.setTenantId(getCurrentUser().getTenantId());
checkEntity(asset.getId(), asset, Resource.ASSET); checkEntity(asset.getId(), asset, Resource.ASSET);
Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); Asset savedAsset = checkNotNull(assetService.saveAsset(asset));
sendNotificationMsgToEdgeService(savedAsset.getTenantId(), null,
savedAsset.getId(), EdgeEventType.ASSET, asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
logEntityAction(savedAsset.getId(), savedAsset, logEntityAction(savedAsset.getId(), savedAsset,
savedAsset.getCustomerId(), savedAsset.getCustomerId(),
asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
if (asset.getId() != null) {
sendNotificationMsgToEdgeService(savedAsset.getTenantId(), savedAsset.getId(), ActionType.UPDATED);
}
return savedAsset; return savedAsset;
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.ASSET), asset, logEntityAction(emptyId(EntityType.ASSET), asset,
@ -130,7 +131,7 @@ public class AssetController extends BaseController {
asset.getCustomerId(), asset.getCustomerId(),
ActionType.DELETED, null, strAssetId); ActionType.DELETED, null, strAssetId);
sendNotificationMsgToEdgeService(getTenantId(), null, assetId, EdgeEventType.ASSET, ActionType.DELETED); sendNotificationMsgToEdgeService(getTenantId(), assetId, ActionType.DELETED);
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.ASSET), logEntityAction(emptyId(EntityType.ASSET),
null, null,
@ -160,6 +161,9 @@ public class AssetController extends BaseController {
savedAsset.getCustomerId(), savedAsset.getCustomerId(),
ActionType.ASSIGNED_TO_CUSTOMER, null, strAssetId, strCustomerId, customer.getName()); ActionType.ASSIGNED_TO_CUSTOMER, null, strAssetId, strCustomerId, customer.getName());
sendNotificationMsgToEdgeService(savedAsset.getTenantId(), savedAsset.getId(),
customerId, ActionType.ASSIGNED_TO_CUSTOMER);
return savedAsset; return savedAsset;
} catch (Exception e) { } catch (Exception e) {
@ -191,6 +195,9 @@ public class AssetController extends BaseController {
asset.getCustomerId(), asset.getCustomerId(),
ActionType.UNASSIGNED_FROM_CUSTOMER, null, strAssetId, customer.getId().toString(), customer.getName()); ActionType.UNASSIGNED_FROM_CUSTOMER, null, strAssetId, customer.getId().toString(), customer.getName());
sendNotificationMsgToEdgeService(savedAsset.getTenantId(), savedAsset.getId(),
customer.getId(), ActionType.UNASSIGNED_FROM_CUSTOMER);
return savedAsset; return savedAsset;
} catch (Exception e) { } catch (Exception e) {
@ -425,7 +432,7 @@ public class AssetController extends BaseController {
savedAsset.getCustomerId(), savedAsset.getCustomerId(),
ActionType.ASSIGNED_TO_EDGE, null, strAssetId, strEdgeId, edge.getName()); ActionType.ASSIGNED_TO_EDGE, null, strAssetId, strEdgeId, edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedAsset.getId(), EdgeEventType.ASSET, ActionType.ASSIGNED_TO_EDGE); sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedAsset.getId(), ActionType.ASSIGNED_TO_EDGE);
return savedAsset; return savedAsset;
} catch (Exception e) { } catch (Exception e) {
@ -458,8 +465,7 @@ public class AssetController extends BaseController {
asset.getCustomerId(), asset.getCustomerId(),
ActionType.UNASSIGNED_FROM_EDGE, null, strAssetId, edge.getId().toString(), edge.getName()); ActionType.UNASSIGNED_FROM_EDGE, null, strAssetId, edge.getId().toString(), edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedAsset.getId(), sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedAsset.getId(), ActionType.UNASSIGNED_FROM_EDGE);
EdgeEventType.ASSET, ActionType.UNASSIGNED_FROM_EDGE);
return savedAsset; return savedAsset;
} catch (Exception e) { } catch (Exception e) {

6
application/src/main/java/org/thingsboard/server/controller/AuthController.java

@ -35,6 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -124,6 +125,9 @@ public class AuthController extends BaseController {
} }
userCredentials.setPassword(passwordEncoder.encode(newPassword)); userCredentials.setPassword(passwordEncoder.encode(newPassword));
userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials); userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials);
sendNotificationMsgToEdgeService(getTenantId(), userCredentials.getUserId(), ActionType.CREDENTIALS_UPDATED);
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }
@ -231,6 +235,8 @@ public class AuthController extends BaseController {
} }
} }
sendNotificationMsgToEdgeService(user.getTenantId(), user.getId(), ActionType.CREDENTIALS_UPDATED);
JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser);
JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser);

88
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceInfo; import org.thingsboard.server.common.data.DeviceInfo;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EntityViewInfo; import org.thingsboard.server.common.data.EntityViewInfo;
@ -94,7 +95,6 @@ import org.thingsboard.server.dao.device.ClaimDevicesService;
import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService;
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.entityview.EntityViewService;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
@ -114,6 +114,8 @@ import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.edge.EdgeNotificationService; import org.thingsboard.server.service.edge.EdgeNotificationService;
import org.thingsboard.server.service.edge.rpc.EdgeGrpcService;
import org.thingsboard.server.service.edge.rpc.init.SyncEdgeService;
import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.queue.TbClusterService; import org.thingsboard.server.service.queue.TbClusterService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
@ -205,9 +207,6 @@ public abstract class BaseController {
@Autowired @Autowired
protected EntityViewService entityViewService; protected EntityViewService entityViewService;
@Autowired
protected EdgeService edgeService;
@Autowired @Autowired
protected TelemetrySubscriptionService tsSubService; protected TelemetrySubscriptionService tsSubService;
@ -226,16 +225,25 @@ public abstract class BaseController {
@Autowired @Autowired
protected TbDeviceProfileCache deviceProfileCache; protected TbDeviceProfileCache deviceProfileCache;
@Autowired @Autowired(required = false)
protected EdgeService edgeService;
@Autowired(required = false)
protected EdgeNotificationService edgeNotificationService; protected EdgeNotificationService edgeNotificationService;
@Autowired @Autowired(required = false)
protected EdgeEventService edgeEventService; protected SyncEdgeService syncEdgeService;
@Autowired(required = false)
protected EdgeGrpcService edgeGrpcService;
@Value("${server.log_controller_error_stack_trace}") @Value("${server.log_controller_error_stack_trace}")
@Getter @Getter
private boolean logControllerErrorStackTrace; private boolean logControllerErrorStackTrace;
@Value("${edges.rpc.enabled}")
@Getter
private boolean edgesSupportEnabled;
@ExceptionHandler(ThingsboardException.class) @ExceptionHandler(ThingsboardException.class)
public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) { public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) {
@ -774,8 +782,7 @@ public abstract class BaseController {
String strTenantName = extractParameter(String.class, 1, additionalInfo); String strTenantName = extractParameter(String.class, 1, additionalInfo);
metaData.putValue("assignedToTenantId", strTenantId); metaData.putValue("assignedToTenantId", strTenantId);
metaData.putValue("assignedToTenantName", strTenantName); metaData.putValue("assignedToTenantName", strTenantName);
} } else if (actionType == ActionType.ASSIGNED_TO_EDGE) {
if (actionType == ActionType.ASSIGNED_TO_EDGE) {
String strEdgeId = extractParameter(String.class, 1, additionalInfo); String strEdgeId = extractParameter(String.class, 1, additionalInfo);
metaData.putValue("assignedEdgeId", strEdgeId); metaData.putValue("assignedEdgeId", strEdgeId);
} else if (actionType == ActionType.UNASSIGNED_FROM_EDGE) { } else if (actionType == ActionType.UNASSIGNED_FROM_EDGE) {
@ -852,31 +859,66 @@ public abstract class BaseController {
} }
return null; return null;
} }
protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityRelation relation, ActionType edgeEventAction) {
protected void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, CustomerId customerId, ActionType action) {
if (!edgesSupportEnabled) {
return;
}
try { try {
sendNotificationMsgToEdgeService(tenantId, null, null, json.writeValueAsString(relation), EdgeEventType.RELATION, edgeEventAction); sendNotificationMsgToEdgeService(tenantId, edgeId, null, json.writeValueAsString(customerId), EdgeEventType.EDGE, action);
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to push relation to core: {}", relation, e); log.warn("Failed to push assign/unassign to/from customer to core: {}", customerId, e);
} }
} }
protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityId entityId, ActionType edgeEventAction) { protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityId entityId, CustomerId customerId, ActionType action) {
EdgeEventType edgeEventType = edgeEventService.getEdgeEventTypeByEntityType(entityId.getEntityType()); if (!edgesSupportEnabled) {
if (edgeEventType != null) { return;
sendNotificationMsgToEdgeService(tenantId, null, entityId, null, edgeEventType, edgeEventAction); }
EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType());
try {
if (type != null) {
sendNotificationMsgToEdgeService(tenantId, null, entityId, json.writeValueAsString(customerId), type, action);
}
} catch (Exception e) {
log.warn("Failed to push assign/unassign to/from customer to core: {}", customerId, e);
}
}
protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityRelation relation, ActionType action) {
if (!edgesSupportEnabled) {
return;
}
try {
if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
!relation.getTo().getEntityType().equals(EntityType.EDGE)) {
sendNotificationMsgToEdgeService(tenantId, null, null, json.writeValueAsString(relation), EdgeEventType.RELATION, action);
}
} catch (Exception e) {
log.warn("Failed to push relation to core: {}", relation, e);
} }
} }
protected void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventType edgeEventType, ActionType edgeEventAction) { protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityId entityId, ActionType action) {
sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, null, edgeEventType, edgeEventAction); sendNotificationMsgToEdgeService(tenantId, null, entityId, action);
}
protected void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, ActionType action) {
if (!edgesSupportEnabled) {
return;
}
EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType());
if (type != null) {
sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, null, type, action);
}
} }
private void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, String entityBody, EdgeEventType edgeEventType, ActionType edgeEventAction) { private void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, ActionType action) {
TransportProtos.EdgeNotificationMsgProto.Builder builder = TransportProtos.EdgeNotificationMsgProto.newBuilder(); TransportProtos.EdgeNotificationMsgProto.Builder builder = TransportProtos.EdgeNotificationMsgProto.newBuilder();
builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits()); builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits());
builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()); builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits());
builder.setEdgeEventType(edgeEventType.name()); builder.setType(type.name());
builder.setEdgeEventAction(edgeEventAction.name()); builder.setAction(action.name());
if (entityId != null) { if (entityId != null) {
builder.setEntityIdMSB(entityId.getId().getMostSignificantBits()); builder.setEntityIdMSB(entityId.getId().getMostSignificantBits());
builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits()); builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits());
@ -886,8 +928,8 @@ public abstract class BaseController {
builder.setEdgeIdMSB(edgeId.getId().getMostSignificantBits()); builder.setEdgeIdMSB(edgeId.getId().getMostSignificantBits());
builder.setEdgeIdLSB(edgeId.getId().getLeastSignificantBits()); builder.setEdgeIdLSB(edgeId.getId().getLeastSignificantBits());
} }
if (entityBody != null) { if (body != null) {
builder.setEntityBody(entityBody); builder.setBody(body);
} }
TransportProtos.EdgeNotificationMsgProto msg = builder.build(); TransportProtos.EdgeNotificationMsgProto msg = builder.build();
tbClusterService.pushMsgToCore(tenantId, entityId != null ? entityId : tenantId, tbClusterService.pushMsgToCore(tenantId, entityId != null ? entityId : tenantId,

5
application/src/main/java/org/thingsboard/server/controller/CustomerController.java

@ -108,6 +108,10 @@ public class CustomerController extends BaseController {
savedCustomer.getId(), savedCustomer.getId(),
customer.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); customer.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
if (customer.getId() != null) {
sendNotificationMsgToEdgeService(savedCustomer.getTenantId(), savedCustomer.getId(),ActionType.UPDATED);
}
return savedCustomer; return savedCustomer;
} catch (Exception e) { } catch (Exception e) {
@ -132,6 +136,7 @@ public class CustomerController extends BaseController {
customer.getId(), customer.getId(),
ActionType.DELETED, null, strCustomerId); ActionType.DELETED, null, strCustomerId);
sendNotificationMsgToEdgeService(getTenantId(), customerId, ActionType.DELETED);
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.CUSTOMER), logEntityAction(emptyId(EntityType.CUSTOMER),

24
application/src/main/java/org/thingsboard/server/controller/DashboardController.java

@ -31,10 +31,8 @@ import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.ShortCustomerInfo;
import org.thingsboard.server.common.data.ShortEdgeInfo;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
@ -116,8 +114,9 @@ public class DashboardController extends BaseController {
null, null,
dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
sendNotificationMsgToEdgeService(savedDashboard.getTenantId(), null, savedDashboard.getId(), if (dashboard.getId() != null) {
EdgeEventType.DASHBOARD, savedDashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED); sendNotificationMsgToEdgeService(savedDashboard.getTenantId(), savedDashboard.getId(), ActionType.UPDATED);
}
return savedDashboard; return savedDashboard;
} catch (Exception e) { } catch (Exception e) {
@ -142,7 +141,7 @@ public class DashboardController extends BaseController {
null, null,
ActionType.DELETED, null, strDashboardId); ActionType.DELETED, null, strDashboardId);
sendNotificationMsgToEdgeService(getTenantId(), null, dashboardId, EdgeEventType.DASHBOARD, ActionType.DELETED); sendNotificationMsgToEdgeService(getTenantId(), dashboardId, ActionType.DELETED);
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.DASHBOARD), logEntityAction(emptyId(EntityType.DASHBOARD),
@ -174,6 +173,7 @@ public class DashboardController extends BaseController {
customerId, customerId,
ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, strCustomerId, customer.getName()); ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, strCustomerId, customer.getName());
sendNotificationMsgToEdgeService(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, ActionType.ASSIGNED_TO_CUSTOMER);
return savedDashboard; return savedDashboard;
} catch (Exception e) { } catch (Exception e) {
@ -205,6 +205,8 @@ public class DashboardController extends BaseController {
customerId, customerId,
ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customer.getId().toString(), customer.getName()); ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customer.getId().toString(), customer.getName());
sendNotificationMsgToEdgeService(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, ActionType.UNASSIGNED_FROM_CUSTOMER);
return savedDashboard; return savedDashboard;
} catch (Exception e) { } catch (Exception e) {
@ -260,6 +262,7 @@ public class DashboardController extends BaseController {
logEntityAction(dashboardId, savedDashboard, logEntityAction(dashboardId, savedDashboard,
customerId, customerId,
ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle());
sendNotificationMsgToEdgeService(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, ActionType.ASSIGNED_TO_CUSTOMER);
} }
for (CustomerId customerId : removedCustomerIds) { for (CustomerId customerId : removedCustomerIds) {
ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId);
@ -267,7 +270,7 @@ public class DashboardController extends BaseController {
logEntityAction(dashboardId, dashboard, logEntityAction(dashboardId, dashboard,
customerId, customerId,
ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle());
sendNotificationMsgToEdgeService(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, ActionType.UNASSIGNED_FROM_CUSTOMER);
} }
return savedDashboard; return savedDashboard;
} }
@ -311,6 +314,7 @@ public class DashboardController extends BaseController {
logEntityAction(dashboardId, savedDashboard, logEntityAction(dashboardId, savedDashboard,
customerId, customerId,
ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle());
sendNotificationMsgToEdgeService(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, ActionType.ASSIGNED_TO_CUSTOMER);
} }
return savedDashboard; return savedDashboard;
} }
@ -354,7 +358,7 @@ public class DashboardController extends BaseController {
logEntityAction(dashboardId, dashboard, logEntityAction(dashboardId, dashboard,
customerId, customerId,
ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle());
sendNotificationMsgToEdgeService(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, ActionType.UNASSIGNED_FROM_CUSTOMER);
} }
return savedDashboard; return savedDashboard;
} }
@ -501,8 +505,7 @@ public class DashboardController extends BaseController {
null, null,
ActionType.ASSIGNED_TO_EDGE, null, strDashboardId, strEdgeId, edge.getName()); ActionType.ASSIGNED_TO_EDGE, null, strDashboardId, strEdgeId, edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedDashboard.getId(), sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedDashboard.getId(), ActionType.ASSIGNED_TO_EDGE);
EdgeEventType.DASHBOARD, ActionType.ASSIGNED_TO_EDGE);
return savedDashboard; return savedDashboard;
} catch (Exception e) { } catch (Exception e) {
@ -534,8 +537,7 @@ public class DashboardController extends BaseController {
null, null,
ActionType.UNASSIGNED_FROM_EDGE, null, strDashboardId, edge.getId().toString(), edge.getName()); ActionType.UNASSIGNED_FROM_EDGE, null, strDashboardId, edge.getId().toString(), edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedDashboard.getId(), sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedDashboard.getId(), ActionType.UNASSIGNED_FROM_EDGE);
EdgeEventType.DASHBOARD, ActionType.UNASSIGNED_FROM_EDGE);
return savedDashboard; return savedDashboard;
} catch (Exception e) { } catch (Exception e) {

20
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -44,7 +44,6 @@ import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.device.DeviceSearchQuery; import org.thingsboard.server.common.data.device.DeviceSearchQuery;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
@ -126,8 +125,9 @@ public class DeviceController extends BaseController {
tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(), tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(),
savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null); savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null);
sendNotificationMsgToEdgeService(savedDevice.getTenantId(), null, savedDevice.getId(), if (device.getId() != null) {
EdgeEventType.DEVICE, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED); sendNotificationMsgToEdgeService(savedDevice.getTenantId(), savedDevice.getId(), ActionType.UPDATED);
}
logEntityAction(savedDevice.getId(), savedDevice, logEntityAction(savedDevice.getId(), savedDevice,
savedDevice.getCustomerId(), savedDevice.getCustomerId(),
@ -160,7 +160,7 @@ public class DeviceController extends BaseController {
device.getCustomerId(), device.getCustomerId(),
ActionType.DELETED, null, strDeviceId); ActionType.DELETED, null, strDeviceId);
sendNotificationMsgToEdgeService(getTenantId(), null, deviceId, EdgeEventType.DEVICE, ActionType.DELETED); sendNotificationMsgToEdgeService(getTenantId(), deviceId, ActionType.DELETED);
deviceStateService.onDeviceDeleted(device); deviceStateService.onDeviceDeleted(device);
} catch (Exception e) { } catch (Exception e) {
@ -192,6 +192,9 @@ public class DeviceController extends BaseController {
savedDevice.getCustomerId(), savedDevice.getCustomerId(),
ActionType.ASSIGNED_TO_CUSTOMER, null, strDeviceId, strCustomerId, customer.getName()); ActionType.ASSIGNED_TO_CUSTOMER, null, strDeviceId, strCustomerId, customer.getName());
sendNotificationMsgToEdgeService(savedDevice.getTenantId(), savedDevice.getId(),
customerId, ActionType.ASSIGNED_TO_CUSTOMER);
return savedDevice; return savedDevice;
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.DEVICE), null, logEntityAction(emptyId(EntityType.DEVICE), null,
@ -220,6 +223,9 @@ public class DeviceController extends BaseController {
device.getCustomerId(), device.getCustomerId(),
ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDeviceId, customer.getId().toString(), customer.getName()); ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDeviceId, customer.getId().toString(), customer.getName());
sendNotificationMsgToEdgeService(savedDevice.getTenantId(), savedDevice.getId(),
customer.getId(), ActionType.UNASSIGNED_FROM_CUSTOMER);
return savedDevice; return savedDevice;
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.DEVICE), null, logEntityAction(emptyId(EntityType.DEVICE), null,
@ -285,7 +291,7 @@ public class DeviceController extends BaseController {
tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId()), null); tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId()), null);
sendNotificationMsgToEdgeService(getTenantId(), null, device.getId(), EdgeEventType.DEVICE, ActionType.CREDENTIALS_UPDATED); sendNotificationMsgToEdgeService(getTenantId(), device.getId(), ActionType.CREDENTIALS_UPDATED);
logEntityAction(device.getId(), device, logEntityAction(device.getId(), device,
device.getCustomerId(), device.getCustomerId(),
@ -646,7 +652,7 @@ public class DeviceController extends BaseController {
savedDevice.getCustomerId(), savedDevice.getCustomerId(),
ActionType.ASSIGNED_TO_EDGE, null, strDeviceId, strEdgeId, edge.getName()); ActionType.ASSIGNED_TO_EDGE, null, strDeviceId, strEdgeId, edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedDevice.getId(), EdgeEventType.DEVICE, ActionType.ASSIGNED_TO_EDGE); sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedDevice.getId(), ActionType.ASSIGNED_TO_EDGE);
return savedDevice; return savedDevice;
} catch (Exception e) { } catch (Exception e) {
@ -677,7 +683,7 @@ public class DeviceController extends BaseController {
device.getCustomerId(), device.getCustomerId(),
ActionType.UNASSIGNED_FROM_EDGE, null, strDeviceId, edge.getId().toString(), edge.getName()); ActionType.UNASSIGNED_FROM_EDGE, null, strDeviceId, edge.getId().toString(), edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedDevice.getId(), EdgeEventType.DEVICE, ActionType.UNASSIGNED_FROM_EDGE); sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedDevice.getId(), ActionType.UNASSIGNED_FROM_EDGE);
return savedDevice; return savedDevice;
} catch (Exception e) { } catch (Exception e) {

63
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
@ -34,6 +33,7 @@ import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeInfo; import org.thingsboard.server.common.data.edge.EdgeInfo;
import org.thingsboard.server.common.data.edge.EdgeSearchQuery; import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
@ -41,10 +41,13 @@ 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.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.EdgeGrpcSession;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;
@ -54,6 +57,7 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RestController @RestController
@TbCoreComponent
@RequestMapping("/api") @RequestMapping("/api")
public class EdgeController extends BaseController { public class EdgeController extends BaseController {
@ -102,6 +106,9 @@ public class EdgeController extends BaseController {
edgeService.assignDefaultRuleChainsToEdge(tenantId, savedEdge.getId()); edgeService.assignDefaultRuleChainsToEdge(tenantId, savedEdge.getId());
} }
tbClusterService.onEntityStateChange(savedEdge.getTenantId(), savedEdge.getId(),
created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
logEntityAction(savedEdge.getId(), savedEdge, null, created ? ActionType.ADDED : ActionType.UPDATED, null); logEntityAction(savedEdge.getId(), savedEdge, null, created ? ActionType.ADDED : ActionType.UPDATED, null);
return savedEdge; return savedEdge;
} catch (Exception e) { } catch (Exception e) {
@ -121,6 +128,9 @@ public class EdgeController extends BaseController {
Edge edge = checkEdgeId(edgeId, Operation.DELETE); Edge edge = checkEdgeId(edgeId, Operation.DELETE);
edgeService.deleteEdge(getTenantId(), edgeId); edgeService.deleteEdge(getTenantId(), edgeId);
tbClusterService.onEntityStateChange(getTenantId(), edgeId,
ComponentLifecycleEvent.DELETED);
logEntityAction(edgeId, edge, logEntityAction(edgeId, edge,
null, null,
ActionType.DELETED, null, strEdgeId); ActionType.DELETED, null, strEdgeId);
@ -169,10 +179,16 @@ public class EdgeController extends BaseController {
Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, customerId)); Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, customerId));
tbClusterService.onEntityStateChange(getTenantId(), edgeId,
ComponentLifecycleEvent.UPDATED);
logEntityAction(edgeId, savedEdge, logEntityAction(edgeId, savedEdge,
savedEdge.getCustomerId(), savedEdge.getCustomerId(),
ActionType.ASSIGNED_TO_CUSTOMER, null, strEdgeId, strCustomerId, customer.getName()); ActionType.ASSIGNED_TO_CUSTOMER, null, strEdgeId, strCustomerId, customer.getName());
sendNotificationMsgToEdgeService(savedEdge.getTenantId(), savedEdge.getId(),
customerId, ActionType.ASSIGNED_TO_CUSTOMER);
return savedEdge; return savedEdge;
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.EDGE), null, logEntityAction(emptyId(EntityType.EDGE), null,
@ -197,10 +213,16 @@ public class EdgeController extends BaseController {
Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(getCurrentUser().getTenantId(), edgeId)); Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(getCurrentUser().getTenantId(), edgeId));
tbClusterService.onEntityStateChange(getTenantId(), edgeId,
ComponentLifecycleEvent.UPDATED);
logEntityAction(edgeId, edge, logEntityAction(edgeId, edge,
edge.getCustomerId(), edge.getCustomerId(),
ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEdgeId, customer.getId().toString(), customer.getName()); ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEdgeId, customer.getId().toString(), customer.getName());
sendNotificationMsgToEdgeService(savedEdge.getTenantId(), savedEdge.getId(),
customer.getId(), ActionType.UNASSIGNED_FROM_CUSTOMER);
return savedEdge; return savedEdge;
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.EDGE), null, logEntityAction(emptyId(EntityType.EDGE), null,
@ -310,6 +332,8 @@ public class EdgeController extends BaseController {
Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(getTenantId(), edge, ruleChainId); Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(getTenantId(), edge, ruleChainId);
tbClusterService.onEntityStateChange(updatedEdge.getTenantId(), updatedEdge.getId(), ComponentLifecycleEvent.UPDATED);
logEntityAction(updatedEdge.getId(), updatedEdge, null, ActionType.UPDATED, null); logEntityAction(updatedEdge.getId(), updatedEdge, null, ActionType.UPDATED, null);
return updatedEdge; return updatedEdge;
@ -413,4 +437,41 @@ public class EdgeController extends BaseController {
} }
} }
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/sync", method = RequestMethod.POST)
public void syncEdge(@RequestBody EdgeId edgeId) throws ThingsboardException {
try {
edgeId = checkNotNull(edgeId);
if (isEdgesSupportEnabled()) {
EdgeGrpcSession session = edgeGrpcService.getEdgeGrpcSessionById(edgeId);
Edge edge = session.getEdge();
syncEdgeService.sync(edge);
} else {
throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL);
}
} catch (Exception e) {
throw handleException(e);
}
}
@RequestMapping(value = "/license/checkInstance", method = RequestMethod.POST)
@ResponseBody
public Object checkInstance(@RequestBody Object request) throws ThingsboardException {
try {
return edgeService.checkInstance(request);
} catch (Exception e) {
throw new ThingsboardException(e, ThingsboardErrorCode.SUBSCRIPTION_VIOLATION);
}
}
@RequestMapping(value = "/license/activateInstance", params = {"licenseSecret", "releaseDate"}, method = RequestMethod.POST)
@ResponseBody
public Object activateInstance(@RequestParam String licenseSecret,
@RequestParam String releaseDate) throws ThingsboardException {
try {
return edgeService.activateInstance(licenseSecret, releaseDate);
} catch (Exception e) {
throw new ThingsboardException(e, ThingsboardErrorCode.SUBSCRIPTION_VIOLATION);
}
}
} }

71
application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java

@ -0,0 +1,71 @@
/**
* Copyright © 2016-2020 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.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
@Slf4j
@RestController
@TbCoreComponent
@RequestMapping("/api")
public class EdgeEventController extends BaseController {
@Autowired
private EdgeEventService edgeEventService;
public static final String EDGE_ID = "edgeId";
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/edge/{edgeId}/events", method = RequestMethod.GET)
@ResponseBody
public PageData<EdgeEvent> getEdgeEvents(
@PathVariable(EDGE_ID) String strEdgeId,
@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder,
@RequestParam(required = false) Long startTime,
@RequestParam(required = false) Long endTime) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
try {
TenantId tenantId = getCurrentUser().getTenantId();
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
checkEdgeId(edgeId, Operation.READ);
TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
return checkNotNull(edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, false));
} catch (Exception e) {
throw handleException(e);
}
}
}

4
application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java

@ -24,9 +24,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
@ -132,8 +130,6 @@ public class EntityRelationController extends BaseController {
try { try {
relationService.deleteEntityRelations(getTenantId(), entityId); relationService.deleteEntityRelations(getTenantId(), entityId);
logEntityAction(entityId, null, getCurrentUser().getCustomerId(), ActionType.RELATIONS_DELETED, null); logEntityAction(entityId, null, getCurrentUser().getCustomerId(), ActionType.RELATIONS_DELETED, null);
sendNotificationMsgToEdgeService(getTenantId(), entityId, ActionType.RELATIONS_DELETED);
} catch (Exception e) { } catch (Exception e) {
logEntityAction(entityId, null, getCurrentUser().getCustomerId(), ActionType.RELATIONS_DELETED, e); logEntityAction(entityId, null, getCurrentUser().getCustomerId(), ActionType.RELATIONS_DELETED, e);
throw handleException(e); throw handleException(e);

21
application/src/main/java/org/thingsboard/server/controller/EntityViewController.java

@ -161,8 +161,10 @@ public class EntityViewController extends BaseController {
logEntityAction(savedEntityView.getId(), savedEntityView, null, logEntityAction(savedEntityView.getId(), savedEntityView, null,
entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
sendNotificationMsgToEdgeService(getTenantId(), null, savedEntityView.getId(), if (entityView.getId() != null) {
EdgeEventType.ENTITY_VIEW, entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED); sendNotificationMsgToEdgeService(savedEntityView.getTenantId(), savedEntityView.getId(), ActionType.UPDATED);
}
return savedEntityView; return savedEntityView;
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.ENTITY_VIEW), entityView, null, logEntityAction(emptyId(EntityType.ENTITY_VIEW), entityView, null,
@ -362,7 +364,7 @@ public class EntityViewController extends BaseController {
logEntityAction(entityViewId, entityView, entityView.getCustomerId(), logEntityAction(entityViewId, entityView, entityView.getCustomerId(),
ActionType.DELETED, null, strEntityViewId); ActionType.DELETED, null, strEntityViewId);
sendNotificationMsgToEdgeService(getTenantId(), null, entityViewId, EdgeEventType.ENTITY_VIEW, ActionType.DELETED); sendNotificationMsgToEdgeService(getTenantId(), entityViewId, ActionType.DELETED);
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.ENTITY_VIEW), logEntityAction(emptyId(EntityType.ENTITY_VIEW),
null, null,
@ -403,6 +405,10 @@ public class EntityViewController extends BaseController {
logEntityAction(entityViewId, savedEntityView, logEntityAction(entityViewId, savedEntityView,
savedEntityView.getCustomerId(), savedEntityView.getCustomerId(),
ActionType.ASSIGNED_TO_CUSTOMER, null, strEntityViewId, strCustomerId, customer.getName()); ActionType.ASSIGNED_TO_CUSTOMER, null, strEntityViewId, strCustomerId, customer.getName());
sendNotificationMsgToEdgeService(savedEntityView.getTenantId(), savedEntityView.getId(),
customerId, ActionType.ASSIGNED_TO_CUSTOMER);
return savedEntityView; return savedEntityView;
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, logEntityAction(emptyId(EntityType.ENTITY_VIEW), null,
@ -429,6 +435,9 @@ public class EntityViewController extends BaseController {
entityView.getCustomerId(), entityView.getCustomerId(),
ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEntityViewId, customer.getId().toString(), customer.getName()); ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEntityViewId, customer.getId().toString(), customer.getName());
sendNotificationMsgToEdgeService(savedEntityView.getTenantId(), savedEntityView.getId(),
customer.getId(), ActionType.UNASSIGNED_FROM_CUSTOMER);
return savedEntityView; return savedEntityView;
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, logEntityAction(emptyId(EntityType.ENTITY_VIEW), null,
@ -620,8 +629,7 @@ public class EntityViewController extends BaseController {
savedEntityView.getCustomerId(), savedEntityView.getCustomerId(),
ActionType.ASSIGNED_TO_EDGE, null, strEntityViewId, strEdgeId, edge.getName()); ActionType.ASSIGNED_TO_EDGE, null, strEntityViewId, strEdgeId, edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedEntityView.getId(), sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedEntityView.getId(), ActionType.ASSIGNED_TO_EDGE);
EdgeEventType.ENTITY_VIEW, ActionType.ASSIGNED_TO_EDGE);
return savedEntityView; return savedEntityView;
} catch (Exception e) { } catch (Exception e) {
@ -651,8 +659,7 @@ public class EntityViewController extends BaseController {
entityView.getCustomerId(), entityView.getCustomerId(),
ActionType.UNASSIGNED_FROM_EDGE, null, strEntityViewId, edge.getId().toString(), edge.getName()); ActionType.UNASSIGNED_FROM_EDGE, null, strEntityViewId, edge.getId().toString(), edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedEntityView.getId(), sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedEntityView.getId(), ActionType.UNASSIGNED_FROM_EDGE);
EdgeEventType.ENTITY_VIEW, ActionType.UNASSIGNED_FROM_EDGE);
return savedEntityView; return savedEntityView;
} catch (Exception e) { } catch (Exception e) {

19
application/src/main/java/org/thingsboard/server/controller/RuleChainController.java

@ -152,9 +152,9 @@ public class RuleChainController extends BaseController {
created ? ActionType.ADDED : ActionType.UPDATED, null); created ? ActionType.ADDED : ActionType.UPDATED, null);
if (RuleChainType.EDGE.equals(savedRuleChain.getType())) { if (RuleChainType.EDGE.equals(savedRuleChain.getType())) {
sendNotificationMsgToEdgeService(savedRuleChain.getTenantId(), null, if (!created) {
savedRuleChain.getId(), EdgeEventType.RULE_CHAIN, sendNotificationMsgToEdgeService(savedRuleChain.getTenantId(), savedRuleChain.getId(), ActionType.UPDATED);
savedRuleChain.getId() == null ? ActionType.ADDED : ActionType.UPDATED); }
} }
return savedRuleChain; return savedRuleChain;
@ -254,9 +254,7 @@ public class RuleChainController extends BaseController {
if (RuleChainType.EDGE.equals(ruleChain.getType())) { if (RuleChainType.EDGE.equals(ruleChain.getType())) {
sendNotificationMsgToEdgeService(ruleChain.getTenantId(), sendNotificationMsgToEdgeService(ruleChain.getTenantId(),
null, ruleChain.getId(), ActionType.UPDATED);
ruleChain.getId(), EdgeEventType.RULE_CHAIN,
ActionType.UPDATED);
} }
return savedRuleChainMetaData; return savedRuleChainMetaData;
@ -322,8 +320,7 @@ public class RuleChainController extends BaseController {
ActionType.DELETED, null, strRuleChainId); ActionType.DELETED, null, strRuleChainId);
if (RuleChainType.EDGE.equals(ruleChain.getType())) { if (RuleChainType.EDGE.equals(ruleChain.getType())) {
sendNotificationMsgToEdgeService(ruleChain.getTenantId(), null, sendNotificationMsgToEdgeService(ruleChain.getTenantId(), ruleChain.getId(), ActionType.DELETED);
ruleChain.getId(), EdgeEventType.RULE_CHAIN, ActionType.DELETED);
} }
} catch (Exception e) { } catch (Exception e) {
@ -485,8 +482,7 @@ public class RuleChainController extends BaseController {
null, null,
ActionType.ASSIGNED_TO_EDGE, null, strRuleChainId, strEdgeId, edge.getName()); ActionType.ASSIGNED_TO_EDGE, null, strRuleChainId, strEdgeId, edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedRuleChain.getId(), sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedRuleChain.getId(), ActionType.ASSIGNED_TO_EDGE);
EdgeEventType.RULE_CHAIN, ActionType.ASSIGNED_TO_EDGE);
return savedRuleChain; return savedRuleChain;
} catch (Exception e) { } catch (Exception e) {
@ -518,8 +514,7 @@ public class RuleChainController extends BaseController {
null, null,
ActionType.UNASSIGNED_FROM_EDGE, null, strRuleChainId, edge.getId().toString(), edge.getName()); ActionType.UNASSIGNED_FROM_EDGE, null, strRuleChainId, edge.getId().toString(), edge.getName());
sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedRuleChain.getId(), sendNotificationMsgToEdgeService(getTenantId(), edgeId, savedRuleChain.getId(), ActionType.UNASSIGNED_FROM_EDGE);
EdgeEventType.RULE_CHAIN, ActionType.UNASSIGNED_FROM_EDGE);
return savedRuleChain; return savedRuleChain;
} catch (Exception e) { } catch (Exception e) {

5
application/src/main/java/org/thingsboard/server/controller/UserController.java

@ -162,6 +162,9 @@ public class UserController extends BaseController {
savedUser.getCustomerId(), savedUser.getCustomerId(),
user.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); user.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
sendNotificationMsgToEdgeService(getTenantId(), savedUser.getId(),
user.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
return savedUser; return savedUser;
} catch (Exception e) { } catch (Exception e) {
@ -237,6 +240,8 @@ public class UserController extends BaseController {
user.getCustomerId(), user.getCustomerId(),
ActionType.DELETED, null, strUserId); ActionType.DELETED, null, strUserId);
sendNotificationMsgToEdgeService(getTenantId(), user.getId(), ActionType.DELETED);
} catch (Exception e) { } catch (Exception e) {
logEntityAction(emptyId(EntityType.USER), logEntityAction(emptyId(EntityType.USER),
null, null,

12
application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
@ -25,6 +26,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.id.WidgetTypeId;
@ -37,6 +39,7 @@ import org.thingsboard.server.service.security.permission.Resource;
import java.util.List; import java.util.List;
@Slf4j
@RestController @RestController
@TbCoreComponent @TbCoreComponent
@RequestMapping("/api") @RequestMapping("/api")
@ -67,8 +70,12 @@ public class WidgetTypeController extends BaseController {
} }
checkEntity(widgetType.getId(), widgetType, Resource.WIDGET_TYPE); checkEntity(widgetType.getId(), widgetType, Resource.WIDGET_TYPE);
WidgetType savedWidgetType = widgetTypeService.saveWidgetType(widgetType);
return checkNotNull(widgetTypeService.saveWidgetType(widgetType)); sendNotificationMsgToEdgeService(getTenantId(), savedWidgetType.getId(),
widgetType.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
return checkNotNull(savedWidgetType);
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }
@ -83,6 +90,9 @@ public class WidgetTypeController extends BaseController {
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId)); WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
checkWidgetTypeId(widgetTypeId, Operation.DELETE); checkWidgetTypeId(widgetTypeId, Operation.DELETE);
widgetTypeService.deleteWidgetType(getCurrentUser().getTenantId(), widgetTypeId); widgetTypeService.deleteWidgetType(getCurrentUser().getTenantId(), widgetTypeId);
sendNotificationMsgToEdgeService(getTenantId(), widgetTypeId, ActionType.DELETED);
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }

11
application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java

@ -25,6 +25,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.WidgetsBundleId; import org.thingsboard.server.common.data.id.WidgetsBundleId;
@ -68,7 +69,12 @@ public class WidgetsBundleController extends BaseController {
} }
checkEntity(widgetsBundle.getId(), widgetsBundle, Resource.WIDGETS_BUNDLE); checkEntity(widgetsBundle.getId(), widgetsBundle, Resource.WIDGETS_BUNDLE);
return checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle)); WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle);
sendNotificationMsgToEdgeService(getTenantId(), savedWidgetsBundle.getId(),
widgetsBundle.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
return checkNotNull(savedWidgetsBundle);
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }
@ -83,6 +89,9 @@ public class WidgetsBundleController extends BaseController {
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId));
checkWidgetsBundleId(widgetsBundleId, Operation.DELETE); checkWidgetsBundleId(widgetsBundleId, Operation.DELETE);
widgetsBundleService.deleteWidgetsBundle(getTenantId(), widgetsBundleId); widgetsBundleService.deleteWidgetsBundle(getTenantId(), widgetsBundleId);
sendNotificationMsgToEdgeService(getTenantId(), widgetsBundleId, ActionType.DELETED);
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }

13
application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java

@ -27,6 +27,7 @@ import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.msg.tools.TbRateLimitsException; import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
@ -66,7 +67,12 @@ public class ThingsboardErrorResponseHandler implements AccessDeniedHandler {
response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setContentType(MediaType.APPLICATION_JSON_VALUE);
if (exception instanceof ThingsboardException) { if (exception instanceof ThingsboardException) {
handleThingsboardException((ThingsboardException) exception, response); ThingsboardException thingsboardException = (ThingsboardException) exception;
if (thingsboardException.getErrorCode() == ThingsboardErrorCode.SUBSCRIPTION_VIOLATION) {
handleSubscriptionException((ThingsboardException) exception, response);
} else {
handleThingsboardException((ThingsboardException) exception, response);
}
} else if (exception instanceof TbRateLimitsException) { } else if (exception instanceof TbRateLimitsException) {
handleRateLimitException(response, (TbRateLimitsException) exception); handleRateLimitException(response, (TbRateLimitsException) exception);
} else if (exception instanceof AccessDeniedException) { } else if (exception instanceof AccessDeniedException) {
@ -126,6 +132,11 @@ public class ThingsboardErrorResponseHandler implements AccessDeniedHandler {
ThingsboardErrorCode.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS)); ThingsboardErrorCode.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS));
} }
private void handleSubscriptionException(ThingsboardException subscriptionException, HttpServletResponse response) throws IOException {
response.setStatus(HttpStatus.FORBIDDEN.value());
mapper.writeValue(response.getWriter(),
(new ObjectMapper()).readValue(((HttpClientErrorException) subscriptionException.getCause()).getResponseBodyAsByteArray(), Object.class));
}
private void handleAccessDeniedException(HttpServletResponse response) throws IOException { private void handleAccessDeniedException(HttpServletResponse response) throws IOException {
response.setStatus(HttpStatus.FORBIDDEN.value()); response.setStatus(HttpStatus.FORBIDDEN.value());

12
application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java

@ -167,7 +167,17 @@ public class ThingsboardInstallService {
databaseTsUpgradeService.upgradeDatabase("2.5.0"); databaseTsUpgradeService.upgradeDatabase("2.5.0");
} }
case "2.5.1": case "2.5.1":
log.info("Upgrading ThingsBoard from version 2.5.1 to 3.0.0 ..."); log.info("Upgrading ThingsBoard from version 2.5.1 to 2.5.5 ...");
case "2.5.5":
log.info("Upgrading ThingsBoard from version 2.5.5 to 2.6.0 ...");
if (databaseTsUpgradeService != null) {
databaseTsUpgradeService.upgradeDatabase("2.5.5");
}
databaseEntitiesUpgradeService.upgradeDatabase("2.5.5");
dataUpdateService.updateData("2.5.5");
case "2.6.0":
log.info("Upgrading ThingsBoard from version 2.6.0 to 3.0.0 ...");
case "3.0.1": case "3.0.1":
log.info("Upgrading ThingsBoard from version 3.0.1 to 3.1.0 ..."); log.info("Upgrading ThingsBoard from version 3.0.1 to 3.1.0 ...");
databaseEntitiesUpgradeService.upgradeDatabase("3.0.1"); databaseEntitiesUpgradeService.upgradeDatabase("3.0.1");

353
application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java

@ -15,39 +15,42 @@
*/ */
package org.thingsboard.server.service.edge; package org.thingsboard.server.service.edge;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
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;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.CustomerId;
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.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.IdBased;
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.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
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.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.executors.DbCallbackExecutorService;
@ -56,14 +59,12 @@ import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; 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.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.stream.Collectors;
@Service @Service
@TbCoreComponent @TbCoreComponent
@ -76,13 +77,13 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
private EdgeService edgeService; private EdgeService edgeService;
@Autowired @Autowired
private RuleChainService ruleChainService; private AlarmService alarmService;
@Autowired @Autowired
private AlarmService alarmService; private UserService userService;
@Autowired @Autowired
private RelationService relationService; private RuleChainService ruleChainService;
@Autowired @Autowired
private EdgeEventService edgeEventService; private EdgeEventService edgeEventService;
@ -106,7 +107,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
@Override @Override
public PageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) { public PageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) {
return edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink); return edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, true);
} }
@Override @Override
@ -119,22 +120,22 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
private void saveEdgeEvent(TenantId tenantId, private void saveEdgeEvent(TenantId tenantId,
EdgeId edgeId, EdgeId edgeId,
EdgeEventType edgeEventType, EdgeEventType type,
ActionType edgeEventAction, ActionType action,
EntityId entityId, EntityId entityId,
JsonNode entityBody) { JsonNode body) {
log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], edgeEventType [{}], edgeEventAction[{}], entityId [{}], entityBody [{}]", log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]",
tenantId, edgeId, edgeEventType, edgeEventAction, entityId, entityBody); tenantId, edgeId, type, action, entityId, body);
EdgeEvent edgeEvent = new EdgeEvent(); EdgeEvent edgeEvent = new EdgeEvent();
edgeEvent.setEdgeId(edgeId); edgeEvent.setEdgeId(edgeId);
edgeEvent.setTenantId(tenantId); edgeEvent.setTenantId(tenantId);
edgeEvent.setEdgeEventType(edgeEventType); edgeEvent.setType(type);
edgeEvent.setEdgeEventAction(edgeEventAction.name()); edgeEvent.setAction(action.name());
if (entityId != null) { if (entityId != null) {
edgeEvent.setEntityId(entityId.getId()); edgeEvent.setEntityId(entityId.getId());
} }
edgeEvent.setEntityBody(entityBody); edgeEvent.setBody(body);
edgeEventService.saveAsync(edgeEvent); edgeEventService.saveAsync(edgeEvent);
} }
@ -142,16 +143,25 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) { public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) {
try { try {
TenantId tenantId = new TenantId(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); TenantId tenantId = new TenantId(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB()));
EdgeEventType edgeEventType = EdgeEventType.valueOf(edgeNotificationMsg.getEdgeEventType()); EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
switch (edgeEventType) { switch (type) {
// TODO: voba - handle edge updates case EDGE:
// case EDGE: processEdge(tenantId, edgeNotificationMsg);
break;
case USER:
case ASSET: case ASSET:
case DEVICE: case DEVICE:
case ENTITY_VIEW: case ENTITY_VIEW:
case DASHBOARD: case DASHBOARD:
case RULE_CHAIN: case RULE_CHAIN:
processEntities(tenantId, edgeNotificationMsg); processEntity(tenantId, edgeNotificationMsg);
break;
case CUSTOMER:
processCustomer(tenantId, edgeNotificationMsg);
break;
case WIDGETS_BUNDLE:
case WIDGET_TYPE:
processWidgetBundleOrWidgetType(tenantId, edgeNotificationMsg);
break; break;
case ALARM: case ALARM:
processAlarm(tenantId, edgeNotificationMsg); processAlarm(tenantId, edgeNotificationMsg);
@ -160,7 +170,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
processRelation(tenantId, edgeNotificationMsg); processRelation(tenantId, edgeNotificationMsg);
break; break;
default: default:
log.debug("Edge event type [{}] is not designed to be pushed to edge", edgeEventType); log.debug("Edge event type [{}] is not designed to be pushed to edge", type);
} }
} catch (Exception e) { } catch (Exception e) {
callback.onFailure(e); callback.onFailure(e);
@ -170,67 +180,219 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
} }
} }
private void processEntities(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { private void processEdge(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
ActionType edgeEventActionType = ActionType.valueOf(edgeNotificationMsg.getEdgeEventAction()); try {
EdgeEventType edgeEventType = EdgeEventType.valueOf(edgeNotificationMsg.getEdgeEventType()); ActionType actionType = ActionType.valueOf(edgeNotificationMsg.getAction());
EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(edgeEventType, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
switch (edgeEventActionType) { ListenableFuture<Edge> edgeFuture;
// TODO: voba - ADDED is not required for CE version ? switch (actionType) {
// case ADDED: case ASSIGNED_TO_CUSTOMER:
CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class);
edgeFuture = edgeService.findEdgeByIdAsync(tenantId, edgeId);
Futures.addCallback(edgeFuture, new FutureCallback<Edge>() {
@Override
public void onSuccess(@Nullable Edge edge) {
if (edge != null && !customerId.isNullUid()) {
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, ActionType.ADDED, customerId, null);
PageData<User> pageData = userService.findCustomerUsers(tenantId, customerId, new PageLink(Integer.MAX_VALUE));
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] user(s) are going to be added to edge.", edge.getId(), pageData.getData().size());
for (User user : pageData.getData()) {
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, ActionType.ADDED, user.getId(), null);
}
}
}
}
@Override
public void onFailure(Throwable t) {
log.error("Can't find edge by id [{}]", edgeNotificationMsg, t);
}
}, dbCallbackExecutorService);
break;
case UNASSIGNED_FROM_CUSTOMER:
CustomerId customerIdToDelete = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class);
edgeFuture = edgeService.findEdgeByIdAsync(tenantId, edgeId);
Futures.addCallback(edgeFuture, new FutureCallback<Edge>() {
@Override
public void onSuccess(@Nullable Edge edge) {
if (edge != null && !customerIdToDelete.isNullUid()) {
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, ActionType.DELETED, customerIdToDelete, null);
}
}
@Override
public void onFailure(Throwable t) {
log.error("Can't find edge by id [{}]", edgeNotificationMsg, t);
}
}, dbCallbackExecutorService);
break;
}
} catch (Exception e) {
log.error("Exception during processing edge event", e);
}
}
private void processWidgetBundleOrWidgetType(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
ActionType actionType = ActionType.valueOf(edgeNotificationMsg.getAction());
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
switch (actionType) {
case ADDED:
case UPDATED: case UPDATED:
ListenableFuture<List<EdgeId>> edgeIdsFuture = findRelatedEdgeIdsByEntityId(tenantId, entityId); case DELETED:
Futures.transform(edgeIdsFuture, edgeIds -> { PageData<Edge> edgesByTenantId = edgeService.findEdgesByTenantId(tenantId, new PageLink(Integer.MAX_VALUE));
if (edgeIds != null && !edgeIds.isEmpty()) { if (edgesByTenantId != null && edgesByTenantId.getData() != null && !edgesByTenantId.getData().isEmpty()) {
for (EdgeId edgeId : edgeIds) { for (Edge edge : edgesByTenantId.getData()) {
try { saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, null);
saveEdgeEvent(tenantId, edgeId, edgeEventType, edgeEventActionType, entityId, null); }
if (edgeEventType.equals(EdgeEventType.RULE_CHAIN)) { }
RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(tenantId, new RuleChainId(entityId.getId())); break;
saveEdgeEvent(tenantId, edgeId, EdgeEventType.RULE_CHAIN_METADATA, edgeEventActionType, ruleChainMetaData.getRuleChainId(), null); }
}
private void processCustomer(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
ActionType actionType = ActionType.valueOf(edgeNotificationMsg.getAction());
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
PageData<Edge> edgesByTenantId = edgeService.findEdgesByTenantId(tenantId, new PageLink(Integer.MAX_VALUE));
if (edgesByTenantId != null && edgesByTenantId.getData() != null && !edgesByTenantId.getData().isEmpty()) {
for (Edge edge : edgesByTenantId.getData()) {
switch (actionType) {
case UPDATED:
if (!edge.getCustomerId().isNullUid() && edge.getCustomerId().equals(entityId)) {
saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, null);
}
break;
case DELETED:
saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, null);
break;
}
}
}
}
private void processEntity(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
ActionType actionType = ActionType.valueOf(edgeNotificationMsg.getAction());
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type,
new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
ListenableFuture<List<EdgeId>> edgeIdsFuture;
switch (actionType) {
case ADDED: // used only for USER entity
case UPDATED:
case CREDENTIALS_UPDATED:
edgeIdsFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId);
Futures.addCallback(edgeIdsFuture, new FutureCallback<List<EdgeId>>() {
@Override
public void onSuccess(@Nullable List<EdgeId> edgeIds) {
if (edgeIds != null && !edgeIds.isEmpty()) {
for (EdgeId edgeId : edgeIds) {
saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null);
}
}
}
@Override
public void onFailure(Throwable throwable) {
log.error("Failed to find related edge ids [{}]", edgeNotificationMsg, throwable);
}
}, dbCallbackExecutorService);
break;
case ASSIGNED_TO_CUSTOMER:
case UNASSIGNED_FROM_CUSTOMER:
edgeIdsFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId);
Futures.addCallback(edgeIdsFuture, new FutureCallback<List<EdgeId>>() {
@Override
public void onSuccess(@Nullable List<EdgeId> edgeIds) {
if (edgeIds != null && !edgeIds.isEmpty()) {
for (EdgeId edgeId : edgeIds) {
try {
CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class);
ListenableFuture<Edge> future = edgeService.findEdgeByIdAsync(tenantId, edgeId);
Futures.addCallback(future, new FutureCallback<Edge>() {
@Override
public void onSuccess(@Nullable Edge edge) {
if (edge != null && edge.getCustomerId() != null &&
!edge.getCustomerId().isNullUid() && edge.getCustomerId().equals(customerId)) {
saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null);
}
}
@Override
public void onFailure(Throwable throwable) {
log.error("Failed to find edge by id [{}]", edgeNotificationMsg, throwable);
}
}, dbCallbackExecutorService);
} catch (Exception e) {
log.error("Can't parse customer id from entity body [{}]", edgeNotificationMsg, e);
} }
} catch (Exception e) {
log.error("[{}] Failed to push event to edge, edgeId [{}], edgeEventType [{}], edgeEventActionType [{}], entityId [{}]",
tenantId, edgeId, edgeEventType, edgeEventActionType, entityId, e);
} }
} }
} }
return null;
@Override
public void onFailure(Throwable throwable) {
log.error("Failed to find related edge ids [{}]", edgeNotificationMsg, throwable);
}
}, dbCallbackExecutorService); }, dbCallbackExecutorService);
break; break;
case DELETED: case DELETED:
PageData<Edge> edgesByTenantId = edgeService.findEdgesByTenantId(tenantId, new PageLink(Integer.MAX_VALUE)); PageData<Edge> edgesByTenantId = edgeService.findEdgesByTenantId(tenantId, new PageLink(Integer.MAX_VALUE));
if (edgesByTenantId != null && edgesByTenantId.getData() != null && !edgesByTenantId.getData().isEmpty()) { if (edgesByTenantId != null && edgesByTenantId.getData() != null && !edgesByTenantId.getData().isEmpty()) {
for (Edge edge : edgesByTenantId.getData()) { for (Edge edge : edgesByTenantId.getData()) {
saveEdgeEvent(tenantId, edge.getId(), edgeEventType, edgeEventActionType, entityId, null); saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, null);
} }
} }
break; break;
case ASSIGNED_TO_EDGE: case ASSIGNED_TO_EDGE:
case UNASSIGNED_FROM_EDGE: case UNASSIGNED_FROM_EDGE:
EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB())); EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
saveEdgeEvent(tenantId, edgeId, edgeEventType, edgeEventActionType, entityId, null); saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null);
break; if (type.equals(EdgeEventType.RULE_CHAIN)) {
case RELATIONS_DELETED: updateDependentRuleChains(tenantId, new RuleChainId(entityId.getId()), edgeId);
// TODO: voba - add support for relations deleted }
break; break;
} }
} }
private void updateDependentRuleChains(TenantId tenantId, RuleChainId processingRuleChainId, EdgeId edgeId) {
PageData<RuleChain> pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, new TimePageLink(Integer.MAX_VALUE));
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
for (RuleChain ruleChain : pageData.getData()) {
if (!ruleChain.getId().equals(processingRuleChainId)) {
List<RuleChainConnectionInfo> connectionInfos =
ruleChainService.loadRuleChainMetaData(ruleChain.getTenantId(), ruleChain.getId()).getRuleChainConnections();
if (connectionInfos != null && !connectionInfos.isEmpty()) {
for (RuleChainConnectionInfo connectionInfo : connectionInfos) {
if (connectionInfo.getTargetRuleChainId().equals(processingRuleChainId)) {
saveEdgeEvent(tenantId,
edgeId,
EdgeEventType.RULE_CHAIN_METADATA,
ActionType.UPDATED,
ruleChain.getId(),
null);
}
}
}
}
}
}
}
private void processAlarm(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { private void processAlarm(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
AlarmId alarmId = new AlarmId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); AlarmId alarmId = new AlarmId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
ListenableFuture<Alarm> alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId); ListenableFuture<Alarm> alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId);
Futures.transform(alarmFuture, alarm -> { Futures.transform(alarmFuture, alarm -> {
if (alarm != null) { if (alarm != null) {
EdgeEventType edgeEventType = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType()); EdgeEventType type = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType());
if (edgeEventType != null) { if (type != null) {
ListenableFuture<List<EdgeId>> relatedEdgeIdsByEntityIdFuture = findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator()); ListenableFuture<List<EdgeId>> relatedEdgeIdsByEntityIdFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator());
Futures.transform(relatedEdgeIdsByEntityIdFuture, relatedEdgeIdsByEntityId -> { Futures.transform(relatedEdgeIdsByEntityIdFuture, relatedEdgeIdsByEntityId -> {
if (relatedEdgeIdsByEntityId != null) { if (relatedEdgeIdsByEntityId != null) {
for (EdgeId edgeId : relatedEdgeIdsByEntityId) { for (EdgeId edgeId : relatedEdgeIdsByEntityId) {
saveEdgeEvent(tenantId, saveEdgeEvent(tenantId,
edgeId, edgeId,
EdgeEventType.ALARM, EdgeEventType.ALARM,
ActionType.valueOf(edgeNotificationMsg.getEdgeEventAction()), ActionType.valueOf(edgeNotificationMsg.getAction()),
alarmId, alarmId,
null); null);
} }
@ -243,67 +405,38 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
}, dbCallbackExecutorService); }, dbCallbackExecutorService);
} }
private void processRelation(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { private void processRelation(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) throws JsonProcessingException {
EntityRelation entityRelation = mapper.convertValue(edgeNotificationMsg.getEntityBody(), EntityRelation.class); EntityRelation relation = mapper.readValue(edgeNotificationMsg.getBody(), EntityRelation.class);
List<ListenableFuture<List<EdgeId>>> futures = new ArrayList<>(); if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
futures.add(findRelatedEdgeIdsByEntityId(tenantId, entityRelation.getTo())); !relation.getTo().getEntityType().equals(EntityType.EDGE)) {
futures.add(findRelatedEdgeIdsByEntityId(tenantId, entityRelation.getFrom())); List<ListenableFuture<List<EdgeId>>> futures = new ArrayList<>();
ListenableFuture<List<List<EdgeId>>> combinedFuture = Futures.allAsList(futures); futures.add(edgeService.findRelatedEdgeIdsByEntityId(tenantId, relation.getTo()));
Futures.transform(combinedFuture, listOfListsEdgeIds -> { futures.add(edgeService.findRelatedEdgeIdsByEntityId(tenantId, relation.getFrom()));
Set<EdgeId> uniqueEdgeIds = new HashSet<>(); ListenableFuture<List<List<EdgeId>>> combinedFuture = Futures.allAsList(futures);
if (listOfListsEdgeIds != null && !listOfListsEdgeIds.isEmpty()) { Futures.transform(combinedFuture, listOfListsEdgeIds -> {
for (List<EdgeId> listOfListsEdgeId : listOfListsEdgeIds) { Set<EdgeId> uniqueEdgeIds = new HashSet<>();
if (listOfListsEdgeId != null) { if (listOfListsEdgeIds != null && !listOfListsEdgeIds.isEmpty()) {
uniqueEdgeIds.addAll(listOfListsEdgeId); for (List<EdgeId> listOfListsEdgeId : listOfListsEdgeIds) {
if (listOfListsEdgeId != null) {
uniqueEdgeIds.addAll(listOfListsEdgeId);
}
} }
} }
} if (!uniqueEdgeIds.isEmpty()) {
if (!uniqueEdgeIds.isEmpty()) { for (EdgeId edgeId : uniqueEdgeIds) {
for (EdgeId edgeId : uniqueEdgeIds) { saveEdgeEvent(tenantId,
saveEdgeEvent(tenantId, edgeId,
edgeId, EdgeEventType.RELATION,
EdgeEventType.RELATION, ActionType.valueOf(edgeNotificationMsg.getAction()),
ActionType.valueOf(edgeNotificationMsg.getEdgeEventAction()), null,
null, mapper.valueToTree(relation));
mapper.valueToTree(entityRelation));
}
}
return null;
}, dbCallbackExecutorService);
}
private ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) {
switch (entityId.getEntityType()) {
case DEVICE:
case ASSET:
case ENTITY_VIEW:
ListenableFuture<List<EntityRelation>> originatorEdgeRelationsFuture = relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
return Futures.transform(originatorEdgeRelationsFuture, originatorEdgeRelations -> {
if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) {
return Collections.singletonList(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId()));
} else {
return Collections.emptyList();
} }
}, dbCallbackExecutorService); }
case DASHBOARD: return null;
return convertToEdgeIds(edgeService.findEdgesByTenantIdAndDashboardId(tenantId, new DashboardId(entityId.getId()))); }, dbCallbackExecutorService);
case RULE_CHAIN:
return convertToEdgeIds(edgeService.findEdgesByTenantIdAndRuleChainId(tenantId, new RuleChainId(entityId.getId())));
default:
return Futures.immediateFuture(Collections.emptyList());
} }
} }
private ListenableFuture<List<EdgeId>> convertToEdgeIds(ListenableFuture<List<Edge>> future) {
return Futures.transform(future, edges -> {
if (edges != null && !edges.isEmpty()) {
return edges.stream().map(IdBased::getId).collect(Collectors.toList());
} else {
return Collections.emptyList();
}
}, dbCallbackExecutorService);
}
private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) { private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) {
switch (entityType) { switch (entityType) {
case DEVICE: case DEVICE:
@ -313,7 +446,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
case ENTITY_VIEW: case ENTITY_VIEW:
return EdgeEventType.ENTITY_VIEW; return EdgeEventType.ENTITY_VIEW;
default: default:
log.info("Unsupported entity type: [{}]", entityType); log.debug("Unsupported entity type: [{}]", entityType);
return null; return null;
} }
} }

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

@ -33,22 +33,35 @@ import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.rpc.EdgeEventStorageSettings; import org.thingsboard.server.service.edge.rpc.EdgeEventStorageSettings;
import org.thingsboard.server.service.edge.rpc.constructor.AlarmUpdateMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.AdminSettingsMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.AssetUpdateMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.AlarmMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DashboardUpdateMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.AssetMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DeviceUpdateMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.CustomerMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DashboardMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DeviceMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.EntityDataMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.EntityDataMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.EntityViewMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.RelationUpdateMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.RelationMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.RuleChainMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.UserUpdateMsgConstructor; import org.thingsboard.server.service.edge.rpc.constructor.UserMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.WidgetTypeMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.WidgetsBundleMsgConstructor;
import org.thingsboard.server.service.edge.rpc.init.SyncEdgeService; import org.thingsboard.server.service.edge.rpc.init.SyncEdgeService;
import org.thingsboard.server.service.edge.rpc.processor.AlarmProcessor;
import org.thingsboard.server.service.edge.rpc.processor.DeviceProcessor;
import org.thingsboard.server.service.edge.rpc.processor.RelationProcessor;
import org.thingsboard.server.service.edge.rpc.processor.TelemetryProcessor;
import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.queue.TbClusterService; import org.thingsboard.server.service.queue.TbClusterService;
import org.thingsboard.server.service.state.DeviceStateService; import org.thingsboard.server.service.state.DeviceStateService;
@Component @Component
@TbCoreComponent
@Data @Data
public class EdgeContextComponent { public class EdgeContextComponent {
@ -56,6 +69,9 @@ public class EdgeContextComponent {
@Autowired @Autowired
private EdgeService edgeService; private EdgeService edgeService;
@Autowired
private PartitionService partitionService;
@Lazy @Lazy
@Autowired @Autowired
private EdgeNotificationService edgeNotificationService; private EdgeNotificationService edgeNotificationService;
@ -108,6 +124,14 @@ public class EdgeContextComponent {
@Autowired @Autowired
private ActorService actorService; private ActorService actorService;
@Lazy
@Autowired
private WidgetsBundleService widgetsBundleService;
@Lazy
@Autowired
private WidgetTypeService widgetTypeService;
@Lazy @Lazy
@Autowired @Autowired
private DeviceStateService deviceStateService; private DeviceStateService deviceStateService;
@ -122,40 +146,72 @@ public class EdgeContextComponent {
@Lazy @Lazy
@Autowired @Autowired
private RuleChainUpdateMsgConstructor ruleChainUpdateMsgConstructor; private RuleChainMsgConstructor ruleChainMsgConstructor;
@Lazy
@Autowired
private AlarmMsgConstructor alarmMsgConstructor;
@Lazy
@Autowired
private DeviceMsgConstructor deviceMsgConstructor;
@Lazy
@Autowired
private AssetMsgConstructor assetMsgConstructor;
@Lazy
@Autowired
private EntityViewMsgConstructor entityViewMsgConstructor;
@Lazy @Lazy
@Autowired @Autowired
private AlarmUpdateMsgConstructor alarmUpdateMsgConstructor; private DashboardMsgConstructor dashboardMsgConstructor;
@Lazy @Lazy
@Autowired @Autowired
private DeviceUpdateMsgConstructor deviceUpdateMsgConstructor; private CustomerMsgConstructor customerMsgConstructor;
@Lazy @Lazy
@Autowired @Autowired
private AssetUpdateMsgConstructor assetUpdateMsgConstructor; private UserMsgConstructor userMsgConstructor;
@Lazy @Lazy
@Autowired @Autowired
private EntityViewUpdateMsgConstructor entityViewUpdateMsgConstructor; private RelationMsgConstructor relationMsgConstructor;
@Lazy @Lazy
@Autowired @Autowired
private DashboardUpdateMsgConstructor dashboardUpdateMsgConstructor; private WidgetsBundleMsgConstructor widgetsBundleMsgConstructor;
@Lazy @Lazy
@Autowired @Autowired
private UserUpdateMsgConstructor userUpdateMsgConstructor; private WidgetTypeMsgConstructor widgetTypeMsgConstructor;
@Lazy @Lazy
@Autowired @Autowired
private RelationUpdateMsgConstructor relationUpdateMsgConstructor; private AdminSettingsMsgConstructor adminSettingsMsgConstructor;
@Lazy @Lazy
@Autowired @Autowired
private EntityDataMsgConstructor entityDataMsgConstructor; private EntityDataMsgConstructor entityDataMsgConstructor;
@Lazy
@Autowired
private AlarmProcessor alarmProcessor;
@Lazy
@Autowired
private DeviceProcessor deviceProcessor;
@Lazy
@Autowired
private RelationProcessor relationProcessor;
@Lazy
@Autowired
private TelemetryProcessor telemetryProcessor;
@Lazy @Lazy
@Autowired @Autowired
private EdgeEventStorageSettings edgeEventStorageSettings; private EdgeEventStorageSettings edgeEventStorageSettings;

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

@ -17,38 +17,47 @@ package org.thingsboard.server.service.edge.rpc;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.Resources; import com.google.common.io.Resources;
import com.google.common.util.concurrent.FutureCallback;
import io.grpc.Server; import io.grpc.Server;
import io.grpc.ServerBuilder; import io.grpc.netty.NettyServerBuilder;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; 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.common.data.DataConstants;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
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.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.BooleanDataEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
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;
import org.thingsboard.server.gen.edge.ResponseMsg; import org.thingsboard.server.gen.edge.ResponseMsg;
import org.thingsboard.server.service.edge.EdgeContextComponent; import org.thingsboard.server.service.edge.EdgeContextComponent;
import org.thingsboard.server.service.state.DefaultDeviceStateService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@Service @Service
@Slf4j @Slf4j
@ConditionalOnProperty(prefix = "edges.rpc", value = "enabled", havingValue = "true") @ConditionalOnProperty(prefix = "edges.rpc", value = "enabled", havingValue = "true")
public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase { public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase implements EdgeRpcService {
private final Map<EdgeId, EdgeGrpcSession> sessions = new ConcurrentHashMap<>(); private final Map<EdgeId, EdgeGrpcSession> sessions = new ConcurrentHashMap<>();
private static final ObjectMapper objectMapper = new ObjectMapper(); private static final ObjectMapper mapper = new ObjectMapper();
@Value("${edges.rpc.port}") @Value("${edges.rpc.port}")
private int rpcPort; private int rpcPort;
@ -58,10 +67,17 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase {
private String certFileResource; private String certFileResource;
@Value("${edges.rpc.ssl.private_key}") @Value("${edges.rpc.ssl.private_key}")
private String privateKeyResource; private String privateKeyResource;
@Value("${edges.state.persistToTelemetry:false}")
private boolean persistToTelemetry;
@Value("${edges.rpc.client_max_keep_alive_time_sec}")
private int clientMaxKeepAliveTimeSec;
@Autowired @Autowired
private EdgeContextComponent ctx; private EdgeContextComponent ctx;
@Autowired
private TelemetrySubscriptionService tsSubService;
private Server server; private Server server;
private ExecutorService executor; private ExecutorService executor;
@ -69,7 +85,9 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase {
@PostConstruct @PostConstruct
public void init() { public void init() {
log.info("Initializing Edge RPC service!"); log.info("Initializing Edge RPC service!");
ServerBuilder builder = ServerBuilder.forPort(rpcPort).addService(this); NettyServerBuilder builder = NettyServerBuilder.forPort(rpcPort)
.permitKeepAliveTime(clientMaxKeepAliveTimeSec, TimeUnit.SECONDS)
.addService(this);
if (sslEnabled) { if (sslEnabled) {
try { try {
File certFile = new File(Resources.getResource(certFileResource).toURI()); File certFile = new File(Resources.getResource(certFileResource).toURI());
@ -102,22 +120,60 @@ 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, objectMapper).getInputStream(); return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, mapper).getInputStream();
}
@Override
public void updateEdge(Edge edge) {
EdgeGrpcSession session = sessions.get(edge.getId());
if (session != null && session.isConnected()) {
session.onConfigurationUpdate(edge);
}
}
@Override
public void deleteEdge(EdgeId edgeId) {
EdgeGrpcSession session = sessions.get(edgeId);
if (session != null && session.isConnected()) {
session.close();
sessions.remove(edgeId);
}
} }
private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) { private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) {
sessions.put(edgeId, edgeGrpcSession); sessions.put(edgeId, edgeGrpcSession);
save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true);
save(edgeId, DefaultDeviceStateService.LAST_CONNECT_TIME, System.currentTimeMillis());
}
public EdgeGrpcSession getEdgeGrpcSessionById(EdgeId edgeId) {
EdgeGrpcSession session = sessions.get(edgeId);
if (session != null && session.isConnected()) {
return session;
} else {
throw new RuntimeException("Edge is not connected");
}
} }
private void processHandleMessages() { private void processHandleMessages() {
executor.submit(() -> { executor.submit(() -> {
while (!Thread.interrupted()) { while (!Thread.interrupted()) {
try { try {
for (EdgeGrpcSession session : sessions.values()) { if (sessions.size() > 0) {
session.processHandleMessages(); for (EdgeGrpcSession session : sessions.values()) {
session.processHandleMessages();
}
} else {
log.trace("No sessions available, sleep for the next run");
try {
Thread.sleep(1000);
} catch (InterruptedException ignore) {}
} }
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to process messages handling!", e); log.warn("Failed to process messages handling!", e);
try {
Thread.sleep(1000);
} catch (InterruptedException ignore) {}
} }
} }
}); });
@ -125,6 +181,51 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase {
private void onEdgeDisconnect(EdgeId edgeId) { private void onEdgeDisconnect(EdgeId edgeId) {
sessions.remove(edgeId); sessions.remove(edgeId);
save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false);
save(edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, System.currentTimeMillis());
} }
private void save(EdgeId edgeId, String key, long value) {
if (persistToTelemetry) {
tsSubService.saveAndNotify(
TenantId.SYS_TENANT_ID, edgeId,
Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry(key, value))),
new AttributeSaveCallback(edgeId, key, value));
} else {
tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(edgeId, key, value));
}
}
private void save(EdgeId edgeId, String key, boolean value) {
if (persistToTelemetry) {
tsSubService.saveAndNotify(
TenantId.SYS_TENANT_ID, edgeId,
Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new BooleanDataEntry(key, value))),
new AttributeSaveCallback(edgeId, key, value));
} else {
tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(edgeId, key, value));
}
}
private static class AttributeSaveCallback implements FutureCallback<Void> {
private final EdgeId edgeId;
private final String key;
private final Object value;
AttributeSaveCallback(EdgeId edgeId, String key, Object value) {
this.edgeId = edgeId;
this.key = key;
this.value = value;
}
@Override
public void onSuccess(@javax.annotation.Nullable Void result) {
log.trace("[{}] Successfully updated attribute [{}] with value [{}]", edgeId, key, value);
}
@Override
public void onFailure(Throwable t) {
log.warn("[{}] Failed to update attribute [{}] with value [{}]", edgeId, key, value, t);
}
}
} }

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

File diff suppressed because it is too large

26
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeRpcService.java

@ -0,0 +1,26 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.EdgeId;
public interface EdgeRpcService {
void updateEdge(Edge edge);
void deleteEdge(EdgeId edgeId);
}

38
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AdminSettingsMsgConstructor.java

@ -0,0 +1,38 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.AdminSettingsUpdateMsg;
@Slf4j
@Component
public class AdminSettingsMsgConstructor {
public AdminSettingsUpdateMsg constructAdminSettingsUpdateMsg(AdminSettings adminSettings) {
AdminSettingsUpdateMsg.Builder builder = AdminSettingsUpdateMsg.newBuilder()
.setKey(adminSettings.getKey())
.setJsonValue(JacksonUtil.toString(adminSettings.getJsonValue()));
if (adminSettings.getId() != null) {
builder.setIsSystem(true);
}
return builder.build();
}
}

2
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmUpdateMsgConstructor.java → application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java

@ -34,7 +34,7 @@ import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component @Component
@Slf4j @Slf4j
public class AlarmUpdateMsgConstructor { public class AlarmMsgConstructor {
@Autowired @Autowired
private DeviceService deviceService; private DeviceService deviceService;

13
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AssetUpdateMsgConstructor.java → application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AssetMsgConstructor.java

@ -19,14 +19,16 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
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.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.AssetUpdateMsg; import org.thingsboard.server.gen.edge.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType; import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component @Component
@Slf4j @Slf4j
public class AssetUpdateMsgConstructor { public class AssetMsgConstructor {
public AssetUpdateMsg constructAssetUpdatedMsg(UpdateMsgType msgType, Asset asset) { public AssetUpdateMsg constructAssetUpdatedMsg(UpdateMsgType msgType, Asset asset, CustomerId customerId) {
AssetUpdateMsg.Builder builder = AssetUpdateMsg.newBuilder() AssetUpdateMsg.Builder builder = AssetUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
.setIdMSB(asset.getId().getId().getMostSignificantBits()) .setIdMSB(asset.getId().getId().getMostSignificantBits())
@ -36,6 +38,13 @@ public class AssetUpdateMsgConstructor {
if (asset.getLabel() != null) { if (asset.getLabel() != null) {
builder.setLabel(asset.getLabel()); builder.setLabel(asset.getLabel());
} }
if (customerId != null) {
builder.setCustomerIdMSB(customerId.getId().getMostSignificantBits());
builder.setCustomerIdLSB(customerId.getId().getLeastSignificantBits());
}
if (asset.getAdditionalInfo() != null) {
builder.setAdditionalInfo(JacksonUtil.toString(asset.getAdditionalInfo()));
}
return builder.build(); return builder.build();
} }

72
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/CustomerMsgConstructor.java

@ -0,0 +1,72 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.CustomerUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component
@Slf4j
public class CustomerMsgConstructor {
public CustomerUpdateMsg constructCustomerUpdatedMsg(UpdateMsgType msgType, Customer customer) {
CustomerUpdateMsg.Builder builder = CustomerUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(customer.getId().getId().getMostSignificantBits())
.setIdLSB(customer.getId().getId().getLeastSignificantBits())
.setTitle(customer.getTitle());
if (customer.getCountry() != null) {
builder.setCountry(customer.getCountry());
}
if (customer.getState() != null) {
builder.setState(customer.getState());
}
if (customer.getCity() != null) {
builder.setCity(customer.getCity());
}
if (customer.getAddress() != null) {
builder.setAddress(customer.getAddress());
}
if (customer.getAddress2() != null) {
builder.setAddress2(customer.getAddress2());
}
if (customer.getZip() != null) {
builder.setZip(customer.getZip());
}
if (customer.getPhone() != null) {
builder.setPhone(customer.getPhone());
}
if (customer.getEmail() != null) {
builder.setEmail(customer.getEmail());
}
if (customer.getAdditionalInfo() != null) {
builder.setAdditionalInfo(JacksonUtil.toString(customer.getAdditionalInfo()));
}
return builder.build();
}
public CustomerUpdateMsg constructCustomerDeleteMsg(CustomerId customerId) {
return CustomerUpdateMsg.newBuilder()
.setMsgType(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE)
.setIdMSB(customerId.getId().getMostSignificantBits())
.setIdLSB(customerId.getId().getLeastSignificantBits()).build();
}
}

16
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardUpdateMsgConstructor.java → application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardMsgConstructor.java

@ -16,30 +16,30 @@
package org.thingsboard.server.service.edge.rpc.constructor; package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.dao.util.mapping.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.DashboardUpdateMsg; import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType; import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component @Component
@Slf4j @Slf4j
public class DashboardUpdateMsgConstructor { public class DashboardMsgConstructor {
@Autowired public DashboardUpdateMsg constructDashboardUpdatedMsg(UpdateMsgType msgType, Dashboard dashboard, CustomerId customerId) {
private DashboardService dashboardService;
public DashboardUpdateMsg constructDashboardUpdatedMsg(UpdateMsgType msgType, Dashboard dashboard) {
dashboard = dashboardService.findDashboardById(dashboard.getTenantId(), dashboard.getId());
DashboardUpdateMsg.Builder builder = DashboardUpdateMsg.newBuilder() DashboardUpdateMsg.Builder builder = DashboardUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
.setIdMSB(dashboard.getId().getId().getMostSignificantBits()) .setIdMSB(dashboard.getId().getId().getMostSignificantBits())
.setIdLSB(dashboard.getId().getId().getLeastSignificantBits()) .setIdLSB(dashboard.getId().getId().getLeastSignificantBits())
.setTitle(dashboard.getTitle()) .setTitle(dashboard.getTitle())
.setConfiguration(JacksonUtil.toString(dashboard.getConfiguration())); .setConfiguration(JacksonUtil.toString(dashboard.getConfiguration()));
if (customerId != null) {
builder.setCustomerIdMSB(customerId.getId().getMostSignificantBits());
builder.setCustomerIdLSB(customerId.getId().getLeastSignificantBits());
}
return builder.build(); return builder.build();
} }

97
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceMsgConstructor.java

@ -0,0 +1,97 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc.constructor;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.DeviceRpcCallMsg;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.RpcRequestMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component
@Slf4j
public class DeviceMsgConstructor {
protected static final ObjectMapper mapper = new ObjectMapper();
public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device, CustomerId customerId) {
DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(device.getId().getId().getMostSignificantBits())
.setIdLSB(device.getId().getId().getLeastSignificantBits())
.setName(device.getName())
.setType(device.getType());
if (device.getLabel() != null) {
builder.setLabel(device.getLabel());
}
if (customerId != null) {
builder.setCustomerIdMSB(customerId.getId().getMostSignificantBits());
builder.setCustomerIdLSB(customerId.getId().getLeastSignificantBits());
}
if (device.getAdditionalInfo() != null) {
builder.setAdditionalInfo(JacksonUtil.toString(device.getAdditionalInfo()));
}
return builder.build();
}
public DeviceCredentialsUpdateMsg constructDeviceCredentialsUpdatedMsg(DeviceCredentials deviceCredentials) {
DeviceCredentialsUpdateMsg.Builder builder = DeviceCredentialsUpdateMsg.newBuilder()
.setDeviceIdMSB(deviceCredentials.getDeviceId().getId().getMostSignificantBits())
.setDeviceIdLSB(deviceCredentials.getDeviceId().getId().getLeastSignificantBits());
if (deviceCredentials.getCredentialsType() != null) {
builder.setCredentialsType(deviceCredentials.getCredentialsType().name())
.setCredentialsId(deviceCredentials.getCredentialsId());
}
if (deviceCredentials.getCredentialsValue() != null) {
builder.setCredentialsValue(deviceCredentials.getCredentialsValue());
}
return builder.build();
}
public DeviceUpdateMsg constructDeviceDeleteMsg(DeviceId deviceId) {
return DeviceUpdateMsg.newBuilder()
.setMsgType(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE)
.setIdMSB(deviceId.getId().getMostSignificantBits())
.setIdLSB(deviceId.getId().getLeastSignificantBits()).build();
}
public DeviceRpcCallMsg constructDeviceRpcCallMsg(JsonNode body) {
RuleEngineDeviceRpcRequest request = mapper.convertValue(body, RuleEngineDeviceRpcRequest.class);
RpcRequestMsg.Builder requestBuilder = RpcRequestMsg.newBuilder();
requestBuilder.setMethod(request.getMethod());
requestBuilder.setParams(request.getBody());
DeviceRpcCallMsg.Builder builder = DeviceRpcCallMsg.newBuilder()
.setDeviceIdMSB(request.getDeviceId().getId().getMostSignificantBits())
.setDeviceIdLSB(request.getDeviceId().getId().getLeastSignificantBits())
.setRequestIdMSB(request.getRequestUUID().getMostSignificantBits())
.setRequestIdLSB(request.getRequestUUID().getLeastSignificantBits())
.setExpirationTime(request.getExpirationTime())
.setOriginServiceId(request.getOriginServiceId())
.setOneway(request.isOneway())
.setRequestMsg(requestBuilder.build());
return builder.build();
}
}

69
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceUpdateMsgConstructor.java

@ -1,69 +0,0 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component
@Slf4j
public class DeviceUpdateMsgConstructor {
@Autowired
private DeviceCredentialsService deviceCredentialsService;
public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device) {
DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(device.getId().getId().getMostSignificantBits())
.setIdLSB(device.getId().getId().getLeastSignificantBits())
.setName(device.getName())
.setType(device.getType());
if (device.getLabel() != null) {
builder.setLabel(device.getLabel());
}
if (msgType.equals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE) ||
msgType.equals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE) ||
msgType.equals(UpdateMsgType.DEVICE_CONFLICT_RPC_MESSAGE)) {
DeviceCredentials deviceCredentials
= deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), device.getId());
if (deviceCredentials != null) {
if (deviceCredentials.getCredentialsType() != null) {
builder.setCredentialsType(deviceCredentials.getCredentialsType().name())
.setCredentialsId(deviceCredentials.getCredentialsId());
}
if (deviceCredentials.getCredentialsValue() != null) {
builder.setCredentialsValue(deviceCredentials.getCredentialsValue());
}
}
}
return builder.build();
}
public DeviceUpdateMsg constructDeviceDeleteMsg(DeviceId deviceId) {
return DeviceUpdateMsg.newBuilder()
.setMsgType(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE)
.setIdMSB(deviceId.getId().getMostSignificantBits())
.setIdLSB(deviceId.getId().getLeastSignificantBits()).build();
}
}

40
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java

@ -15,13 +15,20 @@
*/ */
package org.thingsboard.server.service.edge.rpc.constructor; package org.thingsboard.server.service.edge.rpc.constructor;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.gen.edge.AttributeDeleteMsg;
import org.thingsboard.server.gen.edge.EntityDataProto; import org.thingsboard.server.gen.edge.EntityDataProto;
import org.thingsboard.server.gen.transport.TransportProtos;
import java.util.List;
@Component @Component
@Slf4j @Slf4j
@ -35,20 +42,45 @@ public class EntityDataMsgConstructor {
switch (actionType) { switch (actionType) {
case TIMESERIES_UPDATED: case TIMESERIES_UPDATED:
try { try {
builder.setPostTelemetryMsg(JsonConverter.convertToTelemetryProto(entityData)); JsonObject data = entityData.getAsJsonObject();
long ts;
if (data.get("ts") != null && !data.get("ts").isJsonNull()) {
ts = data.getAsJsonPrimitive("ts").getAsLong();
} else {
ts = System.currentTimeMillis();
}
builder.setPostTelemetryMsg(JsonConverter.convertToTelemetryProto(data.getAsJsonObject("data"), ts));
} catch (Exception e) { } catch (Exception e) {
log.warn("Can't convert to telemetry proto, entityData [{}]", entityData, e); log.warn("Can't convert to telemetry proto, entityData [{}]", entityData, e);
} }
break; break;
case ATTRIBUTES_UPDATED: case ATTRIBUTES_UPDATED:
try { try {
builder.setPostAttributesMsg(JsonConverter.convertToAttributesProto(entityData)); JsonObject data = entityData.getAsJsonObject();
TransportProtos.PostAttributeMsg postAttributeMsg = JsonConverter.convertToAttributesProto(data.getAsJsonObject("kv"));
if (data.has("isPostAttributes") && data.getAsJsonPrimitive("isPostAttributes").getAsBoolean()) {
builder.setPostAttributesMsg(postAttributeMsg);
} else {
builder.setAttributesUpdatedMsg(postAttributeMsg);
}
builder.setPostAttributeScope(data.getAsJsonPrimitive("scope").getAsString());
} catch (Exception e) { } catch (Exception e) {
log.warn("Can't convert to attributes proto, entityData [{}]", entityData, e); log.warn("Can't convert to attributes proto, entityData [{}]", entityData, e);
} }
break; break;
// TODO: voba - add support for attribute delete case ATTRIBUTES_DELETED:
// case ATTRIBUTES_DELETED: try {
AttributeDeleteMsg.Builder attributeDeleteMsg = AttributeDeleteMsg.newBuilder();
attributeDeleteMsg.setScope(entityData.getAsJsonObject().getAsJsonPrimitive("scope").getAsString());
JsonArray jsonArray = entityData.getAsJsonObject().getAsJsonArray("keys");
List<String> keys = new Gson().fromJson(jsonArray.toString(), List.class);
attributeDeleteMsg.addAllAttributeNames(keys);
attributeDeleteMsg.build();
builder.setAttributeDeleteMsg(attributeDeleteMsg);
} catch (Exception e) {
log.warn("Can't convert to AttributeDeleteMsg proto, entityData [{}]", entityData, e);
}
break;
} }
return builder.build(); return builder.build();
} }

17
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityViewUpdateMsgConstructor.java → application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityViewMsgConstructor.java

@ -18,16 +18,18 @@ package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.EdgeEntityType; import org.thingsboard.server.gen.edge.EdgeEntityType;
import org.thingsboard.server.gen.edge.EntityViewUpdateMsg; import org.thingsboard.server.gen.edge.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType; import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component @Component
@Slf4j @Slf4j
public class EntityViewUpdateMsgConstructor { public class EntityViewMsgConstructor {
public EntityViewUpdateMsg constructEntityViewUpdatedMsg(UpdateMsgType msgType, EntityView entityView) { public EntityViewUpdateMsg constructEntityViewUpdatedMsg(UpdateMsgType msgType, EntityView entityView, CustomerId customerId) {
EdgeEntityType entityType; EdgeEntityType entityType;
switch (entityView.getEntityId().getEntityType()) { switch (entityView.getEntityId().getEntityType()) {
case DEVICE: case DEVICE:
@ -45,9 +47,16 @@ public class EntityViewUpdateMsgConstructor {
.setIdLSB(entityView.getId().getId().getLeastSignificantBits()) .setIdLSB(entityView.getId().getId().getLeastSignificantBits())
.setName(entityView.getName()) .setName(entityView.getName())
.setType(entityView.getType()) .setType(entityView.getType())
.setIdMSB(entityView.getEntityId().getId().getMostSignificantBits()) .setEntityIdMSB(entityView.getEntityId().getId().getMostSignificantBits())
.setIdLSB(entityView.getEntityId().getId().getLeastSignificantBits()) .setEntityIdLSB(entityView.getEntityId().getId().getLeastSignificantBits())
.setEntityType(entityType); .setEntityType(entityType);
if (customerId != null) {
builder.setCustomerIdMSB(customerId.getId().getMostSignificantBits());
builder.setCustomerIdLSB(customerId.getId().getLeastSignificantBits());
}
if (entityView.getAdditionalInfo() != null) {
builder.setAdditionalInfo(JacksonUtil.toString(entityView.getAdditionalInfo()));
}
return builder.build(); return builder.build();
} }

2
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RelationUpdateMsgConstructor.java → application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RelationMsgConstructor.java

@ -24,7 +24,7 @@ import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component @Component
@Slf4j @Slf4j
public class RelationUpdateMsgConstructor { public class RelationMsgConstructor {
public RelationUpdateMsg constructRelationUpdatedMsg(UpdateMsgType msgType, EntityRelation entityRelation) { public RelationUpdateMsg constructRelationUpdatedMsg(UpdateMsgType msgType, EntityRelation entityRelation) {
RelationUpdateMsg.Builder builder = RelationUpdateMsg.newBuilder() RelationUpdateMsg.Builder builder = RelationUpdateMsg.newBuilder()

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainUpdateMsgConstructor.java → application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java

@ -38,7 +38,7 @@ import java.util.List;
@Component @Component
@Slf4j @Slf4j
public class RuleChainUpdateMsgConstructor { public class RuleChainMsgConstructor {
private static final ObjectMapper objectMapper = new ObjectMapper(); private static final ObjectMapper objectMapper = new ObjectMapper();
@ -68,6 +68,8 @@ public class RuleChainUpdateMsgConstructor {
.addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections())); .addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections()));
if (ruleChainMetaData.getFirstNodeIndex() != null) { if (ruleChainMetaData.getFirstNodeIndex() != null) {
builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex()); builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex());
} else {
builder.setFirstNodeIndex(-1);
} }
builder.setMsgType(msgType); builder.setMsgType(msgType);
return builder.build(); return builder.build();

37
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/UserUpdateMsgConstructor.java → application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/UserMsgConstructor.java

@ -16,31 +16,34 @@
package org.thingsboard.server.service.edge.rpc.constructor; package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.dao.util.mapping.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.UpdateMsgType; import org.thingsboard.server.gen.edge.UpdateMsgType;
import org.thingsboard.server.gen.edge.UserCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.UserUpdateMsg; import org.thingsboard.server.gen.edge.UserUpdateMsg;
import java.util.UUID;
@Component @Component
@Slf4j @Slf4j
public class UserUpdateMsgConstructor { public class UserMsgConstructor {
@Autowired
private UserService userService;
public UserUpdateMsg constructUserUpdatedMsg(UpdateMsgType msgType, User user) { public UserUpdateMsg constructUserUpdatedMsg(UpdateMsgType msgType, User user, CustomerId customerId) {
UserUpdateMsg.Builder builder = UserUpdateMsg.newBuilder() UserUpdateMsg.Builder builder = UserUpdateMsg.newBuilder()
.setMsgType(msgType) .setMsgType(msgType)
.setIdMSB(user.getId().getId().getMostSignificantBits()) .setIdMSB(user.getId().getId().getMostSignificantBits())
.setIdLSB(user.getId().getId().getLeastSignificantBits()) .setIdLSB(user.getId().getId().getLeastSignificantBits())
.setEmail(user.getEmail()) .setEmail(user.getEmail())
.setAuthority(user.getAuthority().name()) .setAuthority(user.getAuthority().name());
.setEnabled(false); if (customerId != null) {
builder.setCustomerIdMSB(customerId.getId().getMostSignificantBits());
builder.setCustomerIdLSB(customerId.getId().getLeastSignificantBits());
}
if (user.getFirstName() != null) { if (user.getFirstName() != null) {
builder.setFirstName(user.getFirstName()); builder.setFirstName(user.getFirstName());
} }
@ -53,13 +56,6 @@ public class UserUpdateMsgConstructor {
if (user.getAdditionalInfo() != null) { if (user.getAdditionalInfo() != null) {
builder.setAdditionalInfo(JacksonUtil.toString(user.getAdditionalInfo())); builder.setAdditionalInfo(JacksonUtil.toString(user.getAdditionalInfo()));
} }
if (msgType.equals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE) ||
msgType.equals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE)) {
UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
if (userCredentials != null) {
builder.setEnabled(userCredentials.isEnabled()).setPassword(userCredentials.getPassword());
}
}
return builder.build(); return builder.build();
} }
@ -69,4 +65,13 @@ public class UserUpdateMsgConstructor {
.setIdMSB(userId.getId().getMostSignificantBits()) .setIdMSB(userId.getId().getMostSignificantBits())
.setIdLSB(userId.getId().getLeastSignificantBits()).build(); .setIdLSB(userId.getId().getLeastSignificantBits()).build();
} }
public UserCredentialsUpdateMsg constructUserCredentialsUpdatedMsg(UserCredentials userCredentials) {
UserCredentialsUpdateMsg.Builder builder = UserCredentialsUpdateMsg.newBuilder()
.setUserIdMSB(userCredentials.getUserId().getId().getMostSignificantBits())
.setUserIdLSB(userCredentials.getUserId().getId().getLeastSignificantBits())
.setEnabled(userCredentials.isEnabled())
.setPassword(userCredentials.getPassword());
return builder.build();
}
} }

61
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetTypeMsgConstructor.java

@ -0,0 +1,61 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.WidgetTypeId;
import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.UpdateMsgType;
import org.thingsboard.server.gen.edge.WidgetTypeUpdateMsg;
@Component
@Slf4j
public class WidgetTypeMsgConstructor {
public WidgetTypeUpdateMsg constructWidgetTypeUpdateMsg(UpdateMsgType msgType, WidgetType widgetType) {
WidgetTypeUpdateMsg.Builder builder = WidgetTypeUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(widgetType.getId().getId().getMostSignificantBits())
.setIdLSB(widgetType.getId().getId().getLeastSignificantBits());
if (widgetType.getBundleAlias() != null) {
builder.setBundleAlias(widgetType.getBundleAlias());
}
if (widgetType.getAlias() != null) {
builder.setAlias(widgetType.getAlias());
}
if (widgetType.getName() != null) {
builder.setName(widgetType.getName());
}
if (widgetType.getDescriptor() != null) {
builder.setDescriptorJson(JacksonUtil.toString(widgetType.getDescriptor()));
}
if (widgetType.getTenantId().equals(TenantId.SYS_TENANT_ID)) {
builder.setIsSystem(true);
}
return builder.build();
}
public WidgetTypeUpdateMsg constructWidgetTypeDeleteMsg(WidgetTypeId widgetTypeId) {
return WidgetTypeUpdateMsg.newBuilder()
.setMsgType(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE)
.setIdMSB(widgetTypeId.getId().getMostSignificantBits())
.setIdLSB(widgetTypeId.getId().getLeastSignificantBits())
.build();
}
}

54
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetsBundleMsgConstructor.java

@ -0,0 +1,54 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc.constructor;
import com.google.protobuf.ByteString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.WidgetsBundleId;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.gen.edge.UpdateMsgType;
import org.thingsboard.server.gen.edge.WidgetsBundleUpdateMsg;
@Component
@Slf4j
public class WidgetsBundleMsgConstructor {
public WidgetsBundleUpdateMsg constructWidgetsBundleUpdateMsg(UpdateMsgType msgType, WidgetsBundle widgetsBundle) {
WidgetsBundleUpdateMsg.Builder builder = WidgetsBundleUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(widgetsBundle.getId().getId().getMostSignificantBits())
.setIdLSB(widgetsBundle.getId().getId().getLeastSignificantBits())
.setTitle(widgetsBundle.getTitle())
.setAlias(widgetsBundle.getAlias());
if (widgetsBundle.getImage() != null) {
builder.setImage(ByteString.copyFrom(widgetsBundle.getImage()));
}
if (widgetsBundle.getTenantId().equals(TenantId.SYS_TENANT_ID)) {
builder.setIsSystem(true);
}
return builder.build();
}
public WidgetsBundleUpdateMsg constructWidgetsBundleDeleteMsg(WidgetsBundleId widgetsBundleId) {
return WidgetsBundleUpdateMsg.newBuilder()
.setMsgType(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE)
.setIdMSB(widgetsBundleId.getId().getMostSignificantBits())
.setIdLSB(widgetsBundleId.getId().getLeastSignificantBits())
.build();
}
}

549
application/src/main/java/org/thingsboard/server/service/edge/rpc/init/DefaultSyncEdgeService.java

@ -15,22 +15,44 @@
*/ */
package org.thingsboard.server.service.edge.rpc.init; package org.thingsboard.server.service.edge.rpc.init;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
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 com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AdminSettingsId;
import org.thingsboard.server.common.data.id.DeviceId;
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.EntityIdFactory;
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.UserId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.DataType;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
@ -39,45 +61,49 @@ import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
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.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService;
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.EdgeEventService;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.gen.edge.AssetUpdateMsg; import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.gen.edge.DashboardUpdateMsg; import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.AttributesRequestMsg;
import org.thingsboard.server.gen.edge.EntityUpdateMsg; import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.EntityViewUpdateMsg; import org.thingsboard.server.gen.edge.RelationRequestMsg;
import org.thingsboard.server.gen.edge.RelationUpdateMsg;
import org.thingsboard.server.gen.edge.ResponseMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg; import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.RuleChainUpdateMsg; import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.gen.edge.UpdateMsgType;
import org.thingsboard.server.gen.edge.UserUpdateMsg;
import org.thingsboard.server.service.edge.EdgeContextComponent;
import org.thingsboard.server.service.edge.rpc.constructor.AssetUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DashboardUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DeviceUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.RelationUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.UserUpdateMsgConstructor;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Service @Service
@Slf4j @Slf4j
public class DefaultSyncEdgeService implements SyncEdgeService { public class DefaultSyncEdgeService implements SyncEdgeService {
private static final ObjectMapper mapper = new ObjectMapper();
@Autowired
private EdgeEventService edgeEventService;
@Autowired
private AttributesService attributesService;
@Autowired @Autowired
private RuleChainService ruleChainService; private RuleChainService ruleChainService;
@ -100,272 +126,417 @@ public class DefaultSyncEdgeService implements SyncEdgeService {
private UserService userService; private UserService userService;
@Autowired @Autowired
private RuleChainUpdateMsgConstructor ruleChainUpdateMsgConstructor; private WidgetsBundleService widgetsBundleService;
@Autowired
private DeviceUpdateMsgConstructor deviceUpdateMsgConstructor;
@Autowired
private AssetUpdateMsgConstructor assetUpdateMsgConstructor;
@Autowired
private EntityViewUpdateMsgConstructor entityViewUpdateMsgConstructor;
@Autowired @Autowired
private DashboardUpdateMsgConstructor dashboardUpdateMsgConstructor; private WidgetTypeService widgetTypeService;
@Autowired @Autowired
private UserUpdateMsgConstructor userUpdateMsgConstructor; private AdminSettingsService adminSettingsService;
@Autowired @Autowired
private RelationUpdateMsgConstructor relationUpdateMsgConstructor; private DbCallbackExecutorService dbCallbackExecutorService;
@Override @Override
public void sync(EdgeContextComponent ctx, Edge edge, StreamObserver<ResponseMsg> outputStream) { public void sync(Edge edge) {
Set<EntityId> pushedEntityIds = new HashSet<>(); try {
syncUsers(ctx, edge, pushedEntityIds, outputStream); syncWidgetsBundleAndWidgetTypes(edge);
List<ListenableFuture<Void>> futures = new ArrayList<>(); syncAdminSettings(edge);
futures.add(syncRuleChains(ctx, edge, pushedEntityIds, outputStream)); syncRuleChains(edge);
futures.add(syncDevices(ctx, edge, pushedEntityIds, outputStream)); syncUsers(edge);
futures.add(syncAssets(ctx, edge, pushedEntityIds, outputStream)); syncDevices(edge);
futures.add(syncEntityViews(ctx, edge, pushedEntityIds, outputStream)); syncAssets(edge);
futures.add(syncDashboards(ctx, edge, pushedEntityIds, outputStream)); syncEntityViews(edge);
ListenableFuture<List<Void>> joinFuture = Futures.allAsList(futures); syncDashboards(edge);
Futures.transform(joinFuture, result -> { } catch (Exception e) {
syncRelations(ctx, edge, pushedEntityIds, outputStream); log.error("Exception during sync process", e);
return null; }
}, MoreExecutors.directExecutor());
} }
private ListenableFuture<Void> syncRuleChains(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncRuleChains(Edge edge) {
try { try {
PageData<RuleChain> pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE)); PageData<RuleChain> pageData =
ruleChainService.findRuleChainsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] rule chains(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] rule chains(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (RuleChain ruleChain : pageData.getData()) { for (RuleChain ruleChain : pageData.getData()) {
RuleChainUpdateMsg ruleChainUpdateMsg = saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.RULE_CHAIN, ActionType.ADDED, ruleChain.getId(), null);
ruleChainUpdateMsgConstructor.constructRuleChainUpdatedMsg(
edge.getRootRuleChainId(),
UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE,
ruleChain);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setRuleChainUpdateMsg(ruleChainUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(ruleChain.getId());
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge rule chain(s) on sync!", e); log.error("Exception during loading edge rule chain(s) on sync!", e);
} }
return Futures.immediateFuture(null);
} }
private ListenableFuture<Void> syncDevices(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncDevices(Edge edge) {
try { try {
PageData<Device> pageData = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE)); PageData<Device> pageData =
deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (Device device : pageData.getData()) { for (Device device : pageData.getData()) {
DeviceUpdateMsg deviceUpdateMsg = saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.DEVICE, ActionType.ADDED, device.getId(), null);
deviceUpdateMsgConstructor.constructDeviceUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
device);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setDeviceUpdateMsg(deviceUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(device.getId());
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge device(s) on sync!", e); log.error("Exception during loading edge device(s) on sync!", e);
} }
return Futures.immediateFuture(null);
} }
private ListenableFuture<Void> syncAssets(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncAssets(Edge edge) {
try { try {
PageData<Asset> pageData = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE)); PageData<Asset> pageData = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (Asset asset : pageData.getData()) { for (Asset asset : pageData.getData()) {
AssetUpdateMsg assetUpdateMsg = saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.ASSET, ActionType.ADDED, asset.getId(), null);
assetUpdateMsgConstructor.constructAssetUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
asset);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setAssetUpdateMsg(assetUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(asset.getId());
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge asset(s) on sync!", e); log.error("Exception during loading edge asset(s) on sync!", e);
} }
return Futures.immediateFuture(null);
} }
private ListenableFuture<Void> syncEntityViews(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncEntityViews(Edge edge) {
try { try {
PageData<EntityView> pageData = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE)); PageData<EntityView> pageData = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (EntityView entityView : pageData.getData()) { for (EntityView entityView : pageData.getData()) {
EntityViewUpdateMsg entityViewUpdateMsg = saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.ENTITY_VIEW, ActionType.ADDED, entityView.getId(), null);
entityViewUpdateMsgConstructor.constructEntityViewUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
entityView);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setEntityViewUpdateMsg(entityViewUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(entityView.getId());
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge entity view(s) on sync!", e); log.error("Exception during loading edge entity view(s) on sync!", e);
} }
return Futures.immediateFuture(null);
} }
private ListenableFuture<Void> syncDashboards(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncDashboards(Edge edge) {
try { try {
PageData<DashboardInfo> pageData = dashboardService.findDashboardsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE)); PageData<DashboardInfo> pageData = dashboardService.findDashboardsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), new TimePageLink(Integer.MAX_VALUE));
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] dashboard(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] dashboard(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (DashboardInfo dashboardInfo : pageData.getData()) { for (DashboardInfo dashboardInfo : pageData.getData()) {
Dashboard dashboard = dashboardService.findDashboardById(edge.getTenantId(), dashboardInfo.getId()); saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.DASHBOARD, ActionType.ADDED, dashboardInfo.getId(), null);
DashboardUpdateMsg dashboardUpdateMsg =
dashboardUpdateMsgConstructor.constructDashboardUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
dashboard);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setDashboardUpdateMsg(dashboardUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(dashboard.getId());
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge dashboard(s) on sync!", e); log.error("Exception during loading edge dashboard(s) on sync!", e);
} }
return Futures.immediateFuture(null);
} }
private void syncUsers(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncUsers(Edge edge) {
try { try {
PageData<User> pageData = userService.findTenantAdmins(edge.getTenantId(), new PageLink(Integer.MAX_VALUE)); PageData<User> pageData = userService.findTenantAdmins(edge.getTenantId(), new PageLink(Integer.MAX_VALUE));
pushUsersToEdge(pageData, edge, pushedEntityIds, outputStream); pushUsersToEdge(pageData, edge);
if (edge.getCustomerId() != null && !EntityId.NULL_UUID.equals(edge.getCustomerId().getId())) { if (edge.getCustomerId() != null && !EntityId.NULL_UUID.equals(edge.getCustomerId().getId())) {
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, ActionType.ADDED, edge.getCustomerId(), null);
pageData = userService.findCustomerUsers(edge.getTenantId(), edge.getCustomerId(), new PageLink(Integer.MAX_VALUE)); pageData = userService.findCustomerUsers(edge.getTenantId(), edge.getCustomerId(), new PageLink(Integer.MAX_VALUE));
pushUsersToEdge(pageData, edge, pushedEntityIds, outputStream); pushUsersToEdge(pageData, edge);
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge user(s) on sync!", e); log.error("Exception during loading edge user(s) on sync!", e);
} }
} }
private void pushUsersToEdge(PageData<User> pageData, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { private void syncWidgetsBundleAndWidgetTypes(Edge edge) {
List<WidgetsBundle> widgetsBundlesToPush = new ArrayList<>();
List<WidgetType> widgetTypesToPush = new ArrayList<>();
widgetsBundlesToPush.addAll(widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(edge.getTenantId()));
widgetsBundlesToPush.addAll(widgetsBundleService.findSystemWidgetsBundles(edge.getTenantId()));
try {
for (WidgetsBundle widgetsBundle: widgetsBundlesToPush) {
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.WIDGETS_BUNDLE, ActionType.ADDED, widgetsBundle.getId(), null);
widgetTypesToPush.addAll(widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(widgetsBundle.getTenantId(), widgetsBundle.getAlias()));
}
for (WidgetType widgetType: widgetTypesToPush) {
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.WIDGET_TYPE, ActionType.ADDED, widgetType.getId(), null);
}
} catch (Exception e) {
log.error("Exception during loading widgets bundle(s) and widget type(s) on sync!", e);
}
}
private void syncAdminSettings(Edge edge) {
try {
AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail");
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.ADMIN_SETTINGS, ActionType.UPDATED, null, mapper.valueToTree(systemMailSettings));
AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.ADMIN_SETTINGS, ActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings));
AdminSettings systemMailTemplates = loadMailTemplates();
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.ADMIN_SETTINGS, ActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates));
AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.ADMIN_SETTINGS, ActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates));
} catch (Exception e) {
log.error("Can't load admin settings", e);
}
}
private AdminSettings loadMailTemplates() throws Exception {
Map<String, Object> mailTemplates = new HashMap<>();
Pattern startPattern = Pattern.compile("<div class=\"content\".*?>");
Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>");
File[] files = new DefaultResourceLoader().getResource("classpath:/templates/").getFile().listFiles();
for (File file: files) {
Map<String, String> mailTemplate = new HashMap<>();
String name = validateName(file.getName());
String stringTemplate = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
Matcher start = startPattern.matcher(stringTemplate);
Matcher end = endPattern.matcher(stringTemplate);
if (start.find() && end.find()) {
String body = StringUtils.substringBetween(stringTemplate, start.group(), end.group()).replaceAll("\t", "");
String subject = StringUtils.substringBetween(body, "<h2>", "</h2>");
mailTemplate.put("subject", subject);
mailTemplate.put("body", body);
mailTemplates.put(name, mailTemplate);
} else {
log.error("Can't load mail template from file {}", file.getName());
}
}
AdminSettings adminSettings = new AdminSettings();
adminSettings.setId(new AdminSettingsId(Uuids.timeBased()));
adminSettings.setKey("mailTemplates");
adminSettings.setJsonValue(mapper.convertValue(mailTemplates, JsonNode.class));
return adminSettings;
}
private String validateName(String name) throws Exception {
StringBuilder nameBuilder = new StringBuilder();
name = name.replace(".vm", "");
String[] nameParts = name.split("\\.");
if (nameParts.length >= 1) {
nameBuilder.append(nameParts[0]);
for (int i = 1; i < nameParts.length; i++) {
String word = WordUtils.capitalize(nameParts[i]);
nameBuilder.append(word);
}
return nameBuilder.toString();
} else {
throw new Exception("Error during filename validation");
}
}
private AdminSettings convertToTenantAdminSettings(String key, ObjectNode jsonValue) {
AdminSettings tenantMailSettings = new AdminSettings();
jsonValue.put("useSystemMailSettings", true);
tenantMailSettings.setJsonValue(jsonValue);
tenantMailSettings.setKey(key);
return tenantMailSettings;
}
private void pushUsersToEdge(PageData<User> pageData, Edge edge) {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] user(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] user(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (User user : pageData.getData()) { for (User user : pageData.getData()) {
UserUpdateMsg userUpdateMsg = saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, ActionType.ADDED, user.getId(), null);
userUpdateMsgConstructor.constructUserUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
user);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setUserUpdateMsg(userUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
pushedEntityIds.add(user.getId());
} }
} }
} }
private ListenableFuture<Void> syncRelations(EdgeContextComponent ctx, Edge edge, Set<EntityId> pushedEntityIds, StreamObserver<ResponseMsg> outputStream) { @Override
if (!pushedEntityIds.isEmpty()) { public ListenableFuture<Void> processRuleChainMetadataRequestMsg(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg) {
List<ListenableFuture<List<EntityRelation>>> futures = new ArrayList<>(); SettableFuture<Void> futureToSet = SettableFuture.create();
for (EntityId entityId : pushedEntityIds) { if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) {
futures.add(syncRelations(edge, entityId, EntitySearchDirection.FROM)); RuleChainId ruleChainId =
futures.add(syncRelations(edge, entityId, EntitySearchDirection.TO)); new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB()));
} ListenableFuture<EdgeEvent> future = saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.RULE_CHAIN_METADATA, ActionType.ADDED, ruleChainId, null);
ListenableFuture<List<List<EntityRelation>>> relationsListFuture = Futures.allAsList(futures); Futures.addCallback(future, new FutureCallback<EdgeEvent>() {
return Futures.transform(relationsListFuture, relationsList -> { @Override
try { public void onSuccess(@Nullable EdgeEvent result) {
Set<EntityRelation> uniqueEntityRelations = new HashSet<>(); futureToSet.set(null);
if (!relationsList.isEmpty()) { }
for (List<EntityRelation> entityRelations : relationsList) {
if (!entityRelations.isEmpty()) { @Override
uniqueEntityRelations.addAll(entityRelations); public void onFailure(Throwable t) {
log.error("Can't save edge event [{}]", ruleChainMetadataRequestMsg, t);
futureToSet.setException(t);
}
}, dbCallbackExecutorService);
}
return futureToSet;
}
@Override
public ListenableFuture<Void> processAttributesRequestMsg(Edge edge, AttributesRequestMsg attributesRequestMsg) {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(
EntityType.valueOf(attributesRequestMsg.getEntityType()),
new UUID(attributesRequestMsg.getEntityIdMSB(), attributesRequestMsg.getEntityIdLSB()));
final EdgeEventType type = getEdgeQueueTypeByEntityType(entityId.getEntityType());
if (type != null) {
SettableFuture<Void> futureToSet = SettableFuture.create();
ListenableFuture<List<AttributeKvEntry>> ssAttrFuture = attributesService.findAll(edge.getTenantId(), entityId, DataConstants.SERVER_SCOPE);
Futures.addCallback(ssAttrFuture, new FutureCallback<List<AttributeKvEntry>>() {
@Override
public void onSuccess(@Nullable List<AttributeKvEntry> ssAttributes) {
if (ssAttributes != null && !ssAttributes.isEmpty()) {
try {
Map<String, Object> entityData = new HashMap<>();
ObjectNode attributes = mapper.createObjectNode();
for (AttributeKvEntry attr : ssAttributes) {
if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) {
attributes.put(attr.getKey(), attr.getBooleanValue().get());
} else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) {
attributes.put(attr.getKey(), attr.getDoubleValue().get());
} else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) {
attributes.put(attr.getKey(), attr.getLongValue().get());
} else {
attributes.put(attr.getKey(), attr.getValueAsString());
}
}
entityData.put("kv", attributes);
entityData.put("scope", DataConstants.SERVER_SCOPE);
JsonNode body = mapper.valueToTree(entityData);
log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, body);
saveEdgeEvent(edge.getTenantId(),
edge.getId(),
type,
ActionType.ATTRIBUTES_UPDATED,
entityId,
body);
} catch (Exception e) {
log.error("[{}] Failed to send attribute updates to the edge", edge.getName(), e);
throw new RuntimeException("[" + edge.getName() + "] Failed to send attribute updates to the edge", e);
}
} }
futureToSet.set(null);
} }
}
if (!uniqueEntityRelations.isEmpty()) { @Override
log.trace("[{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), uniqueEntityRelations.size()); public void onFailure(Throwable t) {
for (EntityRelation relation : uniqueEntityRelations) { log.error("Can't save attributes [{}]", attributesRequestMsg, t);
futureToSet.setException(t);
}
}, dbCallbackExecutorService);
return futureToSet;
// TODO: voba - push shared attributes to edge?
// ListenableFuture<List<AttributeKvEntry>> shAttrFuture = attributesService.findAll(edge.getTenantId(), entityId, DataConstants.SHARED_SCOPE);
// ListenableFuture<List<AttributeKvEntry>> clAttrFuture = attributesService.findAll(edge.getTenantId(), entityId, DataConstants.CLIENT_SCOPE);
} else {
return Futures.immediateFuture(null);
}
}
private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) {
switch (entityType) {
case DEVICE:
return EdgeEventType.DEVICE;
case ASSET:
return EdgeEventType.ASSET;
case ENTITY_VIEW:
return EdgeEventType.ENTITY_VIEW;
default:
return null;
}
}
@Override
public ListenableFuture<Void> processRelationRequestMsg(Edge edge, RelationRequestMsg relationRequestMsg) {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(
EntityType.valueOf(relationRequestMsg.getEntityType()),
new UUID(relationRequestMsg.getEntityIdMSB(), relationRequestMsg.getEntityIdLSB()));
List<ListenableFuture<List<EntityRelation>>> futures = new ArrayList<>();
futures.add(findRelationByQuery(edge, entityId, EntitySearchDirection.FROM));
futures.add(findRelationByQuery(edge, entityId, EntitySearchDirection.TO));
ListenableFuture<List<List<EntityRelation>>> relationsListFuture = Futures.allAsList(futures);
return Futures.transform(relationsListFuture, relationsList -> {
try {
if (relationsList != null && !relationsList.isEmpty()) {
for (List<EntityRelation> entityRelations : relationsList) {
log.trace("[{}] [{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), entityId, entityRelations.size());
for (EntityRelation relation : entityRelations) {
try { try {
RelationUpdateMsg relationUpdateMsg = if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
relationUpdateMsgConstructor.constructRelationUpdatedMsg( !relation.getTo().getEntityType().equals(EntityType.EDGE)) {
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, saveEdgeEvent(edge.getTenantId(),
relation); edge.getId(),
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() EdgeEventType.RELATION,
.setRelationUpdateMsg(relationUpdateMsg) ActionType.ADDED,
.build(); null,
outputStream.onNext(ResponseMsg.newBuilder() mapper.valueToTree(relation));
.setEntityUpdateMsg(entityUpdateMsg) }
.build());
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading relation [{}] to edge on sync!", relation, e); log.error("Exception during loading relation [{}] to edge on sync!", relation, e);
} }
} }
} }
} catch (Exception e) {
log.error("Exception during loading relation(s) to edge on sync!", e);
} }
return null; } catch (Exception e) {
}, ctx.getDbCallbackExecutor()); log.error("Exception during loading relation(s) to edge on sync!", e);
} else { throw new RuntimeException("Exception during loading relation(s) to edge on sync!", e);
return Futures.immediateFuture(null); }
} return null;
}, dbCallbackExecutorService);
} }
private ListenableFuture<List<EntityRelation>> syncRelations(Edge edge, EntityId entityId, EntitySearchDirection direction) { private ListenableFuture<List<EntityRelation>> findRelationByQuery(Edge edge, EntityId entityId, EntitySearchDirection direction) {
EntityRelationsQuery query = new EntityRelationsQuery(); EntityRelationsQuery query = new EntityRelationsQuery();
query.setParameters(new RelationsSearchParameters(entityId, direction, -1, false)); query.setParameters(new RelationsSearchParameters(entityId, direction, -1, false));
return relationService.findByQuery(edge.getTenantId(), query); return relationService.findByQuery(edge.getTenantId(), query);
} }
@Override @Override
public void syncRuleChainMetadata(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg, StreamObserver<ResponseMsg> outputStream) { public ListenableFuture<Void> processDeviceCredentialsRequestMsg(Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg) {
if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) { SettableFuture<Void> futureToSet = SettableFuture.create();
RuleChainId ruleChainId = new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB())); if (deviceCredentialsRequestMsg.getDeviceIdMSB() != 0 && deviceCredentialsRequestMsg.getDeviceIdLSB() != 0) {
RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(edge.getTenantId(), ruleChainId); DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsRequestMsg.getDeviceIdMSB(), deviceCredentialsRequestMsg.getDeviceIdLSB()));
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = ListenableFuture<EdgeEvent> future = saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.DEVICE, ActionType.CREDENTIALS_UPDATED, deviceId, null);
ruleChainUpdateMsgConstructor.constructRuleChainMetadataUpdatedMsg( Futures.addCallback(future, new FutureCallback<EdgeEvent>() {
UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE, @Override
ruleChainMetaData); public void onSuccess(@Nullable EdgeEvent result) {
if (ruleChainMetadataUpdateMsg != null) { futureToSet.set(null);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() }
.setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg)
.build(); @Override
outputStream.onNext(ResponseMsg.newBuilder() public void onFailure(Throwable t) {
.setEntityUpdateMsg(entityUpdateMsg) log.error("Can't save edge event [{}]", deviceCredentialsRequestMsg, t);
.build()); futureToSet.setException(t);
} }
}, dbCallbackExecutorService);
}
return futureToSet;
}
@Override
public ListenableFuture<Void> processUserCredentialsRequestMsg(Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg) {
SettableFuture<Void> futureToSet = SettableFuture.create();
if (userCredentialsRequestMsg.getUserIdMSB() != 0 && userCredentialsRequestMsg.getUserIdLSB() != 0) {
UserId userId = new UserId(new UUID(userCredentialsRequestMsg.getUserIdMSB(), userCredentialsRequestMsg.getUserIdLSB()));
ListenableFuture<EdgeEvent> future = saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, ActionType.CREDENTIALS_UPDATED, userId, null);
Futures.addCallback(future, new FutureCallback<EdgeEvent>() {
@Override
public void onSuccess(@Nullable EdgeEvent result) {
futureToSet.set(null);
}
@Override
public void onFailure(Throwable t) {
log.error("Can't save edge event [{}]", userCredentialsRequestMsg, t);
futureToSet.setException(t);
}
}, dbCallbackExecutorService);
}
return futureToSet;
}
private ListenableFuture<EdgeEvent> saveEdgeEvent(TenantId tenantId,
EdgeId edgeId,
EdgeEventType type,
ActionType action,
EntityId entityId,
JsonNode body) {
log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]",
tenantId, edgeId, type, action, entityId, body);
EdgeEvent edgeEvent = new EdgeEvent();
edgeEvent.setTenantId(tenantId);
edgeEvent.setEdgeId(edgeId);
edgeEvent.setType(type);
edgeEvent.setAction(action.name());
if (entityId != null) {
edgeEvent.setEntityId(entityId.getId());
} }
edgeEvent.setBody(body);
return edgeEventService.saveAsync(edgeEvent);
} }
} }

20
application/src/main/java/org/thingsboard/server/service/edge/rpc/init/SyncEdgeService.java

@ -15,15 +15,25 @@
*/ */
package org.thingsboard.server.service.edge.rpc.init; package org.thingsboard.server.service.edge.rpc.init;
import io.grpc.stub.StreamObserver; import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.gen.edge.ResponseMsg; import org.thingsboard.server.gen.edge.AttributesRequestMsg;
import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.RelationRequestMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg; import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg;
import org.thingsboard.server.service.edge.EdgeContextComponent; import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg;
public interface SyncEdgeService { public interface SyncEdgeService {
void sync(EdgeContextComponent ctx, Edge edge, StreamObserver<ResponseMsg> outputStream); void sync(Edge edge);
void syncRuleChainMetadata(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg, StreamObserver<ResponseMsg> outputStream); ListenableFuture<Void> processRuleChainMetadataRequestMsg(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg);
ListenableFuture<Void> processAttributesRequestMsg(Edge edge, AttributesRequestMsg attributesRequestMsg);
ListenableFuture<Void> processRelationRequestMsg(Edge edge, RelationRequestMsg relationRequestMsg);
ListenableFuture<Void> processDeviceCredentialsRequestMsg(Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg);
ListenableFuture<Void> processUserCredentialsRequestMsg(Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg);
} }

98
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/AlarmProcessor.java

@ -0,0 +1,98 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc.processor;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.gen.edge.AlarmUpdateMsg;
import org.thingsboard.server.queue.util.TbCoreComponent;
@Component
@Slf4j
@TbCoreComponent
public class AlarmProcessor extends BaseProcessor {
public ListenableFuture<Void> onAlarmUpdate(TenantId tenantId, AlarmUpdateMsg alarmUpdateMsg) {
EntityId originatorId = getAlarmOriginator(tenantId, alarmUpdateMsg.getOriginatorName(),
EntityType.valueOf(alarmUpdateMsg.getOriginatorType()));
if (originatorId == null) {
return Futures.immediateFuture(null);
}
try {
Alarm existentAlarm = alarmService.findLatestByOriginatorAndType(tenantId, originatorId, alarmUpdateMsg.getType()).get();
switch (alarmUpdateMsg.getMsgType()) {
case ENTITY_CREATED_RPC_MESSAGE:
case ENTITY_UPDATED_RPC_MESSAGE:
if (existentAlarm == null || existentAlarm.getStatus().isCleared()) {
existentAlarm = new Alarm();
existentAlarm.setTenantId(tenantId);
existentAlarm.setType(alarmUpdateMsg.getName());
existentAlarm.setOriginator(originatorId);
existentAlarm.setSeverity(AlarmSeverity.valueOf(alarmUpdateMsg.getSeverity()));
existentAlarm.setStartTs(alarmUpdateMsg.getStartTs());
existentAlarm.setClearTs(alarmUpdateMsg.getClearTs());
existentAlarm.setPropagate(alarmUpdateMsg.getPropagate());
}
existentAlarm.setStatus(AlarmStatus.valueOf(alarmUpdateMsg.getStatus()));
existentAlarm.setAckTs(alarmUpdateMsg.getAckTs());
existentAlarm.setEndTs(alarmUpdateMsg.getEndTs());
existentAlarm.setDetails(mapper.readTree(alarmUpdateMsg.getDetails()));
alarmService.createOrUpdateAlarm(existentAlarm);
break;
case ALARM_ACK_RPC_MESSAGE:
if (existentAlarm != null) {
alarmService.ackAlarm(tenantId, existentAlarm.getId(), alarmUpdateMsg.getAckTs());
}
break;
case ALARM_CLEAR_RPC_MESSAGE:
if (existentAlarm != null) {
alarmService.clearAlarm(tenantId, existentAlarm.getId(), mapper.readTree(alarmUpdateMsg.getDetails()), alarmUpdateMsg.getAckTs());
}
break;
case ENTITY_DELETED_RPC_MESSAGE:
if (existentAlarm != null) {
alarmService.deleteAlarm(tenantId, existentAlarm.getId());
}
break;
}
return Futures.immediateFuture(null);
} catch (Exception e) {
log.error("Failed to process alarm update msg [{}]", alarmUpdateMsg, e);
return Futures.immediateFailedFuture(new RuntimeException("Failed to process alarm update msg", e));
}
}
private EntityId getAlarmOriginator(TenantId tenantId, String entityName, EntityType entityType) {
switch (entityType) {
case DEVICE:
return deviceService.findDeviceByTenantIdAndName(tenantId, entityName).getId();
case ASSET:
return assetService.findAssetByTenantIdAndName(tenantId, entityName).getId();
case ENTITY_VIEW:
return entityViewService.findEntityViewByTenantIdAndName(tenantId, entityName).getId();
default:
return null;
}
}
}

113
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseProcessor.java

@ -0,0 +1,113 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc.processor;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.alarm.AlarmService;
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.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.queue.TbClusterService;
import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService;
import org.thingsboard.server.service.state.DeviceStateService;
@Slf4j
public abstract class BaseProcessor {
protected static final ObjectMapper mapper = new ObjectMapper();
@Autowired
protected AlarmService alarmService;
@Autowired
protected DeviceService deviceService;
@Autowired
protected DashboardService dashboardService;
@Autowired
protected AssetService assetService;
@Autowired
protected EntityViewService entityViewService;
@Autowired
protected CustomerService customerService;
@Autowired
protected UserService userService;
@Autowired
protected RelationService relationService;
@Autowired
protected DeviceCredentialsService deviceCredentialsService;
@Autowired
protected AttributesService attributesService;
@Autowired
protected TbClusterService tbClusterService;
@Autowired
protected DeviceStateService deviceStateService;
@Autowired
protected EdgeEventService edgeEventService;
@Autowired
protected DbCallbackExecutorService dbCallbackExecutorService;
protected ListenableFuture<EdgeEvent> saveEdgeEvent(TenantId tenantId,
EdgeId edgeId,
EdgeEventType type,
ActionType action,
EntityId entityId,
JsonNode body) {
log.debug("Pushing event to edge queue. tenantId [{}], edgeId [{}], type[{}], " +
"action [{}], entityId [{}], body [{}]",
tenantId, edgeId, type, action, entityId, body);
EdgeEvent edgeEvent = new EdgeEvent();
edgeEvent.setTenantId(tenantId);
edgeEvent.setEdgeId(edgeId);
edgeEvent.setType(type);
edgeEvent.setAction(action.name());
if (entityId != null) {
edgeEvent.setEntityId(entityId.getId());
}
edgeEvent.setBody(body);
return edgeEventService.saveAsync(edgeEvent);
}
}

252
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceProcessor.java

@ -0,0 +1,252 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc.processor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import org.thingsboard.rule.engine.api.RpcError;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventType;
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.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.DeviceRpcCallMsg;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
import org.thingsboard.server.queue.TbQueueCallback;
import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
import java.util.UUID;
import java.util.concurrent.locks.ReentrantLock;
@Component
@Slf4j
@TbCoreComponent
public class DeviceProcessor extends BaseProcessor {
private static final ReentrantLock deviceCreationLock = new ReentrantLock();
public ListenableFuture<Void> onDeviceUpdate(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
DeviceId edgeDeviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
switch (deviceUpdateMsg.getMsgType()) {
case ENTITY_CREATED_RPC_MESSAGE:
String deviceName = deviceUpdateMsg.getName();
Device device = deviceService.findDeviceByTenantIdAndName(tenantId, deviceName);
if (device != null) {
// device with this name already exists on the cloud - update ID on the edge
if (!device.getId().equals(edgeDeviceId)) {
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, ActionType.ENTITY_EXISTS_REQUEST, device.getId(), null);
}
} else {
Device deviceById = deviceService.findDeviceById(edge.getTenantId(), edgeDeviceId);
if (deviceById != null) {
// this ID already used by other device - create new device and update ID on the edge
device = createDevice(tenantId, edge, deviceUpdateMsg);
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, ActionType.ENTITY_EXISTS_REQUEST, device.getId(), null);
} else {
device = createDevice(tenantId, edge, deviceUpdateMsg);
}
}
// TODO: voba - assign device only in case device is not assigned yet. Missing functionality to check this relation prior assignment
deviceService.assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId());
break;
case ENTITY_UPDATED_RPC_MESSAGE:
updateDevice(tenantId, edge, deviceUpdateMsg);
break;
case ENTITY_DELETED_RPC_MESSAGE:
Device deviceToDelete = deviceService.findDeviceById(tenantId, edgeDeviceId);
if (deviceToDelete != null) {
deviceService.unassignDeviceFromEdge(tenantId, edgeDeviceId, edge.getId());
}
break;
case UNRECOGNIZED:
log.error("Unsupported msg type {}", deviceUpdateMsg.getMsgType());
return Futures.immediateFailedFuture(new RuntimeException("Unsupported msg type " + deviceUpdateMsg.getMsgType()));
}
return Futures.immediateFuture(null);
}
public ListenableFuture<Void> onDeviceCredentialsUpdate(TenantId tenantId, DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg) {
log.debug("Executing onDeviceCredentialsUpdate, deviceCredentialsUpdateMsg [{}]", deviceCredentialsUpdateMsg);
DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsUpdateMsg.getDeviceIdMSB(), deviceCredentialsUpdateMsg.getDeviceIdLSB()));
ListenableFuture<Device> deviceFuture = deviceService.findDeviceByIdAsync(tenantId, deviceId);
return Futures.transform(deviceFuture, device -> {
if (device != null) {
log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]",
device.getName(), deviceCredentialsUpdateMsg.getCredentialsId(), deviceCredentialsUpdateMsg.getCredentialsValue());
try {
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, device.getId());
deviceCredentials.setCredentialsType(DeviceCredentialsType.valueOf(deviceCredentialsUpdateMsg.getCredentialsType()));
deviceCredentials.setCredentialsId(deviceCredentialsUpdateMsg.getCredentialsId());
deviceCredentials.setCredentialsValue(deviceCredentialsUpdateMsg.getCredentialsValue());
deviceCredentialsService.updateDeviceCredentials(tenantId, deviceCredentials);
} catch (Exception e) {
log.error("Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]", device.getName(), deviceCredentialsUpdateMsg, e);
throw new RuntimeException(e);
}
}
return null;
}, dbCallbackExecutorService);
}
private void updateDevice(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
Device device = deviceService.findDeviceById(tenantId, deviceId);
device.setName(deviceUpdateMsg.getName());
device.setType(deviceUpdateMsg.getType());
device.setLabel(deviceUpdateMsg.getLabel());
device.setAdditionalInfo(JacksonUtil.toJsonNode(deviceUpdateMsg.getAdditionalInfo()));
deviceService.saveDevice(device);
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, ActionType.CREDENTIALS_REQUEST, deviceId, null);
}
private Device createDevice(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
Device device;
try {
deviceCreationLock.lock();
DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
device = new Device();
device.setTenantId(edge.getTenantId());
device.setCustomerId(edge.getCustomerId());
device.setId(deviceId);
device.setName(deviceUpdateMsg.getName());
device.setType(deviceUpdateMsg.getType());
device.setLabel(deviceUpdateMsg.getLabel());
device.setAdditionalInfo(JacksonUtil.toJsonNode(deviceUpdateMsg.getAdditionalInfo()));
device = deviceService.saveDevice(device);
createDeviceCredentials(device);
createRelationFromEdge(tenantId, edge.getId(), device.getId());
deviceStateService.onDeviceAdded(device);
pushDeviceCreatedEventToRuleEngine(tenantId, edge, device);
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, ActionType.CREDENTIALS_REQUEST, deviceId, null);
} finally {
deviceCreationLock.unlock();
}
return device;
}
private void createRelationFromEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId) {
EntityRelation relation = new EntityRelation();
relation.setFrom(edgeId);
relation.setTo(entityId);
relation.setTypeGroup(RelationTypeGroup.COMMON);
relation.setType(EntityRelation.EDGE_TYPE);
relationService.saveRelation(tenantId, relation);
}
private void createDeviceCredentials(Device device) {
DeviceCredentials deviceCredentials = new DeviceCredentials();
deviceCredentials.setDeviceId(device.getId());
deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
deviceCredentials.setCredentialsId(RandomStringUtils.randomAlphanumeric(20));
deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials);
}
private void pushDeviceCreatedEventToRuleEngine(TenantId tenantId, Edge edge, Device device) {
try {
DeviceId deviceId = device.getId();
ObjectNode entityNode = mapper.valueToTree(device);
TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId,
getActionTbMsgMetaData(edge, device.getCustomerId()), TbMsgDataType.JSON, mapper.writeValueAsString(entityNode));
tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
// TODO: voba - handle success
log.debug("Successfully send ENTITY_CREATED EVENT to rule engine [{}]", device);
}
@Override
public void onFailure(Throwable t) {
// TODO: voba - handle failure
log.debug("Failed to send ENTITY_CREATED EVENT to rule engine [{}]", device, t);
}
;
});
} catch (JsonProcessingException | IllegalArgumentException e) {
log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), DataConstants.ENTITY_CREATED, e);
}
}
private TbMsgMetaData getActionTbMsgMetaData(Edge edge, CustomerId customerId) {
TbMsgMetaData metaData = getTbMsgMetaData(edge);
if (customerId != null && !customerId.isNullUid()) {
metaData.putValue("customerId", customerId.toString());
}
return metaData;
}
private TbMsgMetaData getTbMsgMetaData(Edge edge) {
TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue("edgeId", edge.getId().toString());
metaData.putValue("edgeName", edge.getName());
return metaData;
}
public ListenableFuture<Void> processDeviceRpcCallResponseMsg(TenantId tenantId, DeviceRpcCallMsg deviceRpcCallMsg) {
SettableFuture<Void> futureToSet = SettableFuture.create();
UUID uuid = new UUID(deviceRpcCallMsg.getRequestIdMSB(), deviceRpcCallMsg.getRequestIdLSB());
FromDeviceRpcResponse response;
if (!StringUtils.isEmpty(deviceRpcCallMsg.getResponseMsg().getError())) {
response = new FromDeviceRpcResponse(uuid, null, RpcError.valueOf(deviceRpcCallMsg.getResponseMsg().getError()));
} else {
response = new FromDeviceRpcResponse(uuid, deviceRpcCallMsg.getResponseMsg().getResponse(), null);
}
TbQueueCallback callback = new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
futureToSet.set(null);
}
@Override
public void onFailure(Throwable t) {
log.error("Can't process push notification to core [{}]", deviceRpcCallMsg, t);
futureToSet.setException(t);
}
};
tbClusterService.pushNotificationToCore(deviceRpcCallMsg.getOriginServiceId(), response, callback);
return futureToSet;
}
}

104
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationProcessor.java

@ -0,0 +1,104 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc.processor;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.gen.edge.RelationUpdateMsg;
import org.thingsboard.server.queue.util.TbCoreComponent;
import java.util.UUID;
@Component
@Slf4j
@TbCoreComponent
public class RelationProcessor extends BaseProcessor {
public ListenableFuture<Void> onRelationUpdate(TenantId tenantId, RelationUpdateMsg relationUpdateMsg) {
log.info("onRelationUpdate {}", relationUpdateMsg);
try {
EntityRelation entityRelation = new EntityRelation();
UUID fromUUID = new UUID(relationUpdateMsg.getFromIdMSB(), relationUpdateMsg.getFromIdLSB());
EntityId fromId = EntityIdFactory.getByTypeAndUuid(EntityType.valueOf(relationUpdateMsg.getFromEntityType()), fromUUID);
entityRelation.setFrom(fromId);
UUID toUUID = new UUID(relationUpdateMsg.getToIdMSB(), relationUpdateMsg.getToIdLSB());
EntityId toId = EntityIdFactory.getByTypeAndUuid(EntityType.valueOf(relationUpdateMsg.getToEntityType()), toUUID);
entityRelation.setTo(toId);
entityRelation.setType(relationUpdateMsg.getType());
entityRelation.setTypeGroup(RelationTypeGroup.valueOf(relationUpdateMsg.getTypeGroup()));
entityRelation.setAdditionalInfo(mapper.readTree(relationUpdateMsg.getAdditionalInfo()));
switch (relationUpdateMsg.getMsgType()) {
case ENTITY_CREATED_RPC_MESSAGE:
case ENTITY_UPDATED_RPC_MESSAGE:
if (isEntityExists(tenantId, entityRelation.getTo())
&& isEntityExists(tenantId, entityRelation.getFrom())) {
relationService.saveRelationAsync(tenantId, entityRelation);
}
break;
case ENTITY_DELETED_RPC_MESSAGE:
relationService.deleteRelation(tenantId, entityRelation);
break;
case UNRECOGNIZED:
log.error("Unsupported msg type");
}
return Futures.immediateFuture(null);
} catch (Exception e) {
log.error("Failed to process relation update msg [{}]", relationUpdateMsg, e);
return Futures.immediateFailedFuture(new RuntimeException("Failed to process relation update msg", e));
}
}
private boolean isEntityExists(TenantId tenantId, EntityId entityId) throws ThingsboardException {
switch (entityId.getEntityType()) {
case DEVICE:
return deviceService.findDeviceById(tenantId, new DeviceId(entityId.getId())) != null;
case ASSET:
return assetService.findAssetById(tenantId, new AssetId(entityId.getId())) != null;
case ENTITY_VIEW:
return entityViewService.findEntityViewById(tenantId, new EntityViewId(entityId.getId())) != null;
case CUSTOMER:
return customerService.findCustomerById(tenantId, new CustomerId(entityId.getId())) != null;
case USER:
return userService.findUserById(tenantId, new UserId(entityId.getId())) != null;
case DASHBOARD:
return dashboardService.findDashboardById(tenantId, new DashboardId(entityId.getId())) != null;
default:
throw new ThingsboardException("Unsupported entity type " + entityId.getEntityType(), ThingsboardErrorCode.INVALID_ARGUMENTS);
}
}
}

244
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/TelemetryProcessor.java

@ -0,0 +1,244 @@
/**
* Copyright © 2016-2020 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.service.edge.rpc.processor;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceId;
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.UserId;
import org.thingsboard.server.common.data.kv.AttributeKey;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.common.transport.util.JsonUtils;
import org.thingsboard.server.gen.edge.AttributeDeleteMsg;
import org.thingsboard.server.gen.edge.EntityDataProto;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.TbQueueCallback;
import org.thingsboard.server.queue.TbQueueMsgMetadata;
import org.thingsboard.server.queue.util.TbCoreComponent;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@Component
@Slf4j
@TbCoreComponent
public class TelemetryProcessor extends BaseProcessor {
private final Gson gson = new Gson();
public List<ListenableFuture<Void>> onTelemetryUpdate(TenantId tenantId, EntityDataProto entityData) {
List<ListenableFuture<Void>> result = new ArrayList<>();
EntityId entityId = constructEntityId(entityData);
if ((entityData.hasPostAttributesMsg() || entityData.hasPostTelemetryMsg() || entityData.hasAttributesUpdatedMsg()) && entityId != null) {
TbMsgMetaData metaData = constructBaseMsgMetadata(tenantId, entityId);
metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE);
if (entityData.hasPostAttributesMsg()) {
result.add(processPostAttributes(tenantId, entityId, entityData.getPostAttributesMsg(), metaData));
}
if (entityData.hasAttributesUpdatedMsg()) {
metaData.putValue("scope", entityData.getPostAttributeScope());
result.add(processAttributesUpdate(tenantId, entityId, entityData.getAttributesUpdatedMsg(), metaData));
}
if (entityData.hasPostTelemetryMsg()) {
result.add(processPostTelemetry(tenantId, entityId, entityData.getPostTelemetryMsg(), metaData));
}
}
if (entityData.hasAttributeDeleteMsg()) {
result.add(processAttributeDeleteMsg(tenantId, entityId, entityData.getAttributeDeleteMsg(), entityData.getEntityType()));
}
return result;
}
private TbMsgMetaData constructBaseMsgMetadata(TenantId tenantId, EntityId entityId) {
TbMsgMetaData metaData = new TbMsgMetaData();
switch (entityId.getEntityType()) {
case DEVICE:
Device device = deviceService.findDeviceById(tenantId, new DeviceId(entityId.getId()));
if (device != null) {
metaData.putValue("deviceName", device.getName());
metaData.putValue("deviceType", device.getType());
}
break;
case ASSET:
Asset asset = assetService.findAssetById(tenantId, new AssetId(entityId.getId()));
if (asset != null) {
metaData.putValue("assetName", asset.getName());
metaData.putValue("assetType", asset.getType());
}
break;
case ENTITY_VIEW:
EntityView entityView = entityViewService.findEntityViewById(tenantId, new EntityViewId(entityId.getId()));
if (entityView != null) {
metaData.putValue("entityViewName", entityView.getName());
metaData.putValue("entityViewType", entityView.getType());
}
break;
default:
log.debug("Using empty metadata for entityId [{}]", entityId);
break;
}
return metaData;
}
private ListenableFuture<Void> processPostTelemetry(TenantId tenantId, EntityId entityId, TransportProtos.PostTelemetryMsg msg, TbMsgMetaData metaData) {
SettableFuture<Void> futureToSet = SettableFuture.create();
for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) {
JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());
metaData.putValue("ts", tsKv.getTs() + "");
TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, metaData, gson.toJson(json));
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
futureToSet.set(null);
}
@Override
public void onFailure(Throwable t) {
log.error("Can't process post telemetry [{}]", msg, t);
futureToSet.setException(t);
}
});
}
return futureToSet;
}
private ListenableFuture<Void> processPostAttributes(TenantId tenantId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) {
SettableFuture<Void> futureToSet = SettableFuture.create();
JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, metaData, gson.toJson(json));
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
futureToSet.set(null);
}
@Override
public void onFailure(Throwable t) {
log.error("Can't process post attributes [{}]", msg, t);
futureToSet.setException(t);
}
});
return futureToSet;
}
private ListenableFuture<Void> processAttributesUpdate(TenantId tenantId, EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) {
SettableFuture<Void> futureToSet = SettableFuture.create();
JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(json);
ListenableFuture<List<Void>> future = attributesService.save(tenantId, entityId, metaData.getValue("scope"), new ArrayList<>(attributes));
Futures.addCallback(future, new FutureCallback<List<Void>>() {
@Override
public void onSuccess(@Nullable List<Void> voids) {
TbMsg tbMsg = TbMsg.newMsg(DataConstants.ATTRIBUTES_UPDATED, entityId, metaData, gson.toJson(json));
tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
futureToSet.set(null);
}
@Override
public void onFailure(Throwable t) {
log.error("Can't process attributes update [{}]", msg, t);
futureToSet.setException(t);
}
});
}
@Override
public void onFailure(Throwable t) {
log.error("Can't process attributes update [{}]", msg, t);
futureToSet.setException(t);
}
}, dbCallbackExecutorService);
return futureToSet;
}
private ListenableFuture<Void> processAttributeDeleteMsg(TenantId tenantId, EntityId entityId, AttributeDeleteMsg attributeDeleteMsg, String entityType) {
SettableFuture<Void> futureToSet = SettableFuture.create();
String scope = attributeDeleteMsg.getScope();
List<String> attributeNames = attributeDeleteMsg.getAttributeNamesList();
attributesService.removeAll(tenantId, entityId, scope, attributeNames);
if (EntityType.DEVICE.name().equals(entityType)) {
Set<AttributeKey> attributeKeys = new HashSet<>();
for (String attributeName : attributeNames) {
attributeKeys.add(new AttributeKey(scope, attributeName));
}
tbClusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete(
tenantId, (DeviceId) entityId, attributeKeys), new TbQueueCallback() {
@Override
public void onSuccess(TbQueueMsgMetadata metadata) {
futureToSet.set(null);
}
@Override
public void onFailure(Throwable t) {
log.error("Can't process attribute delete msg [{}]", attributeDeleteMsg, t);
futureToSet.setException(t);
}
});
}
return futureToSet;
}
private EntityId constructEntityId(EntityDataProto entityData) {
EntityType entityType = EntityType.valueOf(entityData.getEntityType());
switch (entityType) {
case DEVICE:
return new DeviceId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB()));
case ASSET:
return new AssetId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB()));
case ENTITY_VIEW:
return new EntityViewId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB()));
case DASHBOARD:
return new DashboardId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB()));
case TENANT:
return new TenantId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB()));
case CUSTOMER:
return new CustomerId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB()));
case USER:
return new UserId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB()));
default:
log.warn("Unsupported entity type [{}] during construct of entity id. EntityDataProto [{}]", entityData.getEntityType(), entityData);
return null;
}
}
}

2
application/src/main/java/org/thingsboard/server/service/install/AbstractSqlTsDatabaseUpgradeService.java

@ -50,7 +50,7 @@ public abstract class AbstractSqlTsDatabaseUpgradeService {
@Autowired @Autowired
protected InstallScripts installScripts; protected InstallScripts installScripts;
protected abstract void loadSql(Connection conn, String fileName); protected abstract void loadSql(Connection conn, String version, String fileName);
protected void loadFunctions(Path sqlFile, Connection conn) throws Exception { protected void loadFunctions(Path sqlFile, Connection conn) throws Exception {
String sql = new String(Files.readAllBytes(sqlFile), StandardCharsets.UTF_8); String sql = new String(Files.readAllBytes(sqlFile), StandardCharsets.UTF_8);

2
application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseUpgradeService.java

@ -49,6 +49,8 @@ public class CassandraTsDatabaseUpgradeService extends AbstractCassandraDatabase
log.info("Schema updated."); log.info("Schema updated.");
break; break;
case "2.5.0": case "2.5.0":
case "2.5.4":
case "2.5.5":
case "3.1.1": case "3.1.1":
break; break;
default: default:

1
application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java

@ -57,6 +57,7 @@ public class DatabaseHelper {
public static final String DASHBOARD = "dashboard"; public static final String DASHBOARD = "dashboard";
public static final String ENTITY_VIEWS = "entity_views"; public static final String ENTITY_VIEWS = "entity_views";
public static final String ENTITY_VIEW = "entity_view"; public static final String ENTITY_VIEW = "entity_view";
public static final String RULE_CHAIN = "rule_chain";
public static final String ID = "id"; public static final String ID = "id";
public static final String TITLE = "title"; public static final String TITLE = "title";
public static final String TYPE = "type"; public static final String TYPE = "type";

9
application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java

@ -122,10 +122,6 @@ public class InstallScripts {
} }
} }
); );
// TODO: voba
// dirStream.forEach(
// path -> loadRuleChainFromFile(tenantId, path)
// );
} }
} }
@ -151,6 +147,11 @@ public class InstallScripts {
} }
public void createDefaultEdgeRuleChains(TenantId tenantId) {
Path tenantChainsDir = getTenantRuleChainsDir();
loadRuleChainFromFile(tenantId, tenantChainsDir.resolve("edge_root_rule_chain.json"));
}
public void loadSystemWidgets() throws Exception { public void loadSystemWidgets() throws Exception {
Path widgetBundlesDir = Paths.get(getDataDir(), JSON_DIR, SYSTEM_DIR, WIDGET_BUNDLES_DIR); Path widgetBundlesDir = Paths.get(getDataDir(), JSON_DIR, SYSTEM_DIR, WIDGET_BUNDLES_DIR);
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(widgetBundlesDir, path -> path.toString().endsWith(JSON_EXT))) { try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(widgetBundlesDir, path -> path.toString().endsWith(JSON_EXT))) {

20
application/src/main/java/org/thingsboard/server/service/install/PsqlTsDatabaseUpgradeService.java

@ -94,7 +94,7 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
log.info("PostgreSQL version is valid!"); log.info("PostgreSQL version is valid!");
if (isOldSchema(conn, 2004003)) { if (isOldSchema(conn, 2004003)) {
log.info("Load upgrade functions ..."); log.info("Load upgrade functions ...");
loadSql(conn, LOAD_FUNCTIONS_SQL); loadSql(conn, "2.4.3", LOAD_FUNCTIONS_SQL);
log.info("Updating timeseries schema ..."); log.info("Updating timeseries schema ...");
executeQuery(conn, CALL_CREATE_PARTITION_TS_KV_TABLE); executeQuery(conn, CALL_CREATE_PARTITION_TS_KV_TABLE);
if (!partitionType.equals("INDEFINITE")) { if (!partitionType.equals("INDEFINITE")) {
@ -179,9 +179,9 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
} }
log.info("Load TTL functions ..."); log.info("Load TTL functions ...");
loadSql(conn, LOAD_TTL_FUNCTIONS_SQL); loadSql(conn, "2.4.3", LOAD_TTL_FUNCTIONS_SQL);
log.info("Load Drop Partitions functions ..."); log.info("Load Drop Partitions functions ...");
loadSql(conn, LOAD_DROP_PARTITIONS_FUNCTIONS_SQL); loadSql(conn, "2.4.3", LOAD_DROP_PARTITIONS_FUNCTIONS_SQL);
executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005000"); executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005000");
@ -195,12 +195,18 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005001"); executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005001");
} }
break; break;
case "2.5.5":
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
log.info("Load TTL functions ...");
loadSql(conn, "2.6.0", LOAD_TTL_FUNCTIONS_SQL);
}
break;
case "3.1.1": case "3.1.1":
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
log.info("Load TTL functions ..."); log.info("Load TTL functions ...");
loadSql(conn, LOAD_TTL_FUNCTIONS_SQL); loadSql(conn, "2.4.3", LOAD_TTL_FUNCTIONS_SQL);
log.info("Load Drop Partitions functions ..."); log.info("Load Drop Partitions functions ...");
loadSql(conn, LOAD_DROP_PARTITIONS_FUNCTIONS_SQL); loadSql(conn, "2.4.3", LOAD_DROP_PARTITIONS_FUNCTIONS_SQL);
} }
break; break;
default: default:
@ -238,8 +244,8 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
} }
@Override @Override
protected void loadSql(Connection conn, String fileName) { protected void loadSql(Connection conn, String version, String fileName) {
Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", fileName); Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", version, fileName);
try { try {
loadFunctions(schemaUpdateFile, conn); loadFunctions(schemaUpdateFile, conn);
log.info("Functions successfully loaded!"); log.info("Functions successfully loaded!");

2
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -260,7 +260,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
log.info("Schema updated."); log.info("Schema updated.");
} }
break; break;
case "2.6.0": case "2.5.5":
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
log.info("Updating schema ..."); log.info("Updating schema ...");
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.5.0", SCHEMA_UPDATE_SQL); schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.5.0", SCHEMA_UPDATE_SQL);

10
application/src/main/java/org/thingsboard/server/service/install/TimescaleTsDatabaseUpgradeService.java

@ -89,7 +89,7 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr
log.info("PostgreSQL version is valid!"); log.info("PostgreSQL version is valid!");
if (isOldSchema(conn, 2004003)) { if (isOldSchema(conn, 2004003)) {
log.info("Load upgrade functions ..."); log.info("Load upgrade functions ...");
loadSql(conn, LOAD_FUNCTIONS_SQL); loadSql(conn, "2.4.3", LOAD_FUNCTIONS_SQL);
log.info("Updating timescale schema ..."); log.info("Updating timescale schema ...");
executeQuery(conn, CALL_CREATE_TS_KV_LATEST_TABLE); executeQuery(conn, CALL_CREATE_TS_KV_LATEST_TABLE);
executeQuery(conn, CALL_CREATE_NEW_TENANT_TS_KV_TABLE); executeQuery(conn, CALL_CREATE_NEW_TENANT_TS_KV_TABLE);
@ -165,7 +165,7 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr
} }
log.info("Load TTL functions ..."); log.info("Load TTL functions ...");
loadSql(conn, LOAD_TTL_FUNCTIONS_SQL); loadSql(conn, "2.4.3", LOAD_TTL_FUNCTIONS_SQL);
executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005000"); executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005000");
log.info("schema timescale updated!"); log.info("schema timescale updated!");
@ -179,6 +179,8 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr
break; break;
case "3.1.1": case "3.1.1":
break; break;
case "2.5.5":
break;
default: default:
throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
} }
@ -200,8 +202,8 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr
} }
@Override @Override
protected void loadSql(Connection conn, String fileName) { protected void loadSql(Connection conn, String version, String fileName) {
Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", fileName); Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", version, fileName);
try { try {
loadFunctions(schemaUpdateFile, conn); loadFunctions(schemaUpdateFile, conn);
log.info("Functions successfully loaded!"); log.info("Functions successfully loaded!");

5
application/src/main/java/org/thingsboard/server/service/install/cql/CassandraDbHelper.java

@ -37,7 +37,6 @@ import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -159,6 +158,8 @@ public class CassandraDbHelper {
str = new Float(row.getFloat(index)).toString(); str = new Float(row.getFloat(index)).toString();
} else if (type.getProtocolCode() == ProtocolConstants.DataType.TIMESTAMP) { } else if (type.getProtocolCode() == ProtocolConstants.DataType.TIMESTAMP) {
str = ""+row.getInstant(index).toEpochMilli(); str = ""+row.getInstant(index).toEpochMilli();
} else if (type.getProtocolCode() == ProtocolConstants.DataType.BOOLEAN) {
str = new Boolean(row.getBoolean(index)).toString();
} else { } else {
str = row.getString(index); str = row.getString(index);
} }
@ -207,6 +208,8 @@ public class CassandraDbHelper {
boundStatementBuilder.setFloat(column, Float.valueOf(value)); boundStatementBuilder.setFloat(column, Float.valueOf(value));
} else if (type.getProtocolCode() == ProtocolConstants.DataType.TIMESTAMP) { } else if (type.getProtocolCode() == ProtocolConstants.DataType.TIMESTAMP) {
boundStatementBuilder.setInstant(column, Instant.ofEpochMilli(Long.valueOf(value))); boundStatementBuilder.setInstant(column, Instant.ofEpochMilli(Long.valueOf(value)));
} else if (type.getProtocolCode() == ProtocolConstants.DataType.BOOLEAN) {
boundStatementBuilder.setBoolean(column, Boolean.valueOf(value));
} else { } else {
boundStatementBuilder.setString(column, value); boundStatementBuilder.setString(column, value);
} }

33
application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java

@ -15,9 +15,7 @@
*/ */
package org.thingsboard.server.service.install.update; package org.thingsboard.server.service.install.update;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
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 com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
@ -25,16 +23,12 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.thingsboard.rule.engine.profile.TbDeviceProfileNode; import org.thingsboard.rule.engine.profile.TbDeviceProfileNode;
import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration; import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.SearchTextBased;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityViewId; 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.id.UUIDBased;
import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
import org.thingsboard.server.common.data.kv.ReadTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry;
@ -50,7 +44,6 @@ import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.dao.util.mapping.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.service.install.InstallScripts; import org.thingsboard.server.service.install.InstallScripts;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -58,7 +51,6 @@ import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.commons.lang.StringUtils.isBlank; import static org.apache.commons.lang.StringUtils.isBlank;
import static org.thingsboard.server.service.install.DatabaseHelper.objectMapper;
@Service @Service
@Profile("install") @Profile("install")
@ -87,6 +79,10 @@ public class DefaultDataUpdateService implements DataUpdateService {
log.info("Updating data from version 1.4.0 to 2.0.0 ..."); log.info("Updating data from version 1.4.0 to 2.0.0 ...");
tenantsDefaultRuleChainUpdater.updateEntities(null); tenantsDefaultRuleChainUpdater.updateEntities(null);
break; break;
case "2.5.5":
log.info("Updating data from version 2.5.5 to 2.6.0 ...");
tenantsDefaultEdgeRuleChainUpdater.updateEntities(null);
break;
case "3.0.1": case "3.0.1":
log.info("Updating data from version 3.0.1 to 3.1.0 ..."); log.info("Updating data from version 3.0.1 to 3.1.0 ...");
tenantsEntityViewsUpdater.updateEntities(null); tenantsEntityViewsUpdater.updateEntities(null);
@ -121,6 +117,27 @@ public class DefaultDataUpdateService implements DataUpdateService {
} }
}; };
private PaginatedUpdater<String, Tenant> tenantsDefaultEdgeRuleChainUpdater =
new PaginatedUpdater<String, Tenant>() {
@Override
protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
return tenantService.findTenants(pageLink);
}
@Override
protected void updateEntity(Tenant tenant) {
try {
RuleChain defaultEdgeRuleChain = ruleChainService.getDefaultRootEdgeRuleChain(tenant.getId());
if (defaultEdgeRuleChain == null) {
installScripts.createDefaultEdgeRuleChains(tenant.getId());
}
} catch (Exception e) {
log.error("Unable to update Tenant", e);
}
}
};
private PaginatedUpdater<String, Tenant> tenantsRootRuleChainUpdater = private PaginatedUpdater<String, Tenant> tenantsRootRuleChainUpdater =
new PaginatedUpdater<String, Tenant>() { new PaginatedUpdater<String, Tenant>() {

11
application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java

@ -35,9 +35,9 @@ public class TbCoreConsumerStats {
public static final String SUBSCRIPTION_INFO = "subInfo"; public static final String SUBSCRIPTION_INFO = "subInfo";
public static final String DEVICE_CLAIMS = "claimDevice"; public static final String DEVICE_CLAIMS = "claimDevice";
public static final String DEVICE_STATES = "deviceState"; public static final String DEVICE_STATES = "deviceState";
public static final String EDGE_EVENTS = "edgeEvents";
public static final String SUBSCRIPTION_MSGS = "subMsgs"; public static final String SUBSCRIPTION_MSGS = "subMsgs";
public static final String TO_CORE_NOTIFICATIONS = "coreNfs"; public static final String TO_CORE_NOTIFICATIONS = "coreNfs";
public static final String EDGE_NOTIFICATIONS = "edgeNfs";
private final StatsCounter totalCounter; private final StatsCounter totalCounter;
private final StatsCounter sessionEventCounter; private final StatsCounter sessionEventCounter;
@ -49,9 +49,9 @@ public class TbCoreConsumerStats {
private final StatsCounter claimDeviceCounter; private final StatsCounter claimDeviceCounter;
private final StatsCounter deviceStateCounter; private final StatsCounter deviceStateCounter;
private final StatsCounter edgeNotificationCounter;
private final StatsCounter subscriptionMsgCounter; private final StatsCounter subscriptionMsgCounter;
private final StatsCounter toCoreNotificationsCounter; private final StatsCounter toCoreNotificationsCounter;
private final StatsCounter edgeNotificationsCounter;
private final List<StatsCounter> counters = new ArrayList<>(); private final List<StatsCounter> counters = new ArrayList<>();
@ -67,10 +67,9 @@ public class TbCoreConsumerStats {
this.subscriptionInfoCounter = statsFactory.createStatsCounter(statsKey, SUBSCRIPTION_INFO); this.subscriptionInfoCounter = statsFactory.createStatsCounter(statsKey, SUBSCRIPTION_INFO);
this.claimDeviceCounter = statsFactory.createStatsCounter(statsKey, DEVICE_CLAIMS); this.claimDeviceCounter = statsFactory.createStatsCounter(statsKey, DEVICE_CLAIMS);
this.deviceStateCounter = statsFactory.createStatsCounter(statsKey, DEVICE_STATES); this.deviceStateCounter = statsFactory.createStatsCounter(statsKey, DEVICE_STATES);
this.edgeNotificationCounter = statsFactory.createStatsCounter(statsKey, EDGE_EVENTS);
this.subscriptionMsgCounter = statsFactory.createStatsCounter(statsKey, SUBSCRIPTION_MSGS); this.subscriptionMsgCounter = statsFactory.createStatsCounter(statsKey, SUBSCRIPTION_MSGS);
this.toCoreNotificationsCounter = statsFactory.createStatsCounter(statsKey, TO_CORE_NOTIFICATIONS); this.toCoreNotificationsCounter = statsFactory.createStatsCounter(statsKey, TO_CORE_NOTIFICATIONS);
this.edgeNotificationsCounter = statsFactory.createStatsCounter(statsKey, EDGE_NOTIFICATIONS);
counters.add(totalCounter); counters.add(totalCounter);
counters.add(sessionEventCounter); counters.add(sessionEventCounter);
@ -82,9 +81,9 @@ public class TbCoreConsumerStats {
counters.add(claimDeviceCounter); counters.add(claimDeviceCounter);
counters.add(deviceStateCounter); counters.add(deviceStateCounter);
counters.add(edgeNotificationCounter);
counters.add(subscriptionMsgCounter); counters.add(subscriptionMsgCounter);
counters.add(toCoreNotificationsCounter); counters.add(toCoreNotificationsCounter);
counters.add(edgeNotificationsCounter);
} }
public void log(TransportProtos.TransportToDeviceActorMsg msg) { public void log(TransportProtos.TransportToDeviceActorMsg msg) {
@ -119,7 +118,7 @@ public class TbCoreConsumerStats {
public void log(TransportProtos.EdgeNotificationMsgProto msg) { public void log(TransportProtos.EdgeNotificationMsgProto msg) {
totalCounter.increment(); totalCounter.increment();
edgeNotificationCounter.increment(); edgeNotificationsCounter.increment();
} }
public void log(TransportProtos.SubscriptionMgrMsgProto msg) { public void log(TransportProtos.SubscriptionMgrMsgProto msg) {

3
application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbRuleEngineRpcService.java

@ -151,7 +151,8 @@ public class DefaultTbRuleEngineRpcService implements TbRuleEngineDeviceRpcServi
} }
} }
private void sendRpcResponseToTbCore(String originServiceId, FromDeviceRpcResponse response) { @Override
public void sendRpcResponseToTbCore(String originServiceId, FromDeviceRpcResponse response) {
if (serviceId.equals(originServiceId)) { if (serviceId.equals(originServiceId)) {
if (tbCoreRpcService.isPresent()) { if (tbCoreRpcService.isPresent()) {
tbCoreRpcService.get().processRpcResponseFromRuleEngine(response); tbCoreRpcService.get().processRpcResponseFromRuleEngine(response);

9
application/src/main/java/org/thingsboard/server/service/rpc/TbRuleEngineDeviceRpcService.java

@ -29,4 +29,13 @@ public interface TbRuleEngineDeviceRpcService extends RuleEngineRpcService {
*/ */
void processRpcResponseFromDevice(FromDeviceRpcResponse response); void processRpcResponseFromDevice(FromDeviceRpcResponse response);
/**
* Sends Rpc response from the Device to TB Core.
*
* @param originServiceId Service ID of the origin component
* @param response the RPC response
*/
void sendRpcResponseToTbCore(String originServiceId, FromDeviceRpcResponse response);
} }

2
application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java

@ -112,7 +112,7 @@ public class AccessValidator {
@Autowired @Autowired
protected EntityViewService entityViewService; protected EntityViewService entityViewService;
@Autowired @Autowired(required = false)
protected EdgeService edgeService; protected EdgeService edgeService;
@Autowired @Autowired

56
application/src/main/java/org/thingsboard/server/service/ttl/edge/EdgeEventsCleanUpService.java

@ -0,0 +1,56 @@
/**
* Copyright © 2016-2020 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.service.ttl.edge;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.thingsboard.server.dao.util.PsqlDao;
import org.thingsboard.server.service.ttl.AbstractCleanUpService;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
@PsqlDao
@Slf4j
@Service
public class EdgeEventsCleanUpService extends AbstractCleanUpService {
@Value("${sql.ttl.edge_events.edge_events_ttl}")
private long ttl;
@Value("${sql.ttl.edge_events.enabled}")
private boolean ttlTaskExecutionEnabled;
@Scheduled(initialDelayString = "${sql.ttl.edge_events.execution_interval_ms}", fixedDelayString = "${sql.ttl.edge_events.execution_interval_ms}")
public void cleanUp() {
if (ttlTaskExecutionEnabled) {
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
doCleanUp(conn);
} catch (SQLException e) {
log.error("SQLException occurred during TTL task execution ", e);
}
}
}
@Override
protected void doCleanUp(Connection connection) throws SQLException {
long totalEdgeEventsRemoved = executeQuery(connection, "call cleanup_edge_events_by_ttl(" + ttl + ", 0);");
log.info("Total edge events removed by TTL: [{}]", totalEdgeEventsRemoved);
}
}

12
application/src/main/resources/thingsboard.yml

@ -308,6 +308,10 @@ sql:
execution_interval_ms: "${SQL_TTL_EVENTS_EXECUTION_INTERVAL:86400000}" # Number of milliseconds. The current value corresponds to one day execution_interval_ms: "${SQL_TTL_EVENTS_EXECUTION_INTERVAL:86400000}" # Number of milliseconds. The current value corresponds to one day
events_ttl: "${SQL_TTL_EVENTS_EVENTS_TTL:0}" # Number of seconds events_ttl: "${SQL_TTL_EVENTS_EVENTS_TTL:0}" # Number of seconds
debug_events_ttl: "${SQL_TTL_EVENTS_DEBUG_EVENTS_TTL:604800}" # Number of seconds. The current value corresponds to one week debug_events_ttl: "${SQL_TTL_EVENTS_DEBUG_EVENTS_TTL:604800}" # Number of seconds. The current value corresponds to one week
edge_events:
enabled: "${SQL_TTL_EDGE_EVENTS_ENABLED:true}"
execution_interval_ms: "${SQL_TTL_EDGE_EVENTS_EXECUTION_INTERVAL:86400000}" # Number of milliseconds. The current value corresponds to one day
edge_events_ttl: "${SQL_TTL_EDGE_EVENTS_TTL:2628000}" # Number of seconds. The current value corresponds to one month
# Actor system parameters # Actor system parameters
actors: actors:
@ -625,8 +629,9 @@ transport:
# Edges parameters # Edges parameters
edges: edges:
rpc: rpc:
enabled: "${EDGES_RPC_ENABLED:true}" enabled: "${EDGES_RPC_ENABLED:false}"
port: "${EDGES_RPC_PORT:60100}" port: "${EDGES_RPC_PORT:7070}"
client_max_keep_alive_time_sec: "${EDGES_RPC_CLIENT_MAX_KEEP_ALIVE_TIME_SEC:300}"
ssl: ssl:
# Enable/disable SSL support # Enable/disable SSL support
enabled: "${EDGES_RPC_SSL_ENABLED:false}" enabled: "${EDGES_RPC_SSL_ENABLED:false}"
@ -636,6 +641,9 @@ edges:
max_read_records_count: "${EDGES_RPC_STORAGE_MAX_READ_RECORDS_COUNT:50}" max_read_records_count: "${EDGES_RPC_STORAGE_MAX_READ_RECORDS_COUNT:50}"
no_read_records_sleep: "${EDGES_RPC_NO_READ_RECORDS_SLEEP:1000}" no_read_records_sleep: "${EDGES_RPC_NO_READ_RECORDS_SLEEP:1000}"
sleep_between_batches: "${EDGES_RPC_SLEEP_BETWEEN_BATCHES:1000}" sleep_between_batches: "${EDGES_RPC_SLEEP_BETWEEN_BATCHES:1000}"
edge_events_ttl: "${EDGES_EDGE_EVENTS_TTL:0}"
state:
persistToTelemetry: "${EDGES_PERSIST_STATE_TO_TELEMETRY:false}"
swagger: swagger:
api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}" api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}"

16
application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java

@ -24,6 +24,7 @@ import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jwt; import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import org.junit.After; import org.junit.After;
@ -68,6 +69,7 @@ import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.HasId;
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;
@ -543,4 +545,18 @@ public abstract class AbstractWebTest {
return jsonPath("$.message", matcher); return jsonPath("$.message", matcher);
} }
protected Edge constructEdge(String name, String type) {
return constructEdge(tenantId, name, type);
}
protected Edge constructEdge(TenantId tenantId, String name, String type) {
Edge edge = new Edge();
edge.setTenantId(tenantId);
edge.setName(name);
edge.setType(type);
edge.setSecret(RandomStringUtils.randomAlphanumeric(20));
edge.setRoutingKey(RandomStringUtils.randomAlphanumeric(20));
edge.setEdgeLicenseKey(RandomStringUtils.randomAlphanumeric(20));
edge.setCloudEndpoint("http://localhost:8080");
return edge;
}
} }

27
application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java

@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
@ -672,4 +673,30 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@Test
public void testAssignAssetToEdge() throws Exception {
Edge edge = constructEdge("My edge", "default");
Edge savedEdge = doPost("/api/edge", edge, Edge.class);
Asset asset = new Asset();
asset.setName("My asset");
asset.setType("default");
Asset savedAsset = doPost("/api/asset", asset, Asset.class);
doPost("/api/edge/" + savedEdge.getId().getId().toString()
+ "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
PageData<Asset> pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/assets?",
new TypeReference<PageData<Asset>>() {}, new PageLink(100));
Assert.assertEquals(1, pageData.getData().size());
doDelete("/api/edge/" + savedEdge.getId().getId().toString()
+ "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/assets?",
new TypeReference<PageData<Asset>>() {}, new PageLink(100));
Assert.assertEquals(0, pageData.getData().size());
}
} }

57
application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java

@ -15,27 +15,30 @@
*/ */
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.thingsboard.server.common.data.*;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import com.fasterxml.jackson.core.type.TypeReference; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class BaseDashboardControllerTest extends AbstractControllerTest { public abstract class BaseDashboardControllerTest extends AbstractControllerTest {
@ -348,4 +351,30 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
Assert.assertEquals(dashboards, loadedDashboards); Assert.assertEquals(dashboards, loadedDashboards);
} }
@Test
public void testAssignDashboardToEdge() throws Exception {
Edge edge = constructEdge("My edge", "default");
Edge savedEdge = doPost("/api/edge", edge, Edge.class);
Dashboard dashboard = new Dashboard();
dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
doPost("/api/edge/" + savedEdge.getId().getId().toString()
+ "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
PageData<Dashboard> pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/dashboards?",
new TypeReference<PageData<Dashboard>>() {}, new PageLink(100));
Assert.assertEquals(1, pageData.getData().size());
doDelete("/api/edge/" + savedEdge.getId().getId().toString()
+ "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/dashboards?",
new TypeReference<PageData<Dashboard>>() {}, new PageLink(100));
Assert.assertEquals(0, pageData.getData().size());
}
} }

37
application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java

@ -24,10 +24,10 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceCredentialsId; import org.thingsboard.server.common.data.id.DeviceCredentialsId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
@ -463,7 +463,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
pageLink = new PageLink(4, 0, title1); pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
@ -473,7 +473,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
@ -669,7 +669,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
pageLink = new PageLink(4, 0, title1); pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
@ -679,7 +679,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
@ -827,4 +827,31 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
doDelete("/api/tenant/" + savedDifferentTenant.getId().getId().toString()) doDelete("/api/tenant/" + savedDifferentTenant.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test
public void testAssignDeviceToEdge() throws Exception {
Edge edge = constructEdge("My edge", "default");
Edge savedEdge = doPost("/api/edge", edge, Edge.class);
Device device = new Device();
device.setName("My device");
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
doPost("/api/edge/" + savedEdge.getId().getId().toString()
+ "/device/" + savedDevice.getId().getId().toString(), Device.class);
PageData<Device> pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/devices?",
new TypeReference<PageData<Device>>() {}, new PageLink(100));
Assert.assertEquals(1, pageData.getData().size());
doDelete("/api/edge/" + savedEdge.getId().getId().toString()
+ "/device/" + savedDevice.getId().getId().toString(), Device.class);
pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/devices?",
new TypeReference<PageData<Device>>() {}, new PageLink(100));
Assert.assertEquals(0, pageData.getData().size());
}
} }

73
application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java

@ -18,14 +18,17 @@ package org.thingsboard.server.controller;
import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
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.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -33,6 +36,12 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.edge.imitator.EdgeImitator;
import org.thingsboard.server.gen.edge.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.RuleChainUpdateMsg;
import org.thingsboard.server.gen.edge.UserCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.UserUpdateMsg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -90,6 +99,8 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
Assert.assertNotNull(savedEdge.getCustomerId()); Assert.assertNotNull(savedEdge.getCustomerId());
Assert.assertEquals(NULL_UUID, savedEdge.getCustomerId().getId()); Assert.assertEquals(NULL_UUID, savedEdge.getCustomerId().getId());
Assert.assertEquals(edge.getName(), savedEdge.getName()); Assert.assertEquals(edge.getName(), savedEdge.getName());
Assert.assertTrue(StringUtils.isNoneBlank(savedEdge.getEdgeLicenseKey()));
Assert.assertTrue(StringUtils.isNoneBlank(savedEdge.getCloudEndpoint()));
savedEdge.setName("My new edge"); savedEdge.setName("My new edge");
doPost("/api/edge", savedEdge, Edge.class); doPost("/api/edge", savedEdge, Edge.class);
@ -638,17 +649,57 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
private Edge constructEdge(String name, String type) { @Test
return constructEdge(tenantId, name, type); public void testSyncEdge() throws Exception {
Edge edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class);
Device device = new Device();
device.setName("Edge Device 1");
device.setType("test");
Device savedDevice = doPost("/api/device", device, Device.class);
doPost("/api/edge/" + edge.getId().getId().toString()
+ "/device/" + savedDevice.getId().getId().toString(), Device.class);
Asset asset = new Asset();
asset.setName("Edge Asset 1");
asset.setType("test");
Asset savedAsset = doPost("/api/asset", asset, Asset.class);
doPost("/api/edge/" + edge.getId().getId().toString()
+ "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
EdgeImitator edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret());
edgeImitator.ignoreType(UserCredentialsUpdateMsg.class);
edgeImitator.expectMessageAmount(7);
edgeImitator.connect();
edgeImitator.waitForMessages();
Assert.assertEquals(7, edgeImitator.getDownlinkMsgs().size());
Assert.assertTrue(edgeImitator.findMessageByType(RuleChainUpdateMsg.class).isPresent());
Assert.assertTrue(edgeImitator.findMessageByType(DeviceUpdateMsg.class).isPresent());
Assert.assertTrue(edgeImitator.findMessageByType(AssetUpdateMsg.class).isPresent());
Assert.assertTrue(edgeImitator.findMessageByType(UserUpdateMsg.class).isPresent());
edgeImitator.getDownlinkMsgs().clear();
edgeImitator.expectMessageAmount(4);
doPost("/api/edge/sync", edge.getId());
edgeImitator.waitForMessages();
Assert.assertEquals(4, edgeImitator.getDownlinkMsgs().size());
Assert.assertTrue(edgeImitator.findMessageByType(RuleChainUpdateMsg.class).isPresent());
Assert.assertTrue(edgeImitator.findMessageByType(DeviceUpdateMsg.class).isPresent());
Assert.assertTrue(edgeImitator.findMessageByType(AssetUpdateMsg.class).isPresent());
Assert.assertTrue(edgeImitator.findMessageByType(UserUpdateMsg.class).isPresent());
edgeImitator.allowIgnoredTypes();
edgeImitator.disconnect();
doDelete("/api/device/" + savedDevice.getId().getId().toString())
.andExpect(status().isOk());
doDelete("/api/asset/" + savedAsset.getId().getId().toString())
.andExpect(status().isOk());
doDelete("/api/edge/" + edge.getId().getId().toString())
.andExpect(status().isOk());
} }
private Edge constructEdge(TenantId tenantId, String name, String type) {
Edge edge = new Edge();
edge.setTenantId(tenantId);
edge.setName(name);
edge.setType(type);
edge.setSecret(RandomStringUtils.randomAlphanumeric(20));
edge.setRoutingKey(RandomStringUtils.randomAlphanumeric(20));
return edge;
}
} }

125
application/src/test/java/org/thingsboard/server/controller/BaseEdgeEventControllerTest.java

@ -0,0 +1,125 @@
/**
* Copyright © 2016-2020 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.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.security.Authority;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Slf4j
public class BaseEdgeEventControllerTest extends AbstractControllerTest {
private Tenant savedTenant;
private TenantId tenantId;
private User tenantAdmin;
@Before
public void beforeTest() throws Exception {
loginSysAdmin();
Tenant tenant = new Tenant();
tenant.setTitle("My tenant");
savedTenant = doPost("/api/tenant", tenant, Tenant.class);
tenantId = savedTenant.getId();
Assert.assertNotNull(savedTenant);
tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(savedTenant.getId());
tenantAdmin.setEmail("tenant2@thingsboard.org");
tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs");
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
}
@After
public void afterTest() throws Exception {
loginSysAdmin();
doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk());
}
@Test
public void testGetEdgeEvents() throws Exception {
Thread.sleep(1000);
Edge edge = constructEdge("TestEdge", "default");
edge = doPost("/api/edge", edge, Edge.class);
Device device = constructDevice("TestDevice", "default");
Device savedDevice = doPost("/api/device", device, Device.class);
doPost("/api/edge/" + edge.getId().toString() + "/device/" + savedDevice.getId().toString(), Device.class);
Thread.sleep(1000);
Asset asset = constructAsset("TestAsset", "default");
Asset savedAsset = doPost("/api/asset", asset, Asset.class);
doPost("/api/edge/" + edge.getId().toString() + "/asset/" + savedAsset.getId().toString(), Asset.class);
Thread.sleep(1000);
EntityRelation relation = new EntityRelation(savedAsset.getId(), savedDevice.getId(), EntityRelation.CONTAINS_TYPE);
doPost("/api/relation", relation);
Thread.sleep(1000);
List<EdgeEvent> edgeEvents = doGetTypedWithTimePageLink("/api/edge/" + edge.getId().toString() + "/events?",
new TypeReference<PageData<EdgeEvent>>() {
}, new TimePageLink(4)).getData();
Assert.assertFalse(edgeEvents.isEmpty());
Assert.assertEquals(4, edgeEvents.size());
Assert.assertEquals(EdgeEventType.RELATION, edgeEvents.get(0).getType());
Assert.assertEquals(EdgeEventType.ASSET, edgeEvents.get(1).getType());
Assert.assertEquals(EdgeEventType.DEVICE, edgeEvents.get(2).getType());
Assert.assertEquals(EdgeEventType.RULE_CHAIN, edgeEvents.get(3).getType());
}
private Device constructDevice(String name, String type) {
Device device = new Device();
device.setName(name);
device.setType(type);
return device;
}
private Asset constructAsset(String name, String type) {
Asset asset = new Asset();
asset.setName(name);
asset.setType(type);
return asset;
}
}

36
application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java

@ -27,7 +27,13 @@ import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.*; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EntityViewInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.objects.AttributesEntityView; import org.thingsboard.server.common.data.objects.AttributesEntityView;
import org.thingsboard.server.common.data.objects.TelemetryEntityView; import org.thingsboard.server.common.data.objects.TelemetryEntityView;
@ -49,7 +55,6 @@ import java.util.concurrent.TimeUnit;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@ -568,4 +573,31 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
return loadedItems; return loadedItems;
} }
@Test
public void testAssignEntityViewToEdge() throws Exception {
Edge edge = constructEdge("My edge", "default");
Edge savedEdge = doPost("/api/edge", edge, Edge.class);
EntityView savedEntityView = getNewSavedEntityView("My entityView");
doPost("/api/edge/" + savedEdge.getId().getId().toString()
+ "/device/" + testDevice.getId().getId().toString(), Device.class);
doPost("/api/edge/" + savedEdge.getId().getId().toString()
+ "/entityView/" + savedEntityView.getId().getId().toString(), EntityView.class);
PageData<EntityView> pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/entityViews?",
new TypeReference<PageData<EntityView>>() {}, new PageLink(100));
Assert.assertEquals(1, pageData.getData().size());
doDelete("/api/edge/" + savedEdge.getId().getId().toString()
+ "/entityView/" + savedEntityView.getId().getId().toString(), EntityView.class);
pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/entityViews?",
new TypeReference<PageData<EntityView>>() {}, new PageLink(100));
Assert.assertEquals(0, pageData.getData().size());
}
} }

23
application/src/test/java/org/thingsboard/server/controller/nosql/EdgeEventControllerNoSqlTest.java

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2020 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.controller.nosql;
import org.thingsboard.server.controller.BaseEdgeEventControllerTest;
import org.thingsboard.server.dao.service.DaoNoSqlTest;
@DaoNoSqlTest
public class EdgeEventControllerNoSqlTest extends BaseEdgeEventControllerTest {
}

23
application/src/test/java/org/thingsboard/server/controller/sql/EdgeEventControllerSqlTest.java

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2020 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.controller.sql;
import org.thingsboard.server.controller.BaseEdgeEventControllerTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
@DaoSqlTest
public class EdgeEventControllerSqlTest extends BaseEdgeEventControllerTest {
}

1090
application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java

File diff suppressed because it is too large

47
application/src/test/java/org/thingsboard/server/edge/EdgeNoSqlTestSuite.java

@ -0,0 +1,47 @@
/**
* Copyright © 2016-2020 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.edge;
import org.cassandraunit.dataset.cql.ClassPathCQLDataSet;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.extensions.cpsuite.ClasspathSuite;
import org.junit.runner.RunWith;
import org.thingsboard.server.dao.CustomCassandraCQLUnit;
import org.thingsboard.server.queue.memory.InMemoryStorage;
import java.util.Arrays;
@RunWith(ClasspathSuite.class)
@ClasspathSuite.ClassnameFilters({
"org.thingsboard.server.edge.nosql.*Test"})
public class EdgeNoSqlTestSuite {
@ClassRule
public static CustomCassandraCQLUnit cassandraUnit =
new CustomCassandraCQLUnit(
Arrays.asList(
new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false),
new ClassPathCQLDataSet("cassandra/schema-entities.cql", false, false),
new ClassPathCQLDataSet("cassandra/system-data.cql", false, false),
new ClassPathCQLDataSet("cassandra/system-test.cql", false, false)),
"cassandra-test.yaml", 30000l);
@BeforeClass
public static void cleanupInMemStorage(){
InMemoryStorage.getInstance().cleanup();
}
}

41
application/src/test/java/org/thingsboard/server/edge/EdgeSqlTestSuite.java

@ -0,0 +1,41 @@
/**
* Copyright © 2016-2020 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.edge;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.extensions.cpsuite.ClasspathSuite;
import org.junit.runner.RunWith;
import org.thingsboard.server.dao.CustomSqlUnit;
import org.thingsboard.server.queue.memory.InMemoryStorage;
import java.util.Arrays;
@RunWith(ClasspathSuite.class)
@ClasspathSuite.ClassnameFilters({"org.thingsboard.server.edge.sql.*Test"})
public class EdgeSqlTestSuite {
@ClassRule
public static CustomSqlUnit sqlUnit = new CustomSqlUnit(
Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql"),
"sql/hsql/drop-all-tables.sql",
"sql-test.properties");
@BeforeClass
public static void cleanupInMemStorage(){
InMemoryStorage.getInstance().cleanup();
}
}

268
application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java

@ -0,0 +1,268 @@
/**
* Copyright © 2016-2020 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.edge.imitator;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.protobuf.AbstractMessage;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.thingsboard.edge.rpc.EdgeGrpcClient;
import org.thingsboard.edge.rpc.EdgeRpcClient;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.gen.edge.AlarmUpdateMsg;
import org.thingsboard.server.gen.edge.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.CustomerUpdateMsg;
import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.DownlinkMsg;
import org.thingsboard.server.gen.edge.DownlinkResponseMsg;
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.RelationUpdateMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.RuleChainUpdateMsg;
import org.thingsboard.server.gen.edge.UplinkMsg;
import org.thingsboard.server.gen.edge.UplinkResponseMsg;
import org.thingsboard.server.gen.edge.UserCredentialsUpdateMsg;
import org.thingsboard.server.gen.edge.UserUpdateMsg;
import org.thingsboard.server.gen.edge.WidgetTypeUpdateMsg;
import org.thingsboard.server.gen.edge.WidgetsBundleUpdateMsg;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@Slf4j
public class EdgeImitator {
private String routingKey;
private String routingSecret;
private EdgeRpcClient edgeRpcClient;
private CountDownLatch messagesLatch;
private CountDownLatch responsesLatch;
private List<Class<? extends AbstractMessage>> ignoredTypes;
@Getter
private EdgeConfiguration configuration;
@Getter
private UserId userId;
@Getter
private List<AbstractMessage> downlinkMsgs;
public EdgeImitator(String host, int port, String routingKey, String routingSecret) throws NoSuchFieldException, IllegalAccessException {
edgeRpcClient = new EdgeGrpcClient();
messagesLatch = new CountDownLatch(0);
responsesLatch = new CountDownLatch(0);
downlinkMsgs = new ArrayList<>();
ignoredTypes = new ArrayList<>();
this.routingKey = routingKey;
this.routingSecret = routingSecret;
setEdgeCredentials("rpcHost", host);
setEdgeCredentials("rpcPort", port);
setEdgeCredentials("keepAliveTimeSec", 300);
}
private void setEdgeCredentials(String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field fieldToSet = edgeRpcClient.getClass().getDeclaredField(fieldName);
fieldToSet.setAccessible(true);
fieldToSet.set(edgeRpcClient, value);
fieldToSet.setAccessible(false);
}
public void connect() {
edgeRpcClient.connect(routingKey, routingSecret,
this::onUplinkResponse,
this::onEdgeUpdate,
this::onDownlink,
this::onClose);
edgeRpcClient.sendSyncRequestMsg();
}
public void disconnect() throws InterruptedException {
edgeRpcClient.disconnect(false);
}
public void sendUplinkMsg(UplinkMsg uplinkMsg) {
edgeRpcClient.sendUplinkMsg(uplinkMsg);
}
private void onUplinkResponse(UplinkResponseMsg msg) {
log.info("onUplinkResponse: {}", msg);
responsesLatch.countDown();
}
private void onEdgeUpdate(EdgeConfiguration edgeConfiguration) {
this.configuration = edgeConfiguration;
}
private void onUserUpdate(UserUpdateMsg userUpdateMsg) {
this.userId = new UserId(new UUID(userUpdateMsg.getIdMSB(), userUpdateMsg.getIdLSB()));
}
private void onDownlink(DownlinkMsg downlinkMsg) {
ListenableFuture<List<Void>> future = processDownlinkMsg(downlinkMsg);
Futures.addCallback(future, new FutureCallback<List<Void>>() {
@Override
public void onSuccess(@Nullable List<Void> result) {
DownlinkResponseMsg downlinkResponseMsg = DownlinkResponseMsg.newBuilder().setSuccess(true).build();
edgeRpcClient.sendDownlinkResponseMsg(downlinkResponseMsg);
}
@Override
public void onFailure(Throwable t) {
DownlinkResponseMsg downlinkResponseMsg = DownlinkResponseMsg.newBuilder().setSuccess(false).setErrorMsg(t.getMessage()).build();
edgeRpcClient.sendDownlinkResponseMsg(downlinkResponseMsg);
}
}, MoreExecutors.directExecutor());
}
private void onClose(Exception e) {
log.info("onClose: {}", e.getMessage());
}
private ListenableFuture<List<Void>> processDownlinkMsg(DownlinkMsg downlinkMsg) {
List<ListenableFuture<Void>> result = new ArrayList<>();
if (downlinkMsg.getDeviceUpdateMsgList() != null && !downlinkMsg.getDeviceUpdateMsgList().isEmpty()) {
for (DeviceUpdateMsg deviceUpdateMsg: downlinkMsg.getDeviceUpdateMsgList()) {
result.add(saveDownlinkMsg(deviceUpdateMsg));
}
}
if (downlinkMsg.getDeviceCredentialsUpdateMsgList() != null && !downlinkMsg.getDeviceCredentialsUpdateMsgList().isEmpty()) {
for (DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg: downlinkMsg.getDeviceCredentialsUpdateMsgList()) {
result.add(saveDownlinkMsg(deviceCredentialsUpdateMsg));
}
}
if (downlinkMsg.getAssetUpdateMsgList() != null && !downlinkMsg.getAssetUpdateMsgList().isEmpty()) {
for (AssetUpdateMsg assetUpdateMsg: downlinkMsg.getAssetUpdateMsgList()) {
result.add(saveDownlinkMsg(assetUpdateMsg));
}
}
if (downlinkMsg.getRuleChainUpdateMsgList() != null && !downlinkMsg.getRuleChainUpdateMsgList().isEmpty()) {
for (RuleChainUpdateMsg ruleChainUpdateMsg: downlinkMsg.getRuleChainUpdateMsgList()) {
result.add(saveDownlinkMsg(ruleChainUpdateMsg));
}
}
if (downlinkMsg.getRuleChainMetadataUpdateMsgList() != null && !downlinkMsg.getRuleChainMetadataUpdateMsgList().isEmpty()) {
for (RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg: downlinkMsg.getRuleChainMetadataUpdateMsgList()) {
result.add(saveDownlinkMsg(ruleChainMetadataUpdateMsg));
}
}
if (downlinkMsg.getDashboardUpdateMsgList() != null && !downlinkMsg.getDashboardUpdateMsgList().isEmpty()) {
for (DashboardUpdateMsg dashboardUpdateMsg: downlinkMsg.getDashboardUpdateMsgList()) {
result.add(saveDownlinkMsg(dashboardUpdateMsg));
}
}
if (downlinkMsg.getRelationUpdateMsgList() != null && !downlinkMsg.getRelationUpdateMsgList().isEmpty()) {
for (RelationUpdateMsg relationUpdateMsg: downlinkMsg.getRelationUpdateMsgList()) {
result.add(saveDownlinkMsg(relationUpdateMsg));
}
}
if (downlinkMsg.getAlarmUpdateMsgList() != null && !downlinkMsg.getAlarmUpdateMsgList().isEmpty()) {
for (AlarmUpdateMsg alarmUpdateMsg: downlinkMsg.getAlarmUpdateMsgList()) {
result.add(saveDownlinkMsg(alarmUpdateMsg));
}
}
if (downlinkMsg.getEntityDataList() != null && !downlinkMsg.getEntityDataList().isEmpty()) {
for (EntityDataProto entityData: downlinkMsg.getEntityDataList()) {
result.add(saveDownlinkMsg(entityData));
}
}
if (downlinkMsg.getEntityViewUpdateMsgList() != null && !downlinkMsg.getEntityViewUpdateMsgList().isEmpty()) {
for (EntityViewUpdateMsg entityViewUpdateMsg: downlinkMsg.getEntityViewUpdateMsgList()) {
result.add(saveDownlinkMsg(entityViewUpdateMsg));
}
}
if (downlinkMsg.getCustomerUpdateMsgList() != null && !downlinkMsg.getCustomerUpdateMsgList().isEmpty()) {
for (CustomerUpdateMsg customerUpdateMsg: downlinkMsg.getCustomerUpdateMsgList()) {
result.add(saveDownlinkMsg(customerUpdateMsg));
}
}
if (downlinkMsg.getWidgetsBundleUpdateMsgList() != null && !downlinkMsg.getWidgetsBundleUpdateMsgList().isEmpty()) {
for (WidgetsBundleUpdateMsg widgetsBundleUpdateMsg: downlinkMsg.getWidgetsBundleUpdateMsgList()) {
result.add(saveDownlinkMsg(widgetsBundleUpdateMsg));
}
}
if (downlinkMsg.getWidgetTypeUpdateMsgList() != null && !downlinkMsg.getWidgetTypeUpdateMsgList().isEmpty()) {
for (WidgetTypeUpdateMsg widgetTypeUpdateMsg: downlinkMsg.getWidgetTypeUpdateMsgList()) {
result.add(saveDownlinkMsg(widgetTypeUpdateMsg));
}
}
if (downlinkMsg.getUserUpdateMsgList() != null && !downlinkMsg.getUserUpdateMsgList().isEmpty()) {
for (UserUpdateMsg userUpdateMsg: downlinkMsg.getUserUpdateMsgList()) {
onUserUpdate(userUpdateMsg);
result.add(saveDownlinkMsg(userUpdateMsg));
}
}
if (downlinkMsg.getUserCredentialsUpdateMsgList() != null && !downlinkMsg.getUserCredentialsUpdateMsgList().isEmpty()) {
for (UserCredentialsUpdateMsg userCredentialsUpdateMsg: downlinkMsg.getUserCredentialsUpdateMsgList()) {
result.add(saveDownlinkMsg(userCredentialsUpdateMsg));
}
}
return Futures.allAsList(result);
}
private ListenableFuture<Void> saveDownlinkMsg(AbstractMessage message) {
if (!ignoredTypes.contains(message.getClass())) {
downlinkMsgs.add(message);
messagesLatch.countDown();
}
return Futures.immediateFuture(null);
}
public void waitForMessages() throws InterruptedException {
messagesLatch.await(5, TimeUnit.SECONDS);
}
public void expectMessageAmount(int messageAmount) {
messagesLatch = new CountDownLatch(messageAmount);
}
public void waitForResponses() throws InterruptedException { responsesLatch.await(5, TimeUnit.SECONDS); }
public void expectResponsesAmount(int messageAmount) {
responsesLatch = new CountDownLatch(messageAmount);
}
public <T> Optional<T> findMessageByType(Class<T> tClass) {
return (Optional<T>) downlinkMsgs.stream().filter(downlinkMsg -> downlinkMsg.getClass().isAssignableFrom(tClass)).findAny();
}
public AbstractMessage getLatestMessage() {
return downlinkMsgs.get(downlinkMsgs.size() - 1);
}
public void ignoreType(Class<? extends AbstractMessage> type) {
ignoredTypes.add(type);
}
public void allowIgnoredTypes() {
ignoredTypes.clear();
}
}

23
application/src/test/java/org/thingsboard/server/edge/nosql/EdgeNoSqlTest.java

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2020 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.edge.nosql;
import org.thingsboard.server.dao.service.DaoNoSqlTest;
import org.thingsboard.server.edge.BaseEdgeTest;
@DaoNoSqlTest
public class EdgeNoSqlTest extends BaseEdgeTest {
}

23
application/src/test/java/org/thingsboard/server/edge/sql/EdgeSqlTest.java

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2020 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.edge.sql;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.edge.BaseEdgeTest;
@DaoSqlTest
public class EdgeSqlTest extends BaseEdgeTest {
}

3
application/src/test/java/org/thingsboard/server/mqtt/MqttNoSqlTestSuite.java

@ -28,8 +28,7 @@ import java.util.Arrays;
@RunWith(ClasspathSuite.class) @RunWith(ClasspathSuite.class)
@ClasspathSuite.ClassnameFilters({ @ClasspathSuite.ClassnameFilters({
// TODO: voba - fix before final test on cassandra "org.thingsboard.server.mqtt.*.nosql.*Test"})
"org.thingsboard.server.mqtt.*.nosql.*VOBA_FIX_BEFORE_FINAL_TESTTest"})
public class MqttNoSqlTestSuite { public class MqttNoSqlTestSuite {
@ClassRule @ClassRule

2
common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java

@ -58,7 +58,5 @@ public interface DashboardService {
Dashboard unassignDashboardFromEdge(TenantId tenantId, DashboardId dashboardId, EdgeId edgeId); Dashboard unassignDashboardFromEdge(TenantId tenantId, DashboardId dashboardId, EdgeId edgeId);
void unassignEdgeDashboards(TenantId tenantId, EdgeId edgeId);
PageData<DashboardInfo> findDashboardsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); PageData<DashboardInfo> findDashboardsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
} }

2
common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java

@ -89,5 +89,5 @@ public interface DeviceService {
Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId);
PageData<Device> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink); PageData<Device> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
} }

6
common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeEventService.java

@ -16,9 +16,7 @@
package org.thingsboard.server.dao.edge; package org.thingsboard.server.dao.edge;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
@ -26,10 +24,8 @@ import org.thingsboard.server.common.data.page.TimePageLink;
public interface EdgeEventService { public interface EdgeEventService {
EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType);
ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent); ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent);
PageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); PageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate);
} }

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

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
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.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.PageData; import org.thingsboard.server.common.data.page.PageData;
@ -78,4 +79,10 @@ public interface EdgeService {
ListenableFuture<List<Edge>> findEdgesByTenantIdAndRuleChainId(TenantId tenantId, RuleChainId ruleChainId); ListenableFuture<List<Edge>> findEdgesByTenantIdAndRuleChainId(TenantId tenantId, RuleChainId ruleChainId);
ListenableFuture<List<Edge>> findEdgesByTenantIdAndDashboardId(TenantId tenantId, DashboardId dashboardId); ListenableFuture<List<Edge>> findEdgesByTenantIdAndDashboardId(TenantId tenantId, DashboardId dashboardId);
ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId);
Object checkInstance(Object request);
Object activateInstance(String licenseSecret, String releaseDate);
} }

3
common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java

@ -27,6 +27,7 @@ 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.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import java.util.List; import java.util.List;
@ -81,5 +82,5 @@ public interface EntityViewService {
EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId); EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId);
PageData<EntityView> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink); PageData<EntityView> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
} }

5
common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainData; import org.thingsboard.server.common.data.rule.RuleChainData;
@ -76,9 +77,7 @@ public interface RuleChainService {
RuleChain unassignRuleChainFromEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId, boolean remove); RuleChain unassignRuleChainFromEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId, boolean remove);
void unassignEdgeRuleChains(TenantId tenantId, EdgeId edgeId); PageData<RuleChain> findRuleChainsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
PageData<RuleChain> findRuleChainsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink);
RuleChain getDefaultRootEdgeRuleChain(TenantId tenantId); RuleChain getDefaultRootEdgeRuleChain(TenantId tenantId);

7
common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java

@ -16,15 +16,12 @@
package org.thingsboard.server.common.data; package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import java.util.*; import java.util.HashSet;
import java.util.Set;
public class DashboardInfo extends SearchTextBased<DashboardId> implements HasName, HasTenantId { public class DashboardInfo extends SearchTextBased<DashboardId> implements HasName, HasTenantId {

76
common/data/src/main/java/org/thingsboard/server/common/data/EdgeUtils.java

@ -15,59 +15,41 @@
*/ */
package org.thingsboard.server.common.data; package org.thingsboard.server.common.data;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.edge.EdgeEventType;
import java.util.Set;
public final class EdgeUtils { public final class EdgeUtils {
private EdgeUtils() { private EdgeUtils() {
} }
public static boolean isAssignedToEdge(Set<ShortEdgeInfo> assignedEdges, EdgeId edgeId) { public static EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType) {
return assignedEdges != null && assignedEdges.contains(new ShortEdgeInfo(edgeId, null, null)); switch (entityType) {
} case EDGE:
return EdgeEventType.EDGE;
public static ShortEdgeInfo getAssignedEdgeInfo(Set<ShortEdgeInfo> assignedEdges, EdgeId edgeId) { case DEVICE:
if (assignedEdges != null) { return EdgeEventType.DEVICE;
for (ShortEdgeInfo edgeInfo : assignedEdges) { case ASSET:
if (edgeInfo.getEdgeId().equals(edgeId)) { return EdgeEventType.ASSET;
return edgeInfo; case ENTITY_VIEW:
} return EdgeEventType.ENTITY_VIEW;
} case DASHBOARD:
} return EdgeEventType.DASHBOARD;
return null; case USER:
} return EdgeEventType.USER;
case RULE_CHAIN:
public static boolean addAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) { return EdgeEventType.RULE_CHAIN;
if (assignedEdges != null && assignedEdges.contains(edgeInfo)) { case ALARM:
return false; return EdgeEventType.ALARM;
} else { case TENANT:
if (assignedEdges != null) { return EdgeEventType.TENANT;
assignedEdges.add(edgeInfo); case CUSTOMER:
return true; return EdgeEventType.CUSTOMER;
} else { case WIDGETS_BUNDLE:
return false; return EdgeEventType.WIDGETS_BUNDLE;
} case WIDGET_TYPE:
} return EdgeEventType.WIDGET_TYPE;
} default:
return null;
public static boolean updateAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) {
if (assignedEdges != null && assignedEdges.contains(edgeInfo)) {
assignedEdges.remove(edgeInfo);
assignedEdges.add(edgeInfo);
return true;
} else {
return false;
}
}
public static boolean removeAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) {
if (assignedEdges != null && assignedEdges.contains(edgeInfo)) {
assignedEdges.remove(edgeInfo);
return true;
} else {
return false;
} }
} }
} }

50
common/data/src/main/java/org/thingsboard/server/common/data/ShortEdgeInfo.java

@ -1,50 +0,0 @@
/**
* Copyright © 2016-2020 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;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.RuleChainId;
@AllArgsConstructor
public class ShortEdgeInfo {
@Getter @Setter
private EdgeId edgeId;
@Getter @Setter
private String title;
@Getter @Setter
private RuleChainId rootRuleChainId;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ShortEdgeInfo that = (ShortEdgeInfo) o;
return edgeId.equals(that.edgeId);
}
@Override
public int hashCode() {
return edgeId.hashCode();
}
}

4
common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java

@ -45,7 +45,9 @@ public enum ActionType {
ASSIGNED_FROM_TENANT(false), ASSIGNED_FROM_TENANT(false),
ASSIGNED_TO_TENANT(false), ASSIGNED_TO_TENANT(false),
ASSIGNED_TO_EDGE(false), // log edge name ASSIGNED_TO_EDGE(false), // log edge name
UNASSIGNED_FROM_EDGE(false); // log edge name UNASSIGNED_FROM_EDGE(false), // log edge name
CREDENTIALS_REQUEST(false), // request credentials from edge
ENTITY_EXISTS_REQUEST(false); // request to recreate entity on edge
private final boolean isRead; private final boolean isRead;

12
common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.common.data.edge; package org.thingsboard.server.common.data.edge;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@ -25,8 +24,6 @@ import org.thingsboard.server.common.data.HasCustomerId;
import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
import org.thingsboard.server.common.data.ShortCustomerInfo;
import org.thingsboard.server.common.data.ShortEdgeInfo;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
@ -48,6 +45,8 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H
private String label; private String label;
private String routingKey; private String routingKey;
private String secret; private String secret;
private String edgeLicenseKey;
private String cloudEndpoint;
private transient JsonNode configuration; private transient JsonNode configuration;
public Edge() { public Edge() {
@ -67,14 +66,11 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H
this.name = edge.getName(); this.name = edge.getName();
this.routingKey = edge.getRoutingKey(); this.routingKey = edge.getRoutingKey();
this.secret = edge.getSecret(); this.secret = edge.getSecret();
this.edgeLicenseKey = edge.getEdgeLicenseKey();
this.cloudEndpoint = edge.getCloudEndpoint();
this.configuration = edge.getConfiguration(); this.configuration = edge.getConfiguration();
} }
@JsonIgnore
public ShortEdgeInfo toShortEdgeInfo() {
return new ShortEdgeInfo(id, name, rootRuleChainId);
}
@Override @Override
public String getSearchText() { public String getSearchText() {
return getName(); return getName();

8
common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEvent.java

@ -20,7 +20,6 @@ import lombok.Data;
import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.EdgeEventId; import org.thingsboard.server.common.data.id.EdgeEventId;
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.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import java.util.UUID; import java.util.UUID;
@ -30,10 +29,11 @@ public class EdgeEvent extends BaseData<EdgeEventId> {
private TenantId tenantId; private TenantId tenantId;
private EdgeId edgeId; private EdgeId edgeId;
private String edgeEventAction; private String action;
private UUID entityId; private UUID entityId;
private EdgeEventType edgeEventType; private String uid;
private transient JsonNode entityBody; private EdgeEventType type;
private transient JsonNode body;
public EdgeEvent() { public EdgeEvent() {
super(); super();

16
common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java

@ -16,5 +16,19 @@
package org.thingsboard.server.common.data.edge; package org.thingsboard.server.common.data.edge;
public enum EdgeEventType { public enum EdgeEventType {
DASHBOARD, ASSET, DEVICE, ENTITY_VIEW, ALARM, RULE_CHAIN, RULE_CHAIN_METADATA, EDGE, USER, CUSTOMER, RELATION DASHBOARD,
ASSET,
DEVICE,
ENTITY_VIEW,
ALARM,
RULE_CHAIN,
RULE_CHAIN_METADATA,
EDGE,
USER,
CUSTOMER,
RELATION,
TENANT,
WIDGETS_BUNDLE,
WIDGET_TYPE,
ADMIN_SETTINGS
} }

3
common/data/src/main/java/org/thingsboard/server/common/data/exception/ThingsboardErrorCode.java

@ -28,7 +28,8 @@ public enum ThingsboardErrorCode {
BAD_REQUEST_PARAMS(31), BAD_REQUEST_PARAMS(31),
ITEM_NOT_FOUND(32), ITEM_NOT_FOUND(32),
TOO_MANY_REQUESTS(33), TOO_MANY_REQUESTS(33),
TOO_MANY_UPDATES(34); TOO_MANY_UPDATES(34),
SUBSCRIPTION_VIOLATION(40);
private int errorCode; private int errorCode;

4
common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java

@ -91,6 +91,10 @@ public class EntityIdFactory {
return new RuleChainId(uuid); return new RuleChainId(uuid);
case ENTITY_VIEW: case ENTITY_VIEW:
return new EntityViewId(uuid); return new EntityViewId(uuid);
case WIDGETS_BUNDLE:
return new WidgetsBundleId(uuid);
case WIDGET_TYPE:
return new WidgetTypeId(uuid);
case EDGE: case EDGE:
return new EdgeId(uuid); return new EdgeId(uuid);
} }

109
common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java

@ -28,9 +28,9 @@ import org.thingsboard.server.gen.edge.ConnectRequestMsg;
import org.thingsboard.server.gen.edge.ConnectResponseCode; 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.DownlinkMsg; import org.thingsboard.server.gen.edge.DownlinkMsg;
import org.thingsboard.server.gen.edge.DownlinkResponseMsg;
import org.thingsboard.server.gen.edge.EdgeConfiguration; import org.thingsboard.server.gen.edge.EdgeConfiguration;
import org.thingsboard.server.gen.edge.EdgeRpcServiceGrpc; import org.thingsboard.server.gen.edge.EdgeRpcServiceGrpc;
import org.thingsboard.server.gen.edge.EntityUpdateMsg;
import org.thingsboard.server.gen.edge.RequestMsg; import org.thingsboard.server.gen.edge.RequestMsg;
import org.thingsboard.server.gen.edge.RequestMsgType; import org.thingsboard.server.gen.edge.RequestMsgType;
import org.thingsboard.server.gen.edge.ResponseMsg; import org.thingsboard.server.gen.edge.ResponseMsg;
@ -40,7 +40,9 @@ import org.thingsboard.server.gen.edge.UplinkResponseMsg;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
import java.io.File; import java.io.File;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer; import java.util.function.Consumer;
@Service @Service
@ -53,6 +55,8 @@ public class EdgeGrpcClient implements EdgeRpcClient {
private int rpcPort; private int rpcPort;
@Value("${cloud.rpc.timeout}") @Value("${cloud.rpc.timeout}")
private int timeoutSecs; private int timeoutSecs;
@Value("${cloud.rpc.keep_alive_time_sec}")
private int keepAliveTimeSec;
@Value("${cloud.rpc.ssl.enabled}") @Value("${cloud.rpc.ssl.enabled}")
private boolean sslEnabled; private boolean sslEnabled;
@Value("${cloud.rpc.ssl.cert}") @Value("${cloud.rpc.ssl.cert}")
@ -62,15 +66,18 @@ public class EdgeGrpcClient implements EdgeRpcClient {
private StreamObserver<RequestMsg> inputStream; private StreamObserver<RequestMsg> inputStream;
private static final ReentrantLock uplinkMsgLock = new ReentrantLock();
@Override @Override
public void connect(String edgeKey, public void connect(String edgeKey,
String edgeSecret, String edgeSecret,
Consumer<UplinkResponseMsg> onUplinkResponse, Consumer<UplinkResponseMsg> onUplinkResponse,
Consumer<EdgeConfiguration> onEdgeUpdate, Consumer<EdgeConfiguration> onEdgeUpdate,
Consumer<EntityUpdateMsg> onEntityUpdate,
Consumer<DownlinkMsg> onDownlink, Consumer<DownlinkMsg> onDownlink,
Consumer<Exception> onError) { Consumer<Exception> onError) {
NettyChannelBuilder builder = NettyChannelBuilder.forAddress(rpcHost, rpcPort).usePlaintext(); NettyChannelBuilder builder = NettyChannelBuilder.forAddress(rpcHost, rpcPort)
.keepAliveTime(keepAliveTimeSec, TimeUnit.SECONDS)
.usePlaintext();
if (sslEnabled) { if (sslEnabled) {
try { try {
builder.sslContext(GrpcSslContexts.forClient().trustManager(new File(Resources.getResource(certResource).toURI())).build()); builder.sslContext(GrpcSslContexts.forClient().trustManager(new File(Resources.getResource(certResource).toURI())).build());
@ -79,47 +86,19 @@ public class EdgeGrpcClient implements EdgeRpcClient {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
gracefulShutdown();
channel = builder.build(); channel = builder.build();
EdgeRpcServiceGrpc.EdgeRpcServiceStub stub = EdgeRpcServiceGrpc.newStub(channel); EdgeRpcServiceGrpc.EdgeRpcServiceStub stub = EdgeRpcServiceGrpc.newStub(channel);
log.info("[{}] Sending a connect request to the TB!", edgeKey); log.info("[{}] Sending a connect request to the TB!", edgeKey);
this.inputStream = stub.handleMsgs(initOutputStream(edgeKey, onUplinkResponse, onEdgeUpdate, onEntityUpdate, onDownlink, onError)); this.inputStream = stub.handleMsgs(initOutputStream(edgeKey, onUplinkResponse, onEdgeUpdate, onDownlink, onError));
this.inputStream.onNext(RequestMsg.newBuilder() this.inputStream.onNext(RequestMsg.newBuilder()
.setMsgType(RequestMsgType.CONNECT_RPC_MESSAGE) .setMsgType(RequestMsgType.CONNECT_RPC_MESSAGE)
.setConnectRequestMsg(ConnectRequestMsg.newBuilder().setEdgeRoutingKey(edgeKey).setEdgeSecret(edgeSecret).build()) .setConnectRequestMsg(ConnectRequestMsg.newBuilder().setEdgeRoutingKey(edgeKey).setEdgeSecret(edgeSecret).build())
.build()); .build());
} }
private void gracefulShutdown() {
try {
if (channel != null) {
channel.shutdown().awaitTermination(timeoutSecs, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
log.debug("Error during shutdown of the previous channel", e);
}
}
@Override
public void disconnect() throws InterruptedException {
inputStream.onCompleted();
if (channel != null) {
channel.shutdown().awaitTermination(timeoutSecs, TimeUnit.SECONDS);
}
}
@Override
public void sendUplinkMsg(UplinkMsg msg) {
this.inputStream.onNext(RequestMsg.newBuilder()
.setMsgType(RequestMsgType.UPLINK_RPC_MESSAGE)
.setUplinkMsg(msg)
.build());
}
private StreamObserver<ResponseMsg> initOutputStream(String edgeKey, private StreamObserver<ResponseMsg> initOutputStream(String edgeKey,
Consumer<UplinkResponseMsg> onUplinkResponse, Consumer<UplinkResponseMsg> onUplinkResponse,
Consumer<EdgeConfiguration> onEdgeUpdate, Consumer<EdgeConfiguration> onEdgeUpdate,
Consumer<EntityUpdateMsg> onEntityUpdate,
Consumer<DownlinkMsg> onDownlink, Consumer<DownlinkMsg> onDownlink,
Consumer<Exception> onError) { Consumer<Exception> onError) {
return new StreamObserver<ResponseMsg>() { return new StreamObserver<ResponseMsg>() {
@ -132,14 +111,19 @@ public class EdgeGrpcClient implements EdgeRpcClient {
onEdgeUpdate.accept(connectResponseMsg.getConfiguration()); onEdgeUpdate.accept(connectResponseMsg.getConfiguration());
} else { } else {
log.error("[{}] Failed to establish the connection! Code: {}. Error message: {}.", edgeKey, connectResponseMsg.getResponseCode(), connectResponseMsg.getErrorMsg()); log.error("[{}] Failed to establish the connection! Code: {}. Error message: {}.", edgeKey, connectResponseMsg.getResponseCode(), connectResponseMsg.getErrorMsg());
try {
EdgeGrpcClient.this.disconnect(true);
} catch (InterruptedException e) {
log.error("[{}] Got interruption during disconnect!", edgeKey, e);
}
onError.accept(new EdgeConnectionException("Failed to establish the connection! Response code: " + connectResponseMsg.getResponseCode().name())); onError.accept(new EdgeConnectionException("Failed to establish the connection! Response code: " + connectResponseMsg.getResponseCode().name()));
} }
} else if (responseMsg.hasEdgeUpdateMsg()) {
log.debug("[{}] Edge update message received {}", edgeKey, responseMsg.getEdgeUpdateMsg());
onEdgeUpdate.accept(responseMsg.getEdgeUpdateMsg().getConfiguration());
} else if (responseMsg.hasUplinkResponseMsg()) { } else if (responseMsg.hasUplinkResponseMsg()) {
log.debug("[{}] Uplink response message received {}", edgeKey, responseMsg.getUplinkResponseMsg()); log.debug("[{}] Uplink response message received {}", edgeKey, responseMsg.getUplinkResponseMsg());
onUplinkResponse.accept(responseMsg.getUplinkResponseMsg()); onUplinkResponse.accept(responseMsg.getUplinkResponseMsg());
} else if (responseMsg.hasEntityUpdateMsg()) {
log.debug("[{}] Entity update message received {}", edgeKey, responseMsg.getEntityUpdateMsg());
onEntityUpdate.accept(responseMsg.getEntityUpdateMsg());
} else if (responseMsg.hasDownlinkMsg()) { } else if (responseMsg.hasDownlinkMsg()) {
log.debug("[{}] Downlink message received {}", edgeKey, responseMsg.getDownlinkMsg()); log.debug("[{}] Downlink message received {}", edgeKey, responseMsg.getDownlinkMsg());
onDownlink.accept(responseMsg.getDownlinkMsg()); onDownlink.accept(responseMsg.getDownlinkMsg());
@ -149,6 +133,11 @@ public class EdgeGrpcClient implements EdgeRpcClient {
@Override @Override
public void onError(Throwable t) { public void onError(Throwable t) {
log.debug("[{}] The rpc session received an error!", edgeKey, t); log.debug("[{}] The rpc session received an error!", edgeKey, t);
try {
EdgeGrpcClient.this.disconnect(true);
} catch (InterruptedException e) {
log.error("[{}] Got interruption during disconnect!", edgeKey, e);
}
onError.accept(new RuntimeException(t)); onError.accept(new RuntimeException(t));
} }
@ -158,4 +147,54 @@ public class EdgeGrpcClient implements EdgeRpcClient {
} }
}; };
} }
@Override
public void disconnect(boolean onError) throws InterruptedException {
if (!onError) {
try {
inputStream.onCompleted();
} catch (Exception ignored) {}
}
if (channel != null) {
channel.shutdown().awaitTermination(timeoutSecs, TimeUnit.SECONDS);
}
}
@Override
public void sendUplinkMsg(UplinkMsg msg) {
try {
uplinkMsgLock.lock();
this.inputStream.onNext(RequestMsg.newBuilder()
.setMsgType(RequestMsgType.UPLINK_RPC_MESSAGE)
.setUplinkMsg(msg)
.build());
} finally {
uplinkMsgLock.unlock();
}
}
@Override
public void sendSyncRequestMsg() {
try {
uplinkMsgLock.lock();
this.inputStream.onNext(RequestMsg.newBuilder()
.setMsgType(RequestMsgType.SYNC_REQUEST_RPC_MESSAGE)
.build());
} finally {
uplinkMsgLock.unlock();
}
}
@Override
public void sendDownlinkResponseMsg(DownlinkResponseMsg downlinkResponseMsg) {
try {
uplinkMsgLock.lock();
this.inputStream.onNext(RequestMsg.newBuilder()
.setMsgType(RequestMsgType.UPLINK_RPC_MESSAGE)
.setDownlinkResponseMsg(downlinkResponseMsg)
.build());
} finally {
uplinkMsgLock.unlock();
}
}
} }

11
common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeRpcClient.java

@ -16,8 +16,8 @@
package org.thingsboard.edge.rpc; package org.thingsboard.edge.rpc;
import org.thingsboard.server.gen.edge.DownlinkMsg; import org.thingsboard.server.gen.edge.DownlinkMsg;
import org.thingsboard.server.gen.edge.DownlinkResponseMsg;
import org.thingsboard.server.gen.edge.EdgeConfiguration; import org.thingsboard.server.gen.edge.EdgeConfiguration;
import org.thingsboard.server.gen.edge.EntityUpdateMsg;
import org.thingsboard.server.gen.edge.UplinkMsg; import org.thingsboard.server.gen.edge.UplinkMsg;
import org.thingsboard.server.gen.edge.UplinkResponseMsg; import org.thingsboard.server.gen.edge.UplinkResponseMsg;
@ -29,11 +29,14 @@ public interface EdgeRpcClient {
String integrationSecret, String integrationSecret,
Consumer<UplinkResponseMsg> onUplinkResponse, Consumer<UplinkResponseMsg> onUplinkResponse,
Consumer<EdgeConfiguration> onEdgeUpdate, Consumer<EdgeConfiguration> onEdgeUpdate,
Consumer<EntityUpdateMsg> onEntityUpdate,
Consumer<DownlinkMsg> onDownlink, Consumer<DownlinkMsg> onDownlink,
Consumer<Exception> onError); Consumer<Exception> onError);
void disconnect() throws InterruptedException; void disconnect(boolean onError) throws InterruptedException;
void sendUplinkMsg(UplinkMsg uplinkMsg) throws InterruptedException; void sendSyncRequestMsg();
void sendUplinkMsg(UplinkMsg uplinkMsg);
void sendDownlinkResponseMsg(DownlinkResponseMsg downlinkResponseMsg);
} }

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

@ -37,31 +37,24 @@ message RequestMsg {
RequestMsgType msgType = 1; RequestMsgType msgType = 1;
ConnectRequestMsg connectRequestMsg = 2; ConnectRequestMsg connectRequestMsg = 2;
UplinkMsg uplinkMsg = 3; UplinkMsg uplinkMsg = 3;
DownlinkResponseMsg downlinkResponseMsg = 4;
} }
message ResponseMsg { message ResponseMsg {
ConnectResponseMsg connectResponseMsg = 1; ConnectResponseMsg connectResponseMsg = 1;
UplinkResponseMsg uplinkResponseMsg = 2; UplinkResponseMsg uplinkResponseMsg = 2;
EntityUpdateMsg entityUpdateMsg = 3; DownlinkMsg downlinkMsg = 3;
DownlinkMsg downlinkMsg = 4; EdgeUpdateMsg edgeUpdateMsg = 4;
}
message EntityUpdateMsg {
DeviceUpdateMsg deviceUpdateMsg = 1;
RuleChainUpdateMsg ruleChainUpdateMsg = 2;
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = 3;
DashboardUpdateMsg dashboardUpdateMsg = 4;
AssetUpdateMsg assetUpdateMsg = 5;
EntityViewUpdateMsg entityViewUpdateMsg = 6;
AlarmUpdateMsg alarmUpdateMsg = 7;
UserUpdateMsg userUpdateMsg = 8;
CustomerUpdateMsg customerUpdateMsg = 9;
RelationUpdateMsg relationUpdateMsg = 10;
} }
enum RequestMsgType { enum RequestMsgType {
CONNECT_RPC_MESSAGE = 0; CONNECT_RPC_MESSAGE = 0;
UPLINK_RPC_MESSAGE = 1; UPLINK_RPC_MESSAGE = 1;
SYNC_REQUEST_RPC_MESSAGE = 2;
}
message EdgeUpdateMsg {
EdgeConfiguration configuration = 1;
} }
message ConnectRequestMsg { message ConnectRequestMsg {
@ -82,12 +75,16 @@ message ConnectResponseMsg {
} }
message EdgeConfiguration { message EdgeConfiguration {
int64 tenantIdMSB = 1; int64 edgeIdMSB = 1;
int64 tenantIdLSB = 2; int64 edgeIdLSB = 2;
string name = 3; int64 tenantIdMSB = 3;
string routingKey = 4; int64 tenantIdLSB = 4;
string type = 5; string name = 5;
string cloudType = 6; string routingKey = 6;
string type = 7;
string edgeLicenseKey = 8;
string cloudEndpoint = 9;
string cloudType = 10;
} }
enum UpdateMsgType { enum UpdateMsgType {
@ -105,9 +102,17 @@ message EntityDataProto {
string entityType = 3; string entityType = 3;
transport.PostTelemetryMsg postTelemetryMsg = 4; transport.PostTelemetryMsg postTelemetryMsg = 4;
transport.PostAttributeMsg postAttributesMsg = 5; transport.PostAttributeMsg postAttributesMsg = 5;
transport.PostAttributeMsg attributesUpdatedMsg = 6;
string postAttributeScope = 7;
AttributeDeleteMsg attributeDeleteMsg = 8;
// transport.ToDeviceRpcRequestMsg ??? // transport.ToDeviceRpcRequestMsg ???
} }
message AttributeDeleteMsg {
string scope = 1;
repeated string attributeNames = 2;
}
message RuleChainUpdateMsg { message RuleChainUpdateMsg {
UpdateMsgType msgType = 1; UpdateMsgType msgType = 1;
int64 idMSB = 2; int64 idMSB = 2;
@ -158,40 +163,56 @@ message DashboardUpdateMsg {
UpdateMsgType msgType = 1; UpdateMsgType msgType = 1;
int64 idMSB = 2; int64 idMSB = 2;
int64 idLSB = 3; int64 idLSB = 3;
string title = 4; int64 customerIdMSB = 4;
string configuration = 5; int64 customerIdLSB = 5;
string title = 6;
string configuration = 7;
} }
message DeviceUpdateMsg { message DeviceUpdateMsg {
UpdateMsgType msgType = 1; UpdateMsgType msgType = 1;
int64 idMSB = 2; int64 idMSB = 2;
int64 idLSB = 3; int64 idLSB = 3;
string name = 4; int64 customerIdMSB = 4;
string type = 5; int64 customerIdLSB = 5;
string label = 6; string name = 6;
string credentialsType = 7; string type = 7;
string credentialsId = 8; string label = 8;
string credentialsValue = 9; string additionalInfo = 9;
}
message DeviceCredentialsUpdateMsg {
int64 deviceIdMSB = 1;
int64 deviceIdLSB = 2;
string credentialsType = 3;
string credentialsId = 4;
string credentialsValue = 5;
} }
message AssetUpdateMsg { message AssetUpdateMsg {
UpdateMsgType msgType = 1; UpdateMsgType msgType = 1;
int64 idMSB = 2; int64 idMSB = 2;
int64 idLSB = 3; int64 idLSB = 3;
string name = 4; int64 customerIdMSB = 4;
string type = 5; int64 customerIdLSB = 5;
string label = 6; string name = 6;
string type = 7;
string label = 8;
string additionalInfo = 9;
} }
message EntityViewUpdateMsg { message EntityViewUpdateMsg {
UpdateMsgType msgType = 1; UpdateMsgType msgType = 1;
int64 idMSB = 2; int64 idMSB = 2;
int64 idLSB = 3; int64 idLSB = 3;
string name = 4; int64 customerIdMSB = 4;
string type = 5; int64 customerIdLSB = 5;
int64 entityIdMSB = 6; string name = 6;
int64 entityIdLSB = 7; string type = 7;
EdgeEntityType entityType = 8; int64 entityIdMSB = 8;
int64 entityIdLSB = 9;
EdgeEntityType entityType = 10;
string additionalInfo = 11;
} }
message AlarmUpdateMsg { message AlarmUpdateMsg {
@ -243,13 +264,47 @@ message UserUpdateMsg {
UpdateMsgType msgType = 1; UpdateMsgType msgType = 1;
int64 idMSB = 2; int64 idMSB = 2;
int64 idLSB = 3; int64 idLSB = 3;
string email = 4; int64 customerIdMSB = 4;
string authority = 5; int64 customerIdLSB = 5;
string firstName = 6; string email = 6;
string lastName = 7; string authority = 7;
string additionalInfo = 8; string firstName = 8;
bool enabled = 9; string lastName = 9;
string password = 10; string additionalInfo = 10;
}
message WidgetsBundleUpdateMsg {
UpdateMsgType msgType = 1;
int64 idMSB = 2;
int64 idLSB = 3;
string title = 4;
string alias = 5;
bytes image = 6;
bool isSystem = 7;
}
message WidgetTypeUpdateMsg {
UpdateMsgType msgType = 1;
int64 idMSB = 2;
int64 idLSB = 3;
string bundleAlias = 4;
string alias = 5;
string name = 6;
string descriptorJson = 7;
bool isSystem = 8;
}
message AdminSettingsUpdateMsg {
bool isSystem = 1;
string key = 2;
string jsonValue = 3;
}
message UserCredentialsUpdateMsg {
int64 userIdMSB = 1;
int64 userIdLSB = 2;
bool enabled = 3;
string password = 4;
} }
message RuleChainMetadataRequestMsg { message RuleChainMetadataRequestMsg {
@ -257,6 +312,50 @@ message RuleChainMetadataRequestMsg {
int64 ruleChainIdLSB = 2; int64 ruleChainIdLSB = 2;
} }
message AttributesRequestMsg {
int64 entityIdMSB = 1;
int64 entityIdLSB = 2;
string entityType = 3;
}
message RelationRequestMsg {
int64 entityIdMSB = 1;
int64 entityIdLSB = 2;
string entityType = 3;
}
message UserCredentialsRequestMsg {
int64 userIdMSB = 1;
int64 userIdLSB = 2;
}
message DeviceCredentialsRequestMsg {
int64 deviceIdMSB = 1;
int64 deviceIdLSB = 2;
}
message DeviceRpcCallMsg {
int64 deviceIdMSB = 1;
int64 deviceIdLSB = 2;
int64 requestIdMSB = 3;
int64 requestIdLSB = 4;
int64 expirationTime = 5;
bool oneway = 6;
string originServiceId = 7;
RpcRequestMsg requestMsg = 8;
RpcResponseMsg responseMsg = 9;
}
message RpcRequestMsg {
string method = 1;
string params = 2;
}
message RpcResponseMsg {
string response = 1;
string error = 2;
}
enum EdgeEntityType { enum EdgeEntityType {
DEVICE = 0; DEVICE = 0;
ASSET = 1; ASSET = 1;
@ -270,8 +369,15 @@ message UplinkMsg {
int32 uplinkMsgId = 1; int32 uplinkMsgId = 1;
repeated EntityDataProto entityData = 2; repeated EntityDataProto entityData = 2;
repeated DeviceUpdateMsg deviceUpdateMsg = 3; repeated DeviceUpdateMsg deviceUpdateMsg = 3;
repeated AlarmUpdateMsg alarmUpdateMsg = 4; repeated DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg = 4;
repeated RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg = 5; repeated AlarmUpdateMsg alarmUpdateMsg = 5;
repeated RelationUpdateMsg relationUpdateMsg = 6;
repeated RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg = 7;
repeated AttributesRequestMsg attributesRequestMsg = 8;
repeated RelationRequestMsg relationRequestMsg = 9;
repeated UserCredentialsRequestMsg userCredentialsRequestMsg = 10;
repeated DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 11;
repeated DeviceRpcCallMsg deviceRpcCallMsg = 12;
} }
message UplinkResponseMsg { message UplinkResponseMsg {
@ -279,8 +385,30 @@ message UplinkResponseMsg {
string errorMsg = 2; string errorMsg = 2;
} }
message DownlinkResponseMsg {
bool success = 1;
string errorMsg = 2;
}
message DownlinkMsg { message DownlinkMsg {
int32 downlinkMsgId = 1; int32 downlinkMsgId = 1;
repeated EntityDataProto entityData = 2; repeated EntityDataProto entityData = 2;
repeated DeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 3;
repeated DeviceUpdateMsg deviceUpdateMsg = 4;
repeated DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg = 5;
repeated RuleChainUpdateMsg ruleChainUpdateMsg = 6;
repeated RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = 7;
repeated DashboardUpdateMsg dashboardUpdateMsg = 8;
repeated AssetUpdateMsg assetUpdateMsg = 9;
repeated EntityViewUpdateMsg entityViewUpdateMsg = 10;
repeated AlarmUpdateMsg alarmUpdateMsg = 11;
repeated UserUpdateMsg userUpdateMsg = 12;
repeated UserCredentialsUpdateMsg userCredentialsUpdateMsg = 13;
repeated CustomerUpdateMsg customerUpdateMsg = 14;
repeated RelationUpdateMsg relationUpdateMsg = 15;
repeated WidgetsBundleUpdateMsg widgetsBundleUpdateMsg = 16;
repeated WidgetTypeUpdateMsg widgetTypeUpdateMsg = 17;
repeated AdminSettingsUpdateMsg adminSettingsUpdateMsg = 18;
repeated DeviceRpcCallMsg deviceRpcCallMsg = 19;
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save