Browse Source

Improvemetns to Alarm DAO and service

pull/151/head
Andrew Shvayka 9 years ago
parent
commit
7c7b70c5ab
  1. 4
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java
  2. 11
      dao/src/main/java/org/thingsboard/server/dao/AbstractModelDao.java
  3. 4
      dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java
  4. 42
      dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDaoImpl.java
  5. 4
      dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
  6. 37
      dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
  7. 88
      dao/src/main/java/org/thingsboard/server/dao/model/AlarmEntity.java
  8. 2
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  9. 10
      dao/src/main/resources/schema.cql
  10. 13
      dao/src/test/java/org/thingsboard/server/dao/DaoTestSuite.java
  11. 5
      dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java
  12. 98
      dao/src/test/java/org/thingsboard/server/dao/service/AlarmServiceTest.java
  13. 2
      dao/src/test/java/org/thingsboard/server/dao/service/RelationServiceTest.java

4
common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java

@ -16,6 +16,8 @@
package org.thingsboard.server.common.data.alarm;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.id.AssetId;
@ -26,6 +28,8 @@ import org.thingsboard.server.common.data.id.TenantId;
* Created by ashvayka on 11.05.17.
*/
@Data
@Builder
@AllArgsConstructor
public class Alarm extends BaseData<AlarmId> {
private TenantId tenantId;

11
dao/src/main/java/org/thingsboard/server/dao/AbstractModelDao.java

@ -161,9 +161,18 @@ public abstract class AbstractModelDao<T extends BaseEntity<?>> extends Abstract
return getSession().execute(delete);
}
public List<T> find() {
log.debug("Get all entities from column family {}", getColumnFamilyName());
return findListByStatement(QueryBuilder.select().all().from(getColumnFamilyName()).setConsistencyLevel(cluster.getDefaultReadConsistencyLevel()));
}
protected static <T> Function<BaseEntity<T>, T> toDataFunction() {
return new Function<BaseEntity<T>, T>() {
@Nullable
@Override
public T apply(@Nullable BaseEntity<T> entity) {
return entity != null ? entity.toData() : null;
}
};
}
}

4
dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java

@ -22,6 +22,8 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.model.AlarmEntity;
import java.util.UUID;
/**
* Created by ashvayka on 11.05.17.
*/
@ -29,6 +31,8 @@ public interface AlarmDao extends Dao<AlarmEntity> {
ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type);
ListenableFuture<Alarm> findAlarmByIdAsync(UUID key);
AlarmEntity save(Alarm alarm);
}

42
dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDaoImpl.java

@ -1,12 +1,12 @@
/**
* Copyright © 2016-2017 The Thingsboard Authors
*
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,6 +15,11 @@
*/
package org.thingsboard.server.dao.alarm;
import com.datastax.driver.core.querybuilder.Ordering;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@ -23,8 +28,16 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.AbstractModelDao;
import org.thingsboard.server.dao.model.AlarmEntity;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COLUMN_FAMILY_NAME;
import javax.annotation.Nullable;
import java.util.Optional;
import java.util.UUID;
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
import static org.thingsboard.server.dao.model.ModelConstants.*;
@Component
@Slf4j
@ -48,6 +61,23 @@ public class AlarmDaoImpl extends AbstractModelDao<AlarmEntity> implements Alarm
@Override
public ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type) {
return null;
Select select = select().from(ALARM_COLUMN_FAMILY_NAME);
Select.Where query = select.where();
query.and(eq(ALARM_TENANT_ID_PROPERTY, tenantId.getId()));
query.and(eq(ALARM_ORIGINATOR_ID_PROPERTY, originator.getId()));
query.and(eq(ALARM_ORIGINATOR_TYPE_PROPERTY, originator.getEntityType()));
query.and(eq(ALARM_TYPE_PROPERTY, type));
query.limit(1);
query.orderBy(QueryBuilder.asc(ModelConstants.ALARM_TYPE_PROPERTY), QueryBuilder.desc(ModelConstants.ID_PROPERTY));
return Futures.transform(findOneByStatementAsync(query), toDataFunction());
}
@Override
public ListenableFuture<Alarm> findAlarmByIdAsync(UUID key) {
log.debug("Get alarm by id {}", key);
Select.Where query = select().from(ALARM_BY_ID_VIEW_NAME).where(eq(ModelConstants.ID_PROPERTY, key));
query.limit(1);
log.trace("Execute query {}", query);
return Futures.transform(findOneByStatementAsync(query), toDataFunction());
}
}

4
dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java

@ -16,9 +16,11 @@
package org.thingsboard.server.dao.alarm;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmId;
import org.thingsboard.server.common.data.alarm.AlarmQuery;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.page.TimePageData;
@ -37,6 +39,8 @@ public interface AlarmService {
ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long ackTs);
ListenableFuture<Alarm> findAlarmById(AlarmId alarmId);
ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query);
}

37
dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java

