Commit 7c7b70c5abf75cc4ecb588355bd2cc2c04be5888

Authored by Andrew Shvayka
1 parent bee943ba

Improvemetns to Alarm DAO and service

... ... @@ -16,6 +16,8 @@
16 16 package org.thingsboard.server.common.data.alarm;
17 17
18 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import lombok.AllArgsConstructor;
  20 +import lombok.Builder;
19 21 import lombok.Data;
20 22 import org.thingsboard.server.common.data.BaseData;
21 23 import org.thingsboard.server.common.data.id.AssetId;
... ... @@ -26,6 +28,8 @@ import org.thingsboard.server.common.data.id.TenantId;
26 28 * Created by ashvayka on 11.05.17.
27 29 */
28 30 @Data
  31 +@Builder
  32 +@AllArgsConstructor
29 33 public class Alarm extends BaseData<AlarmId> {
30 34
31 35 private TenantId tenantId;
... ...
... ... @@ -161,9 +161,18 @@ public abstract class AbstractModelDao<T extends BaseEntity<?>> extends Abstract
161 161 return getSession().execute(delete);
162 162 }
163 163
164   -
165 164 public List<T> find() {
166 165 log.debug("Get all entities from column family {}", getColumnFamilyName());
167 166 return findListByStatement(QueryBuilder.select().all().from(getColumnFamilyName()).setConsistencyLevel(cluster.getDefaultReadConsistencyLevel()));
168 167 }
  168 +
  169 + protected static <T> Function<BaseEntity<T>, T> toDataFunction() {
  170 + return new Function<BaseEntity<T>, T>() {
  171 + @Nullable
  172 + @Override
  173 + public T apply(@Nullable BaseEntity<T> entity) {
  174 + return entity != null ? entity.toData() : null;
  175 + }
  176 + };
  177 + }
169 178 }
... ...
... ... @@ -22,6 +22,8 @@ import org.thingsboard.server.common.data.id.TenantId;
22 22 import org.thingsboard.server.dao.Dao;
23 23 import org.thingsboard.server.dao.model.AlarmEntity;
24 24
  25 +import java.util.UUID;
  26 +
25 27 /**
26 28 * Created by ashvayka on 11.05.17.
27 29 */
... ... @@ -29,6 +31,8 @@ public interface AlarmDao extends Dao<AlarmEntity> {
29 31
30 32 ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type);
31 33
  34 + ListenableFuture<Alarm> findAlarmByIdAsync(UUID key);
  35 +
32 36 AlarmEntity save(Alarm alarm);
33 37
34 38 }
... ...
1 1 /**
2 2 * Copyright © 2016-2017 The Thingsboard Authors
3   - *
  3 + * <p>
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
  7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -15,6 +15,11 @@
15 15 */
16 16 package org.thingsboard.server.dao.alarm;
17 17
  18 +import com.datastax.driver.core.querybuilder.Ordering;
  19 +import com.datastax.driver.core.querybuilder.QueryBuilder;
  20 +import com.datastax.driver.core.querybuilder.Select;
  21 +import com.google.common.base.Function;
  22 +import com.google.common.util.concurrent.Futures;
18 23 import com.google.common.util.concurrent.ListenableFuture;
19 24 import lombok.extern.slf4j.Slf4j;
20 25 import org.springframework.stereotype.Component;
... ... @@ -23,8 +28,16 @@ import org.thingsboard.server.common.data.id.EntityId;
23 28 import org.thingsboard.server.common.data.id.TenantId;
24 29 import org.thingsboard.server.dao.AbstractModelDao;
25 30 import org.thingsboard.server.dao.model.AlarmEntity;
  31 +import org.thingsboard.server.dao.model.BaseEntity;
  32 +import org.thingsboard.server.dao.model.ModelConstants;
26 33
27   -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COLUMN_FAMILY_NAME;
  34 +import javax.annotation.Nullable;
  35 +import java.util.Optional;
  36 +import java.util.UUID;
  37 +
  38 +import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
  39 +import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
  40 +import static org.thingsboard.server.dao.model.ModelConstants.*;
28 41
29 42 @Component
30 43 @Slf4j
... ... @@ -48,6 +61,23 @@ public class AlarmDaoImpl extends AbstractModelDao<AlarmEntity> implements Alarm
48 61
49 62 @Override
50 63 public ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type) {
51   - return null;
  64 + Select select = select().from(ALARM_COLUMN_FAMILY_NAME);
  65 + Select.Where query = select.where();
  66 + query.and(eq(ALARM_TENANT_ID_PROPERTY, tenantId.getId()));
  67 + query.and(eq(ALARM_ORIGINATOR_ID_PROPERTY, originator.getId()));
  68 + query.and(eq(ALARM_ORIGINATOR_TYPE_PROPERTY, originator.getEntityType()));
  69 + query.and(eq(ALARM_TYPE_PROPERTY, type));
  70 + query.limit(1);
  71 + query.orderBy(QueryBuilder.asc(ModelConstants.ALARM_TYPE_PROPERTY), QueryBuilder.desc(ModelConstants.ID_PROPERTY));
  72 + return Futures.transform(findOneByStatementAsync(query), toDataFunction());
  73 + }
  74 +
  75 + @Override
  76 + public ListenableFuture<Alarm> findAlarmByIdAsync(UUID key) {
  77 + log.debug("Get alarm by id {}", key);
  78 + Select.Where query = select().from(ALARM_BY_ID_VIEW_NAME).where(eq(ModelConstants.ID_PROPERTY, key));
  79 + query.limit(1);
  80 + log.trace("Execute query {}", query);
  81 + return Futures.transform(findOneByStatementAsync(query), toDataFunction());
52 82 }
53 83 }
... ...
... ... @@ -16,9 +16,11 @@
16 16 package org.thingsboard.server.dao.alarm;
17 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.common.data.Device;
19 20 import org.thingsboard.server.common.data.alarm.Alarm;
20 21 import org.thingsboard.server.common.data.alarm.AlarmId;
21 22 import org.thingsboard.server.common.data.alarm.AlarmQuery;
  23 +import org.thingsboard.server.common.data.id.DeviceId;
22 24 import org.thingsboard.server.common.data.id.EntityId;
23 25 import org.thingsboard.server.common.data.page.TimePageData;
24 26
... ... @@ -37,6 +39,8 @@ public interface AlarmService {
37 39
38 40 ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long ackTs);
39 41
  42 + ListenableFuture<Alarm> findAlarmById(AlarmId alarmId);
  43 +
