Commit 3094fb72400687f2d67ec0efeb58917814d12ad0

Authored by Igor Kulikov
1 parent 96878b6d

Add customerId to alarm

... ... @@ -90,6 +90,11 @@ ALTER TABLE device
90 90 ADD COLUMN IF NOT EXISTS firmware_id uuid,
91 91 ADD COLUMN IF NOT EXISTS software_id uuid;
92 92
  93 +ALTER TABLE alarm
  94 + ADD COLUMN IF NOT EXISTS customer_id uuid;
  95 +
  96 +DELETE FROM relation WHERE from_type = 'TENANT' AND relation_type_group = 'RULE_CHAIN';
  97 +
93 98 DO $$
94 99 BEGIN
95 100 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device_profile') THEN
... ...
... ... @@ -27,6 +27,9 @@ import org.thingsboard.rule.engine.profile.TbDeviceProfileNode;
27 27 import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration;
28 28 import org.thingsboard.server.common.data.EntityView;
29 29 import org.thingsboard.server.common.data.Tenant;
  30 +import org.thingsboard.server.common.data.alarm.Alarm;
  31 +import org.thingsboard.server.common.data.alarm.AlarmInfo;
  32 +import org.thingsboard.server.common.data.alarm.AlarmQuery;
30 33 import org.thingsboard.server.common.data.id.EntityViewId;
31 34 import org.thingsboard.server.common.data.id.TenantId;
32 35 import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
... ... @@ -34,9 +37,13 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
34 37 import org.thingsboard.server.common.data.kv.TsKvEntry;
35 38 import org.thingsboard.server.common.data.page.PageData;
36 39 import org.thingsboard.server.common.data.page.PageLink;
  40 +import org.thingsboard.server.common.data.page.TimePageLink;
37 41 import org.thingsboard.server.common.data.rule.RuleChain;
38 42 import org.thingsboard.server.common.data.rule.RuleChainMetaData;
39 43 import org.thingsboard.server.common.data.rule.RuleNode;
  44 +import org.thingsboard.server.dao.alarm.AlarmDao;
  45 +import org.thingsboard.server.dao.alarm.AlarmService;
  46 +import org.thingsboard.server.dao.entity.EntityService;