@ -1,12 +1,12 @@
/**
* Copyright © 2016-2017 The Thingsboard Authors
*
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -91,6 +91,9 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
if (alarm.getStartTs() == 0L) {
alarm.setStartTs(System.currentTimeMillis());
}
if (alarm.getEndTs() == 0L) {
alarm.setEndTs(alarm.getStartTs());
}
Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get();
if (existing == null || existing.getStatus().isCleared()) {
log.debug("New Alarm : {}", alarm);
@ -117,11 +120,10 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
@Override
public ListenableFuture<Boolean> updateAlarm(Alarm update) {
alarmDataValidator.validate(update);
return getAndUpdate(update.getId(), new Function<AlarmEntity, Boolean>() {
return getAndUpdate(update.getId(), new Function<Alarm, Boolean>() {
@Nullable
@Override
public Boolean apply(@Nullable AlarmEntity entity) {
Alarm alarm = getData(entity);
public Boolean apply(@Nullable Alarm alarm) {
if (alarm == null) {
return false;
} else {
@ -139,11 +141,10 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
@Override
public ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTime) {
return getAndUpdate(alarmId, new Function<AlarmEntity, Boolean>() {
return getAndUpdate(alarmId, new Function<Alarm, Boolean>() {
@Nullable
@Override
public Boolean apply(@Nullable AlarmEntity entity) {
Alarm alarm = getData(entity);
public Boolean apply(@Nullable Alarm alarm) {
if (alarm == null || alarm.getStatus().isAck()) {
return false;
} else {
@ -161,11 +162,10 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
@Override
public ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long clearTime) {
return getAndUpdate(alarmId, new Function<AlarmEntity, Boolean>() {
return getAndUpdate(alarmId, new Function<Alarm, Boolean>() {
@Nullable
@Override
public Boolean apply(@Nullable AlarmEntity entity) {
Alarm alarm = getData(entity);
public Boolean apply(@Nullable Alarm alarm) {
if (alarm == null || alarm.getStatus().isCleared()) {
return false;
} else {
@ -181,6 +181,13 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
});
}
@Override
public ListenableFuture<Alarm> findAlarmById(AlarmId alarmId) {
log.trace("Executing findAlarmById [{}]", alarmId);
validateId(alarmId, "Incorrect alarmId " + alarmId);
return alarmDao.findAlarmByIdAsync(alarmId.getId());
}
@Override
public ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query) {
return null;
@ -230,9 +237,9 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
}
}
private ListenableFuture<Boolean> getAndUpdate(AlarmId alarmId, Function<AlarmEntity, Boolean> function) {
private ListenableFuture<Boolean> getAndUpdate(AlarmId alarmId, Function<Alarm, Boolean> function) {
validateId(alarmId, "Alarm id should be specified!");
ListenableFuture<AlarmEntity> entity = alarmDao.findByIdAsync(alarmId.getId());
ListenableFuture<Alarm> entity = alarmDao.findAlarmByIdAsync(alarmId.getId());
return Futures.transform(entity, function);
}

88
dao/src/main/java/org/thingsboard/server/dao/model/AlarmEntity.java

@ -125,6 +125,94 @@ public final class AlarmEntity implements BaseEntity<Alarm> {
this.tenantId = tenantId;
}
public UUID getOriginatorId() {
return originatorId;
}
public void setOriginatorId(UUID originatorId) {
this.originatorId = originatorId;
}
public EntityType getOriginatorType() {
return originatorType;
}
public void setOriginatorType(EntityType originatorType) {
this.originatorType = originatorType;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public AlarmSeverity getSeverity() {
return severity;
}
public void setSeverity(AlarmSeverity severity) {
this.severity = severity;
}
public AlarmStatus getStatus() {
return status;
}
public void setStatus(AlarmStatus status) {
this.status = status;
}
public Long getStartTs() {
return startTs;
}
public void setStartTs(Long startTs) {
this.startTs = startTs;
}
public Long getEndTs() {
return endTs;
}
public void setEndTs(Long endTs) {
this.endTs = endTs;
}
public Long getAckTs() {
return ackTs;
}
public void setAckTs(Long ackTs) {
this.ackTs = ackTs;
}
public Long getClearTs() {
return clearTs;
}
public void setClearTs(Long clearTs) {
this.clearTs = clearTs;
}
public JsonNode getDetails() {
return details;
}
public void setDetails(JsonNode details) {
this.details = details;
}
public Boolean getPropagate() {
return propagate;
}
public void setPropagate(Boolean propagate) {
this.propagate = propagate;
}
@Override
public Alarm toData() {
Alarm alarm = new Alarm(new AlarmId(id));

2
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -157,6 +157,8 @@ public class ModelConstants {
public static final String ALARM_CLEAR_TS_PROPERTY = "clear_ts";
public static final String ALARM_PROPAGATE_PROPERTY = "propagate";
public static final String ALARM_BY_ID_VIEW_NAME = "alarm_by_id";
/**
* Cassandra entity relation constants.
*/

10
dao/src/main/resources/schema.cql

