diff --git a/application/pom.xml b/application/pom.xml
index f3fd1d04e4..9364cfc16a 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 1.2.3-SNAPSHOT
+ 1.3.0-SNAPSHOT
thingsboard
org.thingsboard
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 0000000000..7d29d57dc9
--- /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 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/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
index 24497d461f..dd43e1c4da 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
@@ -21,6 +21,7 @@ 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.asset.Asset;
+import org.thingsboard.server.common.data.asset.TenantAssetType;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
@@ -136,13 +137,18 @@ public class AssetController extends BaseController {
@ResponseBody
public TextPageData getTenantAssets(
@RequestParam int limit,
+ @RequestParam(required = false) String type,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String idOffset,
@RequestParam(required = false) String textOffset) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
- return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink));
+ if (type != null && type.trim().length()>0) {
+ return checkNotNull(assetService.findAssetsByTenantIdAndType(tenantId, type, pageLink));
+ } else {
+ return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink));
+ }
} catch (Exception e) {
throw handleException(e);
}
@@ -167,6 +173,7 @@ public class AssetController extends BaseController {
public TextPageData getCustomerAssets(
@PathVariable("customerId") String strCustomerId,
@RequestParam int limit,
+ @RequestParam(required = false) String type,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String idOffset,
@RequestParam(required = false) String textOffset) throws ThingsboardException {
@@ -176,7 +183,11 @@ public class AssetController extends BaseController {
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId);
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
- return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
+ if (type != null && type.trim().length()>0) {
+ return checkNotNull(assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
+ } else {
+ return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
+ }
} catch (Exception e) {
throw handleException(e);
}
@@ -231,4 +242,18 @@ public class AssetController extends BaseController {
throw handleException(e);
}
}
+
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+ @RequestMapping(value = "/asset/types", method = RequestMethod.GET)
+ @ResponseBody
+ public List getAssetTypes() throws ThingsboardException {
+ try {
+ SecurityUser user = getCurrentUser();
+ TenantId tenantId = user.getTenantId();
+ ListenableFuture> assetTypes = assetService.findAssetTypesByTenantId(tenantId);
+ return checkNotNull(assetTypes.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 12d43e00a4..1feef4a670 100644
--- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
@@ -23,6 +23,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;
@@ -34,6 +36,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;
@@ -81,6 +84,9 @@ public abstract class BaseController {
@Autowired
protected AssetService assetService;
+ @Autowired
+ protected AlarmService alarmService;
+
@Autowired
protected DeviceCredentialsService deviceCredentialsService;
@@ -305,7 +311,7 @@ public abstract class BaseController {
}
}
- private void checkDevice(Device device) throws ThingsboardException {
+ protected void checkDevice(Device device) throws ThingsboardException {
checkNotNull(device);
checkTenantId(device.getTenantId());
if (device.getCustomerId() != null && !device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
@@ -332,6 +338,22 @@ public abstract class BaseController {
}
}
+ Alarm checkAlarmId(AlarmId alarmId) throws ThingsboardException {
+ try {
+ validateId(alarmId, "Incorrect alarmId " + alarmId);
+ Alarm alarm = alarmService.findAlarmByIdAsync(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);
@@ -378,14 +400,26 @@ public abstract class BaseController {
try {
validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
Dashboard dashboard = dashboardService.findDashboardById(dashboardId);
- checkDashboard(dashboard);
+ checkDashboard(dashboard, true);
return dashboard;
} catch (Exception e) {
throw handleException(e, false);
}
}
- private void checkDashboard(Dashboard dashboard) throws ThingsboardException {
+ DashboardInfo checkDashboardInfoId(DashboardId dashboardId) throws ThingsboardException {
+ try {
+ validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
+ DashboardInfo dashboardInfo = dashboardService.findDashboardInfoById(dashboardId);
+ SecurityUser authUser = getCurrentUser();
+ checkDashboard(dashboardInfo, authUser.getAuthority() != Authority.SYS_ADMIN);
+ return dashboardInfo;
+ } catch (Exception e) {
+ throw handleException(e, false);
+ }
+ }
+
+ private void checkDashboard(DashboardInfo dashboard, boolean checkCustomerId) throws ThingsboardException {
checkNotNull(dashboard);
checkTenantId(dashboard.getTenantId());
SecurityUser authUser = getCurrentUser();
@@ -395,7 +429,8 @@ public abstract class BaseController {
ThingsboardErrorCode.PERMISSION_DENIED);
}
}
- if (dashboard.getCustomerId() != null && !dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
+ if (checkCustomerId &&
+ dashboard.getCustomerId() != null && !dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
checkCustomerId(dashboard.getCustomerId());
}
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
index 3812610d20..2a6416ce98 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
@@ -41,6 +41,19 @@ public class DashboardController extends BaseController {
return System.currentTimeMillis();
}
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
+ @RequestMapping(value = "/dashboard/info/{dashboardId}", method = RequestMethod.GET)
+ @ResponseBody
+ public DashboardInfo getDashboardInfoById(@PathVariable("dashboardId") String strDashboardId) throws ThingsboardException {
+ checkParameter("dashboardId", strDashboardId);
+ try {
+ DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
+ return checkDashboardInfoId(dashboardId);
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.GET)
@ResponseBody
@@ -132,6 +145,25 @@ public class DashboardController extends BaseController {
}
}
+ @PreAuthorize("hasAuthority('SYS_ADMIN')")
+ @RequestMapping(value = "/tenant/{tenantId}/dashboards", params = { "limit" }, method = RequestMethod.GET)
+ @ResponseBody
+ public TextPageData getTenantDashboards(
+ @PathVariable("tenantId") String strTenantId,
+ @RequestParam int limit,
+ @RequestParam(required = false) String textSearch,
+ @RequestParam(required = false) String idOffset,
+ @RequestParam(required = false) String textOffset) throws ThingsboardException {
+ try {
+ TenantId tenantId = new TenantId(toUUID(strTenantId));
+ checkTenantId(tenantId);
+ TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
+ return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink));
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/dashboards", params = { "limit" }, method = RequestMethod.GET)
@ResponseBody
diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
index 38efcb82d5..8257767140 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
@@ -21,12 +21,14 @@ 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.Device;
+import org.thingsboard.server.common.data.TenantDeviceType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.security.DeviceCredentials;
+import org.thingsboard.server.dao.device.DeviceSearchQuery;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.exception.ThingsboardException;
@@ -34,6 +36,7 @@ import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
@RestController
@RequestMapping("/api")
@@ -164,13 +167,18 @@ public class DeviceController extends BaseController {
@ResponseBody
public TextPageData getTenantDevices(
@RequestParam int limit,
+ @RequestParam(required = false) String type,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String idOffset,
@RequestParam(required = false) String textOffset) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
- return checkNotNull(deviceService.findDevicesByTenantId(tenantId, pageLink));
+ if (type != null && type.trim().length()>0) {
+ return checkNotNull(deviceService.findDevicesByTenantIdAndType(tenantId, type, pageLink));
+ } else {
+ return checkNotNull(deviceService.findDevicesByTenantId(tenantId, pageLink));
+ }
} catch (Exception e) {
throw handleException(e);
}
@@ -195,6 +203,7 @@ public class DeviceController extends BaseController {
public TextPageData getCustomerDevices(
@PathVariable("customerId") String strCustomerId,
@RequestParam int limit,
+ @RequestParam(required = false) String type,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String idOffset,
@RequestParam(required = false) String textOffset) throws ThingsboardException {
@@ -204,7 +213,11 @@ public class DeviceController extends BaseController {
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId);
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
- return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, pageLink));
+ if (type != null && type.trim().length()>0) {
+ return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
+ } else {
+ return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, pageLink));
+ }
} catch (Exception e) {
throw handleException(e);
}
@@ -235,4 +248,43 @@ public class DeviceController extends BaseController {
throw handleException(e);
}
}
+
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+ @RequestMapping(value = "/devices", method = RequestMethod.POST)
+ @ResponseBody
+ public List findByQuery(@RequestBody DeviceSearchQuery query) throws ThingsboardException {
+ checkNotNull(query);
+ checkNotNull(query.getParameters());
+ checkNotNull(query.getDeviceTypes());
+ checkEntityId(query.getParameters().getEntityId());
+ try {
+ List devices = checkNotNull(deviceService.findDevicesByQuery(query).get());
+ devices = devices.stream().filter(device -> {
+ try {
+ checkDevice(device);
+ return true;
+ } catch (ThingsboardException e) {
+ return false;
+ }
+ }).collect(Collectors.toList());
+ return devices;
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+ @RequestMapping(value = "/device/types", method = RequestMethod.GET)
+ @ResponseBody
+ public List getDeviceTypes() throws ThingsboardException {
+ try {
+ SecurityUser user = getCurrentUser();
+ TenantId tenantId = user.getTenantId();
+ ListenableFuture> deviceTypes = deviceService.findDeviceTypesByTenantId(tenantId);
+ return checkNotNull(deviceTypes.get());
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
index 0c1fd8bf73..1a08d56a7f 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
@@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.*;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.relation.EntityRelation;
+import org.thingsboard.server.common.data.relation.EntityRelationInfo;
+import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.dao.relation.EntityRelationsQuery;
import org.thingsboard.server.exception.ThingsboardErrorCode;
import org.thingsboard.server.exception.ThingsboardException;
@@ -50,19 +52,23 @@ public class EntityRelationController extends BaseController {
@RequestMapping(value = "/relation", method = RequestMethod.DELETE, params = {"fromId", "fromType", "relationType", "toId", "toType"})
@ResponseStatus(value = HttpStatus.OK)
public void deleteRelation(@RequestParam("fromId") String strFromId,
- @RequestParam("fromType") String strFromType, @RequestParam("relationType") String strRelationType,
+ @RequestParam("fromType") String strFromType,
+ @RequestParam("relationType") String strRelationType,
+ @RequestParam("relationTypeGroup") String strRelationTypeGroup,
@RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException {
checkParameter("fromId", strFromId);
checkParameter("fromType", strFromType);
checkParameter("relationType", strRelationType);
+ checkParameter("relationTypeGroup", strRelationTypeGroup);
checkParameter("toId", strToId);
checkParameter("toType", strToType);
EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
checkEntityId(fromId);
checkEntityId(toId);
+ RelationTypeGroup relationTypeGroup = RelationTypeGroup.valueOf(strRelationTypeGroup);
try {
- Boolean found = relationService.deleteRelation(fromId, toId, strRelationType).get();
+ Boolean found = relationService.deleteRelation(fromId, toId, strRelationType, relationTypeGroup).get();
if (!found) {
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
}
@@ -91,7 +97,9 @@ public class EntityRelationController extends BaseController {
@RequestMapping(value = "/relation", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType", "toId", "toType"})
@ResponseStatus(value = HttpStatus.OK)
public void checkRelation(@RequestParam("fromId") String strFromId,
- @RequestParam("fromType") String strFromType, @RequestParam("relationType") String strRelationType,
+ @RequestParam("fromType") String strFromType,
+ @RequestParam("relationType") String strRelationType,
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
@RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException {
try {
checkParameter("fromId", strFromId);
@@ -103,7 +111,8 @@ public class EntityRelationController extends BaseController {
EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
checkEntityId(fromId);
checkEntityId(toId);
- Boolean found = relationService.checkRelation(fromId, toId, strRelationType).get();
+ RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
+ Boolean found = relationService.checkRelation(fromId, toId, strRelationType, typeGroup).get();
if (!found) {
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
}
@@ -115,13 +124,34 @@ public class EntityRelationController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType"})
@ResponseBody
- public List findByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType) throws ThingsboardException {
+ public List findByFrom(@RequestParam("fromId") String strFromId,
+ @RequestParam("fromType") String strFromType,
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
checkParameter("fromId", strFromId);
checkParameter("fromType", strFromType);
EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
checkEntityId(entityId);
+ RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
- return checkNotNull(relationService.findByFrom(entityId).get());
+ return checkNotNull(relationService.findByFrom(entityId, typeGroup).get());
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+ @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {"fromId", "fromType"})
+ @ResponseBody
+ public List findInfoByFrom(@RequestParam("fromId") String strFromId,
+ @RequestParam("fromType") String strFromType,
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
+ checkParameter("fromId", strFromId);
+ checkParameter("fromType", strFromType);
+ EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
+ checkEntityId(entityId);
+ RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
+ try {
+ return checkNotNull(relationService.findInfoByFrom(entityId, typeGroup).get());
} catch (Exception e) {
throw handleException(e);
}
@@ -130,15 +160,18 @@ public class EntityRelationController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType"})
@ResponseBody
- public List findByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType
- , @RequestParam("relationType") String strRelationType) throws ThingsboardException {
+ public List findByFrom(@RequestParam("fromId") String strFromId,
+ @RequestParam("fromType") String strFromType,
+ @RequestParam("relationType") String strRelationType,
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
checkParameter("fromId", strFromId);
checkParameter("fromType", strFromType);
checkParameter("relationType", strRelationType);
EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
checkEntityId(entityId);
+ RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
- return checkNotNull(relationService.findByFromAndType(entityId, strRelationType).get());
+ return checkNotNull(relationService.findByFromAndType(entityId, strRelationType, typeGroup).get());
} catch (Exception e) {
throw handleException(e);
}
@@ -147,13 +180,16 @@ public class EntityRelationController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType"})
@ResponseBody
- public List findByTo(@RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException {
+ public List findByTo(@RequestParam("toId") String strToId,
+ @RequestParam("toType") String strToType,
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
checkParameter("toId", strToId);
checkParameter("toType", strToType);
EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
checkEntityId(entityId);
+ RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
- return checkNotNull(relationService.findByTo(entityId).get());
+ return checkNotNull(relationService.findByTo(entityId, typeGroup).get());
} catch (Exception e) {
throw handleException(e);
}
@@ -162,15 +198,18 @@ public class EntityRelationController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType", "relationType"})
@ResponseBody
- public List findByTo(@RequestParam("toId") String strToId, @RequestParam("toType") String strToType
- , @RequestParam("relationType") String strRelationType) throws ThingsboardException {
+ public List findByTo(@RequestParam("toId") String strToId,
+ @RequestParam("toType") String strToType,
+ @RequestParam("relationType") String strRelationType,
+ @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
checkParameter("toId", strToId);
checkParameter("toType", strToType);
checkParameter("relationType", strRelationType);
EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
checkEntityId(entityId);
+ RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
try {
- return checkNotNull(relationService.findByToAndType(entityId, strRelationType).get());
+ return checkNotNull(relationService.findByToAndType(entityId, strRelationType, typeGroup).get());
} catch (Exception e) {
throw handleException(e);
}
@@ -191,4 +230,16 @@ public class EntityRelationController extends BaseController {
}
}
+ private RelationTypeGroup parseRelationTypeGroup(String strRelationTypeGroup, RelationTypeGroup defaultValue) {
+ RelationTypeGroup result = defaultValue;
+ if (strRelationTypeGroup != null && strRelationTypeGroup.trim().length()>0) {
+ try {
+ result = RelationTypeGroup.valueOf(strRelationTypeGroup);
+ } catch (IllegalArgumentException e) {
+ result = defaultValue;
+ }
+ }
+ return result;
+ }
+
}
diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index 3bacbfa60f..f24761c9e1 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -19,12 +19,18 @@ server:
address: "${HTTP_BIND_ADDRESS:0.0.0.0}"
# Server bind port
port: "${HTTP_BIND_PORT:8080}"
-# Uncomment the following section to enable ssl
-# ssl:
-# key-store: classpath:keystore/keystore.p12
-# key-store-password: thingsboard
-# keyStoreType: PKCS12
-# keyAlias: tomcat
+ # Server SSL configuration
+ ssl:
+ # Enable/disable SSL support
+ enabled: "${SSL_ENABLED:false}"
+ # Path to the key store that holds the SSL certificate
+ key-store: "${SSL_KEY_STORE:classpath:keystore/keystore.p12}"
+ # Password used to access the key store
+ key-store-password: "${SSL_KEY_STORE_PASSWORD:thingsboard}"
+ # Type of the key store
+ key-store-type: "${SSL_KEY_STORE_TYPE:PKCS12}"
+ # Alias that identifies the key in the key store
+ key-alias: "${SSL_KEY_ALIAS:tomcat}"
# Zookeeper connection parameters. Used for service discovery.
zk:
@@ -79,12 +85,18 @@ mqtt:
leak_detector_level: "${NETTY_LEASK_DETECTOR_LVL:DISABLED}"
boss_group_thread_count: "${NETTY_BOSS_GROUP_THREADS:1}"
worker_group_thread_count: "${NETTY_WORKER_GROUP_THREADS:12}"
-# Uncomment the following lines to enable ssl for MQTT
-# ssl:
-# key_store: mqttserver.jks
-# key_store_password: server_ks_password
-# key_password: server_key_password
-# key_store_type: JKS
+ # MQTT SSL configuration
+ ssl:
+ # Enable/disable SSL support
+ enabled: "${MQTT_SSL_ENABLED:false}"
+ # Path to the key store that holds the SSL certificate
+ key_store: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
+ # Password used to access the key store
+ key_store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
+ # Password used to access the key
+ key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
+ # Type of the key store
+ key_store_type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}"
# CoAP server parameters
coap:
diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java
index b9647e514d..435f9a64f3 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java
@@ -98,13 +98,15 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC
@IntegrationTest("server.port:0")
public abstract class AbstractControllerTest {
+ protected static final String TEST_TENANT_NAME = "TEST TENANT";
+
protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org";
private static final String SYS_ADMIN_PASSWORD = "sysadmin";
- protected static final String TENANT_ADMIN_EMAIL = "tenant@thingsboard.org";
+ protected static final String TENANT_ADMIN_EMAIL = "testtenant@thingsboard.org";
private static final String TENANT_ADMIN_PASSWORD = "tenant";
- protected static final String CUSTOMER_USER_EMAIL = "customer@thingsboard.org";
+ protected static final String CUSTOMER_USER_EMAIL = "testcustomer@thingsboard.org";
private static final String CUSTOMER_USER_PASSWORD = "customer";
protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
@@ -147,7 +149,7 @@ public abstract class AbstractControllerTest {
loginSysAdmin();
Tenant tenant = new Tenant();
- tenant.setTitle("Tenant");
+ tenant.setTitle(TEST_TENANT_NAME);
Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant);
tenantId = savedTenant.getId();
diff --git a/application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java
new file mode 100644
index 0000000000..10a2ff7c8f
--- /dev/null
+++ b/application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java
@@ -0,0 +1,659 @@
+/**
+ * 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 static org.hamcrest.Matchers.containsString;
+import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.thingsboard.server.common.data.*;
+import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.asset.TenantAssetType;
+import org.thingsboard.server.common.data.id.CustomerId;
+import org.thingsboard.server.common.data.id.AssetId;
+import org.thingsboard.server.common.data.page.TextPageData;
+import org.thingsboard.server.common.data.page.TextPageLink;
+import org.thingsboard.server.common.data.security.Authority;
+import org.thingsboard.server.dao.model.ModelConstants;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.datastax.driver.core.utils.UUIDs;
+import com.fasterxml.jackson.core.type.TypeReference;
+
+public class AssetControllerTest extends AbstractControllerTest {
+
+ private IdComparator idComparator = new IdComparator<>();
+
+ private Tenant savedTenant;
+ private User tenantAdmin;
+
+ @Before
+ public void beforeTest() throws Exception {
+ loginSysAdmin();
+
+ Tenant tenant = new Tenant();
+ tenant.setTitle("My tenant");
+ savedTenant = doPost("/api/tenant", tenant, Tenant.class);
+ Assert.assertNotNull(savedTenant);
+
+ tenantAdmin = new User();
+ tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
+ tenantAdmin.setTenantId(savedTenant.getId());
+ tenantAdmin.setEmail("tenant2@thingsboard.org");
+ tenantAdmin.setFirstName("Joe");
+ tenantAdmin.setLastName("Downs");
+
+ tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
+ }
+
+ @After
+ public void afterTest() throws Exception {
+ loginSysAdmin();
+
+ doDelete("/api/tenant/"+savedTenant.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ @Test
+ public void testSaveAsset() throws Exception {
+ Asset asset = new Asset();
+ asset.setName("My asset");
+ asset.setType("default");
+ Asset savedAsset = doPost("/api/asset", asset, Asset.class);
+
+ Assert.assertNotNull(savedAsset);
+ Assert.assertNotNull(savedAsset.getId());
+ Assert.assertTrue(savedAsset.getCreatedTime() > 0);
+ Assert.assertEquals(savedTenant.getId(), savedAsset.getTenantId());
+ Assert.assertNotNull(savedAsset.getCustomerId());
+ Assert.assertEquals(NULL_UUID, savedAsset.getCustomerId().getId());
+ Assert.assertEquals(asset.getName(), savedAsset.getName());
+
+ savedAsset.setName("My new asset");
+ doPost("/api/asset", savedAsset, Asset.class);
+
+ Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
+ Assert.assertEquals(foundAsset.getName(), savedAsset.getName());
+ }
+
+ @Test
+ public void testFindAssetById() throws Exception {
+ Asset asset = new Asset();
+ asset.setName("My asset");
+ asset.setType("default");
+ Asset savedAsset = doPost("/api/asset", asset, Asset.class);
+ Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
+ Assert.assertNotNull(foundAsset);
+ Assert.assertEquals(savedAsset, foundAsset);
+ }
+
+ @Test
+ public void testFindAssetTypesByTenantId() throws Exception {
+ List assets = new ArrayList<>();
+ for (int i=0;i<3;i++) {
+ Asset asset = new Asset();
+ asset.setName("My asset B"+i);
+ asset.setType("typeB");
+ assets.add(doPost("/api/asset", asset, Asset.class));
+ }
+ for (int i=0;i<7;i++) {
+ Asset asset = new Asset();
+ asset.setName("My asset C"+i);
+ asset.setType("typeC");
+ assets.add(doPost("/api/asset", asset, Asset.class));
+ }
+ for (int i=0;i<9;i++) {
+ Asset asset = new Asset();
+ asset.setName("My asset A"+i);
+ asset.setType("typeA");
+ assets.add(doPost("/api/asset", asset, Asset.class));
+ }
+ List assetTypes = doGetTyped("/api/asset/types",
+ new TypeReference>(){});
+
+ Assert.assertNotNull(assetTypes);
+ Assert.assertEquals(3, assetTypes.size());
+ Assert.assertEquals("typeA", assetTypes.get(0).getType());
+ Assert.assertEquals("typeB", assetTypes.get(1).getType());
+ Assert.assertEquals("typeC", assetTypes.get(2).getType());
+ }
+
+ @Test
+ public void testDeleteAsset() throws Exception {
+ Asset asset = new Asset();
+ asset.setName("My asset");
+ asset.setType("default");
+ Asset savedAsset = doPost("/api/asset", asset, Asset.class);
+
+ doDelete("/api/asset/"+savedAsset.getId().getId().toString())
+ .andExpect(status().isOk());
+
+ doGet("/api/asset/"+savedAsset.getId().getId().toString())
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ public void testSaveAssetWithEmptyType() throws Exception {
+ Asset asset = new Asset();
+ asset.setName("My asset");
+ doPost("/api/asset", asset)
+ .andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Asset type should be specified")));
+ }
+
+ @Test
+ public void testSaveAssetWithEmptyName() throws Exception {
+ Asset asset = new Asset();
+ asset.setType("default");
+ doPost("/api/asset", asset)
+ .andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Asset name should be specified")));
+ }
+
+ @Test
+ public void testAssignUnassignAssetToCustomer() throws Exception {
+ Asset asset = new Asset();
+ asset.setName("My asset");
+ asset.setType("default");
+ Asset savedAsset = doPost("/api/asset", asset, Asset.class);
+
+ Customer customer = new Customer();
+ customer.setTitle("My customer");
+ Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
+
+ Asset assignedAsset = doPost("/api/customer/" + savedCustomer.getId().getId().toString()
+ + "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
+ Assert.assertEquals(savedCustomer.getId(), assignedAsset.getCustomerId());
+
+ Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
+ Assert.assertEquals(savedCustomer.getId(), foundAsset.getCustomerId());
+
+ Asset unassignedAsset =
+ doDelete("/api/customer/asset/" + savedAsset.getId().getId().toString(), Asset.class);
+ Assert.assertEquals(ModelConstants.NULL_UUID, unassignedAsset.getCustomerId().getId());
+
+ foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
+ Assert.assertEquals(ModelConstants.NULL_UUID, foundAsset.getCustomerId().getId());
+ }
+
+ @Test
+ public void testAssignAssetToNonExistentCustomer() throws Exception {
+ Asset asset = new Asset();
+ asset.setName("My asset");
+ asset.setType("default");
+ Asset savedAsset = doPost("/api/asset", asset, Asset.class);
+
+ doPost("/api/customer/" + UUIDs.timeBased().toString()
+ + "/asset/" + savedAsset.getId().getId().toString())
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ public void testAssignAssetToCustomerFromDifferentTenant() throws Exception {
+ loginSysAdmin();
+
+ Tenant tenant2 = new Tenant();
+ tenant2.setTitle("Different tenant");
+ Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class);
+ Assert.assertNotNull(savedTenant2);
+
+ User tenantAdmin2 = new User();
+ tenantAdmin2.setAuthority(Authority.TENANT_ADMIN);
+ tenantAdmin2.setTenantId(savedTenant2.getId());
+ tenantAdmin2.setEmail("tenant3@thingsboard.org");
+ tenantAdmin2.setFirstName("Joe");
+ tenantAdmin2.setLastName("Downs");
+
+ tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1");
+
+ Customer customer = new Customer();
+ customer.setTitle("Different customer");
+ Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
+
+ login(tenantAdmin.getEmail(), "testPassword1");
+
+ Asset asset = new Asset();
+ asset.setName("My asset");
+ asset.setType("default");
+ Asset savedAsset = doPost("/api/asset", asset, Asset.class);
+
+ doPost("/api/customer/" + savedCustomer.getId().getId().toString()
+ + "/asset/" + savedAsset.getId().getId().toString())
+ .andExpect(status().isForbidden());
+
+ loginSysAdmin();
+
+ doDelete("/api/tenant/"+savedTenant2.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ @Test
+ public void testFindTenantAssets() throws Exception {
+ List assets = new ArrayList<>();
+ for (int i=0;i<178;i++) {
+ Asset asset = new Asset();
+ asset.setName("Asset"+i);
+ asset.setType("default");
+ assets.add(doPost("/api/asset", asset, Asset.class));
+ }
+ List loadedAssets = new ArrayList<>();
+ TextPageLink pageLink = new TextPageLink(23);
+ TextPageData pageData = null;
+ do {
+ pageData = doGetTypedWithPageLink("/api/tenant/assets?",
+ new TypeReference>(){}, pageLink);
+ loadedAssets.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(assets, idComparator);
+ Collections.sort(loadedAssets, idComparator);
+
+ Assert.assertEquals(assets, loadedAssets);
+ }
+
+ @Test
+ public void testFindTenantAssetsByName() throws Exception {
+ String title1 = "Asset title 1";
+ List assetsTitle1 = new ArrayList<>();
+ for (int i=0;i<143;i++) {
+ Asset asset = new Asset();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title1+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ asset.setName(name);
+ asset.setType("default");
+ assetsTitle1.add(doPost("/api/asset", asset, Asset.class));
+ }
+ String title2 = "Asset title 2";
+ List assetsTitle2 = new ArrayList<>();
+ for (int i=0;i<75;i++) {
+ Asset asset = new Asset();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title2+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ asset.setName(name);
+ asset.setType("default");
+ assetsTitle2.add(doPost("/api/asset", asset, Asset.class));
+ }
+
+ List loadedAssetsTitle1 = new ArrayList<>();
+ TextPageLink pageLink = new TextPageLink(15, title1);
+ TextPageData pageData = null;
+ do {
+ pageData = doGetTypedWithPageLink("/api/tenant/assets?",
+ new TypeReference>(){}, pageLink);
+ loadedAssetsTitle1.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(assetsTitle1, idComparator);
+ Collections.sort(loadedAssetsTitle1, idComparator);
+
+ Assert.assertEquals(assetsTitle1, loadedAssetsTitle1);
+
+ List loadedAssetsTitle2 = new ArrayList<>();
+ pageLink = new TextPageLink(4, title2);
+ do {
+ pageData = doGetTypedWithPageLink("/api/tenant/assets?",
+ new TypeReference>(){}, pageLink);
+ loadedAssetsTitle2.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(assetsTitle2, idComparator);
+ Collections.sort(loadedAssetsTitle2, idComparator);
+
+ Assert.assertEquals(assetsTitle2, loadedAssetsTitle2);
+
+ for (Asset asset : loadedAssetsTitle1) {
+ doDelete("/api/asset/"+asset.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4, title1);
+ pageData = doGetTypedWithPageLink("/api/tenant/assets?",
+ new TypeReference>(){}, pageLink);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+
+ for (Asset asset : loadedAssetsTitle2) {
+ doDelete("/api/asset/"+asset.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4, title2);
+ pageData = doGetTypedWithPageLink("/api/tenant/assets?",
+ new TypeReference>(){}, pageLink);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+ }
+
+ @Test
+ public void testFindTenantAssetsByType() throws Exception {
+ String title1 = "Asset title 1";
+ String type1 = "typeA";
+ List assetsType1 = new ArrayList<>();
+ for (int i=0;i<143;i++) {
+ Asset asset = new Asset();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title1+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ asset.setName(name);
+ asset.setType(type1);
+ assetsType1.add(doPost("/api/asset", asset, Asset.class));
+ }
+ String title2 = "Asset title 2";
+ String type2 = "typeB";
+ List assetsType2 = new ArrayList<>();
+ for (int i=0;i<75;i++) {
+ Asset asset = new Asset();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title2+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ asset.setName(name);
+ asset.setType(type2);
+ assetsType2.add(doPost("/api/asset", asset, Asset.class));
+ }
+
+ List loadedAssetsType1 = new ArrayList<>();
+ TextPageLink pageLink = new TextPageLink(15);
+ TextPageData pageData = null;
+ do {
+ pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
+ new TypeReference>(){}, pageLink, type1);
+ loadedAssetsType1.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(assetsType1, idComparator);
+ Collections.sort(loadedAssetsType1, idComparator);
+
+ Assert.assertEquals(assetsType1, loadedAssetsType1);
+
+ List loadedAssetsType2 = new ArrayList<>();
+ pageLink = new TextPageLink(4);
+ do {
+ pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
+ new TypeReference>(){}, pageLink, type2);
+ loadedAssetsType2.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(assetsType2, idComparator);
+ Collections.sort(loadedAssetsType2, idComparator);
+
+ Assert.assertEquals(assetsType2, loadedAssetsType2);
+
+ for (Asset asset : loadedAssetsType1) {
+ doDelete("/api/asset/"+asset.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4);
+ pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
+ new TypeReference>(){}, pageLink, type1);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+
+ for (Asset asset : loadedAssetsType2) {
+ doDelete("/api/asset/"+asset.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4);
+ pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
+ new TypeReference>(){}, pageLink, type2);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+ }
+
+ @Test
+ public void testFindCustomerAssets() throws Exception {
+ Customer customer = new Customer();
+ customer.setTitle("Test customer");
+ customer = doPost("/api/customer", customer, Customer.class);
+ CustomerId customerId = customer.getId();
+
+ List assets = new ArrayList<>();
+ for (int i=0;i<128;i++) {
+ Asset asset = new Asset();
+ asset.setName("Asset"+i);
+ asset.setType("default");
+ asset = doPost("/api/asset", asset, Asset.class);
+ assets.add(doPost("/api/customer/" + customerId.getId().toString()
+ + "/asset/" + asset.getId().getId().toString(), Asset.class));
+ }
+
+ List loadedAssets = new ArrayList<>();
+ TextPageLink pageLink = new TextPageLink(23);
+ TextPageData pageData = null;
+ do {
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
+ new TypeReference>(){}, pageLink);
+ loadedAssets.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(assets, idComparator);
+ Collections.sort(loadedAssets, idComparator);
+
+ Assert.assertEquals(assets, loadedAssets);
+ }
+
+ @Test
+ public void testFindCustomerAssetsByName() throws Exception {
+ Customer customer = new Customer();
+ customer.setTitle("Test customer");
+ customer = doPost("/api/customer", customer, Customer.class);
+ CustomerId customerId = customer.getId();
+
+ String title1 = "Asset title 1";
+ List assetsTitle1 = new ArrayList<>();
+ for (int i=0;i<125;i++) {
+ Asset asset = new Asset();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title1+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ asset.setName(name);
+ asset.setType("default");
+ asset = doPost("/api/asset", asset, Asset.class);
+ assetsTitle1.add(doPost("/api/customer/" + customerId.getId().toString()
+ + "/asset/" + asset.getId().getId().toString(), Asset.class));
+ }
+ String title2 = "Asset title 2";
+ List assetsTitle2 = new ArrayList<>();
+ for (int i=0;i<143;i++) {
+ Asset asset = new Asset();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title2+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ asset.setName(name);
+ asset.setType("default");
+ asset = doPost("/api/asset", asset, Asset.class);
+ assetsTitle2.add(doPost("/api/customer/" + customerId.getId().toString()
+ + "/asset/" + asset.getId().getId().toString(), Asset.class));
+ }
+
+ List loadedAssetsTitle1 = new ArrayList<>();
+ TextPageLink pageLink = new TextPageLink(15, title1);
+ TextPageData pageData = null;
+ do {
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
+ new TypeReference>(){}, pageLink);
+ loadedAssetsTitle1.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(assetsTitle1, idComparator);
+ Collections.sort(loadedAssetsTitle1, idComparator);
+
+ Assert.assertEquals(assetsTitle1, loadedAssetsTitle1);
+
+ List loadedAssetsTitle2 = new ArrayList<>();
+ pageLink = new TextPageLink(4, title2);
+ do {
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
+ new TypeReference>(){}, pageLink);
+ loadedAssetsTitle2.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(assetsTitle2, idComparator);
+ Collections.sort(loadedAssetsTitle2, idComparator);
+
+ Assert.assertEquals(assetsTitle2, loadedAssetsTitle2);
+
+ for (Asset asset : loadedAssetsTitle1) {
+ doDelete("/api/customer/asset/" + asset.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4, title1);
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
+ new TypeReference>(){}, pageLink);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+
+ for (Asset asset : loadedAssetsTitle2) {
+ doDelete("/api/customer/asset/" + asset.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4, title2);
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
+ new TypeReference>(){}, pageLink);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+ }
+
+ @Test
+ public void testFindCustomerAssetsByType() throws Exception {
+ Customer customer = new Customer();
+ customer.setTitle("Test customer");
+ customer = doPost("/api/customer", customer, Customer.class);
+ CustomerId customerId = customer.getId();
+
+ String title1 = "Asset title 1";
+ String type1 = "typeC";
+ List assetsType1 = new ArrayList<>();
+ for (int i=0;i<125;i++) {
+ Asset asset = new Asset();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title1+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ asset.setName(name);
+ asset.setType(type1);
+ asset = doPost("/api/asset", asset, Asset.class);
+ assetsType1.add(doPost("/api/customer/" + customerId.getId().toString()
+ + "/asset/" + asset.getId().getId().toString(), Asset.class));
+ }
+ String title2 = "Asset title 2";
+ String type2 = "typeD";
+ List assetsType2 = new ArrayList<>();
+ for (int i=0;i<143;i++) {
+ Asset asset = new Asset();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title2+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ asset.setName(name);
+ asset.setType(type2);
+ asset = doPost("/api/asset", asset, Asset.class);
+ assetsType2.add(doPost("/api/customer/" + customerId.getId().toString()
+ + "/asset/" + asset.getId().getId().toString(), Asset.class));
+ }
+
+ List loadedAssetsType1 = new ArrayList<>();
+ TextPageLink pageLink = new TextPageLink(15);
+ TextPageData pageData = null;
+ do {
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
+ new TypeReference>(){}, pageLink, type1);
+ loadedAssetsType1.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(assetsType1, idComparator);
+ Collections.sort(loadedAssetsType1, idComparator);
+
+ Assert.assertEquals(assetsType1, loadedAssetsType1);
+
+ List loadedAssetsType2 = new ArrayList<>();
+ pageLink = new TextPageLink(4);
+ do {
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
+ new TypeReference>(){}, pageLink, type2);
+ loadedAssetsType2.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(assetsType2, idComparator);
+ Collections.sort(loadedAssetsType2, idComparator);
+
+ Assert.assertEquals(assetsType2, loadedAssetsType2);
+
+ for (Asset asset : loadedAssetsType1) {
+ doDelete("/api/customer/asset/" + asset.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4);
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
+ new TypeReference>(){}, pageLink, type1);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+
+ for (Asset asset : loadedAssetsType2) {
+ doDelete("/api/customer/asset/" + asset.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4);
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
+ new TypeReference>(){}, pageLink, type2);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+ }
+
+}
diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java
index 304385da91..26eaa5dbb7 100644
--- a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java
@@ -25,10 +25,7 @@ import java.util.List;
import com.datastax.driver.core.utils.UUIDs;
import org.apache.commons.lang3.RandomStringUtils;
-import org.thingsboard.server.common.data.Customer;
-import org.thingsboard.server.common.data.Device;
-import org.thingsboard.server.common.data.Tenant;
-import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.*;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceCredentialsId;
import org.thingsboard.server.common.data.id.DeviceId;
@@ -83,6 +80,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
public void testSaveDevice() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
Assert.assertNotNull(savedDevice);
@@ -114,16 +112,49 @@ public class DeviceControllerTest extends AbstractControllerTest {
public void testFindDeviceById() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
Assert.assertNotNull(foundDevice);
Assert.assertEquals(savedDevice, foundDevice);
}
+
+ @Test
+ public void testFindDeviceTypesByTenantId() throws Exception {
+ List devices = new ArrayList<>();
+ for (int i=0;i<3;i++) {
+ Device device = new Device();
+ device.setName("My device B"+i);
+ device.setType("typeB");
+ devices.add(doPost("/api/device", device, Device.class));
+ }
+ for (int i=0;i<7;i++) {
+ Device device = new Device();
+ device.setName("My device C"+i);
+ device.setType("typeC");
+ devices.add(doPost("/api/device", device, Device.class));
+ }
+ for (int i=0;i<9;i++) {
+ Device device = new Device();
+ device.setName("My device A"+i);
+ device.setType("typeA");
+ devices.add(doPost("/api/device", device, Device.class));
+ }
+ List deviceTypes = doGetTyped("/api/device/types",
+ new TypeReference>(){});
+
+ Assert.assertNotNull(deviceTypes);
+ Assert.assertEquals(3, deviceTypes.size());
+ Assert.assertEquals("typeA", deviceTypes.get(0).getType());
+ Assert.assertEquals("typeB", deviceTypes.get(1).getType());
+ Assert.assertEquals("typeC", deviceTypes.get(2).getType());
+ }
@Test
public void testDeleteDevice() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
doDelete("/api/device/"+savedDevice.getId().getId().toString())
@@ -132,10 +163,20 @@ public class DeviceControllerTest extends AbstractControllerTest {
doGet("/api/device/"+savedDevice.getId().getId().toString())
.andExpect(status().isNotFound());
}
-
+
+ @Test
+ public void testSaveDeviceWithEmptyType() throws Exception {
+ Device device = new Device();
+ device.setName("My device");
+ doPost("/api/device", device)
+ .andExpect(status().isBadRequest())
+ .andExpect(statusReason(containsString("Device type should be specified")));
+ }
+
@Test
public void testSaveDeviceWithEmptyName() throws Exception {
Device device = new Device();
+ device.setType("default");
doPost("/api/device", device)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Device name should be specified")));
@@ -145,6 +186,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
public void testAssignUnassignDeviceToCustomer() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
Customer customer = new Customer();
@@ -170,6 +212,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
public void testAssignDeviceToNonExistentCustomer() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
doPost("/api/customer/" + UUIDs.timeBased().toString()
@@ -203,6 +246,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
doPost("/api/customer/" + savedCustomer.getId().getId().toString()
@@ -219,6 +263,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
public void testFindDeviceCredentialsByDeviceId() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -229,6 +274,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
public void testSaveDeviceCredentials() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -255,6 +301,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -268,6 +315,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -281,6 +329,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
public void testSaveNonExistentDeviceCredentials() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -298,6 +347,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -307,9 +357,10 @@ public class DeviceControllerTest extends AbstractControllerTest {
}
@Test
- public void testSaveDeviceCredentialsWithInvalidCredemtialsIdLength() throws Exception {
+ public void testSaveDeviceCredentialsWithInvalidCredentialsIdLength() throws Exception {
Device device = new Device();
device.setName("My device");
+ device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -325,6 +376,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
for (int i=0;i<178;i++) {
Device device = new Device();
device.setName("Device"+i);
+ device.setType("default");
devices.add(doPost("/api/device", device, Device.class));
}
List loadedDevices = new ArrayList<>();
@@ -355,6 +407,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
String name = title1+suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name);
+ device.setType("default");
devicesTitle1.add(doPost("/api/device", device, Device.class));
}
String title2 = "Device title 2";
@@ -365,6 +418,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
String name = title2+suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name);
+ device.setType("default");
devicesTitle2.add(doPost("/api/device", device, Device.class));
}
@@ -423,6 +477,89 @@ public class DeviceControllerTest extends AbstractControllerTest {
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size());
}
+
+ @Test
+ public void testFindTenantDevicesByType() throws Exception {
+ String title1 = "Device title 1";
+ String type1 = "typeA";
+ List devicesType1 = new ArrayList<>();
+ for (int i=0;i<143;i++) {
+ Device device = new Device();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title1+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ device.setName(name);
+ device.setType(type1);
+ devicesType1.add(doPost("/api/device", device, Device.class));
+ }
+ String title2 = "Device title 2";
+ String type2 = "typeB";
+ List devicesType2 = new ArrayList<>();
+ for (int i=0;i<75;i++) {
+ Device device = new Device();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title2+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ device.setName(name);
+ device.setType(type2);
+ devicesType2.add(doPost("/api/device", device, Device.class));
+ }
+
+ List loadedDevicesType1 = new ArrayList<>();
+ TextPageLink pageLink = new TextPageLink(15);
+ TextPageData pageData = null;
+ do {
+ pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
+ new TypeReference>(){}, pageLink, type1);
+ loadedDevicesType1.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(devicesType1, idComparator);
+ Collections.sort(loadedDevicesType1, idComparator);
+
+ Assert.assertEquals(devicesType1, loadedDevicesType1);
+
+ List loadedDevicesType2 = new ArrayList<>();
+ pageLink = new TextPageLink(4);
+ do {
+ pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
+ new TypeReference>(){}, pageLink, type2);
+ loadedDevicesType2.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(devicesType2, idComparator);
+ Collections.sort(loadedDevicesType2, idComparator);
+
+ Assert.assertEquals(devicesType2, loadedDevicesType2);
+
+ for (Device device : loadedDevicesType1) {
+ doDelete("/api/device/"+device.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4);
+ pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
+ new TypeReference>(){}, pageLink, type1);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+
+ for (Device device : loadedDevicesType2) {
+ doDelete("/api/device/"+device.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4);
+ pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
+ new TypeReference>(){}, pageLink, type2);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+ }
@Test
public void testFindCustomerDevices() throws Exception {
@@ -435,6 +572,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
for (int i=0;i<128;i++) {
Device device = new Device();
device.setName("Device"+i);
+ device.setType("default");
device = doPost("/api/device", device, Device.class);
devices.add(doPost("/api/customer/" + customerId.getId().toString()
+ "/device/" + device.getId().getId().toString(), Device.class));
@@ -473,6 +611,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
String name = title1+suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name);
+ device.setType("default");
device = doPost("/api/device", device, Device.class);
devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString()
+ "/device/" + device.getId().getId().toString(), Device.class));
@@ -485,6 +624,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
String name = title2+suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name);
+ device.setType("default");
device = doPost("/api/device", device, Device.class);
devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString()
+ "/device/" + device.getId().getId().toString(), Device.class));
@@ -546,4 +686,96 @@ public class DeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals(0, pageData.getData().size());
}
+ @Test
+ public void testFindCustomerDevicesByType() throws Exception {
+ Customer customer = new Customer();
+ customer.setTitle("Test customer");
+ customer = doPost("/api/customer", customer, Customer.class);
+ CustomerId customerId = customer.getId();
+
+ String title1 = "Device title 1";
+ String type1 = "typeC";
+ List devicesType1 = new ArrayList<>();
+ for (int i=0;i<125;i++) {
+ Device device = new Device();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title1+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ device.setName(name);
+ device.setType(type1);
+ device = doPost("/api/device", device, Device.class);
+ devicesType1.add(doPost("/api/customer/" + customerId.getId().toString()
+ + "/device/" + device.getId().getId().toString(), Device.class));
+ }
+ String title2 = "Device title 2";
+ String type2 = "typeD";
+ List devicesType2 = new ArrayList<>();
+ for (int i=0;i<143;i++) {
+ Device device = new Device();
+ String suffix = RandomStringUtils.randomAlphanumeric(15);
+ String name = title2+suffix;
+ name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
+ device.setName(name);
+ device.setType(type2);
+ device = doPost("/api/device", device, Device.class);
+ devicesType2.add(doPost("/api/customer/" + customerId.getId().toString()
+ + "/device/" + device.getId().getId().toString(), Device.class));
+ }
+
+ List loadedDevicesType1 = new ArrayList<>();
+ TextPageLink pageLink = new TextPageLink(15);
+ TextPageData pageData = null;
+ do {
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
+ new TypeReference>(){}, pageLink, type1);
+ loadedDevicesType1.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(devicesType1, idComparator);
+ Collections.sort(loadedDevicesType1, idComparator);
+
+ Assert.assertEquals(devicesType1, loadedDevicesType1);
+
+ List loadedDevicesType2 = new ArrayList<>();
+ pageLink = new TextPageLink(4);
+ do {
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
+ new TypeReference>(){}, pageLink, type2);
+ loadedDevicesType2.addAll(pageData.getData());
+ if (pageData.hasNext()) {
+ pageLink = pageData.getNextPageLink();
+ }
+ } while (pageData.hasNext());
+
+ Collections.sort(devicesType2, idComparator);
+ Collections.sort(loadedDevicesType2, idComparator);
+
+ Assert.assertEquals(devicesType2, loadedDevicesType2);
+
+ for (Device device : loadedDevicesType1) {
+ doDelete("/api/customer/device/" + device.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4);
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
+ new TypeReference>(){}, pageLink, type1);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+
+ for (Device device : loadedDevicesType2) {
+ doDelete("/api/customer/device/" + device.getId().getId().toString())
+ .andExpect(status().isOk());
+ }
+
+ pageLink = new TextPageLink(4);
+ pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
+ new TypeReference>(){}, pageLink, type2);
+ Assert.assertFalse(pageData.hasNext());
+ Assert.assertEquals(0, pageData.getData().size());
+ }
+
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java
index 5d72076ee6..dc4a4228f3 100644
--- a/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java
@@ -130,7 +130,7 @@ public class TenantControllerTest extends AbstractControllerTest {
Assert.assertEquals(tenants, loadedTenants);
for (Tenant tenant : loadedTenants) {
- if (!tenant.getTitle().equals("Tenant")) {
+ if (!tenant.getTitle().equals(TEST_TENANT_NAME)) {
doDelete("/api/tenant/"+tenant.getId().getId().toString())
.andExpect(status().isOk());
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java
index 7c0004956b..4fafd617d4 100644
--- a/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java
@@ -182,7 +182,7 @@ public class UserControllerTest extends AbstractControllerTest {
Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant);
- String email = "tenant@thingsboard.org";
+ String email = TENANT_ADMIN_EMAIL;
User user = new User();
user.setAuthority(Authority.TENANT_ADMIN);
user.setTenantId(savedTenant.getId());
diff --git a/application/src/test/java/org/thingsboard/server/system/HttpDeviceApiTest.java b/application/src/test/java/org/thingsboard/server/system/HttpDeviceApiTest.java
index b65a5a60ea..af8b50fc48 100644
--- a/application/src/test/java/org/thingsboard/server/system/HttpDeviceApiTest.java
+++ b/application/src/test/java/org/thingsboard/server/system/HttpDeviceApiTest.java
@@ -47,6 +47,7 @@ public class HttpDeviceApiTest extends AbstractControllerTest {
loginTenantAdmin();
device = new Device();
device.setName("My device");
+ device.setType("default");
device = doPost("/api/device", device, Device.class);
deviceCredentials =
diff --git a/common/data/pom.xml b/common/data/pom.xml
index aca4c9c0d0..ffee17c00d 100644
--- a/common/data/pom.xml
+++ b/common/data/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 1.2.3-SNAPSHOT
+ 1.3.0-SNAPSHOT
common
org.thingsboard.common
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java
index 71a45270b8..ec535bf44c 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java
@@ -15,12 +15,14 @@
*/
package org.thingsboard.server.common.data;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonProperty.Access;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import com.fasterxml.jackson.databind.JsonNode;
-public class Customer extends ContactBased{
+public class Customer extends ContactBased implements HasName {
private static final long serialVersionUID = -1599722990298929275L;
@@ -59,6 +61,12 @@ public class Customer extends ContactBased{
this.title = title;
}
+ @Override
+ @JsonProperty(access = Access.READ_ONLY)
+ public String getName() {
+ return title;
+ }
+
public JsonNode getAdditionalInfo() {
return additionalInfo;
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java
index d88df160f8..3be3b79d56 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java
@@ -15,11 +15,12 @@
*/
package org.thingsboard.server.common.data;
+import com.fasterxml.jackson.annotation.JsonProperty;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.TenantId;
-public class DashboardInfo extends SearchTextBased {
+public class DashboardInfo extends SearchTextBased implements HasName {
private TenantId tenantId;
private CustomerId customerId;
@@ -64,6 +65,12 @@ public class DashboardInfo extends SearchTextBased {
this.title = title;
}
+ @Override
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public String getName() {
+ return title;
+ }
+
@Override
public String getSearchText() {
return title;
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java
index 6b312836b3..7d3d4f5742 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java
@@ -21,13 +21,14 @@ import org.thingsboard.server.common.data.id.TenantId;
import com.fasterxml.jackson.databind.JsonNode;
-public class Device extends SearchTextBased {
+public class Device extends SearchTextBased implements HasName {
private static final long serialVersionUID = 2807343040519543363L;
private TenantId tenantId;
private CustomerId customerId;
private String name;
+ private String type;
private JsonNode additionalInfo;
public Device() {
@@ -43,6 +44,7 @@ public class Device extends SearchTextBased {
this.tenantId = device.getTenantId();
this.customerId = device.getCustomerId();
this.name = device.getName();
+ this.type = device.getType();
this.additionalInfo = device.getAdditionalInfo();
}
@@ -62,6 +64,7 @@ public class Device extends SearchTextBased {
this.customerId = customerId;
}
+ @Override
public String getName() {
return name;
}
@@ -70,6 +73,14 @@ public class Device extends SearchTextBased {
this.name = name;
}
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
public JsonNode getAdditionalInfo() {
return additionalInfo;
}
@@ -90,6 +101,7 @@ public class Device extends SearchTextBased {
result = prime * result + ((additionalInfo == null) ? 0 : additionalInfo.hashCode());
result = prime * result + ((customerId == null) ? 0 : customerId.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode());
return result;
}
@@ -118,6 +130,11 @@ public class Device extends SearchTextBased {
return false;
} else if (!name.equals(other.name))
return false;
+ if (type == null) {
+ if (other.type != null)
+ return false;
+ } else if (!type.equals(other.type))
+ return false;
if (tenantId == null) {
if (other.tenantId != null)
return false;
@@ -135,6 +152,8 @@ public class Device extends SearchTextBased {
builder.append(customerId);
builder.append(", name=");
builder.append(name);
+ builder.append(", type=");
+ builder.append(type);
builder.append(", additionalInfo=");
builder.append(additionalInfo);
builder.append(", createdTime=");
diff --git a/ui/src/app/dashboard/device-aliases.scss b/common/data/src/main/java/org/thingsboard/server/common/data/HasName.java
similarity index 81%
rename from ui/src/app/dashboard/device-aliases.scss
rename to common/data/src/main/java/org/thingsboard/server/common/data/HasName.java
index 9b1c489287..f43198908e 100644
--- a/ui/src/app/dashboard/device-aliases.scss
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/HasName.java
@@ -13,13 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.thingsboard.server.common.data;
+
+public interface HasName {
+
+ String getName();
-.tb-aliases-dialog {
- .md-dialog-content {
- padding-bottom: 0px;
- }
- .tb-alias {
- padding: 10px 0 0 10px;
- margin: 5px;
- }
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java
index aee1510608..4501759e55 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java
@@ -15,11 +15,12 @@
*/
package org.thingsboard.server.common.data;
+import com.fasterxml.jackson.annotation.JsonProperty;
import org.thingsboard.server.common.data.id.TenantId;
import com.fasterxml.jackson.databind.JsonNode;
-public class Tenant extends ContactBased{
+public class Tenant extends ContactBased implements HasName {
private static final long serialVersionUID = 8057243243859922101L;
@@ -50,6 +51,12 @@ public class Tenant extends ContactBased{
this.title = title;
}
+ @Override
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public String getName() {
+ return title;
+ }
+
public String getRegion() {
return region;
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/TenantDeviceType.java b/common/data/src/main/java/org/thingsboard/server/common/data/TenantDeviceType.java
new file mode 100644
index 0000000000..d611a2507b
--- /dev/null
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/TenantDeviceType.java
@@ -0,0 +1,79 @@
+/**
+ * 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.common.data;
+
+import org.thingsboard.server.common.data.id.TenantId;
+
+public class TenantDeviceType {
+
+ private static final long serialVersionUID = 8057240243859922101L;
+
+ private String type;
+ private TenantId tenantId;
+
+ public TenantDeviceType() {
+ super();
+ }
+
+ public TenantDeviceType(String type, TenantId tenantId) {
+ this.type = type;
+ this.tenantId = tenantId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public TenantId getTenantId() {
+ return tenantId;
+ }
+
+ public void setTenantId(TenantId tenantId) {
+ this.tenantId = tenantId;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = type != null ? type.hashCode() : 0;
+ result = 31 * result + (tenantId != null ? tenantId.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ TenantDeviceType that = (TenantDeviceType) o;
+
+ if (type != null ? !type.equals(that.type) : that.type != null) return false;
+ return tenantId != null ? tenantId.equals(that.tenantId) : that.tenantId == null;
+
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("TenantDeviceType{");
+ sb.append("type='").append(type).append('\'');
+ sb.append(", tenantId=").append(tenantId);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/User.java b/common/data/src/main/java/org/thingsboard/server/common/data/User.java
index 74fa4cff96..1b97e2e49f 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/User.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/User.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data;
+import com.fasterxml.jackson.annotation.JsonProperty;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
@@ -22,7 +23,7 @@ import org.thingsboard.server.common.data.security.Authority;
import com.fasterxml.jackson.databind.JsonNode;
-public class User extends SearchTextBased {
+public class User extends SearchTextBased implements HasName {
private static final long serialVersionUID = 8250339805336035966L;
@@ -77,6 +78,12 @@ public class User extends SearchTextBased {
this.email = email;
}
+ @Override
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public String getName() {
+ return email;
+ }
+
public Authority getAuthority() {
return authority;
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java
index 669167000f..09695e5ee8 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java
@@ -15,12 +15,13 @@
*/
package org.thingsboard.server.common.data.alarm;
+import com.fasterxml.jackson.annotation.JsonProperty;
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;
+import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
@@ -30,7 +31,7 @@ import org.thingsboard.server.common.data.id.TenantId;
@Data
@Builder
@AllArgsConstructor
-public class Alarm extends BaseData {
+public class Alarm extends BaseData implements HasName {
private TenantId tenantId;
private String type;
@@ -52,4 +53,9 @@ public class Alarm extends BaseData {
super(id);
}
+ @Override
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public String getName() {
+ return type;
+ }
}
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 2dc0189ed0..00ca6c34ab 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,8 @@
*/
package org.thingsboard.server.common.data.alarm;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
@@ -24,9 +26,10 @@ import org.thingsboard.server.common.data.page.TimePageLink;
* Created by ashvayka on 11.05.17.
*/
@Data
+@Builder
+@AllArgsConstructor
public class AlarmQuery {
- private TenantId tenantId;
private EntityId affectedEntityId;
private TimePageLink pageLink;
private AlarmStatus status;
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java
index 2e20b7745c..dafa514f61 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java
@@ -16,12 +16,13 @@
package org.thingsboard.server.common.data.asset;
import com.fasterxml.jackson.databind.JsonNode;
+import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.SearchTextBased;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
-public class Asset extends SearchTextBased {
+public class Asset extends SearchTextBased implements HasName {
private static final long serialVersionUID = 2807343040519543363L;
@@ -64,6 +65,7 @@ public class Asset extends SearchTextBased {
this.customerId = customerId;
}
+ @Override
public String getName() {
return name;
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/asset/TenantAssetType.java b/common/data/src/main/java/org/thingsboard/server/common/data/asset/TenantAssetType.java
new file mode 100644
index 0000000000..bd23f2aa5a
--- /dev/null
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/asset/TenantAssetType.java
@@ -0,0 +1,79 @@
+/**
+ * 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.common.data.asset;
+
+import org.thingsboard.server.common.data.id.TenantId;
+
+public class TenantAssetType {
+
+ private static final long serialVersionUID = 8057290243855622101L;
+
+ private String type;
+ private TenantId tenantId;
+
+ public TenantAssetType() {
+ super();
+ }
+
+ public TenantAssetType(String type, TenantId tenantId) {
+ this.type = type;
+ this.tenantId = tenantId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public TenantId getTenantId() {
+ return tenantId;
+ }
+
+ public void setTenantId(TenantId tenantId) {
+ this.tenantId = tenantId;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = type != null ? type.hashCode() : 0;
+ result = 31 * result + (tenantId != null ? tenantId.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ TenantAssetType that = (TenantAssetType) o;
+
+ if (type != null ? !type.equals(that.type) : that.type != null) return false;
+ return tenantId != null ? tenantId.equals(that.tenantId) : that.tenantId == null;
+
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("TenantAssetType{");
+ sb.append("type='").append(type).append('\'');
+ sb.append(", tenantId=").append(tenantId);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java
index 21093ce3f5..1f77904a44 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java
@@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.id;
import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.alarm.AlarmId;
import java.util.UUID;
@@ -50,6 +51,8 @@ public class EntityIdFactory {
return new DeviceId(uuid);
case ASSET:
return new AssetId(uuid);
+ case ALARM:
+ return new AlarmId(uuid);
}
throw new IllegalArgumentException("EntityType " + type + " is not supported!");
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/PluginMetaData.java b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/PluginMetaData.java
index 5019cd119f..e5eb149fbc 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/PluginMetaData.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/PluginMetaData.java
@@ -15,13 +15,14 @@
*/
package org.thingsboard.server.common.data.plugin;
+import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.SearchTextBased;
import org.thingsboard.server.common.data.id.PluginId;
import org.thingsboard.server.common.data.id.TenantId;
import com.fasterxml.jackson.databind.JsonNode;
-public class PluginMetaData extends SearchTextBased {
+public class PluginMetaData extends SearchTextBased implements HasName {
private static final long serialVersionUID = 1L;
@@ -75,6 +76,7 @@ public class PluginMetaData extends SearchTextBased {
this.tenantId = tenantId;
}
+ @Override
public String getName() {
return name;
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java
index 8fcf2691af..8dab589596 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java
@@ -30,6 +30,7 @@ public class EntityRelation {
private EntityId from;
private EntityId to;
private String type;
+ private RelationTypeGroup typeGroup;
private JsonNode additionalInfo;
public EntityRelation() {
@@ -37,21 +38,27 @@ public class EntityRelation {
}
public EntityRelation(EntityId from, EntityId to, String type) {
- this(from, to, type, null);
+ this(from, to, type, RelationTypeGroup.COMMON);
}
- public EntityRelation(EntityId from, EntityId to, String type, JsonNode additionalInfo) {
+ public EntityRelation(EntityId from, EntityId to, String type, RelationTypeGroup typeGroup) {
+ this(from, to, type, typeGroup, null);
+ }
+
+ public EntityRelation(EntityId from, EntityId to, String type, RelationTypeGroup typeGroup, JsonNode additionalInfo) {
this.from = from;
this.to = to;
this.type = type;
+ this.typeGroup = typeGroup;
this.additionalInfo = additionalInfo;
}
- public EntityRelation(EntityRelation device) {
- this.from = device.getFrom();
- this.to = device.getTo();
- this.type = device.getType();
- this.additionalInfo = device.getAdditionalInfo();
+ public EntityRelation(EntityRelation entityRelation) {
+ this.from = entityRelation.getFrom();
+ this.to = entityRelation.getTo();
+ this.type = entityRelation.getType();
+ this.typeGroup = entityRelation.getTypeGroup();
+ this.additionalInfo = entityRelation.getAdditionalInfo();
}
public EntityId getFrom() {
@@ -78,6 +85,14 @@ public class EntityRelation {
this.type = type;
}
+ public RelationTypeGroup getTypeGroup() {
+ return typeGroup;
+ }
+
+ public void setTypeGroup(RelationTypeGroup typeGroup) {
+ this.typeGroup = typeGroup;
+ }
+
public JsonNode getAdditionalInfo() {
return additionalInfo;
}
@@ -90,14 +105,22 @@ public class EntityRelation {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- EntityRelation relation = (EntityRelation) o;
- return Objects.equals(from, relation.from) &&
- Objects.equals(to, relation.to) &&
- Objects.equals(type, relation.type);
+
+ EntityRelation that = (EntityRelation) o;
+
+ if (from != null ? !from.equals(that.from) : that.from != null) return false;
+ if (to != null ? !to.equals(that.to) : that.to != null) return false;
+ if (type != null ? !type.equals(that.type) : that.type != null) return false;
+ return typeGroup == that.typeGroup;
+
}
@Override
public int hashCode() {
- return Objects.hash(from, to, type);
+ int result = from != null ? from.hashCode() : 0;
+ result = 31 * result + (to != null ? to.hashCode() : 0);
+ result = 31 * result + (type != null ? type.hashCode() : 0);
+ result = 31 * result + (typeGroup != null ? typeGroup.hashCode() : 0);
+ return result;
}
}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java
new file mode 100644
index 0000000000..709ad7937a
--- /dev/null
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java
@@ -0,0 +1,59 @@
+/**
+ * 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.common.data.relation;
+
+public class EntityRelationInfo extends EntityRelation {
+
+ private static final long serialVersionUID = 2807343097519543363L;
+
+ private String toName;
+
+ public EntityRelationInfo() {
+ super();
+ }
+
+ public EntityRelationInfo(EntityRelation entityRelation) {
+ super(entityRelation);
+ }
+
+ public String getToName() {
+ return toName;
+ }
+
+ public void setToName(String toName) {
+ this.toName = toName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ if (!super.equals(o)) return false;
+
+ EntityRelationInfo that = (EntityRelationInfo) o;
+
+ return toName != null ? toName.equals(that.toName) : that.toName == null;
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = super.hashCode();
+ result = 31 * result + (toName != null ? toName.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationTypeGroup.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationTypeGroup.java
new file mode 100644
index 0000000000..82798ab792
--- /dev/null
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationTypeGroup.java
@@ -0,0 +1,23 @@
+/**
+ * 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.common.data.relation;
+
+public enum RelationTypeGroup {
+
+ COMMON,
+ ALARM
+
+}
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleMetaData.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleMetaData.java
index ececfdd72c..1451d2c1a6 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleMetaData.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleMetaData.java
@@ -17,13 +17,14 @@ package org.thingsboard.server.common.data.rule;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
+import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.SearchTextBased;
import org.thingsboard.server.common.data.id.RuleId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
@Data
-public class RuleMetaData extends SearchTextBased {
+public class RuleMetaData extends SearchTextBased implements HasName {
private static final long serialVersionUID = -5656679015122935465L;
@@ -63,4 +64,9 @@ public class RuleMetaData extends SearchTextBased {
return name;
}
+ @Override
+ public String getName() {
+ return name;
+ }
+
}
diff --git a/common/message/pom.xml b/common/message/pom.xml
index 01d3b45b32..5362f685ef 100644
--- a/common/message/pom.xml
+++ b/common/message/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 1.2.3-SNAPSHOT
+ 1.3.0-SNAPSHOT
common
org.thingsboard.common
diff --git a/common/pom.xml b/common/pom.xml
index 9c7b51e1c8..798bec4ca7 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 1.2.3-SNAPSHOT
+ 1.3.0-SNAPSHOT
thingsboard
org.thingsboard
diff --git a/common/transport/pom.xml b/common/transport/pom.xml
index 4a2bb52a2f..c5377563a1 100644
--- a/common/transport/pom.xml
+++ b/common/transport/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 1.2.3-SNAPSHOT
+ 1.3.0-SNAPSHOT
common
org.thingsboard.common
diff --git a/dao/pom.xml b/dao/pom.xml
index ced5c381f4..a3c9b2cfa4 100644
--- a/dao/pom.xml
+++ b/dao/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 1.2.3-SNAPSHOT
+ 1.3.0-SNAPSHOT
thingsboard
org.thingsboard
diff --git a/dao/src/main/java/org/thingsboard/server/dao/CassandraAbstractModelDao.java b/dao/src/main/java/org/thingsboard/server/dao/CassandraAbstractModelDao.java
index b35ed37cf2..0fba69c0c8 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/CassandraAbstractModelDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/CassandraAbstractModelDao.java
@@ -131,7 +131,7 @@ public abstract class CassandraAbstractModelDao, D> exte
log.debug("Save entity {}", entity);
if (entity.getId() == null) {
entity.setId(UUIDs.timeBased());
- } else {
+ } else if (isDeleteOnSave()) {
removeById(entity.getId());
}
Statement saveStatement = getSaveQuery(entity);
@@ -140,6 +140,10 @@ public abstract class CassandraAbstractModelDao, D> exte
return new EntityResultSet<>(resultSet, entity);
}
+ protected boolean isDeleteOnSave() {
+ return true;
+ }
+
@Override
public D save(D domain) {
E entity;
diff --git a/dao/src/main/java/org/thingsboard/server/dao/CassandraAbstractSearchTimeDao.java b/dao/src/main/java/org/thingsboard/server/dao/CassandraAbstractSearchTimeDao.java
index cb60ea4be7..bc6b3e779b 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/CassandraAbstractSearchTimeDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/CassandraAbstractSearchTimeDao.java
@@ -44,6 +44,26 @@ public abstract class CassandraAbstractSearchTimeDao, D>
}
protected List findPageWithTimeSearch(String searchView, List clauses, List topLevelOrderings, TimePageLink pageLink) {
+ return findPageWithTimeSearch(searchView, clauses, topLevelOrderings, pageLink, ModelConstants.ID_PROPERTY);
+ }
+
+ protected List findPageWithTimeSearch(String searchView, List clauses, TimePageLink pageLink, String idColumn) {
+ return findPageWithTimeSearch(searchView, clauses, Collections.emptyList(), pageLink, idColumn);
+ }
+
+ protected List findPageWithTimeSearch(String searchView, List clauses, List topLevelOrderings, TimePageLink pageLink, String idColumn) {
+ return findListByStatement(buildQuery(searchView, clauses, topLevelOrderings, pageLink, idColumn));
+ }
+
+ public static Where buildQuery(String searchView, List clauses, TimePageLink pageLink, String idColumn) {
+ return buildQuery(searchView, clauses, Collections.emptyList(), pageLink, idColumn);
+ }
+
+ public static Where buildQuery(String searchView, List clauses, Ordering order, TimePageLink pageLink, String idColumn) {
+ return buildQuery(searchView, clauses, Collections.singletonList(order), pageLink, idColumn);
+ }
+
+ public static Where buildQuery(String searchView, List clauses, List topLevelOrderings, TimePageLink pageLink, String idColumn) {
Select select = select().from(searchView);
Where query = select.where();
for (Clause clause : clauses) {
@@ -52,34 +72,35 @@ public abstract class CassandraAbstractSearchTimeDao, D>
query.limit(pageLink.getLimit());
if (pageLink.isAscOrder()) {
if (pageLink.getIdOffset() != null) {
- query.and(QueryBuilder.gt(ModelConstants.ID_PROPERTY, pageLink.getIdOffset()));
+ query.and(QueryBuilder.gt(idColumn, pageLink.getIdOffset()));
} else if (pageLink.getStartTime() != null) {
final UUID startOf = UUIDs.startOf(pageLink.getStartTime());
- query.and(QueryBuilder.gte(ModelConstants.ID_PROPERTY, startOf));
+ query.and(QueryBuilder.gte(idColumn, startOf));
}
if (pageLink.getEndTime() != null) {
final UUID endOf = UUIDs.endOf(pageLink.getEndTime());
- query.and(QueryBuilder.lte(ModelConstants.ID_PROPERTY, endOf));
+ query.and(QueryBuilder.lte(idColumn, endOf));
}
} else {
if (pageLink.getIdOffset() != null) {
- query.and(QueryBuilder.lt(ModelConstants.ID_PROPERTY, pageLink.getIdOffset()));
+ query.and(QueryBuilder.lt(idColumn, pageLink.getIdOffset()));
} else if (pageLink.getEndTime() != null) {
final UUID endOf = UUIDs.endOf(pageLink.getEndTime());
- query.and(QueryBuilder.lte(ModelConstants.ID_PROPERTY, endOf));
+ query.and(QueryBuilder.lte(idColumn, endOf));
}
if (pageLink.getStartTime() != null) {
final UUID startOf = UUIDs.startOf(pageLink.getStartTime());
- query.and(QueryBuilder.gte(ModelConstants.ID_PROPERTY, startOf));
+ query.and(QueryBuilder.gte(idColumn, startOf));
}
}
List orderings = new ArrayList<>(topLevelOrderings);
if (pageLink.isAscOrder()) {
- orderings.add(QueryBuilder.asc(ModelConstants.ID_PROPERTY));
+ orderings.add(QueryBuilder.asc(idColumn));
} else {
- orderings.add(QueryBuilder.desc(ModelConstants.ID_PROPERTY));
+ orderings.add(QueryBuilder.desc(idColumn));
}
query.orderBy(orderings.toArray(new Ordering[orderings.size()]));
- return findListByStatement(query);
+ return query;
}
+
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java
index a178c6e75f..712bbd1adf 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java
@@ -17,10 +17,12 @@ package org.thingsboard.server.dao.alarm;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.alarm.Alarm;
+import org.thingsboard.server.common.data.alarm.AlarmQuery;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.Dao;
+import java.util.List;
import java.util.UUID;
/**
@@ -30,4 +32,9 @@ public interface AlarmDao extends Dao {
ListenableFuture findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type);
+ ListenableFuture findAlarmByIdAsync(UUID key);
+
+ Alarm save(Alarm alarm);
+
+ ListenableFuture> findAlarms(AlarmQuery query);
}
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 6508db21a1..5399d9dd7f 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
@@ -16,16 +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;
-import java.util.Optional;
-
/**
* Created by ashvayka on 11.05.17.
*/
@@ -33,13 +28,11 @@ public interface AlarmService {
Alarm createOrUpdateAlarm(Alarm alarm);
- ListenableFuture updateAlarm(Alarm alarm);
-
ListenableFuture ackAlarm(AlarmId alarmId, long ackTs);
ListenableFuture clearAlarm(AlarmId alarmId, long ackTs);
- ListenableFuture findAlarmById(AlarmId alarmId);
+ ListenableFuture findAlarmByIdAsync(AlarmId alarmId);
ListenableFuture> findAlarms(AlarmQuery query);
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 59ec547aa3..77cc574757 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
@@ -31,7 +31,8 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.relation.EntityRelation;
-import org.thingsboard.server.dao.entity.BaseEntityService;
+import org.thingsboard.server.common.data.relation.RelationTypeGroup;
+import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.relation.EntityRelationsQuery;
import org.thingsboard.server.dao.relation.EntitySearchDirection;
@@ -41,18 +42,22 @@ import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.tenant.TenantDao;
import javax.annotation.Nullable;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
import java.util.List;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import static org.thingsboard.server.dao.service.Validator.validateId;
@Service
@Slf4j
-public class BaseAlarmService extends BaseEntityService implements AlarmService {
+public class BaseAlarmService extends AbstractEntityService implements AlarmService {
- private static final String ALARM_RELATION_PREFIX = "ALARM_";
- private static final String ALARM_RELATION = "ALARM_ANY";
+ public static final String ALARM_RELATION_PREFIX = "ALARM_";
+ public static final String ALARM_RELATION = "ALARM_ANY";
@Autowired
private AlarmDao alarmDao;
@@ -63,6 +68,20 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
@Autowired
private RelationService relationService;
+ protected ExecutorService readResultsProcessingExecutor;
+
+ @PostConstruct
+ public void startExecutor() {
+ readResultsProcessingExecutor = Executors.newCachedThreadPool();
+ }
+
+ @PreDestroy
+ public void stopExecutor() {
+ if (readResultsProcessingExecutor != null) {
+ readResultsProcessingExecutor.shutdownNow();
+ }
+ }
+
@Override
public Alarm createOrUpdateAlarm(Alarm alarm) {
alarmDataValidator.validate(alarm);
@@ -73,51 +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 = alarmDao.save(alarm);
- EntityRelationsQuery query = new EntityRelationsQuery();
- query.setParameters(new RelationsSearchParameters(saved.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE));
- List 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);
}
- return saved;
} else {
- log.debug("Alarm before merge: {}", alarm);
- alarm = merge(existing, alarm);
- log.debug("Alarm after merge: {}", alarm);
- return alarmDao.save(alarm);
+ return updateAlarm(alarm).get();
}
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
}
- @Override
- public ListenableFuture updateAlarm(Alarm update) {
+ private Alarm createAlarm(Alarm alarm) throws InterruptedException, ExecutionException {
+ log.debug("New Alarm : {}", alarm);
+ Alarm saved = alarmDao.save(alarm);
+ EntityRelationsQuery query = new EntityRelationsQuery();
+ query.setParameters(new RelationsSearchParameters(saved.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE));
+ List 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, RelationTypeGroup.ALARM));
+ createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name(), RelationTypeGroup.ALARM));
+ }
+ createRelation(new EntityRelation(alarm.getOriginator(), saved.getId(), ALARM_RELATION, RelationTypeGroup.ALARM));
+ createRelation(new EntityRelation(alarm.getOriginator(), saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name(), RelationTypeGroup.ALARM));
+ return saved;
+ }
+
+ protected ListenableFuture updateAlarm(Alarm update) {
alarmDataValidator.validate(update);
- return getAndUpdate(update.getId(), new Function() {
+ return getAndUpdate(update.getId(), new Function() {
@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(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();
+ Alarm result = alarmDao.save(merge(oldAlarm, newAlarm));
+ if (oldStatus != newStatus) {
+ updateRelations(oldAlarm, oldStatus, newStatus);
+ }
+ return result;
+ }
+
@Override
public ListenableFuture ackAlarm(AlarmId alarmId, long ackTime) {
return getAndUpdate(alarmId, new Function() {
@@ -161,7 +190,7 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
}
@Override
- public ListenableFuture findAlarmById(AlarmId alarmId) {
+ public ListenableFuture findAlarmByIdAsync(AlarmId alarmId) {
log.trace("Executing findAlarmById [{}]", alarmId);
validateId(alarmId, "Incorrect alarmId " + alarmId);
return alarmDao.findByIdAsync(alarmId.getId());
@@ -169,7 +198,14 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
@Override
public ListenableFuture> findAlarms(AlarmQuery query) {
- return null;
+ ListenableFuture> alarms = alarmDao.findAlarms(query);
+ return Futures.transform(alarms, new Function, TimePageData>() {
+ @Nullable
+ @Override
+ public TimePageData apply(@Nullable List alarms) {
+ return new TimePageData<>(alarms, query.getPageLink());
+ }
+ });
}
private void deleteRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException {
@@ -207,19 +243,21 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService
query.setParameters(new RelationsSearchParameters(alarm.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE));
List parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList());
for (EntityId parentId : parentEntities) {
- deleteRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + oldStatus.name()));
- createRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + newStatus.name()));
+ deleteRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + oldStatus.name(), RelationTypeGroup.ALARM));
+ createRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + newStatus.name(), RelationTypeGroup.ALARM));
}
+ deleteRelation(new EntityRelation(alarm.getOriginator(), alarm.getId(), ALARM_RELATION_PREFIX + oldStatus.name(), RelationTypeGroup.ALARM));
+ createRelation(new EntityRelation(alarm.getOriginator(), alarm.getId(), ALARM_RELATION_PREFIX + newStatus.name(), RelationTypeGroup.ALARM));
} catch (ExecutionException | InterruptedException e) {
log.warn("[{}] Failed to update relations. Old status: [{}], New status: [{}]", alarm.getId(), oldStatus, newStatus);
throw new RuntimeException(e);
}
}
- private ListenableFuture getAndUpdate(AlarmId alarmId, Function function) {
+ private ListenableFuture getAndUpdate(AlarmId alarmId, Function function) {
validateId(alarmId, "Alarm id should be specified!");
- ListenableFuture entity = alarmDao.findByIdAsync(alarmId.getId());
- return Futures.transform(entity, function);
+ ListenableFuture entity = alarmDao.findAlarmByIdAsync(alarmId.getId());
+ return Futures.transform(entity, function, readResultsProcessingExecutor);
}
private DataValidator alarmDataValidator =
diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/CassandraAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/CassandraAlarmDao.java
index 378f0ee0ac..926127e89d 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/alarm/CassandraAlarmDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/CassandraAlarmDao.java
@@ -17,16 +17,27 @@ package org.thingsboard.server.dao.alarm;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
+import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.alarm.Alarm;
+import org.thingsboard.server.common.data.alarm.AlarmQuery;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.relation.EntityRelation;
+import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.dao.CassandraAbstractModelDao;
-import org.thingsboard.server.dao.model.nosql.AlarmEntity;
import org.thingsboard.server.dao.model.ModelConstants;
+import org.thingsboard.server.dao.model.nosql.AlarmEntity;
+import org.thingsboard.server.dao.relation.RelationDao;
+import java.util.ArrayList;
+import java.util.List;
import java.util.UUID;
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
@@ -35,8 +46,12 @@ import static org.thingsboard.server.dao.model.ModelConstants.*;
@Component
@Slf4j
+@ConditionalOnProperty(prefix = "cassandra", value = "enabled", havingValue = "true", matchIfMissing = false)
public class CassandraAlarmDao extends CassandraAbstractModelDao implements AlarmDao {
+ @Autowired
+ private RelationDao relationDao;
+
@Override
protected Class getColumnFamilyClass() {
return AlarmEntity.class;
@@ -47,6 +62,10 @@ public class CassandraAlarmDao extends CassandraAbstractModelDao> findAlarms(AlarmQuery query) {
+ log.trace("Try to find alarms by entity [{}], status [{}] and pageLink [{}]", query.getAffectedEntityId(), query.getStatus(), query.getPageLink());
+ EntityId affectedEntity = query.getAffectedEntityId();
+ String relationType = query.getStatus() == null ? BaseAlarmService.ALARM_RELATION : BaseAlarmService.ALARM_RELATION_PREFIX + query.getStatus().name();
+ ListenableFuture> relations = relationDao.findRelations(affectedEntity, relationType, RelationTypeGroup.ALARM, EntityType.ALARM, query.getPageLink());
+ return Futures.transform(relations, (AsyncFunction, List>) input -> {
+ List> alarmFutures = new ArrayList<>(input.size());
+ for (EntityRelation relation : input) {
+ alarmFutures.add(findAlarmByIdAsync(relation.getTo().getId()));
+ }
+ return Futures.successfulAsList(alarmFutures);
+ });
+ }
+
+ @Override
+ public ListenableFuture findAlarmByIdAsync(UUID key) {
+ return findByIdAsync(key);
+ }
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java
index b002a986c1..2b720ae04a 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java
@@ -17,8 +17,10 @@ package org.thingsboard.server.dao.asset;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.asset.TenantAssetType;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.Dao;
+import org.thingsboard.server.dao.model.TenantAssetTypeEntity;
import java.util.List;
import java.util.Optional;
@@ -47,6 +49,16 @@ public interface AssetDao extends Dao {
*/
List findAssetsByTenantId(UUID tenantId, TextPageLink pageLink);
+ /**
+ * Find assets by tenantId, type and page link.
+ *
+ * @param tenantId the tenantId
+ * @param type the type
+ * @param pageLink the page link
+ * @return the list of asset objects
+ */
+ List findAssetsByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink);
+
/**
* Find assets by tenantId and assets Ids.
*
@@ -66,6 +78,17 @@ public interface AssetDao extends Dao {
*/
List findAssetsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink);
+ /**
+ * Find assets by tenantId, customerId, type and page link.
+ *
+ * @param tenantId the tenantId
+ * @param customerId the customerId
+ * @param type the type
+ * @param pageLink the page link
+ * @return the list of asset objects
+ */
+ List findAssetsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink);
+
/**
* Find assets by tenantId, customerId and assets Ids.
*
@@ -84,4 +107,12 @@ public interface AssetDao extends Dao {
* @return the optional asset object
*/
Optional findAssetsByTenantIdAndName(UUID tenantId, String name);
+
+ /**
+ * Find tenants asset types.
+ *
+ * @return the list of tenant asset type objects
+ */
+ ListenableFuture> findTenantAssetTypesAsync();
+
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetService.java
index 7a61bd8019..25baeda0d5 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetService.java
@@ -17,6 +17,7 @@ package org.thingsboard.server.dao.asset;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.asset.TenantAssetType;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
@@ -34,7 +35,7 @@ public interface AssetService {
Optional findAssetByTenantIdAndName(TenantId tenantId, String name);
- Asset saveAsset(Asset device);
+ Asset saveAsset(Asset asset);
Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId);
@@ -44,16 +45,21 @@ public interface AssetService {
TextPageData findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink);
+ TextPageData findAssetsByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink);
+
ListenableFuture> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List assetIds);
void deleteAssetsByTenantId(TenantId tenantId);
TextPageData findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink);
+ TextPageData findAssetsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink);
+
ListenableFuture> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List assetIds);
void unassignCustomerAssets(TenantId tenantId, CustomerId customerId);
ListenableFuture> findAssetsByQuery(AssetSearchQuery query);
+ ListenableFuture> findAssetTypesByTenantId(TenantId tenantId);
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
index c664e623a4..a3cd65e191 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
@@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.asset.TenantAssetType;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
@@ -36,8 +37,9 @@ import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.dao.customer.CustomerDao;
-import org.thingsboard.server.dao.entity.BaseEntityService;
+import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
+import org.thingsboard.server.dao.model.*;
import org.thingsboard.server.dao.relation.EntitySearchDirection;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -45,6 +47,7 @@ import org.thingsboard.server.dao.tenant.TenantDao;
import javax.annotation.Nullable;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -55,7 +58,7 @@ import static org.thingsboard.server.dao.service.Validator.*;
@Service
@Slf4j
-public class BaseAssetService extends BaseEntityService implements AssetService {
+public class BaseAssetService extends AbstractEntityService implements AssetService {
@Autowired
private AssetDao assetDao;
@@ -125,6 +128,16 @@ public class BaseAssetService extends BaseEntityService implements AssetService
return new TextPageData<>(assets, pageLink);
}
+ @Override
+ public TextPageData findAssetsByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink) {
+ log.trace("Executing findAssetsByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
+ validateId(tenantId, "Incorrect tenantId " + tenantId);
+ validateString(type, "Incorrect type " + type);
+ validatePageLink(pageLink, "Incorrect page link " + pageLink);
+ List assets = assetDao.findAssetsByTenantIdAndType(tenantId.getId(), type, pageLink);
+ return new TextPageData<>(assets, pageLink);
+ }
+
@Override
public ListenableFuture> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List assetIds) {
log.trace("Executing findAssetsByTenantIdAndIdsAsync, tenantId [{}], assetIds [{}]", tenantId, assetIds);
@@ -150,6 +163,17 @@ public class BaseAssetService extends BaseEntityService implements AssetService
return new TextPageData(assets, pageLink);
}
+ @Override
+ public TextPageData findAssetsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink) {
+ log.trace("Executing findAssetsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink);
+ validateId(tenantId, "Incorrect tenantId " + tenantId);
+ validateId(customerId, "Incorrect customerId " + customerId);
+ validateString(type, "Incorrect type " + type);
+ validatePageLink(pageLink, "Incorrect page link " + pageLink);
+ List assets = assetDao.findAssetsByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
+ return new TextPageData<>(assets, pageLink);
+ }
+
@Override
public ListenableFuture> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List assetIds) {
log.trace("Executing findAssetsByTenantIdAndCustomerIdAndIdsAsync, tenantId [{}], customerId [{}], assetIds [{}]", tenantId, customerId, assetIds);
@@ -193,6 +217,25 @@ public class BaseAssetService extends BaseEntityService implements AssetService
return assets;
}
+ @Override
+ public ListenableFuture> findAssetTypesByTenantId(TenantId tenantId) {
+ log.trace("Executing findAssetTypesByTenantId, tenantId [{}]", tenantId);
+ validateId(tenantId, "Incorrect tenantId " + tenantId);
+ ListenableFuture> tenantAssetTypeEntities = assetDao.findTenantAssetTypesAsync();
+ ListenableFuture> tenantAssetTypes = Futures.transform(tenantAssetTypeEntities,
+ (Function, List>) assetTypeEntities -> {
+ List assetTypes = new ArrayList<>();
+ for (TenantAssetType assetType : assetTypeEntities) {
+ if (assetType.getTenantId().equals(tenantId.getId())) {
+ assetTypes.add(assetType);
+ }
+ }
+ assetTypes.sort(Comparator.comparing(TenantAssetType::getType));
+ return assetTypes;
+ });
+ return tenantAssetTypes;
+ }
+
private DataValidator assetValidator =
new DataValidator() {
@@ -218,6 +261,9 @@ public class BaseAssetService extends BaseEntityService implements AssetService
@Override
protected void validateDataImpl(Asset asset) {
+ if (StringUtils.isEmpty(asset.getType())) {
+ throw new DataValidationException("Asset type should be specified!");
+ }
if (StringUtils.isEmpty(asset.getName())) {
throw new DataValidationException("Asset name should be specified!");
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java
index 6dca69f291..d53a2e4b6b 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java
@@ -15,16 +15,25 @@
*/
package org.thingsboard.server.dao.asset;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.querybuilder.Select;
+import com.datastax.driver.mapping.Result;
+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.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.asset.TenantAssetType;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.CassandraAbstractSearchTextDao;
import org.thingsboard.server.dao.DaoUtil;
+import org.thingsboard.server.dao.model.TenantAssetTypeEntity;
import org.thingsboard.server.dao.model.nosql.AssetEntity;
+import javax.annotation.Nullable;
import java.util.*;
import static com.datastax.driver.core.querybuilder.QueryBuilder.*;
@@ -32,6 +41,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.*;
@Component
@Slf4j
+@ConditionalOnProperty(prefix = "cassandra", value = "enabled", havingValue = "true", matchIfMissing = false)
public class CassandraAssetDao extends CassandraAbstractSearchTextDao implements AssetDao {
@Override
@@ -61,6 +71,15 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao findAssetsByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
+ log.debug("Try to find assets by tenantId [{}], type [{}] and pageLink [{}]", tenantId, type, pageLink);
+ List assetEntities = findPageWithTextSearch(ASSET_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
+ Arrays.asList(eq(ASSET_TYPE_PROPERTY, type),
+ eq(ASSET_TENANT_ID_PROPERTY, tenantId)), pageLink);
+ log.trace("Found assets [{}] by tenantId [{}], type [{}] and pageLink [{}]", assetEntities, tenantId, type, pageLink);
+ return DaoUtil.convertDataList(assetEntities);
+ }
+
public ListenableFuture> findAssetsByTenantIdAndIdsAsync(UUID tenantId, List assetIds) {
log.debug("Try to find assets by tenantId [{}] and asset Ids [{}]", tenantId, assetIds);
Select select = select().from(getColumnFamilyName());
@@ -82,6 +101,19 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao findAssetsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
+ log.debug("Try to find assets by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink);
+ List assetEntities = findPageWithTextSearch(ASSET_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
+ Arrays.asList(eq(ASSET_TYPE_PROPERTY, type),
+ eq(ASSET_CUSTOMER_ID_PROPERTY, customerId),
+ eq(ASSET_TENANT_ID_PROPERTY, tenantId)),
+ pageLink);
+
+ log.trace("Found assets [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", assetEntities, tenantId, customerId, type, pageLink);
+ return DaoUtil.convertDataList(assetEntities);
+ }
+
@Override
public ListenableFuture> findAssetsByTenantIdAndCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List assetIds) {
log.debug("Try to find assets by tenantId [{}], customerId [{}] and asset Ids [{}]", tenantId, customerId, assetIds);
@@ -103,4 +135,37 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao> findTenantAssetTypesAsync() {
+ Select statement = select().distinct().column(ASSET_TYPE_PROPERTY).column(ASSET_TENANT_ID_PROPERTY).from(ASSET_TYPES_BY_TENANT_VIEW_NAME);
+ statement.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
+ ResultSetFuture resultSetFuture = getSession().executeAsync(statement);
+ ListenableFuture> result = Futures.transform(resultSetFuture, new Function>() {
+ @Nullable
+ @Override
+ public List apply(@Nullable ResultSet resultSet) {
+ Result result = cluster.getMapper(TenantAssetTypeEntity.class).map(resultSet);
+ if (result != null) {
+ return result.all();
+ } else {
+ return Collections.emptyList();
+ }
+ }
+ });
+ return Futures.transform(result, new Function, List>() {
+ @Nullable
+ @Override
+ public List apply(@Nullable List entityList) {
+ List list = Collections.emptyList();
+ if (entityList != null && !entityList.isEmpty()) {
+ list = new ArrayList<>();
+ for (TenantAssetTypeEntity object : entityList) {
+ list.add(object.toTenantAssetType());
+ }
+ }
+ return list;
+ }
+ });
+ }
+
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/CassandraBaseAttributesDao.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/CassandraBaseAttributesDao.java
index f19dee4d61..db5babecf6 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/attributes/CassandraBaseAttributesDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/CassandraBaseAttributesDao.java
@@ -22,6 +22,7 @@ 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.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
@@ -47,6 +48,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.*;
*/
@Component
@Slf4j
+@ConditionalOnProperty(prefix = "cassandra", value = "enabled", havingValue = "true", matchIfMissing = false)
public class CassandraBaseAttributesDao extends CassandraAbstractAsyncDao implements AttributesDao {
private PreparedStatement saveStmt;
diff --git a/dao/src/main/java/org/thingsboard/server/dao/cache/ServiceCacheConfiguration.java b/dao/src/main/java/org/thingsboard/server/dao/cache/ServiceCacheConfiguration.java
index b4fbc65507..7c435bf779 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/cache/ServiceCacheConfiguration.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/cache/ServiceCacheConfiguration.java
@@ -45,7 +45,6 @@ public class ServiceCacheConfiguration {
@Value("${cache.device_credentials.time_to_live}")
private Integer cacheDeviceCredentialsTTL;
-
@Value("${zk.enabled}")
private boolean zkEnabled;
@Value("${zk.url}")
diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CassandraCustomerDao.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CassandraCustomerDao.java
index 92ca9c4e17..7a1c67db83 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/customer/CassandraCustomerDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CassandraCustomerDao.java
@@ -23,6 +23,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_TENANT_ID
import java.util.Optional;
import com.datastax.driver.core.querybuilder.Select;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.page.TextPageLink;
@@ -38,6 +39,7 @@ import java.util.UUID;
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
@Component
@Slf4j
+@ConditionalOnProperty(prefix = "cassandra", value = "enabled", havingValue = "true", matchIfMissing = false)
public class CassandraCustomerDao extends CassandraAbstractSearchTextDao implements CustomerDao {
@Override
diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
index 7fa4211e03..65eb89f9fc 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
@@ -16,9 +16,11 @@
package org.thingsboard.server.dao.customer;
import static org.thingsboard.server.dao.service.Validator.validateId;
+
import java.io.IOException;
import java.util.List;
import java.util.Optional;
+
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.ListenableFuture;
@@ -34,7 +36,7 @@ import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService;
-import org.thingsboard.server.dao.entity.BaseEntityService;
+import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.service.DataValidator;
@@ -42,27 +44,28 @@ import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.service.Validator;
import org.thingsboard.server.dao.tenant.TenantDao;
import org.thingsboard.server.dao.user.UserService;
+
@Service
@Slf4j
-public class CustomerServiceImpl extends BaseEntityService implements CustomerService {
+public class CustomerServiceImpl extends AbstractEntityService implements CustomerService {
private static final String PUBLIC_CUSTOMER_TITLE = "Public";
@Autowired
private CustomerDao customerDao;
-
+
@Autowired
private UserService userService;
-
+
@Autowired
private TenantDao tenantDao;
-
+
@Autowired
private DeviceService deviceService;
-
+
@Autowired
private DashboardService dashboardService;
-
+
@Override
public Customer findCustomerById(CustomerId customerId) {
log.trace("Executing findCustomerById [{}]", customerId);
@@ -134,7 +137,7 @@ public class CustomerServiceImpl extends BaseEntityService implements CustomerSe
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId);
customersByTenantRemover.removeEntitites(tenantId);
}
-
+
private DataValidator customerValidator =
new DataValidator() {
@@ -178,19 +181,19 @@ public class CustomerServiceImpl extends BaseEntityService implements CustomerSe
}
}
}
- };
+ };
private PaginatedRemover customersByTenantRemover =
new PaginatedRemover() {
-
- @Override
- protected List findEntities(TenantId id, TextPageLink pageLink) {
- return customerDao.findCustomersByTenantId(id.getId(), pageLink);
- }
- @Override
- protected void removeEntity(Customer entity) {
- deleteCustomer(new CustomerId(entity.getUuidId()));
- }
- };
+ @Override
+ protected List findEntities(TenantId id, TextPageLink pageLink) {
+ return customerDao.findCustomersByTenantId(id.getId(), pageLink);
+ }
+
+ @Override
+ protected void removeEntity(Customer entity) {
+ deleteCustomer(new CustomerId(entity.getUuidId()));
+ }
+ };
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/CassandraDashboardDao.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/CassandraDashboardDao.java
index 82d5a26576..c0ea1dc0f4 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/CassandraDashboardDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/CassandraDashboardDao.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.dashboard;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.dao.CassandraAbstractSearchTextDao;
@@ -23,6 +24,7 @@ import org.thingsboard.server.dao.model.nosql.DashboardEntity;
import static org.thingsboard.server.dao.model.ModelConstants.DASHBOARD_COLUMN_FAMILY_NAME;
@Component
+@ConditionalOnProperty(prefix = "cassandra", value = "enabled", havingValue = "true", matchIfMissing = false)
public class CassandraDashboardDao extends CassandraAbstractSearchTextDao implements DashboardDao {
@Override
diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/CassandraDashboardInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/CassandraDashboardInfoDao.java
index b0c3e891d3..366ec1f82a 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/CassandraDashboardInfoDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/CassandraDashboardInfoDao.java
@@ -16,6 +16,7 @@
package org.thingsboard.server.dao.dashboard;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.page.TextPageLink;
@@ -33,6 +34,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.*;
@Component
@Slf4j
+@ConditionalOnProperty(prefix = "cassandra", value = "enabled", havingValue = "true", matchIfMissing = false)
public class CassandraDashboardInfoDao extends CassandraAbstractSearchTextDao implements DashboardInfoDao {
@Override
diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java
index b49b5b44fe..74d85445f8 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.dashboard;
+import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.id.CustomerId;
@@ -27,6 +28,12 @@ public interface DashboardService {
Dashboard findDashboardById(DashboardId dashboardId);
+ ListenableFuture findDashboardByIdAsync(DashboardId dashboardId);
+
+ DashboardInfo findDashboardInfoById(DashboardId dashboardId);
+
+ ListenableFuture findDashboardInfoByIdAsync(DashboardId dashboardId);
+
Dashboard saveDashboard(Dashboard dashboard);
Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId);
diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
index bdca53648b..523f774909 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.dashboard;
+import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -29,7 +30,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.customer.CustomerDao;
-import org.thingsboard.server.dao.entity.BaseEntityService;
+import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.service.DataValidator;
@@ -39,9 +40,11 @@ import org.thingsboard.server.dao.tenant.TenantDao;
import java.util.List;
+import static org.thingsboard.server.dao.service.Validator.validateId;
+
@Service
@Slf4j
-public class DashboardServiceImpl extends BaseEntityService implements DashboardService {
+public class DashboardServiceImpl extends AbstractEntityService implements DashboardService {
@Autowired
private DashboardDao dashboardDao;
@@ -62,6 +65,27 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard
return dashboardDao.findById(dashboardId.getId());
}
+ @Override
+ public ListenableFuture findDashboardByIdAsync(DashboardId dashboardId) {
+ log.trace("Executing findDashboardByIdAsync [{}]", dashboardId);
+ validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
+ return dashboardDao.findByIdAsync(dashboardId.getId());
+ }
+
+ @Override
+ public DashboardInfo findDashboardInfoById(DashboardId dashboardId) {
+ log.trace("Executing findDashboardInfoById [{}]", dashboardId);
+ Validator.validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
+ return dashboardInfoDao.findById(dashboardId.getId());
+ }
+
+ @Override
+ public ListenableFuture findDashboardInfoByIdAsync(DashboardId dashboardId) {
+ log.trace("Executing findDashboardInfoByIdAsync [{}]", dashboardId);
+ validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
+ return dashboardInfoDao.findByIdAsync(dashboardId.getId());
+ }
+
@Override
public Dashboard saveDashboard(Dashboard dashboard) {
log.trace("Executing saveDashboard [{}]", dashboard);
diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceCredentialsDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceCredentialsDao.java
index 14ac5bfd45..517b8cb019 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceCredentialsDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceCredentialsDao.java
@@ -17,6 +17,7 @@ package org.thingsboard.server.dao.device;
import com.datastax.driver.core.querybuilder.Select.Where;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.CassandraAbstractModelDao;
@@ -31,6 +32,7 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
@Component
@Slf4j
+@ConditionalOnProperty(prefix = "cassandra", value = "enabled", havingValue = "true", matchIfMissing = false)
public class CassandraDeviceCredentialsDao extends CassandraAbstractModelDao implements DeviceCredentialsDao {
@Override
diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java
index b326fcb25e..23b3fc9a99 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java
@@ -15,16 +15,25 @@
*/
package org.thingsboard.server.dao.device;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.querybuilder.Select;
+import com.datastax.driver.mapping.Result;
+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.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.TenantDeviceType;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.CassandraAbstractSearchTextDao;
import org.thingsboard.server.dao.DaoUtil;
+import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
import org.thingsboard.server.dao.model.nosql.DeviceEntity;
+import javax.annotation.Nullable;
import java.util.*;
import static com.datastax.driver.core.querybuilder.QueryBuilder.*;
@@ -32,6 +41,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.*;
@Component
@Slf4j
+@ConditionalOnProperty(prefix = "cassandra", value = "enabled", havingValue = "true", matchIfMissing = false)
public class CassandraDeviceDao extends CassandraAbstractSearchTextDao implements DeviceDao {
@Override
@@ -54,6 +64,16 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao