thingsboard-memoizeit
Changes
dao/src/main/resources/schema.cql 2(+1 -1)
Details
diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
new file mode 100644
index 0000000..7d29d57
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
@@ -0,0 +1,129 @@
+/**
+ * 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.controller;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.thingsboard.server.common.data.Customer;
+import org.thingsboard.server.common.data.Event;
+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.alarm.AlarmStatus;
+import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.id.*;
+import org.thingsboard.server.common.data.page.TextPageData;
+import org.thingsboard.server.common.data.page.TextPageLink;
+import org.thingsboard.server.common.data.page.TimePageData;
+import org.thingsboard.server.common.data.page.TimePageLink;
+import org.thingsboard.server.dao.asset.AssetSearchQuery;
+import org.thingsboard.server.dao.exception.IncorrectParameterException;
+import org.thingsboard.server.dao.model.ModelConstants;
+import org.thingsboard.server.exception.ThingsboardErrorCode;
+import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.service.security.model.SecurityUser;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/api")
+public class AlarmController extends BaseController {
+
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+ @RequestMapping(value = "/alarm/{alarmId}", method = RequestMethod.GET)
+ @ResponseBody
+ public Alarm getAlarmById(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException {
+ checkParameter("alarmId", strAlarmId);
+ try {
+ AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
+ return checkAlarmId(alarmId);
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+ @RequestMapping(value = "/alarm", method = RequestMethod.POST)
+ @ResponseBody
+ public Alarm saveAlarm(@RequestBody Alarm alarm) throws ThingsboardException {
+ try {
+ alarm.setTenantId(getCurrentUser().getTenantId());
+ return checkNotNull(alarmService.createOrUpdateAlarm(alarm));
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @RequestMapping(value = "/alarm/{alarmId}/ack", method = RequestMethod.POST)
+ @ResponseStatus(value = HttpStatus.OK)
+ public void ackAlarm(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException {
+ checkParameter("alarmId", strAlarmId);
+ try {
+ AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
+ checkAlarmId(alarmId);
+ alarmService.ackAlarm(alarmId, System.currentTimeMillis()).get();
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @RequestMapping(value = "/alarm/{alarmId}/clear", method = RequestMethod.POST)
+ @ResponseStatus(value = HttpStatus.OK)
+ public void clearAlarm(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException {
+ checkParameter("alarmId", strAlarmId);
+ try {
+ AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
+ checkAlarmId(alarmId);
+ alarmService.clearAlarm(alarmId, System.currentTimeMillis()).get();
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+ @RequestMapping(value = "/alarm/{entityType}/{entityId}", method = RequestMethod.GET)
+ @ResponseBody
+ public TimePageData<Alarm> getAlarms(
+ @PathVariable("entityType") String strEntityType,
+ @PathVariable("entityId") String strEntityId,
+ @RequestParam(required = false) String status,
+ @RequestParam int limit,
+ @RequestParam(required = false) Long startTime,
+ @RequestParam(required = false) Long endTime,
+ @RequestParam(required = false, defaultValue = "false") boolean ascOrder,
+ @RequestParam(required = false) String offset
+ ) throws ThingsboardException {
+ checkParameter("EntityId", strEntityId);
+ checkParameter("EntityType", strEntityType);
+ EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId);
+ AlarmStatus alarmStatus = StringUtils.isEmpty(status) ? null : AlarmStatus.valueOf(status);
+ checkEntityId(entityId);
+ try {
+ TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
+ return checkNotNull(alarmService.findAlarms(new AlarmQuery(entityId, pageLink, alarmStatus)).get());
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
index d4adebe..ec93d29 100644
--- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
@@ -25,6 +25,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.thingsboard.server.actors.service.ActorService;
import org.thingsboard.server.common.data.*;
+import org.thingsboard.server.common.data.alarm.Alarm;
+import org.thingsboard.server.common.data.alarm.AlarmId;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.*;
import org.thingsboard.server.common.data.page.TextPageLink;
@@ -36,6 +38,7 @@ import org.thingsboard.server.common.data.rule.RuleMetaData;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
+import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
@@ -84,6 +87,9 @@ public abstract class BaseController {
protected AssetService assetService;
@Autowired
+ protected AlarmService alarmService;
+
+ @Autowired
protected DeviceCredentialsService deviceCredentialsService;
@Autowired
@@ -334,6 +340,22 @@ public abstract class BaseController {
}
}
+ Alarm checkAlarmId(AlarmId alarmId) throws ThingsboardException {
+ try {
+ validateId(alarmId, "Incorrect alarmId " + alarmId);
+ Alarm alarm = alarmService.findAlarmById(alarmId).get();
+ checkAlarm(alarm);
+ return alarm;
+ } catch (Exception e) {
+ throw handleException(e, false);
+ }
+ }
+
+ protected void checkAlarm(Alarm alarm) throws ThingsboardException {
+ checkNotNull(alarm);
+ checkTenantId(alarm.getTenantId());
+ }
+
WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, boolean modify) throws ThingsboardException {
try {
validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId);
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmQuery.java
index 9c4f921..00ca6c3 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmQuery.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmQuery.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data.alarm;
+import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId;
@@ -26,9 +27,9 @@ import org.thingsboard.server.common.data.page.TimePageLink;
*/
@Data
@Builder
+@AllArgsConstructor
public class AlarmQuery {
- private TenantId tenantId;
private EntityId affectedEntityId;
private TimePageLink pageLink;
private AlarmStatus status;
diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
index 3d35723..3c4da18 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
@@ -28,8 +28,6 @@ public interface AlarmService {
Alarm createOrUpdateAlarm(Alarm alarm);
- ListenableFuture<Boolean> updateAlarm(Alarm alarm);
-
ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTs);
ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long ackTs);
diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
index 2675fa2..a5bf27c 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
@@ -82,7 +82,6 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
}
}
-
@Override
public Alarm createOrUpdateAlarm(Alarm alarm) {
alarmDataValidator.validate(alarm);
@@ -93,53 +92,61 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
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);
- Alarm saved = getData(alarmDao.save(new AlarmEntity(alarm)));
- EntityRelationsQuery query = new EntityRelationsQuery();
- query.setParameters(new RelationsSearchParameters(saved.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE));
- List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList());
- for (EntityId parentId : parentEntities) {
- createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION));
- createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name()));
+ if (alarm.getId() == null) {
+ Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get();
+ if (existing == null || existing.getStatus().isCleared()) {
+ return createAlarm(alarm);
+ } else {
+ return updateAlarm(existing, alarm);
}
- createRelation(new EntityRelation(alarm.getOriginator(), saved.getId(), ALARM_RELATION));
- createRelation(new EntityRelation(alarm.getOriginator(), saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name()));
- return saved;
} else {
- log.debug("Alarm before merge: {}", alarm);
- alarm = merge(existing, alarm);
- log.debug("Alarm after merge: {}", alarm);
- return getData(alarmDao.save(new AlarmEntity(alarm)));
+ return updateAlarm(alarm).get();
}
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
}
- @Override
- public ListenableFuture<Boolean> updateAlarm(Alarm update) {
+ private Alarm createAlarm(Alarm alarm) throws InterruptedException, ExecutionException {
+ log.debug("New Alarm : {}", alarm);
+ Alarm saved = getData(alarmDao.save(new AlarmEntity(alarm)));
+ EntityRelationsQuery query = new EntityRelationsQuery();
+ query.setParameters(new RelationsSearchParameters(saved.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE));
+ List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList());
+ for (EntityId parentId : parentEntities) {
+ createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION));
+ createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name()));
+ }
+ createRelation(new EntityRelation(alarm.getOriginator(), saved.getId(), ALARM_RELATION));
+ createRelation(new EntityRelation(alarm.getOriginator(), saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name()));
+ return saved;
+ }
+
+ protected ListenableFuture<Alarm> updateAlarm(Alarm update) {
alarmDataValidator.validate(update);
- return getAndUpdate(update.getId(), new Function<Alarm, Boolean>() {
+ return getAndUpdate(update.getId(), new Function<Alarm, Alarm>() {
@Nullable
@Override
- public Boolean apply(@Nullable Alarm alarm) {
+ public Alarm apply(@Nullable Alarm alarm) {
if (alarm == null) {
- return false;
+ return null;
} else {
- AlarmStatus oldStatus = alarm.getStatus();
- AlarmStatus newStatus = update.getStatus();
- alarmDao.save(new AlarmEntity(merge(alarm, update)));
- if (oldStatus != newStatus) {
- updateRelations(alarm, oldStatus, newStatus);
- }
- return true;
+ return updateAlarm(alarm, update);
}
}
});
}
+ private Alarm updateAlarm(Alarm oldAlarm, Alarm newAlarm) {
+ AlarmStatus oldStatus = oldAlarm.getStatus();
+ AlarmStatus newStatus = newAlarm.getStatus();
+ AlarmEntity result = alarmDao.save(new AlarmEntity(merge(oldAlarm, newAlarm)));
+ if (oldStatus != newStatus) {
+ updateRelations(oldAlarm, oldStatus, newStatus);
+ }
+ return result.toData();
+ }
+
@Override
public ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTime) {
return getAndUpdate(alarmId, new Function<Alarm, Boolean>() {
@@ -247,7 +254,7 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
}
}
- private ListenableFuture<Boolean> getAndUpdate(AlarmId alarmId, Function<Alarm, Boolean> function) {
+ private <T> ListenableFuture<T> getAndUpdate(AlarmId alarmId, Function<Alarm, T> function) {
validateId(alarmId, "Alarm id should be specified!");
ListenableFuture<Alarm> entity = alarmDao.findAlarmByIdAsync(alarmId.getId());
return Futures.transform(entity, function, readResultsProcessingExecutor);
dao/src/main/resources/schema.cql 2(+1 -1)
diff --git a/dao/src/main/resources/schema.cql b/dao/src/main/resources/schema.cql
index 44afed9..e0ef1e2 100644
--- a/dao/src/main/resources/schema.cql
+++ b/dao/src/main/resources/schema.cql
@@ -276,7 +276,7 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.relation_by_type_and_child_ty
from thingsboard.relation
WHERE from_id IS NOT NULL AND from_type IS NOT NULL AND relation_type IS NOT NULL AND to_id IS NOT NULL AND to_type IS NOT NULL
PRIMARY KEY ((from_id, from_type), relation_type, to_type, to_id)
- WITH CLUSTERING ORDER BY ( relation_type ASC, from_type ASC, from_id ASC);
+ WITH CLUSTERING ORDER BY ( relation_type ASC, to_type ASC, to_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.reverse_relation AS
SELECT *
diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AlarmServiceTest.java
index 4264cbd..4bf43f9 100644
--- a/dao/src/test/java/org/thingsboard/server/dao/service/AlarmServiceTest.java
+++ b/dao/src/test/java/org/thingsboard/server/dao/service/AlarmServiceTest.java
@@ -117,20 +117,20 @@ public class AlarmServiceTest extends AbstractServiceTest {
Alarm created = alarmService.createOrUpdateAlarm(alarm);
// Check child relation
- TimePageData<Alarm> alarms = alarmService.findAlarms(AlarmQuery.builder().tenantId(tenantId)
+ TimePageData<Alarm> alarms = alarmService.findAlarms(AlarmQuery.builder()
.affectedEntityId(childId)
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
- new TimePageLink(1, 0L, System.currentTimeMillis(), true)
+ new TimePageLink(1, 0L, System.currentTimeMillis(), false)
).build()).get();
Assert.assertNotNull(alarms.getData());
Assert.assertEquals(1, alarms.getData().size());
Assert.assertEquals(created, alarms.getData().get(0));
// Check parent relation
- alarms = alarmService.findAlarms(AlarmQuery.builder().tenantId(tenantId)
+ alarms = alarmService.findAlarms(AlarmQuery.builder()
.affectedEntityId(parentId)
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
- new TimePageLink(1, 0L, System.currentTimeMillis(), true)
+ new TimePageLink(1, 0L, System.currentTimeMillis(), false)
).build()).get();
Assert.assertNotNull(alarms.getData());
Assert.assertEquals(1, alarms.getData().size());
@@ -139,20 +139,20 @@ public class AlarmServiceTest extends AbstractServiceTest {
alarmService.ackAlarm(created.getId(), System.currentTimeMillis()).get();
created = alarmService.findAlarmById(created.getId()).get();
- alarms = alarmService.findAlarms(AlarmQuery.builder().tenantId(tenantId)
+ alarms = alarmService.findAlarms(AlarmQuery.builder()
.affectedEntityId(childId)
.status(AlarmStatus.ACTIVE_ACK).pageLink(
- new TimePageLink(1, 0L, System.currentTimeMillis(), true)
+ new TimePageLink(1, 0L, System.currentTimeMillis(), false)
).build()).get();
Assert.assertNotNull(alarms.getData());
Assert.assertEquals(1, alarms.getData().size());
Assert.assertEquals(created, alarms.getData().get(0));
// Check not existing relation
- alarms = alarmService.findAlarms(AlarmQuery.builder().tenantId(tenantId)
+ alarms = alarmService.findAlarms(AlarmQuery.builder()
.affectedEntityId(childId)
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
- new TimePageLink(1, 0L, System.currentTimeMillis(), true)
+ new TimePageLink(1, 0L, System.currentTimeMillis(), false)
).build()).get();
Assert.assertNotNull(alarms.getData());
Assert.assertEquals(0, alarms.getData().size());
@@ -160,10 +160,10 @@ public class AlarmServiceTest extends AbstractServiceTest {
alarmService.clearAlarm(created.getId(), System.currentTimeMillis()).get();
created = alarmService.findAlarmById(created.getId()).get();
- alarms = alarmService.findAlarms(AlarmQuery.builder().tenantId(tenantId)
+ alarms = alarmService.findAlarms(AlarmQuery.builder()
.affectedEntityId(childId)
.status(AlarmStatus.CLEARED_ACK).pageLink(
- new TimePageLink(1, 0L, System.currentTimeMillis(), true)
+ new TimePageLink(1, 0L, System.currentTimeMillis(), false)
).build()).get();
Assert.assertNotNull(alarms.getData());
Assert.assertEquals(1, alarms.getData().size());