@ -250,7 +250,15 @@ CREATE TABLE IF NOT EXISTS thingsboard.alarm (
details text,
propagate boolean,
PRIMARY KEY ((tenant_id, originator_id, originator_type), type, id)
);
) WITH CLUSTERING ORDER BY ( type ASC, id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.alarm_by_id AS
SELECT *
from thingsboard.alarm
WHERE tenant_id IS NOT NULL AND originator_id IS NOT NULL AND originator_type IS NOT NULL AND type IS NOT NULL
AND type IS NOT NULL AND id IS NOT NULL
PRIMARY KEY (id, tenant_id, originator_id, originator_type, type)
WITH CLUSTERING ORDER BY ( tenant_id ASC, originator_id ASC, originator_type ASC, type ASC);
CREATE TABLE IF NOT EXISTS thingsboard.relation (
from_id timeuuid,

13
dao/src/test/java/org/thingsboard/server/dao/DaoTestSuite.java

@ -25,12 +25,13 @@ import java.util.Arrays;
@RunWith(ClasspathSuite.class)
@ClassnameFilters({
"org.thingsboard.server.dao.service.*Test",
"org.thingsboard.server.dao.kv.*Test",
"org.thingsboard.server.dao.plugin.*Test",
"org.thingsboard.server.dao.rule.*Test",
"org.thingsboard.server.dao.attributes.*Test",
"org.thingsboard.server.dao.timeseries.*Test"
"org.thingsboard.server.dao.service.AlarmServiceTest",
// "org.thingsboard.server.dao.service.*Test",
// "org.thingsboard.server.dao.kv.*Test",
// "org.thingsboard.server.dao.plugin.*Test",
// "org.thingsboard.server.dao.rule.*Test",
// "org.thingsboard.server.dao.attributes.*Test",
// "org.thingsboard.server.dao.timeseries.*Test"
})
public class DaoTestSuite {

5
dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java

@ -32,6 +32,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased;
@ -40,6 +41,7 @@ import org.thingsboard.server.common.data.plugin.ComponentScope;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.plugin.PluginMetaData;
import org.thingsboard.server.common.data.rule.RuleMetaData;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.component.ComponentDescriptorService;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
@ -114,6 +116,9 @@ public abstract class AbstractServiceTest {
@Autowired
protected RelationService relationService;
@Autowired
protected AlarmService alarmService;
@Autowired
private ComponentDescriptorService componentDescriptorService;

98
dao/src/test/java/org/thingsboard/server/dao/service/AlarmServiceTest.java

@ -0,0 +1,98 @@
/**
* Copyright © 2016-2017 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.service;
import com.datastax.driver.core.utils.UUIDs;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.relation.EntityRelationsQuery;
import org.thingsboard.server.dao.relation.EntitySearchDirection;
import org.thingsboard.server.dao.relation.EntityTypeFilter;
import org.thingsboard.server.dao.relation.RelationsSearchParameters;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class AlarmServiceTest extends AbstractServiceTest {
public static final String TEST_ALARM = "TEST_ALARM";
private TenantId tenantId;
@Before
public void before() {
Tenant tenant = new Tenant();
tenant.setTitle("My tenant");
Tenant savedTenant = tenantService.saveTenant(tenant);
Assert.assertNotNull(savedTenant);
tenantId = savedTenant.getId();
}
@After
public void after() {
tenantService.deleteTenant(tenantId);
}
@Test
public void testSaveAndFetchAlarm() throws ExecutionException, InterruptedException {
AssetId parentId = new AssetId(UUIDs.timeBased());
AssetId childId = new AssetId(UUIDs.timeBased());
EntityRelation relation = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE);
Assert.assertTrue(relationService.saveRelation(relation).get());
long ts = System.currentTimeMillis();
Alarm alarm = Alarm.builder().tenantId(tenantId).originator(childId)
.type(TEST_ALARM)
.severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK)
.startTs(ts).build();
Alarm created = alarmService.createOrUpdateAlarm(alarm);
Assert.assertNotNull(created);
Assert.assertNotNull(created.getId());
Assert.assertNotNull(created.getOriginator());
Assert.assertNotNull(created.getSeverity());
Assert.assertNotNull(created.getStatus());
Assert.assertEquals(tenantId, created.getTenantId());
Assert.assertEquals(childId, created.getOriginator());
Assert.assertEquals(TEST_ALARM, created.getType());
Assert.assertEquals(AlarmSeverity.CRITICAL, created.getSeverity());
Assert.assertEquals(AlarmStatus.ACTIVE_UNACK, created.getStatus());
Assert.assertEquals(ts, created.getStartTs());
Assert.assertEquals(ts, created.getEndTs());
Assert.assertEquals(0L, created.getAckTs());
Assert.assertEquals(0L, created.getClearTs());
Alarm fetched = alarmService.findAlarmById(created.getId()).get();
Assert.assertEquals(created, fetched);
}
}

2
dao/src/test/java/org/thingsboard/server/dao/service/RelationServiceImplTest.java → dao/src/test/java/org/thingsboard/server/dao/service/RelationServiceTest.java

@ -36,7 +36,7 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class RelationServiceImplTest extends AbstractServiceTest {
public class RelationServiceTest extends AbstractServiceTest {
@Before
public void before() {
Loading…
Cancel
Save