40 44 ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query);
41 45
42 46 }
... ...
1 1 /**
2 2 * Copyright © 2016-2017 The Thingsboard Authors
3   - *
  3 + * <p>
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
  7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -91,6 +91,9 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
91 91 if (alarm.getStartTs() == 0L) {
92 92 alarm.setStartTs(System.currentTimeMillis());
93 93 }
  94 + if (alarm.getEndTs() == 0L) {
  95 + alarm.setEndTs(alarm.getStartTs());
  96 + }
94 97 Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get();
95 98 if (existing == null || existing.getStatus().isCleared()) {
96 99 log.debug("New Alarm : {}", alarm);
... ... @@ -117,11 +120,10 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
117 120 @Override
118 121 public ListenableFuture<Boolean> updateAlarm(Alarm update) {
119 122 alarmDataValidator.validate(update);
120   - return getAndUpdate(update.getId(), new Function<AlarmEntity, Boolean>() {
  123 + return getAndUpdate(update.getId(), new Function<Alarm, Boolean>() {
121 124 @Nullable
122 125 @Override
123   - public Boolean apply(@Nullable AlarmEntity entity) {
124   - Alarm alarm = getData(entity);
  126 + public Boolean apply(@Nullable Alarm alarm) {
125 127 if (alarm == null) {
126 128 return false;
127 129 } else {
... ... @@ -139,11 +141,10 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
139 141
140 142 @Override
141 143 public ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTime) {
142   - return getAndUpdate(alarmId, new Function<AlarmEntity, Boolean>() {
  144 + return getAndUpdate(alarmId, new Function<Alarm, Boolean>() {
143 145 @Nullable
144 146 @Override
145   - public Boolean apply(@Nullable AlarmEntity entity) {
146   - Alarm alarm = getData(entity);
  147 + public Boolean apply(@Nullable Alarm alarm) {
147 148 if (alarm == null || alarm.getStatus().isAck()) {
148 149 return false;
149 150 } else {
... ... @@ -161,11 +162,10 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
161 162
162 163 @Override
163 164 public ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long clearTime) {
164   - return getAndUpdate(alarmId, new Function<AlarmEntity, Boolean>() {
  165 + return getAndUpdate(alarmId, new Function<Alarm, Boolean>() {
165 166 @Nullable
166 167 @Override
167   - public Boolean apply(@Nullable AlarmEntity entity) {
168   - Alarm alarm = getData(entity);
  168 + public Boolean apply(@Nullable Alarm alarm) {
169 169 if (alarm == null || alarm.getStatus().isCleared()) {
170 170 return false;
171 171 } else {
... ... @@ -182,6 +182,13 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
182 182 }
183 183
184 184 @Override
  185 + public ListenableFuture<Alarm> findAlarmById(AlarmId alarmId) {
  186 + log.trace("Executing findAlarmById [{}]", alarmId);
  187 + validateId(alarmId, "Incorrect alarmId " + alarmId);
  188 + return alarmDao.findAlarmByIdAsync(alarmId.getId());
  189 + }
  190 +
  191 + @Override
185 192 public ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query) {
186 193 return null;
187 194 }
... ... @@ -230,9 +237,9 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
230 237 }
231 238 }
232 239
233   - private ListenableFuture<Boolean> getAndUpdate(AlarmId alarmId, Function<AlarmEntity, Boolean> function) {
  240 + private ListenableFuture<Boolean> getAndUpdate(AlarmId alarmId, Function<Alarm, Boolean> function) {
234 241 validateId(alarmId, "Alarm id should be specified!");
235   - ListenableFuture<AlarmEntity> entity = alarmDao.findByIdAsync(alarmId.getId());
  242 + ListenableFuture<Alarm> entity = alarmDao.findAlarmByIdAsync(alarmId.getId());
236 243 return Futures.transform(entity, function);
237 244 }
238 245
... ...
... ... @@ -125,6 +125,94 @@ public final class AlarmEntity implements BaseEntity<Alarm> {
125 125 this.tenantId = tenantId;
126 126 }
127 127
  128 + public UUID getOriginatorId() {
  129 + return originatorId;
  130 + }
  131 +
  132 + public void setOriginatorId(UUID originatorId) {
  133 + this.originatorId = originatorId;
  134 + }
  135 +
  136 + public EntityType getOriginatorType() {
  137 + return originatorType;
  138 + }
  139 +
  140 + public void setOriginatorType(EntityType originatorType) {
  141 + this.originatorType = originatorType;
  142 + }
  143 +
  144 + public String getType() {
  145 + return type;
  146 + }
  147 +
  148 + public void setType(String type) {
  149 + this.type = type;
  150 + }
  151 +
  152 + public AlarmSeverity getSeverity() {
  153 + return severity;
  154 + }
  155 +
  156 + public void setSeverity(AlarmSeverity severity) {
  157 + this.severity = severity;
  158 + }
  159 +
  160 + public AlarmStatus getStatus() {
  161 + return status;
  162 + }
  163 +
  164 + public void setStatus(AlarmStatus status) {
  165 + this.status = status;
  166 + }
  167 +
  168 + public Long getStartTs() {
  169 + return startTs;
  170 + }
  171 +
  172 + public void setStartTs(Long startTs) {
  173 + this.startTs = startTs;
  174 + }
  175 +
  176 + public Long getEndTs() {
  177 + return endTs;
  178 + }
  179 +
  180 + public void setEndTs(Long endTs) {
  181 + this.endTs = endTs;
  182 + }
  183 +
  184 + public Long getAckTs() {
  185 + return ackTs;
  186 + }
  187 +
  188 + public void setAckTs(Long ackTs) {
  189 + this.ackTs = ackTs;
  190 + }
  191 +
  192 + public Long getClearTs() {
  193 + return clearTs;
  194 + }
  195 +
  196 + public void setClearTs(Long clearTs) {
  197 + this.clearTs = clearTs;
  198 + }
  199 +
  200 + public JsonNode getDetails() {
  201 + return details;
  202 + }
  203 +
  204 + public void setDetails(JsonNode details) {
  205 + this.details = details;
  206 + }
  207 +
  208 + public Boolean getPropagate() {
  209 + return propagate;
  210 + }
  211 +
  212 + public void setPropagate(Boolean propagate) {
  213 + this.propagate = propagate;
  214 + }
  215 +
128 216 @Override
129 217 public Alarm toData() {
130 218 Alarm alarm = new Alarm(new AlarmId(id));
... ...
... ... @@ -157,6 +157,8 @@ public class ModelConstants {
157 157 public static final String ALARM_CLEAR_TS_PROPERTY = "clear_ts";
158 158 public static final String ALARM_PROPAGATE_PROPERTY = "propagate";
159 159
  160 + public static final String ALARM_BY_ID_VIEW_NAME = "alarm_by_id";
  161 +
160 162 /**
161 163 * Cassandra entity relation constants.
162 164 */
... ...
... ... @@ -250,7 +250,15 @@ CREATE TABLE IF NOT EXISTS thingsboard.alarm (
250 250 details text,
251 251 propagate boolean,
252 252 PRIMARY KEY ((tenant_id, originator_id, originator_type), type, id)
253   -);
  253 +) WITH CLUSTERING ORDER BY ( type ASC, id DESC);
  254 +
  255 +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.alarm_by_id AS
  256 + SELECT *
  257 + from thingsboard.alarm
  258 + WHERE tenant_id IS NOT NULL AND originator_id IS NOT NULL AND originator_type IS NOT NULL AND type IS NOT NULL
  259 + AND type IS NOT NULL AND id IS NOT NULL
  260 + PRIMARY KEY (id, tenant_id, originator_id, originator_type, type)
  261 + WITH CLUSTERING ORDER BY ( tenant_id ASC, originator_id ASC, originator_type ASC, type ASC);
