Showing
18 changed files
with
281 additions
and
109 deletions
... | ... | @@ -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 | } | ... | ... |
... | ... | @@ -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" | ... | ... |