40 47 import org.thingsboard.server.dao.entityview.EntityViewService;
41 48 import org.thingsboard.server.dao.rule.RuleChainService;
42 49 import org.thingsboard.server.dao.tenant.TenantService;
... ... @@ -72,6 +79,15 @@ public class DefaultDataUpdateService implements DataUpdateService {
72 79 @Autowired
73 80 private TimeseriesService tsService;
74 81
  82 + @Autowired
  83 + private AlarmService alarmService;
  84 +
  85 + @Autowired
  86 + private EntityService entityService;
  87 +
  88 + @Autowired
  89 + private AlarmDao alarmDao;
  90 +
75 91 @Override
76 92 public void updateData(String fromVersion) throws Exception {
77 93 switch (fromVersion) {
... ... @@ -90,14 +106,25 @@ public class DefaultDataUpdateService implements DataUpdateService {
90 106 case "3.2.2":
91 107 log.info("Updating data from version 3.2.2 to 3.3.0 ...");
92 108 tenantsDefaultEdgeRuleChainUpdater.updateEntities(null);
  109 + tenantsAlarmsCustomerUpdater.updateEntities(null);
93 110 break;
94 111 default:
95 112 throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion);
96 113 }
97 114 }
98 115
99   - private PaginatedUpdater<String, Tenant> tenantsDefaultRuleChainUpdater =
100   - new PaginatedUpdater<String, Tenant>() {
  116 + private final PaginatedUpdater<String, Tenant> tenantsDefaultRuleChainUpdater =
  117 + new PaginatedUpdater<>() {
  118 +
  119 + @Override
  120 + protected String getName() {
  121 + return "Tenants default rule chain updater";
  122 + }
  123 +
  124 + @Override
  125 + protected boolean forceReportTotal() {
  126 + return true;
  127 + }
101 128
102 129 @Override
103 130 protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
... ... @@ -117,8 +144,18 @@ public class DefaultDataUpdateService implements DataUpdateService {
117 144 }
118 145 };
119 146
120   - private PaginatedUpdater<String, Tenant> tenantsDefaultEdgeRuleChainUpdater =
121   - new PaginatedUpdater<String, Tenant>() {
  147 + private final PaginatedUpdater<String, Tenant> tenantsDefaultEdgeRuleChainUpdater =
  148 + new PaginatedUpdater<>() {
  149 +
  150 + @Override
  151 + protected String getName() {
  152 + return "Tenants default edge rule chain updater";
  153 + }
  154 +
  155 + @Override
  156 + protected boolean forceReportTotal() {
  157 + return true;
  158 + }
122 159
123 160 @Override
124 161 protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
... ... @@ -138,8 +175,18 @@ public class DefaultDataUpdateService implements DataUpdateService {
138 175 }
139 176 };
140 177
141   - private PaginatedUpdater<String, Tenant> tenantsRootRuleChainUpdater =
142   - new PaginatedUpdater<String, Tenant>() {
  178 + private final PaginatedUpdater<String, Tenant> tenantsRootRuleChainUpdater =
  179 + new PaginatedUpdater<>() {
  180 +
  181 + @Override
  182 + protected String getName() {
  183 + return "Tenants root rule chain updater";
  184 + }
  185 +
  186 + @Override
  187 + protected boolean forceReportTotal() {
  188 + return true;
  189 + }
143 190
144 191 @Override
145 192 protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
... ... @@ -192,8 +239,18 @@ public class DefaultDataUpdateService implements DataUpdateService {
192 239 }
193 240 };
194 241
195   - private PaginatedUpdater<String, Tenant> tenantsEntityViewsUpdater =
196   - new PaginatedUpdater<String, Tenant>() {
  242 + private final PaginatedUpdater<String, Tenant> tenantsEntityViewsUpdater =
  243 + new PaginatedUpdater<>() {
  244 +
  245 + @Override
  246 + protected String getName() {
  247 + return "Tenants entity views updater";
  248 + }
  249 +
  250 + @Override
  251 + protected boolean forceReportTotal() {
  252 + return true;
  253 + }
197 254
198 255 @Override
199 256 protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
... ... @@ -261,4 +318,48 @@ public class DefaultDataUpdateService implements DataUpdateService {
261 318 }, MoreExecutors.directExecutor());
262 319 }
263 320
  321 + private final PaginatedUpdater<String, Tenant> tenantsAlarmsCustomerUpdater =
  322 + new PaginatedUpdater<>() {
  323 +
  324 + @Override
  325 + protected String getName() {
  326 + return "Tenants alarms customer updater";
  327 + }
  328 +
  329 + @Override
  330 + protected boolean forceReportTotal() {
  331 + return true;
  332 + }
  333 +
  334 + @Override
  335 + protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
  336 + return tenantService.findTenants(pageLink);
  337 + }
  338 +
  339 + @Override
  340 + protected void updateEntity(Tenant tenant) {
  341 + updateTenantAlarmsCustomer(tenant.getId());
  342 + }
  343 + };
  344 +
  345 + private void updateTenantAlarmsCustomer(TenantId tenantId) {
  346 + AlarmQuery alarmQuery = new AlarmQuery(null, new TimePageLink(100), null, null, false);
  347 + PageData<AlarmInfo> alarms = alarmDao.findAlarms(tenantId, alarmQuery);
  348 + boolean hasNext = true;
  349 + while (hasNext) {
  350 + for (Alarm alarm : alarms.getData()) {
  351 + if (alarm.getCustomerId() == null && alarm.getOriginator() != null) {
  352 + alarm.setCustomerId(entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator()));
  353 + alarmDao.save(tenantId, alarm);
  354 + }
  355 + }
  356 + if (alarms.hasNext()) {
  357 + alarmQuery.setPageLink(alarmQuery.getPageLink().nextPageLink());
  358 + alarms = alarmDao.findAlarms(tenantId, alarmQuery);
  359 + } else {
  360 + hasNext = false;
  361 + }
  362 + }
  363 + }
  364 +
264 365 }
... ...
... ... @@ -15,16 +15,20 @@
15 15 */
16 16 package org.thingsboard.server.service.install.update;
17 17
  18 +import lombok.extern.slf4j.Slf4j;
18 19 import org.thingsboard.server.common.data.SearchTextBased;
19 20 import org.thingsboard.server.common.data.id.UUIDBased;
20 21 import org.thingsboard.server.common.data.page.PageData;
21 22 import org.thingsboard.server.common.data.page.PageLink;
22 23
  24 +@Slf4j
23 25 public abstract class PaginatedUpdater<I, D extends SearchTextBased<? extends UUIDBased>> {
24 26
25 27 private static final int DEFAULT_LIMIT = 100;
  28 + private int updated = 0;
26 29
27 30 public void updateEntities(I id) {
  31 + updated = 0;
28 32 PageLink pageLink = new PageLink(DEFAULT_LIMIT);
29 33 boolean hasNext = true;
30 34 while (hasNext) {
... ... @@ -32,13 +36,25 @@ public abstract class PaginatedUpdater<I, D extends SearchTextBased<? extends UU
32 36 for (D entity : entities.getData()) {
33 37 updateEntity(entity);
34 38 }
  39 + updated += entities.getData().size();
35 40 hasNext = entities.hasNext();
36 41 if (hasNext) {
  42 + log.info("{}: {} entities updated so far...", getName(), updated);
37 43 pageLink = pageLink.nextPageLink();
  44 + } else {
  45 + if (updated > DEFAULT_LIMIT || forceReportTotal()) {
  46 + log.info("{}: {} total entities updated.", getName(), updated);
  47 + }
38 48 }
39 49 }
40 50 }
41 51
  52 + protected boolean forceReportTotal() {
  53 + return false;
  54 + }
  55 +
  56 + protected abstract String getName();
  57 +
42 58 protected abstract PageData<D> findEntities(I id, PageLink pageLink);
43 59
44 60 protected abstract void updateEntity(D entity);
... ...
... ... @@ -28,6 +28,8 @@ public interface EntityService {
28 28
29 29 ListenableFuture<String> fetchEntityNameAsync(TenantId tenantId, EntityId entityId);
30 30
  31 + CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId);
  32 +
31 33 void deleteEntityRelations(TenantId tenantId, EntityId entityId);
32 34
33 35 long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query);
... ...
... ... @@ -21,9 +21,11 @@ import lombok.AllArgsConstructor;
21 21 import lombok.Builder;
22 22 import lombok.Data;
23 23 import org.thingsboard.server.common.data.BaseData;
  24 +import org.thingsboard.server.common.data.HasCustomerId;
24 25 import org.thingsboard.server.common.data.HasName;
25 26 import org.thingsboard.server.common.data.HasTenantId;
26 27 import org.thingsboard.server.common.data.id.AlarmId;
  28 +import org.thingsboard.server.common.data.id.CustomerId;
27 29 import org.thingsboard.server.common.data.id.EntityId;
28 30 import org.thingsboard.server.common.data.id.TenantId;
29 31
... ... @@ -35,9 +37,10 @@ import java.util.List;
35 37 @Data
36 38 @Builder
37 39 @AllArgsConstructor
38   -public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId {
  40 +public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId, HasCustomerId {
39 41
40 42 private TenantId tenantId;
  43 + private CustomerId customerId;
41 44 private String type;
42 45 private EntityId originator;
43 46 private AlarmSeverity severity;
... ... @@ -62,6 +65,7 @@ public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId {
62 65 super(alarm.getId());
63 66 this.createdTime = alarm.getCreatedTime();
64 67 this.tenantId = alarm.getTenantId();
  68 + this.customerId = alarm.getCustomerId();
65 69 this.type = alarm.getType();
66 70 this.originator = alarm.getOriginator();
67 71 this.severity = alarm.getSeverity();
... ...
... ... @@ -110,6 +110,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
110 110 if (alarm.getEndTs() == 0L) {
111 111 alarm.setEndTs(alarm.getStartTs());
112 112 }
  113 + alarm.setCustomerId(entityService.fetchEntityCustomerId(alarm.getTenantId(), alarm.getOriginator()));
113 114 if (alarm.getId() == null) {
114 115 Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get();
115 116 if (existing == null || existing.getStatus().isCleared()) {
... ... @@ -355,6 +356,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
355 356 existing.setStatus(alarm.getStatus());
356 357 existing.setSeverity(alarm.getSeverity());
357 358 existing.setDetails(alarm.getDetails());
  359 + existing.setCustomerId(alarm.getCustomerId());
358 360 existing.setPropagate(existing.isPropagate() || alarm.isPropagate());
359 361 List<String> existingPropagateRelationTypes = existing.getPropagateRelationTypes();
360 362 List<String> newRelationTypes = alarm.getPropagateRelationTypes();
... ...
... ... @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.MoreExecutors;
22 22 import lombok.extern.slf4j.Slf4j;
23 23 import org.springframework.beans.factory.annotation.Autowired;
24 24 import org.springframework.stereotype.Service;
  25 +import org.thingsboard.server.common.data.HasCustomerId;
25 26 import org.thingsboard.server.common.data.HasName;
26 27 import org.thingsboard.server.common.data.id.AlarmId;
27 28 import org.thingsboard.server.common.data.id.AssetId;
... ... @@ -54,6 +55,7 @@ import org.thingsboard.server.dao.rule.RuleChainService;
54 55 import org.thingsboard.server.dao.tenant.TenantService;
55 56 import org.thingsboard.server.dao.user.UserService;
56 57
  58 +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
57 59 import static org.thingsboard.server.dao.service.Validator.validateId;
58 60
59 61 /**
... ... @@ -175,6 +177,50 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
175 177 return entityName;
176 178 }
177 179
  180 + @Override
  181 + public CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId) {
  182 + log.trace("Executing fetchEntityCustomerId [{}]", entityId);
  183 + HasCustomerId hasCustomerId = null;
  184 + switch (entityId.getEntityType()) {
  185 + case TENANT:
  186 + case RULE_CHAIN:
  187 + case RULE_NODE:
  188 + case DASHBOARD:
  189 + case WIDGETS_BUNDLE:
  190 + case WIDGET_TYPE:
  191 + case TENANT_PROFILE:
  192 + case DEVICE_PROFILE:
  193 + case API_USAGE_STATE:
  194 + case TB_RESOURCE:
  195 + case FIRMWARE:
  196 + break;
  197 + case CUSTOMER:
  198 + hasCustomerId = () -> new CustomerId(entityId.getId());
  199 + break;
  200 + case USER:
  201 + hasCustomerId = userService.findUserById(tenantId, new UserId(entityId.getId()));
  202 + break;
  203 + case ASSET:
  204 + hasCustomerId = assetService.findAssetById(tenantId, new AssetId(entityId.getId()));
  205 + break;
  206 + case DEVICE:
  207 + hasCustomerId = deviceService.findDeviceById(tenantId, new DeviceId(entityId.getId()));
  208 + break;
  209 + case ALARM:
  210 + try {
  211 + hasCustomerId = alarmService.findAlarmByIdAsync(tenantId, new AlarmId(entityId.getId())).get();
  212 + } catch (Exception e) {}
  213 + break;
  214 + case ENTITY_VIEW:
  215 + hasCustomerId = entityViewService.findEntityViewById(tenantId, new EntityViewId(entityId.getId()));
  216 + break;
  217 + case EDGE:
  218 + hasCustomerId = edgeService.findEdgeById(tenantId, new EdgeId(entityId.getId()));
  219 + break;
  220 + }
  221 + return hasCustomerId != null ? hasCustomerId.getCustomerId() : new CustomerId(NULL_UUID);
  222 + }
  223 +
178 224 private static void validateEntityCountQuery(EntityCountQuery query) {
179 225 if (query == null) {
180 226 throw new IncorrectParameterException("Query must be specified.");
... ...
... ... @@ -258,6 +258,7 @@ public class ModelConstants {
258 258 */
259 259 public static final String ALARM_COLUMN_FAMILY_NAME = "alarm";
260 260 public static final String ALARM_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
  261 + public static final String ALARM_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
261 262 public static final String ALARM_TYPE_PROPERTY = "type";
262 263 public static final String ALARM_DETAILS_PROPERTY = "details";
263 264 public static final String ALARM_ORIGINATOR_ID_PROPERTY = "originator_id";
... ...
... ... @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.alarm.Alarm;
27 27 import org.thingsboard.server.common.data.alarm.AlarmSeverity;
28 28 import org.thingsboard.server.common.data.alarm.AlarmStatus;
29 29 import org.thingsboard.server.common.data.id.AlarmId;
  30 +import org.thingsboard.server.common.data.id.CustomerId;
30 31 import org.thingsboard.server.common.data.id.EntityIdFactory;
31 32 import org.thingsboard.server.common.data.id.TenantId;
32 33 import org.thingsboard.server.dao.model.BaseEntity;
... ... @@ -44,6 +45,7 @@ import java.util.UUID;
44 45
45 46 import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ACK_TS_PROPERTY;
46 47 import static org.thingsboard.server.dao.model.ModelConstants.ALARM_CLEAR_TS_PROPERTY;
  48 +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_CUSTOMER_ID_PROPERTY;
47 49 import static org.thingsboard.server.dao.model.ModelConstants.ALARM_END_TS_PROPERTY;
48 50 import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY;
49 51 import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY;
... ... @@ -64,6 +66,9 @@ public abstract class AbstractAlarmEntity<T extends Alarm> extends BaseSqlEntity
64 66 @Column(name = ALARM_TENANT_ID_PROPERTY)
65 67 private UUID tenantId;
66 68
  69 + @Column(name = ALARM_CUSTOMER_ID_PROPERTY)
  70 + private UUID customerId;
  71 +
67 72 @Column(name = ALARM_ORIGINATOR_ID_PROPERTY)
68 73 private UUID originatorId;
69 74
... ... @@ -115,6 +120,9 @@ public abstract class AbstractAlarmEntity<T extends Alarm> extends BaseSqlEntity
115 120 if (alarm.getTenantId() != null) {
116 121 this.tenantId = alarm.getTenantId().getId();
117 122 }
  123 + if (alarm.getCustomerId() != null) {
  124 + this.customerId = alarm.getCustomerId().getId();
  125 + }
118 126 this.type = alarm.getType();
119 127 this.originatorId = alarm.getOriginator().getId();
120 128 this.originatorType = alarm.getOriginator().getEntityType();
... ... @@ -138,6 +146,7 @@ public abstract class AbstractAlarmEntity<T extends Alarm> extends BaseSqlEntity
138 146 this.setId(alarmEntity.getId());
139 147 this.setCreatedTime(alarmEntity.getCreatedTime());
140 148 this.tenantId = alarmEntity.getTenantId();
  149 + this.customerId = alarmEntity.getCustomerId();
141 150 this.type = alarmEntity.getType();
142 151 this.originatorId = alarmEntity.getOriginatorId();
143 152 this.originatorType = alarmEntity.getOriginatorType();
... ... @@ -159,6 +168,9 @@ public abstract class AbstractAlarmEntity<T extends Alarm> extends BaseSqlEntity
159 168 if (tenantId != null) {
160 169 alarm.setTenantId(new TenantId(tenantId));
161 170 }
  171 + if (customerId != null) {
  172 + alarm.setCustomerId(new CustomerId(customerId));
  173 + }
162 174 alarm.setOriginator(EntityIdFactory.getByTypeAndUuid(originatorType, originatorId));
163 175 alarm.setType(type);
164 176 alarm.setSeverity(severity);
... ...
... ... @@ -19,6 +19,7 @@ import lombok.Data;
19 19 import lombok.EqualsAndHashCode;
20 20 import org.hibernate.annotations.TypeDef;
21 21 import org.thingsboard.server.common.data.alarm.Alarm;
  22 +import org.thingsboard.server.common.data.alarm.AlarmInfo;
22 23 import org.thingsboard.server.dao.util.mapping.JsonStringType;
23 24
24 25 import javax.persistence.Entity;
... ... @@ -37,6 +38,10 @@ public final class AlarmEntity extends AbstractAlarmEntity<Alarm> {
37 38 super();
38 39 }
39 40
  41 + public AlarmEntity(AlarmInfo alarmInfo) {
  42 + super(alarmInfo);
  43 + }
  44 +
40 45 public AlarmEntity(Alarm alarm) {
41 46 super(alarm);
42 47 }
... ...
... ... @@ -100,12 +100,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
100 100 @Transactional
101 101 public RuleChain saveRuleChain(RuleChain ruleChain) {
102 102 ruleChainValidator.validate(ruleChain, RuleChain::getTenantId);
103   - RuleChain savedRuleChain = ruleChainDao.save(ruleChain.getTenantId(), ruleChain);
104   - if (ruleChain.isRoot() && ruleChain.getId() == null) {
105   - createRelation(ruleChain.getTenantId(), new EntityRelation(savedRuleChain.getTenantId(), savedRuleChain.getId(),
106   - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
107   - }
108   - return savedRuleChain;
  103 + return ruleChainDao.save(ruleChain.getTenantId(), ruleChain);
109 104 }
110 105
111 106 @Override
... ... @@ -114,29 +109,20 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
114 109 RuleChain ruleChain = ruleChainDao.findById(tenantId, ruleChainId.getId());
115 110 if (!ruleChain.isRoot()) {
116 111 RuleChain previousRootRuleChain = getRootTenantRuleChain(ruleChain.getTenantId());
117   - try {
118   - if (previousRootRuleChain == null) {
119   - setRootAndSave(tenantId, ruleChain);
120   - return true;
121   - } else if (!previousRootRuleChain.getId().equals(ruleChain.getId())) {
122   - deleteRelation(tenantId, new EntityRelation(previousRootRuleChain.getTenantId(), previousRootRuleChain.getId(),
123   - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
124   - previousRootRuleChain.setRoot(false);
125   - ruleChainDao.save(tenantId, previousRootRuleChain);
126   - setRootAndSave(tenantId, ruleChain);
127   - return true;
128   - }
129   - } catch (ExecutionException | InterruptedException e) {
130   - log.warn("[{}] Failed to set root rule chain, ruleChainId: [{}]", ruleChainId);
131   - throw new RuntimeException(e);
  112 + if (previousRootRuleChain == null) {
  113 + setRootAndSave(tenantId, ruleChain);
  114 + return true;
  115 + } else if (!previousRootRuleChain.getId().equals(ruleChain.getId())) {
  116 + previousRootRuleChain.setRoot(false);
  117 + ruleChainDao.save(tenantId, previousRootRuleChain);
  118 + setRootAndSave(tenantId, ruleChain);
  119 + return true;
132 120 }
133 121 }
134 122 return false;
135 123 }
136 124
137   - private void setRootAndSave(TenantId tenantId, RuleChain ruleChain) throws ExecutionException, InterruptedException {
138   - createRelation(tenantId, new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(),
139   - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
  125 + private void setRootAndSave(TenantId tenantId, RuleChain ruleChain) {
140 126 ruleChain.setRoot(true);
141 127 ruleChainDao.save(tenantId, ruleChain);
142 128 }
... ... @@ -179,41 +165,45 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
179 165 toDelete.add(existingNode);
180 166 }
181 167 }
182   - for (RuleNode node : toAddOrUpdate) {
183   - node.setRuleChainId(ruleChain.getId());
184   - RuleNode savedNode = ruleNodeDao.save(tenantId, node);
185   - createRelation(tenantId, new EntityRelation(ruleChainMetaData.getRuleChainId(), savedNode.getId(),
186   - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
187   - int index = nodes.indexOf(node);
188   - nodes.set(index, savedNode);
189   - ruleNodeIndexMap.put(savedNode.getId(), index);
  168 + if (nodes != null) {
  169 + for (RuleNode node : toAddOrUpdate) {
  170 + node.setRuleChainId(ruleChain.getId());
  171 + RuleNode savedNode = ruleNodeDao.save(tenantId, node);
  172 + createRelation(tenantId, new EntityRelation(ruleChainMetaData.getRuleChainId(), savedNode.getId(),
  173 + EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
  174 + int index = nodes.indexOf(node);
  175 + nodes.set(index, savedNode);
  176 + ruleNodeIndexMap.put(savedNode.getId(), index);
  177 + }
190 178 }
191 179 for (RuleNode node : toDelete) {
192 180 deleteRuleNode(tenantId, node.getId());
193 181 }
194 182 RuleNodeId firstRuleNodeId = null;
195   - if (ruleChainMetaData.getFirstNodeIndex() != null) {
196   - firstRuleNodeId = nodes.get(ruleChainMetaData.getFirstNodeIndex()).getId();
197   - }
198   - if ((ruleChain.getFirstRuleNodeId() != null && !ruleChain.getFirstRuleNodeId().equals(firstRuleNodeId))
199   - || (ruleChain.getFirstRuleNodeId() == null && firstRuleNodeId != null)) {
200   - ruleChain.setFirstRuleNodeId(firstRuleNodeId);
201   - ruleChainDao.save(tenantId, ruleChain);
202   - }
203   - if (ruleChainMetaData.getConnections() != null) {
204   - for (NodeConnectionInfo nodeConnection : ruleChainMetaData.getConnections()) {
205   - EntityId from = nodes.get(nodeConnection.getFromIndex()).getId();
206   - EntityId to = nodes.get(nodeConnection.getToIndex()).getId();
207   - String type = nodeConnection.getType();
208   - createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE));
  183 + if (nodes != null) {
  184 + if (ruleChainMetaData.getFirstNodeIndex() != null) {
  185 + firstRuleNodeId = nodes.get(ruleChainMetaData.getFirstNodeIndex()).getId();
209 186 }
210   - }
211   - if (ruleChainMetaData.getRuleChainConnections() != null) {
212   - for (RuleChainConnectionInfo nodeToRuleChainConnection : ruleChainMetaData.getRuleChainConnections()) {
213   - EntityId from = nodes.get(nodeToRuleChainConnection.getFromIndex()).getId();
214   - EntityId to = nodeToRuleChainConnection.getTargetRuleChainId();
215   - String type = nodeToRuleChainConnection.getType();
216   - createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE, nodeToRuleChainConnection.getAdditionalInfo()));
  187 + if ((ruleChain.getFirstRuleNodeId() != null && !ruleChain.getFirstRuleNodeId().equals(firstRuleNodeId))
  188 + || (ruleChain.getFirstRuleNodeId() == null && firstRuleNodeId != null)) {
  189 + ruleChain.setFirstRuleNodeId(firstRuleNodeId);
  190 + ruleChainDao.save(tenantId, ruleChain);
  191 + }
  192 + if (ruleChainMetaData.getConnections() != null) {
  193 + for (NodeConnectionInfo nodeConnection : ruleChainMetaData.getConnections()) {
  194 + EntityId from = nodes.get(nodeConnection.getFromIndex()).getId();
  195 + EntityId to = nodes.get(nodeConnection.getToIndex()).getId();
  196 + String type = nodeConnection.getType();
  197 + createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE));
  198 + }
  199 + }
  200 + if (ruleChainMetaData.getRuleChainConnections() != null) {
  201 + for (RuleChainConnectionInfo nodeToRuleChainConnection : ruleChainMetaData.getRuleChainConnections()) {
  202 + EntityId from = nodes.get(nodeToRuleChainConnection.getFromIndex()).getId();
  203 + EntityId to = nodeToRuleChainConnection.getTargetRuleChainId();
  204 + String type = nodeToRuleChainConnection.getType();
  205 + createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE, nodeToRuleChainConnection.getAdditionalInfo()));
  206 + }
217 207 }
218 208 }
219 209
... ... @@ -307,24 +297,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
307 297
308 298 @Override
309 299 public RuleChain getRootTenantRuleChain(TenantId tenantId) {
310   - return getRootRuleChainByType(tenantId, RuleChainType.CORE);
311   - }
312   -
313   - private RuleChain getRootRuleChainByType(TenantId tenantId, RuleChainType type) {
314 300 Validator.validateId(tenantId, "Incorrect tenant id for search request.");
315   - List<EntityRelation> relations = relationService.findByFrom(tenantId, tenantId, RelationTypeGroup.RULE_CHAIN);
316   - if (relations != null && !relations.isEmpty()) {
317   - for (EntityRelation relation : relations) {
318   - RuleChainId ruleChainId = new RuleChainId(relation.getTo().getId());
319   - RuleChain ruleChainById = findRuleChainById(tenantId, ruleChainId);
320   - if (type.equals(ruleChainById.getType())) {
321   - return ruleChainById;
322   - }
323   - }
324   - return null;
325   - } else {
326   - return null;
327   - }
  301 + return ruleChainDao.findRootRuleChainByTenantIdAndType(tenantId.getId(), RuleChainType.CORE);
328 302 }
329 303
330 304 @Override
... ... @@ -366,7 +340,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
366 340 boolean valid = true;
367 341 EntityType toType = relation.getTo().getEntityType();
368 342 if (toType == EntityType.RULE_NODE || toType == EntityType.RULE_CHAIN) {
369   - BaseData entity;
  343 + BaseData<?> entity;
370 344 if (relation.getTo().getEntityType() == EntityType.RULE_NODE) {
371 345 entity = ruleNodeDao.findById(tenantId, relation.getTo().getId());
372 346 } else {
... ... @@ -501,9 +475,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
501 475 ObjectNode objNode = (ObjectNode) node;
502 476 objNode.put("id", tenantId.getId().toString());
503 477 } else {
504   - Iterator<JsonNode> childIter = node.iterator();
505   - while (childIter.hasNext()) {
506   - searchTenantIdRecursive(tenantId, childIter.next());
  478 + for (JsonNode jsonNode : node) {
  479 + searchTenantIdRecursive(tenantId, jsonNode);
507 480 }
508 481 }
509 482 }
... ... @@ -608,7 +581,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
608 581
609 582 @Override
610 583 public RuleChain getEdgeTemplateRootRuleChain(TenantId tenantId) {
611   - return getRootRuleChainByType(tenantId, RuleChainType.EDGE);
  584 + Validator.validateId(tenantId, "Incorrect tenant id for search request.");
  585 + return ruleChainDao.findRootRuleChainByTenantIdAndType(tenantId.getId(), RuleChainType.EDGE);
612 586 }
613 587
614 588 @Override
... ... @@ -618,13 +592,9 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
618 592 if (previousEdgeTemplateRootRuleChain == null || !previousEdgeTemplateRootRuleChain.getId().equals(ruleChain.getId())) {
619 593 try {
620 594 if (previousEdgeTemplateRootRuleChain != null) {
621   - deleteRelation(tenantId, new EntityRelation(previousEdgeTemplateRootRuleChain.getTenantId(), previousEdgeTemplateRootRuleChain.getId(),
622   - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
623 595 previousEdgeTemplateRootRuleChain.setRoot(false);
624 596 ruleChainDao.save(tenantId, previousEdgeTemplateRootRuleChain);
625 597 }
626   - createRelation(tenantId, new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(),
627   - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
628 598 ruleChain.setRoot(true);
629 599 ruleChainDao.save(tenantId, ruleChain);
630 600 return true;
... ... @@ -699,8 +669,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
699 669 ruleNodeDao.removeById(tenantId, entityId.getId());
700 670 }
701 671
702   - private DataValidator<RuleChain> ruleChainValidator =
703   - new DataValidator<RuleChain>() {
  672 + private final DataValidator<RuleChain> ruleChainValidator =
  673 + new DataValidator<>() {
704 674 @Override
705 675 protected void validateCreate(TenantId tenantId, RuleChain data) {
706 676 DefaultTenantProfileConfiguration profileConfiguration =
... ... @@ -739,8 +709,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
739 709 }
740 710 };
741 711
742   - private PaginatedRemover<TenantId, RuleChain> tenantRuleChainsRemover =
743   - new PaginatedRemover<TenantId, RuleChain>() {
  712 + private final PaginatedRemover<TenantId, RuleChain> tenantRuleChainsRemover =
  713 + new PaginatedRemover<>() {
744 714
745 715 @Override
746 716 protected PageData<RuleChain> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
... ...
... ... @@ -51,6 +51,15 @@ public interface RuleChainDao extends Dao<RuleChain>, TenantEntityDao {
51 51 PageData<RuleChain> findRuleChainsByTenantIdAndType(UUID tenantId, RuleChainType type, PageLink pageLink);
52 52
53 53 /**
  54 + * Find root rule chain by tenantId and type
  55 + *
  56 + * @param tenantId the tenantId
  57 + * @param type the type
  58 + * @return the rule chain object
  59 + */
  60 + RuleChain findRootRuleChainByTenantIdAndType(UUID tenantId, RuleChainType type);
  61 +
  62 + /**
54 63 * Find rule chains by tenantId, edgeId and page link.
55 64 *
56 65 * @param tenantId the tenantId
... ...
... ... @@ -120,13 +120,7 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, UUID> {
120 120 Pageable pageable);
121 121
122 122 @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " +
123   - "WHERE a.tenantId = :tenantId " +
124   - "AND (" +
125   - "a.originatorId IN (SELECT d.id from DeviceEntity d WHERE d.customerId = :customerId) " +
126   - "OR a.originatorId IN (SELECT asset.id from AssetEntity asset WHERE asset.customerId = :customerId) " +
127   - "OR a.originatorId IN (SELECT u.id from UserEntity u WHERE u.customerId = :customerId) " +
128   - "OR a.originatorId = :customerId" +
129   - ") " +
  123 + "WHERE a.tenantId = :tenantId AND a.customerId = :customerId " +
130 124 "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
131 125 "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
132 126 "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " +
... ... @@ -137,13 +131,7 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, UUID> {
137 131 countQuery = "" +
138 132 "SELECT count(a) " +
139 133 "FROM AlarmEntity a " +
140   - "WHERE a.tenantId = :tenantId " +
141   - "AND (" +
142   - "a.originatorId IN (SELECT d.id from DeviceEntity d WHERE d.customerId = :customerId) " +
143   - "OR a.originatorId IN (SELECT asset.id from AssetEntity asset WHERE asset.customerId = :customerId) " +
144   - "OR a.originatorId IN (SELECT u.id from UserEntity u WHERE u.customerId = :customerId) " +
145   - "OR a.originatorId = :customerId" +
146   - ") " +
  134 + "WHERE a.tenantId = :tenantId AND a.customerId = :customerId " +
147 135 "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
148 136 "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
149 137 "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " +
... ...
... ... @@ -83,6 +83,12 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao<RuleChainEntity, R
83 83 }
84 84
85 85 @Override
  86 + public RuleChain findRootRuleChainByTenantIdAndType(UUID tenantId, RuleChainType type) {
  87 + log.debug("Try to find root rule chain by tenantId [{}] and type [{}]", tenantId, type);
  88 + return DaoUtil.getData(ruleChainRepository.findByTenantIdAndTypeAndRootIsTrue(tenantId, type));
  89 + }
  90 +
  91 + @Override
86 92 public PageData<RuleChain> findRuleChainsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, PageLink pageLink) {
87 93 log.debug("Try to find rule chains by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink);
88 94
... ...
... ... @@ -50,5 +50,8 @@ public interface RuleChainRepository extends PagingAndSortingRepository<RuleChai
50 50 @Param("edgeId") UUID edgeId,
51 51 @Param("searchText") String searchText,
52 52 Pageable pageable);
  53 +
  54 + RuleChainEntity findByTenantIdAndTypeAndRootIsTrue(UUID tenantId, RuleChainType ruleChainType);
  55 +
53 56 Long countByTenantId(UUID tenantId);
54 57 }
... ...
... ... @@ -35,6 +35,7 @@ CREATE TABLE IF NOT EXISTS alarm (
35 35 start_ts bigint,
36 36 status varchar(255),
37 37 tenant_id uuid,
  38 + customer_id uuid,
38 39 propagate_relation_types varchar,
39 40 type varchar(255)
40 41 );
... ...
... ... @@ -53,6 +53,7 @@ CREATE TABLE IF NOT EXISTS alarm (
53 53 start_ts bigint,
54 54 status varchar(255),
55 55 tenant_id uuid,
  56 + customer_id uuid,
56 57 propagate_relation_types varchar,
57 58 type varchar(255)
58 59 );
... ...
... ... @@ -188,12 +188,12 @@
188 188 </mat-drawer-content>
189 189 </mat-drawer-container>
190 190 <section fxLayout="row" class="layout-wrap tb-footer-buttons" fxLayoutAlign="start end">
191   - <tb-footer-fab-buttons *ngIf="!embedded"
  191 + <tb-footer-fab-buttons *ngIf="!embedded && !isMobileApp"
192 192 [fxShow]="!isAddingWidget && isEdit && !widgetEditMode"
193 193 relative
194 194 [footerFabButtons]="addWidgetFabButtons">
195 195 </tb-footer-fab-buttons>
196   - <button *ngIf="(isTenantAdmin() || isSystemAdmin()) && !forceFullscreen && !embedded"
  196 + <button *ngIf="(isTenantAdmin() || isSystemAdmin()) && !forceFullscreen && !embedded && !isMobileApp"
197 197 mat-fab color="accent" class="tb-btn-footer"
198 198 [ngClass]="{'tb-hide': !isEdit || isAddingWidget}"
199 199 [disabled]="isLoading$ | async"
... ... @@ -202,7 +202,7 @@
202 202 matTooltipPosition="above">
203 203 <mat-icon>done</mat-icon>
204 204 </button>
205   - <button *ngIf="(isTenantAdmin() || isSystemAdmin()) && !forceFullscreen && !embedded"
  205 + <button *ngIf="(isTenantAdmin() || isSystemAdmin()) && !forceFullscreen && !embedded && !isMobileApp"
206 206 mat-fab color="accent" class="tb-btn-footer"
207 207 [ngClass]="{'tb-hide': isAddingWidget || (isLoading$ | async)}"
208 208 [disabled]="isLoading$ | async"
... ...