254 262
255 263 CREATE TABLE IF NOT EXISTS thingsboard.relation (
256 264 from_id timeuuid,
... ...
... ... @@ -25,12 +25,13 @@ import java.util.Arrays;
25 25
26 26 @RunWith(ClasspathSuite.class)
27 27 @ClassnameFilters({
28   - "org.thingsboard.server.dao.service.*Test",
29   - "org.thingsboard.server.dao.kv.*Test",
30   - "org.thingsboard.server.dao.plugin.*Test",
31   - "org.thingsboard.server.dao.rule.*Test",
32   - "org.thingsboard.server.dao.attributes.*Test",
33   - "org.thingsboard.server.dao.timeseries.*Test"
  28 + "org.thingsboard.server.dao.service.AlarmServiceTest",
  29 +// "org.thingsboard.server.dao.service.*Test",
  30 +// "org.thingsboard.server.dao.kv.*Test",
  31 +// "org.thingsboard.server.dao.plugin.*Test",
  32 +// "org.thingsboard.server.dao.rule.*Test",
  33 +// "org.thingsboard.server.dao.attributes.*Test",
  34 +// "org.thingsboard.server.dao.timeseries.*Test"
34 35 })
35 36 public class DaoTestSuite {
36 37
... ...
... ... @@ -32,6 +32,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
32 32 import org.springframework.test.context.support.AnnotationConfigContextLoader;
33 33 import org.thingsboard.server.common.data.BaseData;
34 34 import org.thingsboard.server.common.data.Event;
  35 +import org.thingsboard.server.common.data.alarm.AlarmStatus;
35 36 import org.thingsboard.server.common.data.id.EntityId;
36 37 import org.thingsboard.server.common.data.id.TenantId;
37 38 import org.thingsboard.server.common.data.id.UUIDBased;
... ... @@ -40,6 +41,7 @@ import org.thingsboard.server.common.data.plugin.ComponentScope;
40 41 import org.thingsboard.server.common.data.plugin.ComponentType;
41 42 import org.thingsboard.server.common.data.plugin.PluginMetaData;
42 43 import org.thingsboard.server.common.data.rule.RuleMetaData;
  44 +import org.thingsboard.server.dao.alarm.AlarmService;
43 45 import org.thingsboard.server.dao.component.ComponentDescriptorService;
44 46 import org.thingsboard.server.dao.customer.CustomerService;
45 47 import org.thingsboard.server.dao.dashboard.DashboardService;
... ... @@ -115,6 +117,9 @@ public abstract class AbstractServiceTest {
115 117 protected RelationService relationService;
116 118
117 119 @Autowired
  120 + protected AlarmService alarmService;
  121 +
  122 + @Autowired
118 123 private ComponentDescriptorService componentDescriptorService;
119 124
120 125 class IdComparator<D extends BaseData<? extends UUIDBased>> implements Comparator<D> {
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.service;
  17 +
  18 +import com.datastax.driver.core.utils.UUIDs;
  19 +import org.junit.After;
  20 +import org.junit.Assert;
  21 +import org.junit.Before;
  22 +import org.junit.Test;
  23 +import org.thingsboard.server.common.data.EntityType;
  24 +import org.thingsboard.server.common.data.Tenant;
  25 +import org.thingsboard.server.common.data.alarm.Alarm;
  26 +import org.thingsboard.server.common.data.alarm.AlarmSeverity;
  27 +import org.thingsboard.server.common.data.alarm.AlarmStatus;
  28 +import org.thingsboard.server.common.data.id.AssetId;
  29 +import org.thingsboard.server.common.data.id.DeviceId;
  30 +import org.thingsboard.server.common.data.id.TenantId;
  31 +import org.thingsboard.server.common.data.relation.EntityRelation;
  32 +import org.thingsboard.server.dao.exception.DataValidationException;
  33 +import org.thingsboard.server.dao.relation.EntityRelationsQuery;
  34 +import org.thingsboard.server.dao.relation.EntitySearchDirection;
  35 +import org.thingsboard.server.dao.relation.EntityTypeFilter;
  36 +import org.thingsboard.server.dao.relation.RelationsSearchParameters;
  37 +
  38 +import java.util.Collections;
  39 +import java.util.List;
  40 +import java.util.concurrent.ExecutionException;
  41 +
  42 +public class AlarmServiceTest extends AbstractServiceTest {
  43 +
  44 + public static final String TEST_ALARM = "TEST_ALARM";
  45 + private TenantId tenantId;
  46 +
  47 + @Before
  48 + public void before() {
  49 + Tenant tenant = new Tenant();
  50 + tenant.setTitle("My tenant");
  51 + Tenant savedTenant = tenantService.saveTenant(tenant);
  52 + Assert.assertNotNull(savedTenant);
  53 + tenantId = savedTenant.getId();
  54 + }
  55 +
  56 + @After
  57 + public void after() {
  58 + tenantService.deleteTenant(tenantId);
  59 + }
  60 +
  61 +
  62 + @Test
  63 + public void testSaveAndFetchAlarm() throws ExecutionException, InterruptedException {
  64 + AssetId parentId = new AssetId(UUIDs.timeBased());
  65 + AssetId childId = new AssetId(UUIDs.timeBased());
  66 +
  67 + EntityRelation relation = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE);
  68 +
  69 + Assert.assertTrue(relationService.saveRelation(relation).get());
  70 +
  71 + long ts = System.currentTimeMillis();
  72 + Alarm alarm = Alarm.builder().tenantId(tenantId).originator(childId)
  73 + .type(TEST_ALARM)
  74 + .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK)
  75 + .startTs(ts).build();
  76 +
  77 + Alarm created = alarmService.createOrUpdateAlarm(alarm);
  78 +
  79 + Assert.assertNotNull(created);
  80 + Assert.assertNotNull(created.getId());
  81 + Assert.assertNotNull(created.getOriginator());
  82 + Assert.assertNotNull(created.getSeverity());
  83 + Assert.assertNotNull(created.getStatus());
  84 +
  85 + Assert.assertEquals(tenantId, created.getTenantId());
  86 + Assert.assertEquals(childId, created.getOriginator());
  87 + Assert.assertEquals(TEST_ALARM, created.getType());
  88 + Assert.assertEquals(AlarmSeverity.CRITICAL, created.getSeverity());
  89 + Assert.assertEquals(AlarmStatus.ACTIVE_UNACK, created.getStatus());
  90 + Assert.assertEquals(ts, created.getStartTs());
  91 + Assert.assertEquals(ts, created.getEndTs());
  92 + Assert.assertEquals(0L, created.getAckTs());
  93 + Assert.assertEquals(0L, created.getClearTs());
  94 +
  95 + Alarm fetched = alarmService.findAlarmById(created.getId()).get();
  96 + Assert.assertEquals(created, fetched);
  97 + }
  98 +}
... ...
dao/src/test/java/org/thingsboard/server/dao/service/RelationServiceTest.java renamed from dao/src/test/java/org/thingsboard/server/dao/service/RelationServiceImplTest.java
... ... @@ -36,7 +36,7 @@ import java.util.Collections;
36 36 import java.util.List;
37 37 import java.util.concurrent.ExecutionException;
38 38
39   -public class RelationServiceImplTest extends AbstractServiceTest {
  39 +public class RelationServiceTest extends AbstractServiceTest {
40 40
41 41 @Before
42 42 public void before() {
... ...