Commit 9f38981b9d9f5dc3c66518746c9705dcb897c7bb

Authored by Volodymyr Babak
2 parents e5d664b4 4054d3de

Merge remote-tracking branch 'upstream/master' into feature/mqtt-plugin

Showing 62 changed files with 3199 additions and 204 deletions

Too many changes to show.

To preserve performance only 62 of 202 files are displayed.

  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.controller;
  17 +
  18 +import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.apache.commons.lang3.StringUtils;
  20 +import org.springframework.http.HttpStatus;
  21 +import org.springframework.security.access.prepost.PreAuthorize;
  22 +import org.springframework.web.bind.annotation.*;
  23 +import org.thingsboard.server.common.data.Customer;
  24 +import org.thingsboard.server.common.data.Event;
  25 +import org.thingsboard.server.common.data.alarm.Alarm;
  26 +import org.thingsboard.server.common.data.alarm.AlarmId;
  27 +import org.thingsboard.server.common.data.alarm.AlarmQuery;
  28 +import org.thingsboard.server.common.data.alarm.AlarmStatus;
  29 +import org.thingsboard.server.common.data.asset.Asset;
  30 +import org.thingsboard.server.common.data.id.*;
  31 +import org.thingsboard.server.common.data.page.TextPageData;
  32 +import org.thingsboard.server.common.data.page.TextPageLink;
  33 +import org.thingsboard.server.common.data.page.TimePageData;
  34 +import org.thingsboard.server.common.data.page.TimePageLink;
  35 +import org.thingsboard.server.dao.asset.AssetSearchQuery;
  36 +import org.thingsboard.server.dao.exception.IncorrectParameterException;
  37 +import org.thingsboard.server.dao.model.ModelConstants;
  38 +import org.thingsboard.server.exception.ThingsboardErrorCode;
  39 +import org.thingsboard.server.exception.ThingsboardException;
  40 +import org.thingsboard.server.service.security.model.SecurityUser;
  41 +
  42 +import java.util.ArrayList;
  43 +import java.util.List;
  44 +import java.util.stream.Collectors;
  45 +
  46 +@RestController
  47 +@RequestMapping("/api")
  48 +public class AlarmController extends BaseController {
  49 +
  50 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  51 + @RequestMapping(value = "/alarm/{alarmId}", method = RequestMethod.GET)
  52 + @ResponseBody
  53 + public Alarm getAlarmById(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException {
  54 + checkParameter("alarmId", strAlarmId);
  55 + try {
  56 + AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
  57 + return checkAlarmId(alarmId);
  58 + } catch (Exception e) {
  59 + throw handleException(e);
  60 + }
  61 + }
  62 +
  63 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  64 + @RequestMapping(value = "/alarm", method = RequestMethod.POST)
  65 + @ResponseBody
  66 + public Alarm saveAlarm(@RequestBody Alarm alarm) throws ThingsboardException {
  67 + try {
  68 + alarm.setTenantId(getCurrentUser().getTenantId());
  69 + return checkNotNull(alarmService.createOrUpdateAlarm(alarm));
  70 + } catch (Exception e) {
  71 + throw handleException(e);
  72 + }
  73 + }
  74 +
  75 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  76 + @RequestMapping(value = "/alarm/{alarmId}/ack", method = RequestMethod.POST)
  77 + @ResponseStatus(value = HttpStatus.OK)
  78 + public void ackAlarm(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException {
  79 + checkParameter("alarmId", strAlarmId);
  80 + try {
  81 + AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
  82 + checkAlarmId(alarmId);
  83 + alarmService.ackAlarm(alarmId, System.currentTimeMillis()).get();
  84 + } catch (Exception e) {
  85 + throw handleException(e);
  86 + }
  87 + }
  88 +
  89 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  90 + @RequestMapping(value = "/alarm/{alarmId}/clear", method = RequestMethod.POST)
  91 + @ResponseStatus(value = HttpStatus.OK)
  92 + public void clearAlarm(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException {
  93 + checkParameter("alarmId", strAlarmId);
  94 + try {
  95 + AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
  96 + checkAlarmId(alarmId);
  97 + alarmService.clearAlarm(alarmId, System.currentTimeMillis()).get();
  98 + } catch (Exception e) {
  99 + throw handleException(e);
  100 + }
  101 + }
  102 +
  103 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  104 + @RequestMapping(value = "/alarm/{entityType}/{entityId}", method = RequestMethod.GET)
  105 + @ResponseBody
  106 + public TimePageData<Alarm> getAlarms(
  107 + @PathVariable("entityType") String strEntityType,
  108 + @PathVariable("entityId") String strEntityId,
  109 + @RequestParam(required = false) String status,
  110 + @RequestParam int limit,
  111 + @RequestParam(required = false) Long startTime,
  112 + @RequestParam(required = false) Long endTime,
  113 + @RequestParam(required = false, defaultValue = "false") boolean ascOrder,
  114 + @RequestParam(required = false) String offset
  115 + ) throws ThingsboardException {
  116 + checkParameter("EntityId", strEntityId);
  117 + checkParameter("EntityType", strEntityType);
  118 + EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId);
  119 + AlarmStatus alarmStatus = StringUtils.isEmpty(status) ? null : AlarmStatus.valueOf(status);
  120 + checkEntityId(entityId);
  121 + try {
  122 + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
  123 + return checkNotNull(alarmService.findAlarms(new AlarmQuery(entityId, pageLink, alarmStatus)).get());
  124 + } catch (Exception e) {
  125 + throw handleException(e);
  126 + }
  127 + }
  128 +
  129 +}
@@ -21,6 +21,7 @@ import org.springframework.security.access.prepost.PreAuthorize; @@ -21,6 +21,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
21 import org.springframework.web.bind.annotation.*; 21 import org.springframework.web.bind.annotation.*;
22 import org.thingsboard.server.common.data.Customer; 22 import org.thingsboard.server.common.data.Customer;
23 import org.thingsboard.server.common.data.asset.Asset; 23 import org.thingsboard.server.common.data.asset.Asset;
  24 +import org.thingsboard.server.common.data.asset.TenantAssetType;
24 import org.thingsboard.server.common.data.id.AssetId; 25 import org.thingsboard.server.common.data.id.AssetId;
25 import org.thingsboard.server.common.data.id.CustomerId; 26 import org.thingsboard.server.common.data.id.CustomerId;
26 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
@@ -136,13 +137,18 @@ public class AssetController extends BaseController { @@ -136,13 +137,18 @@ public class AssetController extends BaseController {
136 @ResponseBody 137 @ResponseBody
137 public TextPageData<Asset> getTenantAssets( 138 public TextPageData<Asset> getTenantAssets(
138 @RequestParam int limit, 139 @RequestParam int limit,
  140 + @RequestParam(required = false) String type,
139 @RequestParam(required = false) String textSearch, 141 @RequestParam(required = false) String textSearch,
140 @RequestParam(required = false) String idOffset, 142 @RequestParam(required = false) String idOffset,
141 @RequestParam(required = false) String textOffset) throws ThingsboardException { 143 @RequestParam(required = false) String textOffset) throws ThingsboardException {
142 try { 144 try {
143 TenantId tenantId = getCurrentUser().getTenantId(); 145 TenantId tenantId = getCurrentUser().getTenantId();
144 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 146 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
145 - return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink)); 147 + if (type != null && type.trim().length()>0) {
  148 + return checkNotNull(assetService.findAssetsByTenantIdAndType(tenantId, type, pageLink));
  149 + } else {
  150 + return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink));
  151 + }
146 } catch (Exception e) { 152 } catch (Exception e) {
147 throw handleException(e); 153 throw handleException(e);
148 } 154 }
@@ -167,6 +173,7 @@ public class AssetController extends BaseController { @@ -167,6 +173,7 @@ public class AssetController extends BaseController {
167 public TextPageData<Asset> getCustomerAssets( 173 public TextPageData<Asset> getCustomerAssets(
168 @PathVariable("customerId") String strCustomerId, 174 @PathVariable("customerId") String strCustomerId,
169 @RequestParam int limit, 175 @RequestParam int limit,
  176 + @RequestParam(required = false) String type,
170 @RequestParam(required = false) String textSearch, 177 @RequestParam(required = false) String textSearch,
171 @RequestParam(required = false) String idOffset, 178 @RequestParam(required = false) String idOffset,
172 @RequestParam(required = false) String textOffset) throws ThingsboardException { 179 @RequestParam(required = false) String textOffset) throws ThingsboardException {
@@ -176,7 +183,11 @@ public class AssetController extends BaseController { @@ -176,7 +183,11 @@ public class AssetController extends BaseController {
176 CustomerId customerId = new CustomerId(toUUID(strCustomerId)); 183 CustomerId customerId = new CustomerId(toUUID(strCustomerId));
177 checkCustomerId(customerId); 184 checkCustomerId(customerId);
178 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 185 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
179 - return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); 186 + if (type != null && type.trim().length()>0) {
  187 + return checkNotNull(assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
  188 + } else {
  189 + return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
  190 + }
180 } catch (Exception e) { 191 } catch (Exception e) {
181 throw handleException(e); 192 throw handleException(e);
182 } 193 }
@@ -231,4 +242,18 @@ public class AssetController extends BaseController { @@ -231,4 +242,18 @@ public class AssetController extends BaseController {
231 throw handleException(e); 242 throw handleException(e);
232 } 243 }
233 } 244 }
  245 +
  246 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  247 + @RequestMapping(value = "/asset/types", method = RequestMethod.GET)
  248 + @ResponseBody
  249 + public List<TenantAssetType> getAssetTypes() throws ThingsboardException {
  250 + try {
  251 + SecurityUser user = getCurrentUser();
  252 + TenantId tenantId = user.getTenantId();
  253 + ListenableFuture<List<TenantAssetType>> assetTypes = assetService.findAssetTypesByTenantId(tenantId);
  254 + return checkNotNull(assetTypes.get());
  255 + } catch (Exception e) {
  256 + throw handleException(e);
  257 + }
  258 + }
234 } 259 }
@@ -25,6 +25,8 @@ import org.springframework.security.core.context.SecurityContextHolder; @@ -25,6 +25,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
25 import org.springframework.web.bind.annotation.ExceptionHandler; 25 import org.springframework.web.bind.annotation.ExceptionHandler;
26 import org.thingsboard.server.actors.service.ActorService; 26 import org.thingsboard.server.actors.service.ActorService;
27 import org.thingsboard.server.common.data.*; 27 import org.thingsboard.server.common.data.*;
  28 +import org.thingsboard.server.common.data.alarm.Alarm;
  29 +import org.thingsboard.server.common.data.alarm.AlarmId;
28 import org.thingsboard.server.common.data.asset.Asset; 30 import org.thingsboard.server.common.data.asset.Asset;
29 import org.thingsboard.server.common.data.id.*; 31 import org.thingsboard.server.common.data.id.*;
30 import org.thingsboard.server.common.data.page.TextPageLink; 32 import org.thingsboard.server.common.data.page.TextPageLink;
@@ -36,6 +38,7 @@ import org.thingsboard.server.common.data.rule.RuleMetaData; @@ -36,6 +38,7 @@ import org.thingsboard.server.common.data.rule.RuleMetaData;
36 import org.thingsboard.server.common.data.security.Authority; 38 import org.thingsboard.server.common.data.security.Authority;
37 import org.thingsboard.server.common.data.widget.WidgetType; 39 import org.thingsboard.server.common.data.widget.WidgetType;
38 import org.thingsboard.server.common.data.widget.WidgetsBundle; 40 import org.thingsboard.server.common.data.widget.WidgetsBundle;
  41 +import org.thingsboard.server.dao.alarm.AlarmService;
39 import org.thingsboard.server.dao.asset.AssetService; 42 import org.thingsboard.server.dao.asset.AssetService;
40 import org.thingsboard.server.dao.customer.CustomerService; 43 import org.thingsboard.server.dao.customer.CustomerService;
41 import org.thingsboard.server.dao.dashboard.DashboardService; 44 import org.thingsboard.server.dao.dashboard.DashboardService;
@@ -84,6 +87,9 @@ public abstract class BaseController { @@ -84,6 +87,9 @@ public abstract class BaseController {
84 protected AssetService assetService; 87 protected AssetService assetService;
85 88
86 @Autowired 89 @Autowired
  90 + protected AlarmService alarmService;
  91 +
  92 + @Autowired
87 protected DeviceCredentialsService deviceCredentialsService; 93 protected DeviceCredentialsService deviceCredentialsService;
88 94
89 @Autowired 95 @Autowired
@@ -334,6 +340,22 @@ public abstract class BaseController { @@ -334,6 +340,22 @@ public abstract class BaseController {
334 } 340 }
335 } 341 }
336 342
  343 + Alarm checkAlarmId(AlarmId alarmId) throws ThingsboardException {
  344 + try {
  345 + validateId(alarmId, "Incorrect alarmId " + alarmId);
  346 + Alarm alarm = alarmService.findAlarmByIdAsync(alarmId).get();
  347 + checkAlarm(alarm);
  348 + return alarm;
  349 + } catch (Exception e) {
  350 + throw handleException(e, false);
  351 + }
  352 + }
  353 +
  354 + protected void checkAlarm(Alarm alarm) throws ThingsboardException {
  355 + checkNotNull(alarm);
  356 + checkTenantId(alarm.getTenantId());
  357 + }
  358 +
337 WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, boolean modify) throws ThingsboardException { 359 WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, boolean modify) throws ThingsboardException {
338 try { 360 try {
339 validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId); 361 validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId);
@@ -21,6 +21,7 @@ import org.springframework.security.access.prepost.PreAuthorize; @@ -21,6 +21,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
21 import org.springframework.web.bind.annotation.*; 21 import org.springframework.web.bind.annotation.*;
22 import org.thingsboard.server.common.data.Customer; 22 import org.thingsboard.server.common.data.Customer;
23 import org.thingsboard.server.common.data.Device; 23 import org.thingsboard.server.common.data.Device;
  24 +import org.thingsboard.server.common.data.TenantDeviceType;
24 import org.thingsboard.server.common.data.id.CustomerId; 25 import org.thingsboard.server.common.data.id.CustomerId;
25 import org.thingsboard.server.common.data.id.DeviceId; 26 import org.thingsboard.server.common.data.id.DeviceId;
26 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
@@ -166,13 +167,18 @@ public class DeviceController extends BaseController { @@ -166,13 +167,18 @@ public class DeviceController extends BaseController {
166 @ResponseBody 167 @ResponseBody
167 public TextPageData<Device> getTenantDevices( 168 public TextPageData<Device> getTenantDevices(
168 @RequestParam int limit, 169 @RequestParam int limit,
  170 + @RequestParam(required = false) String type,
169 @RequestParam(required = false) String textSearch, 171 @RequestParam(required = false) String textSearch,
170 @RequestParam(required = false) String idOffset, 172 @RequestParam(required = false) String idOffset,
171 @RequestParam(required = false) String textOffset) throws ThingsboardException { 173 @RequestParam(required = false) String textOffset) throws ThingsboardException {
172 try { 174 try {
173 TenantId tenantId = getCurrentUser().getTenantId(); 175 TenantId tenantId = getCurrentUser().getTenantId();
174 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 176 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
175 - return checkNotNull(deviceService.findDevicesByTenantId(tenantId, pageLink)); 177 + if (type != null && type.trim().length()>0) {
  178 + return checkNotNull(deviceService.findDevicesByTenantIdAndType(tenantId, type, pageLink));
  179 + } else {
  180 + return checkNotNull(deviceService.findDevicesByTenantId(tenantId, pageLink));
  181 + }
176 } catch (Exception e) { 182 } catch (Exception e) {
177 throw handleException(e); 183 throw handleException(e);
178 } 184 }
@@ -197,6 +203,7 @@ public class DeviceController extends BaseController { @@ -197,6 +203,7 @@ public class DeviceController extends BaseController {
197 public TextPageData<Device> getCustomerDevices( 203 public TextPageData<Device> getCustomerDevices(
198 @PathVariable("customerId") String strCustomerId, 204 @PathVariable("customerId") String strCustomerId,
199 @RequestParam int limit, 205 @RequestParam int limit,
  206 + @RequestParam(required = false) String type,
200 @RequestParam(required = false) String textSearch, 207 @RequestParam(required = false) String textSearch,
201 @RequestParam(required = false) String idOffset, 208 @RequestParam(required = false) String idOffset,
202 @RequestParam(required = false) String textOffset) throws ThingsboardException { 209 @RequestParam(required = false) String textOffset) throws ThingsboardException {
@@ -206,7 +213,11 @@ public class DeviceController extends BaseController { @@ -206,7 +213,11 @@ public class DeviceController extends BaseController {
206 CustomerId customerId = new CustomerId(toUUID(strCustomerId)); 213 CustomerId customerId = new CustomerId(toUUID(strCustomerId));
207 checkCustomerId(customerId); 214 checkCustomerId(customerId);
208 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 215 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
209 - return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, pageLink)); 216 + if (type != null && type.trim().length()>0) {
  217 + return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
  218 + } else {
  219 + return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, pageLink));
  220 + }
210 } catch (Exception e) { 221 } catch (Exception e) {
211 throw handleException(e); 222 throw handleException(e);
212 } 223 }
@@ -261,4 +272,19 @@ public class DeviceController extends BaseController { @@ -261,4 +272,19 @@ public class DeviceController extends BaseController {
261 throw handleException(e); 272 throw handleException(e);
262 } 273 }
263 } 274 }
  275 +
  276 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  277 + @RequestMapping(value = "/device/types", method = RequestMethod.GET)
  278 + @ResponseBody
  279 + public List<TenantDeviceType> getDeviceTypes() throws ThingsboardException {
  280 + try {
  281 + SecurityUser user = getCurrentUser();
  282 + TenantId tenantId = user.getTenantId();
  283 + ListenableFuture<List<TenantDeviceType>> deviceTypes = deviceService.findDeviceTypesByTenantId(tenantId);
  284 + return checkNotNull(deviceTypes.get());
  285 + } catch (Exception e) {
  286 + throw handleException(e);
  287 + }
  288 + }
  289 +
264 } 290 }
@@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.*; @@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.*;
21 import org.thingsboard.server.common.data.id.EntityId; 21 import org.thingsboard.server.common.data.id.EntityId;
22 import org.thingsboard.server.common.data.id.EntityIdFactory; 22 import org.thingsboard.server.common.data.id.EntityIdFactory;
23 import org.thingsboard.server.common.data.relation.EntityRelation; 23 import org.thingsboard.server.common.data.relation.EntityRelation;
  24 +import org.thingsboard.server.common.data.relation.EntityRelationInfo;
  25 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
24 import org.thingsboard.server.dao.relation.EntityRelationsQuery; 26 import org.thingsboard.server.dao.relation.EntityRelationsQuery;
25 import org.thingsboard.server.exception.ThingsboardErrorCode; 27 import org.thingsboard.server.exception.ThingsboardErrorCode;
26 import org.thingsboard.server.exception.ThingsboardException; 28 import org.thingsboard.server.exception.ThingsboardException;
@@ -32,7 +34,7 @@ import java.util.List; @@ -32,7 +34,7 @@ import java.util.List;
32 @RequestMapping("/api") 34 @RequestMapping("/api")
33 public class EntityRelationController extends BaseController { 35 public class EntityRelationController extends BaseController {
34 36
35 - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 37 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
36 @RequestMapping(value = "/relation", method = RequestMethod.POST) 38 @RequestMapping(value = "/relation", method = RequestMethod.POST)
37 @ResponseStatus(value = HttpStatus.OK) 39 @ResponseStatus(value = HttpStatus.OK)
38 public void saveRelation(@RequestBody EntityRelation relation) throws ThingsboardException { 40 public void saveRelation(@RequestBody EntityRelation relation) throws ThingsboardException {
@@ -40,17 +42,22 @@ public class EntityRelationController extends BaseController { @@ -40,17 +42,22 @@ public class EntityRelationController extends BaseController {
40 checkNotNull(relation); 42 checkNotNull(relation);
41 checkEntityId(relation.getFrom()); 43 checkEntityId(relation.getFrom());
42 checkEntityId(relation.getTo()); 44 checkEntityId(relation.getTo());
  45 + if (relation.getTypeGroup() == null) {
  46 + relation.setTypeGroup(RelationTypeGroup.COMMON);
  47 + }
43 relationService.saveRelation(relation).get(); 48 relationService.saveRelation(relation).get();
44 } catch (Exception e) { 49 } catch (Exception e) {
45 throw handleException(e); 50 throw handleException(e);
46 } 51 }
47 } 52 }
48 53
49 - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 54 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
50 @RequestMapping(value = "/relation", method = RequestMethod.DELETE, params = {"fromId", "fromType", "relationType", "toId", "toType"}) 55 @RequestMapping(value = "/relation", method = RequestMethod.DELETE, params = {"fromId", "fromType", "relationType", "toId", "toType"})
51 @ResponseStatus(value = HttpStatus.OK) 56 @ResponseStatus(value = HttpStatus.OK)
52 public void deleteRelation(@RequestParam("fromId") String strFromId, 57 public void deleteRelation(@RequestParam("fromId") String strFromId,
53 - @RequestParam("fromType") String strFromType, @RequestParam("relationType") String strRelationType, 58 + @RequestParam("fromType") String strFromType,
  59 + @RequestParam("relationType") String strRelationType,
  60 + @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
54 @RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException { 61 @RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException {
55 checkParameter("fromId", strFromId); 62 checkParameter("fromId", strFromId);
56 checkParameter("fromType", strFromType); 63 checkParameter("fromType", strFromType);
@@ -61,8 +68,9 @@ public class EntityRelationController extends BaseController { @@ -61,8 +68,9 @@ public class EntityRelationController extends BaseController {
61 EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId); 68 EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
62 checkEntityId(fromId); 69 checkEntityId(fromId);
63 checkEntityId(toId); 70 checkEntityId(toId);
  71 + RelationTypeGroup relationTypeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
64 try { 72 try {
65 - Boolean found = relationService.deleteRelation(fromId, toId, strRelationType).get(); 73 + Boolean found = relationService.deleteRelation(fromId, toId, strRelationType, relationTypeGroup).get();
66 if (!found) { 74 if (!found) {
67 throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); 75 throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
68 } 76 }
@@ -71,7 +79,7 @@ public class EntityRelationController extends BaseController { @@ -71,7 +79,7 @@ public class EntityRelationController extends BaseController {
71 } 79 }
72 } 80 }
73 81
74 - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 82 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN', 'CUSTOMER_USER')")
75 @RequestMapping(value = "/relations", method = RequestMethod.DELETE, params = {"id", "type"}) 83 @RequestMapping(value = "/relations", method = RequestMethod.DELETE, params = {"id", "type"})
76 @ResponseStatus(value = HttpStatus.OK) 84 @ResponseStatus(value = HttpStatus.OK)
77 public void deleteRelations(@RequestParam("entityId") String strId, 85 public void deleteRelations(@RequestParam("entityId") String strId,
@@ -87,11 +95,13 @@ public class EntityRelationController extends BaseController { @@ -87,11 +95,13 @@ public class EntityRelationController extends BaseController {
87 } 95 }
88 } 96 }
89 97
90 - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 98 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
91 @RequestMapping(value = "/relation", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType", "toId", "toType"}) 99 @RequestMapping(value = "/relation", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType", "toId", "toType"})
92 @ResponseStatus(value = HttpStatus.OK) 100 @ResponseStatus(value = HttpStatus.OK)
93 public void checkRelation(@RequestParam("fromId") String strFromId, 101 public void checkRelation(@RequestParam("fromId") String strFromId,
94 - @RequestParam("fromType") String strFromType, @RequestParam("relationType") String strRelationType, 102 + @RequestParam("fromType") String strFromType,
  103 + @RequestParam("relationType") String strRelationType,
  104 + @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
95 @RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException { 105 @RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException {
96 try { 106 try {
97 checkParameter("fromId", strFromId); 107 checkParameter("fromId", strFromId);
@@ -103,7 +113,8 @@ public class EntityRelationController extends BaseController { @@ -103,7 +113,8 @@ public class EntityRelationController extends BaseController {
103 EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId); 113 EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
104 checkEntityId(fromId); 114 checkEntityId(fromId);
105 checkEntityId(toId); 115 checkEntityId(toId);
106 - Boolean found = relationService.checkRelation(fromId, toId, strRelationType).get(); 116 + RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
  117 + Boolean found = relationService.checkRelation(fromId, toId, strRelationType, typeGroup).get();
107 if (!found) { 118 if (!found) {
108 throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); 119 throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
109 } 120 }
@@ -112,71 +123,119 @@ public class EntityRelationController extends BaseController { @@ -112,71 +123,119 @@ public class EntityRelationController extends BaseController {
112 } 123 }
113 } 124 }
114 125
115 - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 126 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
116 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType"}) 127 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType"})
117 @ResponseBody 128 @ResponseBody
118 - public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType) throws ThingsboardException { 129 + public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId,
  130 + @RequestParam("fromType") String strFromType,
  131 + @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
  132 + checkParameter("fromId", strFromId);
  133 + checkParameter("fromType", strFromType);
  134 + EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
  135 + checkEntityId(entityId);
  136 + RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
  137 + try {
  138 + return checkNotNull(relationService.findByFrom(entityId, typeGroup).get());
  139 + } catch (Exception e) {
  140 + throw handleException(e);
  141 + }
  142 + }
  143 +
  144 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
  145 + @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {"fromId", "fromType"})
  146 + @ResponseBody
  147 + public List<EntityRelationInfo> findInfoByFrom(@RequestParam("fromId") String strFromId,
  148 + @RequestParam("fromType") String strFromType,
  149 + @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
119 checkParameter("fromId", strFromId); 150 checkParameter("fromId", strFromId);
120 checkParameter("fromType", strFromType); 151 checkParameter("fromType", strFromType);
121 EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); 152 EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
122 checkEntityId(entityId); 153 checkEntityId(entityId);
  154 + RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
123 try { 155 try {
124 - return checkNotNull(relationService.findByFrom(entityId).get()); 156 + return checkNotNull(relationService.findInfoByFrom(entityId, typeGroup).get());
125 } catch (Exception e) { 157 } catch (Exception e) {
126 throw handleException(e); 158 throw handleException(e);
127 } 159 }
128 } 160 }
129 161
130 - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 162 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
131 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType"}) 163 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType"})
132 @ResponseBody 164 @ResponseBody
133 - public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType  
134 - , @RequestParam("relationType") String strRelationType) throws ThingsboardException { 165 + public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId,
  166 + @RequestParam("fromType") String strFromType,
  167 + @RequestParam("relationType") String strRelationType,
  168 + @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
135 checkParameter("fromId", strFromId); 169 checkParameter("fromId", strFromId);
136 checkParameter("fromType", strFromType); 170 checkParameter("fromType", strFromType);
137 checkParameter("relationType", strRelationType); 171 checkParameter("relationType", strRelationType);
138 EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); 172 EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
139 checkEntityId(entityId); 173 checkEntityId(entityId);
  174 + RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
140 try { 175 try {
141 - return checkNotNull(relationService.findByFromAndType(entityId, strRelationType).get()); 176 + return checkNotNull(relationService.findByFromAndType(entityId, strRelationType, typeGroup).get());
142 } catch (Exception e) { 177 } catch (Exception e) {
143 throw handleException(e); 178 throw handleException(e);
144 } 179 }
145 } 180 }
146 181
147 - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 182 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
148 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType"}) 183 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType"})
149 @ResponseBody 184 @ResponseBody
150 - public List<EntityRelation> findByTo(@RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException { 185 + public List<EntityRelation> findByTo(@RequestParam("toId") String strToId,
  186 + @RequestParam("toType") String strToType,
  187 + @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
151 checkParameter("toId", strToId); 188 checkParameter("toId", strToId);
152 checkParameter("toType", strToType); 189 checkParameter("toType", strToType);
153 EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId); 190 EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
154 checkEntityId(entityId); 191 checkEntityId(entityId);
  192 + RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
155 try { 193 try {
156 - return checkNotNull(relationService.findByTo(entityId).get()); 194 + return checkNotNull(relationService.findByTo(entityId, typeGroup).get());
157 } catch (Exception e) { 195 } catch (Exception e) {
158 throw handleException(e); 196 throw handleException(e);
159 } 197 }
160 } 198 }
161 199
162 - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 200 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
  201 + @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {"toId", "toType"})
  202 + @ResponseBody
  203 + public List<EntityRelationInfo> findInfoByTo(@RequestParam("toId") String strToId,
  204 + @RequestParam("toType") String strToType,
  205 + @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
  206 + checkParameter("toId", strToId);
  207 + checkParameter("toType", strToType);
  208 + EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
  209 + checkEntityId(entityId);
  210 + RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
  211 + try {
  212 + return checkNotNull(relationService.findInfoByTo(entityId, typeGroup).get());
  213 + } catch (Exception e) {
  214 + throw handleException(e);
  215 + }
  216 + }
  217 +
  218 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
163 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType", "relationType"}) 219 @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType", "relationType"})
164 @ResponseBody 220 @ResponseBody
165 - public List<EntityRelation> findByTo(@RequestParam("toId") String strToId, @RequestParam("toType") String strToType  
166 - , @RequestParam("relationType") String strRelationType) throws ThingsboardException { 221 + public List<EntityRelation> findByTo(@RequestParam("toId") String strToId,
  222 + @RequestParam("toType") String strToType,
  223 + @RequestParam("relationType") String strRelationType,
  224 + @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
167 checkParameter("toId", strToId); 225 checkParameter("toId", strToId);
168 checkParameter("toType", strToType); 226 checkParameter("toType", strToType);
169 checkParameter("relationType", strRelationType); 227 checkParameter("relationType", strRelationType);
170 EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId); 228 EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
171 checkEntityId(entityId); 229 checkEntityId(entityId);
  230 + RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
172 try { 231 try {
173 - return checkNotNull(relationService.findByToAndType(entityId, strRelationType).get()); 232 + return checkNotNull(relationService.findByToAndType(entityId, strRelationType, typeGroup).get());
174 } catch (Exception e) { 233 } catch (Exception e) {
175 throw handleException(e); 234 throw handleException(e);
176 } 235 }
177 } 236 }
178 237
179 - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 238 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
180 @RequestMapping(value = "/relations", method = RequestMethod.POST) 239 @RequestMapping(value = "/relations", method = RequestMethod.POST)
181 @ResponseBody 240 @ResponseBody
182 public List<EntityRelation> findByQuery(@RequestBody EntityRelationsQuery query) throws ThingsboardException { 241 public List<EntityRelation> findByQuery(@RequestBody EntityRelationsQuery query) throws ThingsboardException {
@@ -191,4 +250,16 @@ public class EntityRelationController extends BaseController { @@ -191,4 +250,16 @@ public class EntityRelationController extends BaseController {
191 } 250 }
192 } 251 }
193 252
  253 + private RelationTypeGroup parseRelationTypeGroup(String strRelationTypeGroup, RelationTypeGroup defaultValue) {
  254 + RelationTypeGroup result = defaultValue;
  255 + if (strRelationTypeGroup != null && strRelationTypeGroup.trim().length()>0) {
  256 + try {
  257 + result = RelationTypeGroup.valueOf(strRelationTypeGroup);
  258 + } catch (IllegalArgumentException e) {
  259 + result = defaultValue;
  260 + }
  261 + }
  262 + return result;
  263 + }
  264 +
194 } 265 }
@@ -19,12 +19,18 @@ server: @@ -19,12 +19,18 @@ server:
19 address: "${HTTP_BIND_ADDRESS:0.0.0.0}" 19 address: "${HTTP_BIND_ADDRESS:0.0.0.0}"
20 # Server bind port 20 # Server bind port
21 port: "${HTTP_BIND_PORT:8080}" 21 port: "${HTTP_BIND_PORT:8080}"
22 -# Uncomment the following section to enable ssl  
23 -# ssl:  
24 -# key-store: classpath:keystore/keystore.p12  
25 -# key-store-password: thingsboard  
26 -# keyStoreType: PKCS12  
27 -# keyAlias: tomcat 22 + # Server SSL configuration
  23 + ssl:
  24 + # Enable/disable SSL support
  25 + enabled: "${SSL_ENABLED:false}"
  26 + # Path to the key store that holds the SSL certificate
  27 + key-store: "${SSL_KEY_STORE:classpath:keystore/keystore.p12}"
  28 + # Password used to access the key store
  29 + key-store-password: "${SSL_KEY_STORE_PASSWORD:thingsboard}"
  30 + # Type of the key store
  31 + key-store-type: "${SSL_KEY_STORE_TYPE:PKCS12}"
  32 + # Alias that identifies the key in the key store
  33 + key-alias: "${SSL_KEY_ALIAS:tomcat}"
28 34
29 # Zookeeper connection parameters. Used for service discovery. 35 # Zookeeper connection parameters. Used for service discovery.
30 zk: 36 zk:
@@ -79,12 +85,18 @@ mqtt: @@ -79,12 +85,18 @@ mqtt:
79 leak_detector_level: "${NETTY_LEASK_DETECTOR_LVL:DISABLED}" 85 leak_detector_level: "${NETTY_LEASK_DETECTOR_LVL:DISABLED}"
80 boss_group_thread_count: "${NETTY_BOSS_GROUP_THREADS:1}" 86 boss_group_thread_count: "${NETTY_BOSS_GROUP_THREADS:1}"
81 worker_group_thread_count: "${NETTY_WORKER_GROUP_THREADS:12}" 87 worker_group_thread_count: "${NETTY_WORKER_GROUP_THREADS:12}"
82 -# Uncomment the following lines to enable ssl for MQTT  
83 -# ssl:  
84 -# key_store: mqttserver.jks  
85 -# key_store_password: server_ks_password  
86 -# key_password: server_key_password  
87 -# key_store_type: JKS 88 + # MQTT SSL configuration
  89 + ssl:
  90 + # Enable/disable SSL support
  91 + enabled: "${MQTT_SSL_ENABLED:false}"
  92 + # Path to the key store that holds the SSL certificate
  93 + key_store: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
  94 + # Password used to access the key store
  95 + key_store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
  96 + # Password used to access the key
  97 + key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
  98 + # Type of the key store
  99 + key_store_type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}"
88 100
89 # CoAP server parameters 101 # CoAP server parameters
90 coap: 102 coap:
@@ -98,13 +98,15 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC @@ -98,13 +98,15 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC
98 @IntegrationTest("server.port:0") 98 @IntegrationTest("server.port:0")
99 public abstract class AbstractControllerTest { 99 public abstract class AbstractControllerTest {
100 100
  101 + protected static final String TEST_TENANT_NAME = "TEST TENANT";
  102 +
101 protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org"; 103 protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org";
102 private static final String SYS_ADMIN_PASSWORD = "sysadmin"; 104 private static final String SYS_ADMIN_PASSWORD = "sysadmin";
103 105
104 - protected static final String TENANT_ADMIN_EMAIL = "tenant@thingsboard.org"; 106 + protected static final String TENANT_ADMIN_EMAIL = "testtenant@thingsboard.org";
105 private static final String TENANT_ADMIN_PASSWORD = "tenant"; 107 private static final String TENANT_ADMIN_PASSWORD = "tenant";
106 108
107 - protected static final String CUSTOMER_USER_EMAIL = "customer@thingsboard.org"; 109 + protected static final String CUSTOMER_USER_EMAIL = "testcustomer@thingsboard.org";
108 private static final String CUSTOMER_USER_PASSWORD = "customer"; 110 private static final String CUSTOMER_USER_PASSWORD = "customer";
109 111
110 protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(), 112 protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
@@ -147,7 +149,7 @@ public abstract class AbstractControllerTest { @@ -147,7 +149,7 @@ public abstract class AbstractControllerTest {
147 loginSysAdmin(); 149 loginSysAdmin();
148 150
149 Tenant tenant = new Tenant(); 151 Tenant tenant = new Tenant();
150 - tenant.setTitle("Tenant"); 152 + tenant.setTitle(TEST_TENANT_NAME);
151 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 153 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
152 Assert.assertNotNull(savedTenant); 154 Assert.assertNotNull(savedTenant);
153 tenantId = savedTenant.getId(); 155 tenantId = savedTenant.getId();
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.controller;
  17 +
  18 +import static org.hamcrest.Matchers.containsString;
  19 +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
  20 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  21 +
  22 +import java.util.ArrayList;
  23 +import java.util.Collections;
  24 +import java.util.List;
  25 +
  26 +import org.apache.commons.lang3.RandomStringUtils;
  27 +import org.thingsboard.server.common.data.*;
  28 +import org.thingsboard.server.common.data.asset.Asset;
  29 +import org.thingsboard.server.common.data.asset.TenantAssetType;
  30 +import org.thingsboard.server.common.data.id.CustomerId;
  31 +import org.thingsboard.server.common.data.id.AssetId;
  32 +import org.thingsboard.server.common.data.page.TextPageData;
  33 +import org.thingsboard.server.common.data.page.TextPageLink;
  34 +import org.thingsboard.server.common.data.security.Authority;
  35 +import org.thingsboard.server.dao.model.ModelConstants;
  36 +import org.junit.After;
  37 +import org.junit.Assert;
  38 +import org.junit.Before;
  39 +import org.junit.Test;
  40 +
  41 +import com.datastax.driver.core.utils.UUIDs;
  42 +import com.fasterxml.jackson.core.type.TypeReference;
  43 +
  44 +public class AssetControllerTest extends AbstractControllerTest {
  45 +
  46 + private IdComparator<Asset> idComparator = new IdComparator<>();
  47 +
  48 + private Tenant savedTenant;
  49 + private User tenantAdmin;
  50 +
  51 + @Before
  52 + public void beforeTest() throws Exception {
  53 + loginSysAdmin();
  54 +
  55 + Tenant tenant = new Tenant();
  56 + tenant.setTitle("My tenant");
  57 + savedTenant = doPost("/api/tenant", tenant, Tenant.class);
  58 + Assert.assertNotNull(savedTenant);
  59 +
  60 + tenantAdmin = new User();
  61 + tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
  62 + tenantAdmin.setTenantId(savedTenant.getId());
  63 + tenantAdmin.setEmail("tenant2@thingsboard.org");
  64 + tenantAdmin.setFirstName("Joe");
  65 + tenantAdmin.setLastName("Downs");
  66 +
  67 + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
  68 + }
  69 +
  70 + @After
  71 + public void afterTest() throws Exception {
  72 + loginSysAdmin();
  73 +
  74 + doDelete("/api/tenant/"+savedTenant.getId().getId().toString())
  75 + .andExpect(status().isOk());
  76 + }
  77 +
  78 + @Test
  79 + public void testSaveAsset() throws Exception {
  80 + Asset asset = new Asset();
  81 + asset.setName("My asset");
  82 + asset.setType("default");
  83 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  84 +
  85 + Assert.assertNotNull(savedAsset);
  86 + Assert.assertNotNull(savedAsset.getId());
  87 + Assert.assertTrue(savedAsset.getCreatedTime() > 0);
  88 + Assert.assertEquals(savedTenant.getId(), savedAsset.getTenantId());
  89 + Assert.assertNotNull(savedAsset.getCustomerId());
  90 + Assert.assertEquals(NULL_UUID, savedAsset.getCustomerId().getId());
  91 + Assert.assertEquals(asset.getName(), savedAsset.getName());
  92 +
  93 + savedAsset.setName("My new asset");
  94 + doPost("/api/asset", savedAsset, Asset.class);
  95 +
  96 + Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  97 + Assert.assertEquals(foundAsset.getName(), savedAsset.getName());
  98 + }
  99 +
  100 + @Test
  101 + public void testFindAssetById() throws Exception {
  102 + Asset asset = new Asset();
  103 + asset.setName("My asset");
  104 + asset.setType("default");
  105 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  106 + Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  107 + Assert.assertNotNull(foundAsset);
  108 + Assert.assertEquals(savedAsset, foundAsset);
  109 + }
  110 +
  111 + @Test
  112 + public void testFindAssetTypesByTenantId() throws Exception {
  113 + List<Asset> assets = new ArrayList<>();
  114 + for (int i=0;i<3;i++) {
  115 + Asset asset = new Asset();
  116 + asset.setName("My asset B"+i);
  117 + asset.setType("typeB");
  118 + assets.add(doPost("/api/asset", asset, Asset.class));
  119 + }
  120 + for (int i=0;i<7;i++) {
  121 + Asset asset = new Asset();
  122 + asset.setName("My asset C"+i);
  123 + asset.setType("typeC");
  124 + assets.add(doPost("/api/asset", asset, Asset.class));
  125 + }
  126 + for (int i=0;i<9;i++) {
  127 + Asset asset = new Asset();
  128 + asset.setName("My asset A"+i);
  129 + asset.setType("typeA");
  130 + assets.add(doPost("/api/asset", asset, Asset.class));
  131 + }
  132 + List<TenantAssetType> assetTypes = doGetTyped("/api/asset/types",
  133 + new TypeReference<List<TenantAssetType>>(){});
  134 +
  135 + Assert.assertNotNull(assetTypes);
  136 + Assert.assertEquals(3, assetTypes.size());
  137 + Assert.assertEquals("typeA", assetTypes.get(0).getType());
  138 + Assert.assertEquals("typeB", assetTypes.get(1).getType());
  139 + Assert.assertEquals("typeC", assetTypes.get(2).getType());
  140 + }
  141 +
  142 + @Test
  143 + public void testDeleteAsset() throws Exception {
  144 + Asset asset = new Asset();
  145 + asset.setName("My asset");
  146 + asset.setType("default");
  147 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  148 +
  149 + doDelete("/api/asset/"+savedAsset.getId().getId().toString())
  150 + .andExpect(status().isOk());
  151 +
  152 + doGet("/api/asset/"+savedAsset.getId().getId().toString())
  153 + .andExpect(status().isNotFound());
  154 + }
  155 +
  156 + @Test
  157 + public void testSaveAssetWithEmptyType() throws Exception {
  158 + Asset asset = new Asset();
  159 + asset.setName("My asset");
  160 + doPost("/api/asset", asset)
  161 + .andExpect(status().isBadRequest())
  162 + .andExpect(statusReason(containsString("Asset type should be specified")));
  163 + }
  164 +
  165 + @Test
  166 + public void testSaveAssetWithEmptyName() throws Exception {
  167 + Asset asset = new Asset();
  168 + asset.setType("default");
  169 + doPost("/api/asset", asset)
  170 + .andExpect(status().isBadRequest())
  171 + .andExpect(statusReason(containsString("Asset name should be specified")));
  172 + }
  173 +
  174 + @Test
  175 + public void testAssignUnassignAssetToCustomer() throws Exception {
  176 + Asset asset = new Asset();
  177 + asset.setName("My asset");
  178 + asset.setType("default");
  179 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  180 +
  181 + Customer customer = new Customer();
  182 + customer.setTitle("My customer");
  183 + Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
  184 +
  185 + Asset assignedAsset = doPost("/api/customer/" + savedCustomer.getId().getId().toString()
  186 + + "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  187 + Assert.assertEquals(savedCustomer.getId(), assignedAsset.getCustomerId());
  188 +
  189 + Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  190 + Assert.assertEquals(savedCustomer.getId(), foundAsset.getCustomerId());
  191 +
  192 + Asset unassignedAsset =
  193 + doDelete("/api/customer/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  194 + Assert.assertEquals(ModelConstants.NULL_UUID, unassignedAsset.getCustomerId().getId());
  195 +
  196 + foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  197 + Assert.assertEquals(ModelConstants.NULL_UUID, foundAsset.getCustomerId().getId());
  198 + }
  199 +
  200 + @Test
  201 + public void testAssignAssetToNonExistentCustomer() throws Exception {
  202 + Asset asset = new Asset();
  203 + asset.setName("My asset");
  204 + asset.setType("default");
  205 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  206 +
  207 + doPost("/api/customer/" + UUIDs.timeBased().toString()
  208 + + "/asset/" + savedAsset.getId().getId().toString())
  209 + .andExpect(status().isNotFound());
  210 + }
  211 +
  212 + @Test
  213 + public void testAssignAssetToCustomerFromDifferentTenant() throws Exception {
  214 + loginSysAdmin();
  215 +
  216 + Tenant tenant2 = new Tenant();
  217 + tenant2.setTitle("Different tenant");
  218 + Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class);
  219 + Assert.assertNotNull(savedTenant2);
  220 +
  221 + User tenantAdmin2 = new User();
  222 + tenantAdmin2.setAuthority(Authority.TENANT_ADMIN);
  223 + tenantAdmin2.setTenantId(savedTenant2.getId());
  224 + tenantAdmin2.setEmail("tenant3@thingsboard.org");
  225 + tenantAdmin2.setFirstName("Joe");
  226 + tenantAdmin2.setLastName("Downs");
  227 +
  228 + tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1");
  229 +
  230 + Customer customer = new Customer();
  231 + customer.setTitle("Different customer");
  232 + Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
  233 +
  234 + login(tenantAdmin.getEmail(), "testPassword1");
  235 +
  236 + Asset asset = new Asset();
  237 + asset.setName("My asset");
  238 + asset.setType("default");
  239 + Asset savedAsset = doPost("/api/asset", asset, Asset.class);
  240 +
  241 + doPost("/api/customer/" + savedCustomer.getId().getId().toString()
  242 + + "/asset/" + savedAsset.getId().getId().toString())
  243 + .andExpect(status().isForbidden());
  244 +
  245 + loginSysAdmin();
  246 +
  247 + doDelete("/api/tenant/"+savedTenant2.getId().getId().toString())
  248 + .andExpect(status().isOk());
  249 + }
  250 +
  251 + @Test
  252 + public void testFindTenantAssets() throws Exception {
  253 + List<Asset> assets = new ArrayList<>();
  254 + for (int i=0;i<178;i++) {
  255 + Asset asset = new Asset();
  256 + asset.setName("Asset"+i);
  257 + asset.setType("default");
  258 + assets.add(doPost("/api/asset", asset, Asset.class));
  259 + }
  260 + List<Asset> loadedAssets = new ArrayList<>();
  261 + TextPageLink pageLink = new TextPageLink(23);
  262 + TextPageData<Asset> pageData = null;
  263 + do {
  264 + pageData = doGetTypedWithPageLink("/api/tenant/assets?",
  265 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  266 + loadedAssets.addAll(pageData.getData());
  267 + if (pageData.hasNext()) {
  268 + pageLink = pageData.getNextPageLink();
  269 + }
  270 + } while (pageData.hasNext());
  271 +
  272 + Collections.sort(assets, idComparator);
  273 + Collections.sort(loadedAssets, idComparator);
  274 +
  275 + Assert.assertEquals(assets, loadedAssets);
  276 + }
  277 +
  278 + @Test
  279 + public void testFindTenantAssetsByName() throws Exception {
  280 + String title1 = "Asset title 1";
  281 + List<Asset> assetsTitle1 = new ArrayList<>();
  282 + for (int i=0;i<143;i++) {
  283 + Asset asset = new Asset();
  284 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  285 + String name = title1+suffix;
  286 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  287 + asset.setName(name);
  288 + asset.setType("default");
  289 + assetsTitle1.add(doPost("/api/asset", asset, Asset.class));
  290 + }
  291 + String title2 = "Asset title 2";
  292 + List<Asset> assetsTitle2 = new ArrayList<>();
  293 + for (int i=0;i<75;i++) {
  294 + Asset asset = new Asset();
  295 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  296 + String name = title2+suffix;
  297 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  298 + asset.setName(name);
  299 + asset.setType("default");
  300 + assetsTitle2.add(doPost("/api/asset", asset, Asset.class));
  301 + }
  302 +
  303 + List<Asset> loadedAssetsTitle1 = new ArrayList<>();
  304 + TextPageLink pageLink = new TextPageLink(15, title1);
  305 + TextPageData<Asset> pageData = null;
  306 + do {
  307 + pageData = doGetTypedWithPageLink("/api/tenant/assets?",
  308 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  309 + loadedAssetsTitle1.addAll(pageData.getData());
  310 + if (pageData.hasNext()) {
  311 + pageLink = pageData.getNextPageLink();
  312 + }
  313 + } while (pageData.hasNext());
  314 +
  315 + Collections.sort(assetsTitle1, idComparator);
  316 + Collections.sort(loadedAssetsTitle1, idComparator);
  317 +
  318 + Assert.assertEquals(assetsTitle1, loadedAssetsTitle1);
  319 +
  320 + List<Asset> loadedAssetsTitle2 = new ArrayList<>();
  321 + pageLink = new TextPageLink(4, title2);
  322 + do {
  323 + pageData = doGetTypedWithPageLink("/api/tenant/assets?",
  324 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  325 + loadedAssetsTitle2.addAll(pageData.getData());
  326 + if (pageData.hasNext()) {
  327 + pageLink = pageData.getNextPageLink();
  328 + }
  329 + } while (pageData.hasNext());
  330 +
  331 + Collections.sort(assetsTitle2, idComparator);
  332 + Collections.sort(loadedAssetsTitle2, idComparator);
  333 +
  334 + Assert.assertEquals(assetsTitle2, loadedAssetsTitle2);
  335 +
  336 + for (Asset asset : loadedAssetsTitle1) {
  337 + doDelete("/api/asset/"+asset.getId().getId().toString())
  338 + .andExpect(status().isOk());
  339 + }
  340 +
  341 + pageLink = new TextPageLink(4, title1);
  342 + pageData = doGetTypedWithPageLink("/api/tenant/assets?",
  343 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  344 + Assert.assertFalse(pageData.hasNext());
  345 + Assert.assertEquals(0, pageData.getData().size());
  346 +
  347 + for (Asset asset : loadedAssetsTitle2) {
  348 + doDelete("/api/asset/"+asset.getId().getId().toString())
  349 + .andExpect(status().isOk());
  350 + }
  351 +
  352 + pageLink = new TextPageLink(4, title2);
  353 + pageData = doGetTypedWithPageLink("/api/tenant/assets?",
  354 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  355 + Assert.assertFalse(pageData.hasNext());
  356 + Assert.assertEquals(0, pageData.getData().size());
  357 + }
  358 +
  359 + @Test
  360 + public void testFindTenantAssetsByType() throws Exception {
  361 + String title1 = "Asset title 1";
  362 + String type1 = "typeA";
  363 + List<Asset> assetsType1 = new ArrayList<>();
  364 + for (int i=0;i<143;i++) {
  365 + Asset asset = new Asset();
  366 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  367 + String name = title1+suffix;
  368 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  369 + asset.setName(name);
  370 + asset.setType(type1);
  371 + assetsType1.add(doPost("/api/asset", asset, Asset.class));
  372 + }
  373 + String title2 = "Asset title 2";
  374 + String type2 = "typeB";
  375 + List<Asset> assetsType2 = new ArrayList<>();
  376 + for (int i=0;i<75;i++) {
  377 + Asset asset = new Asset();
  378 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  379 + String name = title2+suffix;
  380 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  381 + asset.setName(name);
  382 + asset.setType(type2);
  383 + assetsType2.add(doPost("/api/asset", asset, Asset.class));
  384 + }
  385 +
  386 + List<Asset> loadedAssetsType1 = new ArrayList<>();
  387 + TextPageLink pageLink = new TextPageLink(15);
  388 + TextPageData<Asset> pageData = null;
  389 + do {
  390 + pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
  391 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type1);
  392 + loadedAssetsType1.addAll(pageData.getData());
  393 + if (pageData.hasNext()) {
  394 + pageLink = pageData.getNextPageLink();
  395 + }
  396 + } while (pageData.hasNext());
  397 +
  398 + Collections.sort(assetsType1, idComparator);
  399 + Collections.sort(loadedAssetsType1, idComparator);
  400 +
  401 + Assert.assertEquals(assetsType1, loadedAssetsType1);
  402 +
  403 + List<Asset> loadedAssetsType2 = new ArrayList<>();
  404 + pageLink = new TextPageLink(4);
  405 + do {
  406 + pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
  407 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type2);
  408 + loadedAssetsType2.addAll(pageData.getData());
  409 + if (pageData.hasNext()) {
  410 + pageLink = pageData.getNextPageLink();
  411 + }
  412 + } while (pageData.hasNext());
  413 +
  414 + Collections.sort(assetsType2, idComparator);
  415 + Collections.sort(loadedAssetsType2, idComparator);
  416 +
  417 + Assert.assertEquals(assetsType2, loadedAssetsType2);
  418 +
  419 + for (Asset asset : loadedAssetsType1) {
  420 + doDelete("/api/asset/"+asset.getId().getId().toString())
  421 + .andExpect(status().isOk());
  422 + }
  423 +
  424 + pageLink = new TextPageLink(4);
  425 + pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
  426 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type1);
  427 + Assert.assertFalse(pageData.hasNext());
  428 + Assert.assertEquals(0, pageData.getData().size());
  429 +
  430 + for (Asset asset : loadedAssetsType2) {
  431 + doDelete("/api/asset/"+asset.getId().getId().toString())
  432 + .andExpect(status().isOk());
  433 + }
  434 +
  435 + pageLink = new TextPageLink(4);
  436 + pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
  437 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type2);
  438 + Assert.assertFalse(pageData.hasNext());
  439 + Assert.assertEquals(0, pageData.getData().size());
  440 + }
  441 +
  442 + @Test
  443 + public void testFindCustomerAssets() throws Exception {
  444 + Customer customer = new Customer();
  445 + customer.setTitle("Test customer");
  446 + customer = doPost("/api/customer", customer, Customer.class);
  447 + CustomerId customerId = customer.getId();
  448 +
  449 + List<Asset> assets = new ArrayList<>();
  450 + for (int i=0;i<128;i++) {
  451 + Asset asset = new Asset();
  452 + asset.setName("Asset"+i);
  453 + asset.setType("default");
  454 + asset = doPost("/api/asset", asset, Asset.class);
  455 + assets.add(doPost("/api/customer/" + customerId.getId().toString()
  456 + + "/asset/" + asset.getId().getId().toString(), Asset.class));
  457 + }
  458 +
  459 + List<Asset> loadedAssets = new ArrayList<>();
  460 + TextPageLink pageLink = new TextPageLink(23);
  461 + TextPageData<Asset> pageData = null;
  462 + do {
  463 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
  464 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  465 + loadedAssets.addAll(pageData.getData());
  466 + if (pageData.hasNext()) {
  467 + pageLink = pageData.getNextPageLink();
  468 + }
  469 + } while (pageData.hasNext());
  470 +
  471 + Collections.sort(assets, idComparator);
  472 + Collections.sort(loadedAssets, idComparator);
  473 +
  474 + Assert.assertEquals(assets, loadedAssets);
  475 + }
  476 +
  477 + @Test
  478 + public void testFindCustomerAssetsByName() throws Exception {
  479 + Customer customer = new Customer();
  480 + customer.setTitle("Test customer");
  481 + customer = doPost("/api/customer", customer, Customer.class);
  482 + CustomerId customerId = customer.getId();
  483 +
  484 + String title1 = "Asset title 1";
  485 + List<Asset> assetsTitle1 = new ArrayList<>();
  486 + for (int i=0;i<125;i++) {
  487 + Asset asset = new Asset();
  488 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  489 + String name = title1+suffix;
  490 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  491 + asset.setName(name);
  492 + asset.setType("default");
  493 + asset = doPost("/api/asset", asset, Asset.class);
  494 + assetsTitle1.add(doPost("/api/customer/" + customerId.getId().toString()
  495 + + "/asset/" + asset.getId().getId().toString(), Asset.class));
  496 + }
  497 + String title2 = "Asset title 2";
  498 + List<Asset> assetsTitle2 = new ArrayList<>();
  499 + for (int i=0;i<143;i++) {
  500 + Asset asset = new Asset();
  501 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  502 + String name = title2+suffix;
  503 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  504 + asset.setName(name);
  505 + asset.setType("default");
  506 + asset = doPost("/api/asset", asset, Asset.class);
  507 + assetsTitle2.add(doPost("/api/customer/" + customerId.getId().toString()
  508 + + "/asset/" + asset.getId().getId().toString(), Asset.class));
  509 + }
  510 +
  511 + List<Asset> loadedAssetsTitle1 = new ArrayList<>();
  512 + TextPageLink pageLink = new TextPageLink(15, title1);
  513 + TextPageData<Asset> pageData = null;
  514 + do {
  515 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
  516 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  517 + loadedAssetsTitle1.addAll(pageData.getData());
  518 + if (pageData.hasNext()) {
  519 + pageLink = pageData.getNextPageLink();
  520 + }
  521 + } while (pageData.hasNext());
  522 +
  523 + Collections.sort(assetsTitle1, idComparator);
  524 + Collections.sort(loadedAssetsTitle1, idComparator);
  525 +
  526 + Assert.assertEquals(assetsTitle1, loadedAssetsTitle1);
  527 +
  528 + List<Asset> loadedAssetsTitle2 = new ArrayList<>();
  529 + pageLink = new TextPageLink(4, title2);
  530 + do {
  531 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
  532 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  533 + loadedAssetsTitle2.addAll(pageData.getData());
  534 + if (pageData.hasNext()) {
  535 + pageLink = pageData.getNextPageLink();
  536 + }
  537 + } while (pageData.hasNext());
  538 +
  539 + Collections.sort(assetsTitle2, idComparator);
  540 + Collections.sort(loadedAssetsTitle2, idComparator);
  541 +
  542 + Assert.assertEquals(assetsTitle2, loadedAssetsTitle2);
  543 +
  544 + for (Asset asset : loadedAssetsTitle1) {
  545 + doDelete("/api/customer/asset/" + asset.getId().getId().toString())
  546 + .andExpect(status().isOk());
  547 + }
  548 +
  549 + pageLink = new TextPageLink(4, title1);
  550 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
  551 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  552 + Assert.assertFalse(pageData.hasNext());
  553 + Assert.assertEquals(0, pageData.getData().size());
  554 +
  555 + for (Asset asset : loadedAssetsTitle2) {
  556 + doDelete("/api/customer/asset/" + asset.getId().getId().toString())
  557 + .andExpect(status().isOk());
  558 + }
  559 +
  560 + pageLink = new TextPageLink(4, title2);
  561 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
  562 + new TypeReference<TextPageData<Asset>>(){}, pageLink);
  563 + Assert.assertFalse(pageData.hasNext());
  564 + Assert.assertEquals(0, pageData.getData().size());
  565 + }
  566 +
  567 + @Test
  568 + public void testFindCustomerAssetsByType() throws Exception {
  569 + Customer customer = new Customer();
  570 + customer.setTitle("Test customer");
  571 + customer = doPost("/api/customer", customer, Customer.class);
  572 + CustomerId customerId = customer.getId();
  573 +
  574 + String title1 = "Asset title 1";
  575 + String type1 = "typeC";
  576 + List<Asset> assetsType1 = new ArrayList<>();
  577 + for (int i=0;i<125;i++) {
  578 + Asset asset = new Asset();
  579 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  580 + String name = title1+suffix;
  581 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  582 + asset.setName(name);
  583 + asset.setType(type1);
  584 + asset = doPost("/api/asset", asset, Asset.class);
  585 + assetsType1.add(doPost("/api/customer/" + customerId.getId().toString()
  586 + + "/asset/" + asset.getId().getId().toString(), Asset.class));
  587 + }
  588 + String title2 = "Asset title 2";
  589 + String type2 = "typeD";
  590 + List<Asset> assetsType2 = new ArrayList<>();
  591 + for (int i=0;i<143;i++) {
  592 + Asset asset = new Asset();
  593 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  594 + String name = title2+suffix;
  595 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  596 + asset.setName(name);
  597 + asset.setType(type2);
  598 + asset = doPost("/api/asset", asset, Asset.class);
  599 + assetsType2.add(doPost("/api/customer/" + customerId.getId().toString()
  600 + + "/asset/" + asset.getId().getId().toString(), Asset.class));
  601 + }
  602 +
  603 + List<Asset> loadedAssetsType1 = new ArrayList<>();
  604 + TextPageLink pageLink = new TextPageLink(15);
  605 + TextPageData<Asset> pageData = null;
  606 + do {
  607 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
  608 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type1);
  609 + loadedAssetsType1.addAll(pageData.getData());
  610 + if (pageData.hasNext()) {
  611 + pageLink = pageData.getNextPageLink();
  612 + }
  613 + } while (pageData.hasNext());
  614 +
  615 + Collections.sort(assetsType1, idComparator);
  616 + Collections.sort(loadedAssetsType1, idComparator);
  617 +
  618 + Assert.assertEquals(assetsType1, loadedAssetsType1);
  619 +
  620 + List<Asset> loadedAssetsType2 = new ArrayList<>();
  621 + pageLink = new TextPageLink(4);
  622 + do {
  623 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
  624 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type2);
  625 + loadedAssetsType2.addAll(pageData.getData());
  626 + if (pageData.hasNext()) {
  627 + pageLink = pageData.getNextPageLink();
  628 + }
  629 + } while (pageData.hasNext());
  630 +
  631 + Collections.sort(assetsType2, idComparator);
  632 + Collections.sort(loadedAssetsType2, idComparator);
  633 +
  634 + Assert.assertEquals(assetsType2, loadedAssetsType2);
  635 +
  636 + for (Asset asset : loadedAssetsType1) {
  637 + doDelete("/api/customer/asset/" + asset.getId().getId().toString())
  638 + .andExpect(status().isOk());
  639 + }
  640 +
  641 + pageLink = new TextPageLink(4);
  642 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
  643 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type1);
  644 + Assert.assertFalse(pageData.hasNext());
  645 + Assert.assertEquals(0, pageData.getData().size());
  646 +
  647 + for (Asset asset : loadedAssetsType2) {
  648 + doDelete("/api/customer/asset/" + asset.getId().getId().toString())
  649 + .andExpect(status().isOk());
  650 + }
  651 +
  652 + pageLink = new TextPageLink(4);
  653 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
  654 + new TypeReference<TextPageData<Asset>>(){}, pageLink, type2);
  655 + Assert.assertFalse(pageData.hasNext());
  656 + Assert.assertEquals(0, pageData.getData().size());
  657 + }
  658 +
  659 +}
@@ -24,10 +24,7 @@ import java.util.Collections; @@ -24,10 +24,7 @@ import java.util.Collections;
24 import java.util.List; 24 import java.util.List;
25 25
26 import org.apache.commons.lang3.RandomStringUtils; 26 import org.apache.commons.lang3.RandomStringUtils;
27 -import org.thingsboard.server.common.data.Customer;  
28 -import org.thingsboard.server.common.data.Device;  
29 -import org.thingsboard.server.common.data.Tenant;  
30 -import org.thingsboard.server.common.data.User; 27 +import org.thingsboard.server.common.data.*;
31 import org.thingsboard.server.common.data.id.CustomerId; 28 import org.thingsboard.server.common.data.id.CustomerId;
32 import org.thingsboard.server.common.data.id.DeviceCredentialsId; 29 import org.thingsboard.server.common.data.id.DeviceCredentialsId;
33 import org.thingsboard.server.common.data.id.DeviceId; 30 import org.thingsboard.server.common.data.id.DeviceId;
@@ -83,6 +80,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -83,6 +80,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
83 public void testSaveDevice() throws Exception { 80 public void testSaveDevice() throws Exception {
84 Device device = new Device(); 81 Device device = new Device();
85 device.setName("My device"); 82 device.setName("My device");
  83 + device.setType("default");
86 Device savedDevice = doPost("/api/device", device, Device.class); 84 Device savedDevice = doPost("/api/device", device, Device.class);
87 85
88 Assert.assertNotNull(savedDevice); 86 Assert.assertNotNull(savedDevice);
@@ -114,16 +112,49 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -114,16 +112,49 @@ public class DeviceControllerTest extends AbstractControllerTest {
114 public void testFindDeviceById() throws Exception { 112 public void testFindDeviceById() throws Exception {
115 Device device = new Device(); 113 Device device = new Device();
116 device.setName("My device"); 114 device.setName("My device");
  115 + device.setType("default");
117 Device savedDevice = doPost("/api/device", device, Device.class); 116 Device savedDevice = doPost("/api/device", device, Device.class);
118 Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); 117 Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
119 Assert.assertNotNull(foundDevice); 118 Assert.assertNotNull(foundDevice);
120 Assert.assertEquals(savedDevice, foundDevice); 119 Assert.assertEquals(savedDevice, foundDevice);
121 } 120 }
  121 +
  122 + @Test
  123 + public void testFindDeviceTypesByTenantId() throws Exception {
  124 + List<Device> devices = new ArrayList<>();
  125 + for (int i=0;i<3;i++) {
  126 + Device device = new Device();
  127 + device.setName("My device B"+i);
  128 + device.setType("typeB");
  129 + devices.add(doPost("/api/device", device, Device.class));
  130 + }
  131 + for (int i=0;i<7;i++) {
  132 + Device device = new Device();
  133 + device.setName("My device C"+i);
  134 + device.setType("typeC");
  135 + devices.add(doPost("/api/device", device, Device.class));
  136 + }
  137 + for (int i=0;i<9;i++) {
  138 + Device device = new Device();
  139 + device.setName("My device A"+i);
  140 + device.setType("typeA");
  141 + devices.add(doPost("/api/device", device, Device.class));
  142 + }
  143 + List<TenantDeviceType> deviceTypes = doGetTyped("/api/device/types",
  144 + new TypeReference<List<TenantDeviceType>>(){});
  145 +
  146 + Assert.assertNotNull(deviceTypes);
  147 + Assert.assertEquals(3, deviceTypes.size());
  148 + Assert.assertEquals("typeA", deviceTypes.get(0).getType());
  149 + Assert.assertEquals("typeB", deviceTypes.get(1).getType());
  150 + Assert.assertEquals("typeC", deviceTypes.get(2).getType());
  151 + }
122 152
123 @Test 153 @Test
124 public void testDeleteDevice() throws Exception { 154 public void testDeleteDevice() throws Exception {
125 Device device = new Device(); 155 Device device = new Device();
126 device.setName("My device"); 156 device.setName("My device");
  157 + device.setType("default");
127 Device savedDevice = doPost("/api/device", device, Device.class); 158 Device savedDevice = doPost("/api/device", device, Device.class);
128 159
129 doDelete("/api/device/"+savedDevice.getId().getId().toString()) 160 doDelete("/api/device/"+savedDevice.getId().getId().toString())
@@ -132,10 +163,20 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -132,10 +163,20 @@ public class DeviceControllerTest extends AbstractControllerTest {
132 doGet("/api/device/"+savedDevice.getId().getId().toString()) 163 doGet("/api/device/"+savedDevice.getId().getId().toString())
133 .andExpect(status().isNotFound()); 164 .andExpect(status().isNotFound());
134 } 165 }
135 - 166 +
  167 + @Test
  168 + public void testSaveDeviceWithEmptyType() throws Exception {
  169 + Device device = new Device();
  170 + device.setName("My device");
  171 + doPost("/api/device", device)
  172 + .andExpect(status().isBadRequest())
  173 + .andExpect(statusReason(containsString("Device type should be specified")));
  174 + }
  175 +
136 @Test 176 @Test
137 public void testSaveDeviceWithEmptyName() throws Exception { 177 public void testSaveDeviceWithEmptyName() throws Exception {
138 Device device = new Device(); 178 Device device = new Device();
  179 + device.setType("default");
139 doPost("/api/device", device) 180 doPost("/api/device", device)
140 .andExpect(status().isBadRequest()) 181 .andExpect(status().isBadRequest())
141 .andExpect(statusReason(containsString("Device name should be specified"))); 182 .andExpect(statusReason(containsString("Device name should be specified")));
@@ -145,6 +186,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -145,6 +186,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
145 public void testAssignUnassignDeviceToCustomer() throws Exception { 186 public void testAssignUnassignDeviceToCustomer() throws Exception {
146 Device device = new Device(); 187 Device device = new Device();
147 device.setName("My device"); 188 device.setName("My device");
  189 + device.setType("default");
148 Device savedDevice = doPost("/api/device", device, Device.class); 190 Device savedDevice = doPost("/api/device", device, Device.class);
149 191
150 Customer customer = new Customer(); 192 Customer customer = new Customer();
@@ -170,6 +212,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -170,6 +212,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
170 public void testAssignDeviceToNonExistentCustomer() throws Exception { 212 public void testAssignDeviceToNonExistentCustomer() throws Exception {
171 Device device = new Device(); 213 Device device = new Device();
172 device.setName("My device"); 214 device.setName("My device");
  215 + device.setType("default");
173 Device savedDevice = doPost("/api/device", device, Device.class); 216 Device savedDevice = doPost("/api/device", device, Device.class);
174 217
175 doPost("/api/customer/" + UUIDs.timeBased().toString() 218 doPost("/api/customer/" + UUIDs.timeBased().toString()
@@ -203,6 +246,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -203,6 +246,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
203 246
204 Device device = new Device(); 247 Device device = new Device();
205 device.setName("My device"); 248 device.setName("My device");
  249 + device.setType("default");
206 Device savedDevice = doPost("/api/device", device, Device.class); 250 Device savedDevice = doPost("/api/device", device, Device.class);
207 251
208 doPost("/api/customer/" + savedCustomer.getId().getId().toString() 252 doPost("/api/customer/" + savedCustomer.getId().getId().toString()
@@ -219,6 +263,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -219,6 +263,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
219 public void testFindDeviceCredentialsByDeviceId() throws Exception { 263 public void testFindDeviceCredentialsByDeviceId() throws Exception {
220 Device device = new Device(); 264 Device device = new Device();
221 device.setName("My device"); 265 device.setName("My device");
  266 + device.setType("default");
222 Device savedDevice = doPost("/api/device", device, Device.class); 267 Device savedDevice = doPost("/api/device", device, Device.class);
223 DeviceCredentials deviceCredentials = 268 DeviceCredentials deviceCredentials =
224 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 269 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -229,6 +274,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -229,6 +274,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
229 public void testSaveDeviceCredentials() throws Exception { 274 public void testSaveDeviceCredentials() throws Exception {
230 Device device = new Device(); 275 Device device = new Device();
231 device.setName("My device"); 276 device.setName("My device");
  277 + device.setType("default");
232 Device savedDevice = doPost("/api/device", device, Device.class); 278 Device savedDevice = doPost("/api/device", device, Device.class);
233 DeviceCredentials deviceCredentials = 279 DeviceCredentials deviceCredentials =
234 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 280 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -255,6 +301,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -255,6 +301,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
255 public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception { 301 public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception {
256 Device device = new Device(); 302 Device device = new Device();
257 device.setName("My device"); 303 device.setName("My device");
  304 + device.setType("default");
258 Device savedDevice = doPost("/api/device", device, Device.class); 305 Device savedDevice = doPost("/api/device", device, Device.class);
259 DeviceCredentials deviceCredentials = 306 DeviceCredentials deviceCredentials =
260 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 307 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -268,6 +315,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -268,6 +315,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
268 public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception { 315 public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception {
269 Device device = new Device(); 316 Device device = new Device();
270 device.setName("My device"); 317 device.setName("My device");
  318 + device.setType("default");
271 Device savedDevice = doPost("/api/device", device, Device.class); 319 Device savedDevice = doPost("/api/device", device, Device.class);
272 DeviceCredentials deviceCredentials = 320 DeviceCredentials deviceCredentials =
273 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 321 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -281,6 +329,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -281,6 +329,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
281 public void testSaveNonExistentDeviceCredentials() throws Exception { 329 public void testSaveNonExistentDeviceCredentials() throws Exception {
282 Device device = new Device(); 330 Device device = new Device();
283 device.setName("My device"); 331 device.setName("My device");
  332 + device.setType("default");
284 Device savedDevice = doPost("/api/device", device, Device.class); 333 Device savedDevice = doPost("/api/device", device, Device.class);
285 DeviceCredentials deviceCredentials = 334 DeviceCredentials deviceCredentials =
286 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 335 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -298,6 +347,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -298,6 +347,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
298 public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception { 347 public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception {
299 Device device = new Device(); 348 Device device = new Device();
300 device.setName("My device"); 349 device.setName("My device");
  350 + device.setType("default");
301 Device savedDevice = doPost("/api/device", device, Device.class); 351 Device savedDevice = doPost("/api/device", device, Device.class);
302 DeviceCredentials deviceCredentials = 352 DeviceCredentials deviceCredentials =
303 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 353 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -307,9 +357,10 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -307,9 +357,10 @@ public class DeviceControllerTest extends AbstractControllerTest {
307 } 357 }
308 358
309 @Test 359 @Test
310 - public void testSaveDeviceCredentialsWithInvalidCredemtialsIdLength() throws Exception { 360 + public void testSaveDeviceCredentialsWithInvalidCredentialsIdLength() throws Exception {
311 Device device = new Device(); 361 Device device = new Device();
312 device.setName("My device"); 362 device.setName("My device");
  363 + device.setType("default");
313 Device savedDevice = doPost("/api/device", device, Device.class); 364 Device savedDevice = doPost("/api/device", device, Device.class);
314 DeviceCredentials deviceCredentials = 365 DeviceCredentials deviceCredentials =
315 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); 366 doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
@@ -325,6 +376,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -325,6 +376,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
325 for (int i=0;i<178;i++) { 376 for (int i=0;i<178;i++) {
326 Device device = new Device(); 377 Device device = new Device();
327 device.setName("Device"+i); 378 device.setName("Device"+i);
  379 + device.setType("default");
328 devices.add(doPost("/api/device", device, Device.class)); 380 devices.add(doPost("/api/device", device, Device.class));
329 } 381 }
330 List<Device> loadedDevices = new ArrayList<>(); 382 List<Device> loadedDevices = new ArrayList<>();
@@ -355,6 +407,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -355,6 +407,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
355 String name = title1+suffix; 407 String name = title1+suffix;
356 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 408 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
357 device.setName(name); 409 device.setName(name);
  410 + device.setType("default");
358 devicesTitle1.add(doPost("/api/device", device, Device.class)); 411 devicesTitle1.add(doPost("/api/device", device, Device.class));
359 } 412 }
360 String title2 = "Device title 2"; 413 String title2 = "Device title 2";
@@ -365,6 +418,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -365,6 +418,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
365 String name = title2+suffix; 418 String name = title2+suffix;
366 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 419 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
367 device.setName(name); 420 device.setName(name);
  421 + device.setType("default");
368 devicesTitle2.add(doPost("/api/device", device, Device.class)); 422 devicesTitle2.add(doPost("/api/device", device, Device.class));
369 } 423 }
370 424
@@ -423,6 +477,89 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -423,6 +477,89 @@ public class DeviceControllerTest extends AbstractControllerTest {
423 Assert.assertFalse(pageData.hasNext()); 477 Assert.assertFalse(pageData.hasNext());
424 Assert.assertEquals(0, pageData.getData().size()); 478 Assert.assertEquals(0, pageData.getData().size());
425 } 479 }
  480 +
  481 + @Test
  482 + public void testFindTenantDevicesByType() throws Exception {
  483 + String title1 = "Device title 1";
  484 + String type1 = "typeA";
  485 + List<Device> devicesType1 = new ArrayList<>();
  486 + for (int i=0;i<143;i++) {
  487 + Device device = new Device();
  488 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  489 + String name = title1+suffix;
  490 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  491 + device.setName(name);
  492 + device.setType(type1);
  493 + devicesType1.add(doPost("/api/device", device, Device.class));
  494 + }
  495 + String title2 = "Device title 2";
  496 + String type2 = "typeB";
  497 + List<Device> devicesType2 = new ArrayList<>();
  498 + for (int i=0;i<75;i++) {
  499 + Device device = new Device();
  500 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  501 + String name = title2+suffix;
  502 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  503 + device.setName(name);
  504 + device.setType(type2);
  505 + devicesType2.add(doPost("/api/device", device, Device.class));
  506 + }
  507 +
  508 + List<Device> loadedDevicesType1 = new ArrayList<>();
  509 + TextPageLink pageLink = new TextPageLink(15);
  510 + TextPageData<Device> pageData = null;
  511 + do {
  512 + pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
  513 + new TypeReference<TextPageData<Device>>(){}, pageLink, type1);
  514 + loadedDevicesType1.addAll(pageData.getData());
  515 + if (pageData.hasNext()) {
  516 + pageLink = pageData.getNextPageLink();
  517 + }
  518 + } while (pageData.hasNext());
  519 +
  520 + Collections.sort(devicesType1, idComparator);
  521 + Collections.sort(loadedDevicesType1, idComparator);
  522 +
  523 + Assert.assertEquals(devicesType1, loadedDevicesType1);
  524 +
  525 + List<Device> loadedDevicesType2 = new ArrayList<>();
  526 + pageLink = new TextPageLink(4);
  527 + do {
  528 + pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
  529 + new TypeReference<TextPageData<Device>>(){}, pageLink, type2);
  530 + loadedDevicesType2.addAll(pageData.getData());
  531 + if (pageData.hasNext()) {
  532 + pageLink = pageData.getNextPageLink();
  533 + }
  534 + } while (pageData.hasNext());
  535 +
  536 + Collections.sort(devicesType2, idComparator);
  537 + Collections.sort(loadedDevicesType2, idComparator);
  538 +
  539 + Assert.assertEquals(devicesType2, loadedDevicesType2);
  540 +
  541 + for (Device device : loadedDevicesType1) {
  542 + doDelete("/api/device/"+device.getId().getId().toString())
  543 + .andExpect(status().isOk());
  544 + }
  545 +
  546 + pageLink = new TextPageLink(4);
  547 + pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
  548 + new TypeReference<TextPageData<Device>>(){}, pageLink, type1);
  549 + Assert.assertFalse(pageData.hasNext());
  550 + Assert.assertEquals(0, pageData.getData().size());
  551 +
  552 + for (Device device : loadedDevicesType2) {
  553 + doDelete("/api/device/"+device.getId().getId().toString())
  554 + .andExpect(status().isOk());
  555 + }
  556 +
  557 + pageLink = new TextPageLink(4);
  558 + pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
  559 + new TypeReference<TextPageData<Device>>(){}, pageLink, type2);
  560 + Assert.assertFalse(pageData.hasNext());
  561 + Assert.assertEquals(0, pageData.getData().size());
  562 + }
426 563
427 @Test 564 @Test
428 public void testFindCustomerDevices() throws Exception { 565 public void testFindCustomerDevices() throws Exception {
@@ -435,6 +572,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -435,6 +572,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
435 for (int i=0;i<128;i++) { 572 for (int i=0;i<128;i++) {
436 Device device = new Device(); 573 Device device = new Device();
437 device.setName("Device"+i); 574 device.setName("Device"+i);
  575 + device.setType("default");
438 device = doPost("/api/device", device, Device.class); 576 device = doPost("/api/device", device, Device.class);
439 devices.add(doPost("/api/customer/" + customerId.getId().toString() 577 devices.add(doPost("/api/customer/" + customerId.getId().toString()
440 + "/device/" + device.getId().getId().toString(), Device.class)); 578 + "/device/" + device.getId().getId().toString(), Device.class));
@@ -473,6 +611,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -473,6 +611,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
473 String name = title1+suffix; 611 String name = title1+suffix;
474 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 612 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
475 device.setName(name); 613 device.setName(name);
  614 + device.setType("default");
476 device = doPost("/api/device", device, Device.class); 615 device = doPost("/api/device", device, Device.class);
477 devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString() 616 devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString()
478 + "/device/" + device.getId().getId().toString(), Device.class)); 617 + "/device/" + device.getId().getId().toString(), Device.class));
@@ -485,6 +624,7 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -485,6 +624,7 @@ public class DeviceControllerTest extends AbstractControllerTest {
485 String name = title2+suffix; 624 String name = title2+suffix;
486 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); 625 name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
487 device.setName(name); 626 device.setName(name);
  627 + device.setType("default");
488 device = doPost("/api/device", device, Device.class); 628 device = doPost("/api/device", device, Device.class);
489 devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString() 629 devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString()
490 + "/device/" + device.getId().getId().toString(), Device.class)); 630 + "/device/" + device.getId().getId().toString(), Device.class));
@@ -546,4 +686,96 @@ public class DeviceControllerTest extends AbstractControllerTest { @@ -546,4 +686,96 @@ public class DeviceControllerTest extends AbstractControllerTest {
546 Assert.assertEquals(0, pageData.getData().size()); 686 Assert.assertEquals(0, pageData.getData().size());
547 } 687 }
548 688
  689 + @Test
  690 + public void testFindCustomerDevicesByType() throws Exception {
  691 + Customer customer = new Customer();
  692 + customer.setTitle("Test customer");
  693 + customer = doPost("/api/customer", customer, Customer.class);
  694 + CustomerId customerId = customer.getId();
  695 +
  696 + String title1 = "Device title 1";
  697 + String type1 = "typeC";
  698 + List<Device> devicesType1 = new ArrayList<>();
  699 + for (int i=0;i<125;i++) {
  700 + Device device = new Device();
  701 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  702 + String name = title1+suffix;
  703 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  704 + device.setName(name);
  705 + device.setType(type1);
  706 + device = doPost("/api/device", device, Device.class);
  707 + devicesType1.add(doPost("/api/customer/" + customerId.getId().toString()
  708 + + "/device/" + device.getId().getId().toString(), Device.class));
  709 + }
  710 + String title2 = "Device title 2";
  711 + String type2 = "typeD";
  712 + List<Device> devicesType2 = new ArrayList<>();
  713 + for (int i=0;i<143;i++) {
  714 + Device device = new Device();
  715 + String suffix = RandomStringUtils.randomAlphanumeric(15);
  716 + String name = title2+suffix;
  717 + name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
  718 + device.setName(name);
  719 + device.setType(type2);
  720 + device = doPost("/api/device", device, Device.class);
  721 + devicesType2.add(doPost("/api/customer/" + customerId.getId().toString()
  722 + + "/device/" + device.getId().getId().toString(), Device.class));
  723 + }
  724 +
  725 + List<Device> loadedDevicesType1 = new ArrayList<>();
  726 + TextPageLink pageLink = new TextPageLink(15);
  727 + TextPageData<Device> pageData = null;
  728 + do {
  729 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
  730 + new TypeReference<TextPageData<Device>>(){}, pageLink, type1);
  731 + loadedDevicesType1.addAll(pageData.getData());
  732 + if (pageData.hasNext()) {
  733 + pageLink = pageData.getNextPageLink();
  734 + }
  735 + } while (pageData.hasNext());
  736 +
  737 + Collections.sort(devicesType1, idComparator);
  738 + Collections.sort(loadedDevicesType1, idComparator);
  739 +
  740 + Assert.assertEquals(devicesType1, loadedDevicesType1);
  741 +
  742 + List<Device> loadedDevicesType2 = new ArrayList<>();
  743 + pageLink = new TextPageLink(4);
  744 + do {
  745 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
  746 + new TypeReference<TextPageData<Device>>(){}, pageLink, type2);
  747 + loadedDevicesType2.addAll(pageData.getData());
  748 + if (pageData.hasNext()) {
  749 + pageLink = pageData.getNextPageLink();
  750 + }
  751 + } while (pageData.hasNext());
  752 +
  753 + Collections.sort(devicesType2, idComparator);
  754 + Collections.sort(loadedDevicesType2, idComparator);
  755 +
  756 + Assert.assertEquals(devicesType2, loadedDevicesType2);
  757 +
  758 + for (Device device : loadedDevicesType1) {
  759 + doDelete("/api/customer/device/" + device.getId().getId().toString())
  760 + .andExpect(status().isOk());
  761 + }
  762 +
  763 + pageLink = new TextPageLink(4);
  764 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
  765 + new TypeReference<TextPageData<Device>>(){}, pageLink, type1);
  766 + Assert.assertFalse(pageData.hasNext());
  767 + Assert.assertEquals(0, pageData.getData().size());
  768 +
  769 + for (Device device : loadedDevicesType2) {
  770 + doDelete("/api/customer/device/" + device.getId().getId().toString())
  771 + .andExpect(status().isOk());
  772 + }
  773 +
  774 + pageLink = new TextPageLink(4);
  775 + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&",
  776 + new TypeReference<TextPageData<Device>>(){}, pageLink, type2);
  777 + Assert.assertFalse(pageData.hasNext());
  778 + Assert.assertEquals(0, pageData.getData().size());
  779 + }
  780 +
549 } 781 }
@@ -130,7 +130,7 @@ public class TenantControllerTest extends AbstractControllerTest { @@ -130,7 +130,7 @@ public class TenantControllerTest extends AbstractControllerTest {
130 Assert.assertEquals(tenants, loadedTenants); 130 Assert.assertEquals(tenants, loadedTenants);
131 131
132 for (Tenant tenant : loadedTenants) { 132 for (Tenant tenant : loadedTenants) {
133 - if (!tenant.getTitle().equals("Tenant")) { 133 + if (!tenant.getTitle().equals(TEST_TENANT_NAME)) {
134 doDelete("/api/tenant/"+tenant.getId().getId().toString()) 134 doDelete("/api/tenant/"+tenant.getId().getId().toString())
135 .andExpect(status().isOk()); 135 .andExpect(status().isOk());
136 } 136 }
@@ -182,7 +182,7 @@ public class UserControllerTest extends AbstractControllerTest { @@ -182,7 +182,7 @@ public class UserControllerTest extends AbstractControllerTest {
182 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 182 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
183 Assert.assertNotNull(savedTenant); 183 Assert.assertNotNull(savedTenant);
184 184
185 - String email = "tenant@thingsboard.org"; 185 + String email = TENANT_ADMIN_EMAIL;
186 User user = new User(); 186 User user = new User();
187 user.setAuthority(Authority.TENANT_ADMIN); 187 user.setAuthority(Authority.TENANT_ADMIN);
188 user.setTenantId(savedTenant.getId()); 188 user.setTenantId(savedTenant.getId());
@@ -47,6 +47,7 @@ public class HttpDeviceApiTest extends AbstractControllerTest { @@ -47,6 +47,7 @@ public class HttpDeviceApiTest extends AbstractControllerTest {
47 loginTenantAdmin(); 47 loginTenantAdmin();
48 device = new Device(); 48 device = new Device();
49 device.setName("My device"); 49 device.setName("My device");
  50 + device.setType("default");
50 device = doPost("/api/device", device, Device.class); 51 device = doPost("/api/device", device, Device.class);
51 52
52 deviceCredentials = 53 deviceCredentials =
@@ -15,12 +15,14 @@ @@ -15,12 +15,14 @@
15 */ 15 */
16 package org.thingsboard.server.common.data; 16 package org.thingsboard.server.common.data;
17 17
  18 +import com.fasterxml.jackson.annotation.JsonProperty;
  19 +import com.fasterxml.jackson.annotation.JsonProperty.Access;
18 import org.thingsboard.server.common.data.id.CustomerId; 20 import org.thingsboard.server.common.data.id.CustomerId;
19 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
20 22
21 import com.fasterxml.jackson.databind.JsonNode; 23 import com.fasterxml.jackson.databind.JsonNode;
22 24
23 -public class Customer extends ContactBased<CustomerId>{ 25 +public class Customer extends ContactBased<CustomerId> implements HasName {
24 26
25 private static final long serialVersionUID = -1599722990298929275L; 27 private static final long serialVersionUID = -1599722990298929275L;
26 28
@@ -59,6 +61,12 @@ public class Customer extends ContactBased<CustomerId>{ @@ -59,6 +61,12 @@ public class Customer extends ContactBased<CustomerId>{
59 this.title = title; 61 this.title = title;
60 } 62 }
61 63
  64 + @Override
  65 + @JsonProperty(access = Access.READ_ONLY)
  66 + public String getName() {
  67 + return title;
  68 + }
  69 +
62 public JsonNode getAdditionalInfo() { 70 public JsonNode getAdditionalInfo() {
63 return additionalInfo; 71 return additionalInfo;
64 } 72 }
@@ -15,11 +15,12 @@ @@ -15,11 +15,12 @@
15 */ 15 */
16 package org.thingsboard.server.common.data; 16 package org.thingsboard.server.common.data;
17 17
  18 +import com.fasterxml.jackson.annotation.JsonProperty;
18 import org.thingsboard.server.common.data.id.CustomerId; 19 import org.thingsboard.server.common.data.id.CustomerId;
19 import org.thingsboard.server.common.data.id.DashboardId; 20 import org.thingsboard.server.common.data.id.DashboardId;
20 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
21 22
22 -public class DashboardInfo extends SearchTextBased<DashboardId> { 23 +public class DashboardInfo extends SearchTextBased<DashboardId> implements HasName {
23 24
24 private TenantId tenantId; 25 private TenantId tenantId;
25 private CustomerId customerId; 26 private CustomerId customerId;
@@ -65,6 +66,12 @@ public class DashboardInfo extends SearchTextBased<DashboardId> { @@ -65,6 +66,12 @@ public class DashboardInfo extends SearchTextBased<DashboardId> {
65 } 66 }
66 67
67 @Override 68 @Override
  69 + @JsonProperty(access = JsonProperty.Access.READ_ONLY)
  70 + public String getName() {
  71 + return title;
  72 + }
  73 +
  74 + @Override
68 public String getSearchText() { 75 public String getSearchText() {
69 return title; 76 return title;
70 } 77 }
@@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.id.TenantId;
21 21
22 import com.fasterxml.jackson.databind.JsonNode; 22 import com.fasterxml.jackson.databind.JsonNode;
23 23
24 -public class Device extends SearchTextBased<DeviceId> { 24 +public class Device extends SearchTextBased<DeviceId> implements HasName {
25 25
26 private static final long serialVersionUID = 2807343040519543363L; 26 private static final long serialVersionUID = 2807343040519543363L;
27 27
@@ -64,6 +64,7 @@ public class Device extends SearchTextBased<DeviceId> { @@ -64,6 +64,7 @@ public class Device extends SearchTextBased<DeviceId> {
64 this.customerId = customerId; 64 this.customerId = customerId;
65 } 65 }
66 66
  67 + @Override
67 public String getName() { 68 public String getName() {
68 return name; 69 return name;
69 } 70 }
@@ -13,33 +13,10 @@ @@ -13,33 +13,10 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -.tb-device-filter {  
17 - #device_list_chips {  
18 - .md-chips {  
19 - padding-bottom: 1px;  
20 - }  
21 - }  
22 - .device-name-filter-input {  
23 - margin-top: 10px;  
24 - margin-bottom: 0px;  
25 - .md-errors-spacer {  
26 - min-height: 0px;  
27 - }  
28 - }  
29 - .tb-filter-switch {  
30 - padding-left: 10px;  
31 - .filter-switch {  
32 - margin: 0;  
33 - }  
34 - .filter-label {  
35 - margin: 5px 0;  
36 - }  
37 - }  
38 - .tb-error-messages {  
39 - margin-top: -11px;  
40 - height: 35px;  
41 - .tb-error-message {  
42 - padding-left: 1px;  
43 - }  
44 - }  
45 -}  
  16 +package org.thingsboard.server.common.data;
  17 +
  18 +public interface HasName {
  19 +
  20 + String getName();
  21 +
  22 +}
@@ -15,11 +15,12 @@ @@ -15,11 +15,12 @@
15 */ 15 */
16 package org.thingsboard.server.common.data; 16 package org.thingsboard.server.common.data;
17 17
  18 +import com.fasterxml.jackson.annotation.JsonProperty;
18 import org.thingsboard.server.common.data.id.TenantId; 19 import org.thingsboard.server.common.data.id.TenantId;
19 20
20 import com.fasterxml.jackson.databind.JsonNode; 21 import com.fasterxml.jackson.databind.JsonNode;
21 22
22 -public class Tenant extends ContactBased<TenantId>{ 23 +public class Tenant extends ContactBased<TenantId> implements HasName {
23 24
24 private static final long serialVersionUID = 8057243243859922101L; 25 private static final long serialVersionUID = 8057243243859922101L;
25 26
@@ -50,6 +51,12 @@ public class Tenant extends ContactBased<TenantId>{ @@ -50,6 +51,12 @@ public class Tenant extends ContactBased<TenantId>{
50 this.title = title; 51 this.title = title;
51 } 52 }
52 53
  54 + @Override
  55 + @JsonProperty(access = JsonProperty.Access.READ_ONLY)
  56 + public String getName() {
  57 + return title;
  58 + }
  59 +
53 public String getRegion() { 60 public String getRegion() {
54 return region; 61 return region;
55 } 62 }
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data;
  17 +
  18 +import org.thingsboard.server.common.data.id.TenantId;
  19 +
  20 +public class TenantDeviceType {
  21 +
  22 + private static final long serialVersionUID = 8057240243859922101L;
  23 +
  24 + private String type;
  25 + private TenantId tenantId;
  26 +
  27 + public TenantDeviceType() {
  28 + super();
  29 + }
  30 +
  31 + public TenantDeviceType(String type, TenantId tenantId) {
  32 + this.type = type;
  33 + this.tenantId = tenantId;
  34 + }
  35 +
  36 + public String getType() {
  37 + return type;
  38 + }
  39 +
  40 + public void setType(String type) {
  41 + this.type = type;
  42 + }
  43 +
  44 + public TenantId getTenantId() {
  45 + return tenantId;
  46 + }
  47 +
  48 + public void setTenantId(TenantId tenantId) {
  49 + this.tenantId = tenantId;
  50 + }
  51 +
  52 + @Override
  53 + public int hashCode() {
  54 + int result = type != null ? type.hashCode() : 0;
  55 + result = 31 * result + (tenantId != null ? tenantId.hashCode() : 0);
  56 + return result;
  57 + }
  58 +
  59 + @Override
  60 + public boolean equals(Object o) {
  61 + if (this == o) return true;
  62 + if (o == null || getClass() != o.getClass()) return false;
  63 +
  64 + TenantDeviceType that = (TenantDeviceType) o;
  65 +
  66 + if (type != null ? !type.equals(that.type) : that.type != null) return false;
  67 + return tenantId != null ? tenantId.equals(that.tenantId) : that.tenantId == null;
  68 +
  69 + }
  70 +
  71 + @Override
  72 + public String toString() {
  73 + final StringBuilder sb = new StringBuilder("TenantDeviceType{");
  74 + sb.append("type='").append(type).append('\'');
  75 + sb.append(", tenantId=").append(tenantId);
  76 + sb.append('}');
  77 + return sb.toString();
  78 + }
  79 +}
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.common.data; 16 package org.thingsboard.server.common.data;
17 17
  18 +import com.fasterxml.jackson.annotation.JsonProperty;
18 import org.thingsboard.server.common.data.id.CustomerId; 19 import org.thingsboard.server.common.data.id.CustomerId;
19 import org.thingsboard.server.common.data.id.TenantId; 20 import org.thingsboard.server.common.data.id.TenantId;
20 import org.thingsboard.server.common.data.id.UserId; 21 import org.thingsboard.server.common.data.id.UserId;
@@ -22,7 +23,7 @@ import org.thingsboard.server.common.data.security.Authority; @@ -22,7 +23,7 @@ import org.thingsboard.server.common.data.security.Authority;
22 23
23 import com.fasterxml.jackson.databind.JsonNode; 24 import com.fasterxml.jackson.databind.JsonNode;
24 25
25 -public class User extends SearchTextBased<UserId> { 26 +public class User extends SearchTextBased<UserId> implements HasName {
26 27
27 private static final long serialVersionUID = 8250339805336035966L; 28 private static final long serialVersionUID = 8250339805336035966L;
28 29
@@ -77,6 +78,12 @@ public class User extends SearchTextBased<UserId> { @@ -77,6 +78,12 @@ public class User extends SearchTextBased<UserId> {
77 this.email = email; 78 this.email = email;
78 } 79 }
79 80
  81 + @Override
  82 + @JsonProperty(access = JsonProperty.Access.READ_ONLY)
  83 + public String getName() {
  84 + return email;
  85 + }
  86 +
80 public Authority getAuthority() { 87 public Authority getAuthority() {
81 return authority; 88 return authority;
82 } 89 }
@@ -15,26 +15,47 @@ @@ -15,26 +15,47 @@
15 */ 15 */
16 package org.thingsboard.server.common.data.alarm; 16 package org.thingsboard.server.common.data.alarm;
17 17
  18 +import com.fasterxml.jackson.annotation.JsonProperty;
18 import com.fasterxml.jackson.databind.JsonNode; 19 import com.fasterxml.jackson.databind.JsonNode;
  20 +import lombok.AllArgsConstructor;
  21 +import lombok.Builder;
19 import lombok.Data; 22 import lombok.Data;
20 import org.thingsboard.server.common.data.BaseData; 23 import org.thingsboard.server.common.data.BaseData;
  24 +import org.thingsboard.server.common.data.HasName;
21 import org.thingsboard.server.common.data.id.EntityId; 25 import org.thingsboard.server.common.data.id.EntityId;
  26 +import org.thingsboard.server.common.data.id.TenantId;
22 27
23 /** 28 /**
24 * Created by ashvayka on 11.05.17. 29 * Created by ashvayka on 11.05.17.
25 */ 30 */
26 @Data 31 @Data
27 -public class Alarm extends BaseData<AlarmId> { 32 +@Builder
  33 +@AllArgsConstructor
  34 +public class Alarm extends BaseData<AlarmId> implements HasName {
28 35
29 - private long startTs;  
30 - private long endTs;  
31 - private long ackTs;  
32 - private long clearTs; 36 + private TenantId tenantId;
33 private String type; 37 private String type;
34 private EntityId originator; 38 private EntityId originator;
35 private AlarmSeverity severity; 39 private AlarmSeverity severity;
36 private AlarmStatus status; 40 private AlarmStatus status;
  41 + private long startTs;
  42 + private long endTs;
  43 + private long ackTs;
  44 + private long clearTs;
37 private JsonNode details; 45 private JsonNode details;
38 private boolean propagate; 46 private boolean propagate;
39 47
  48 + public Alarm() {
  49 + super();
  50 + }
  51 +
  52 + public Alarm(AlarmId id) {
  53 + super(id);
  54 + }
  55 +
  56 + @Override
  57 + @JsonProperty(access = JsonProperty.Access.READ_ONLY)
  58 + public String getName() {
  59 + return type;
  60 + }
40 } 61 }
@@ -15,14 +15,19 @@ @@ -15,14 +15,19 @@
15 */ 15 */
16 package org.thingsboard.server.common.data.alarm; 16 package org.thingsboard.server.common.data.alarm;
17 17
  18 +import lombok.AllArgsConstructor;
  19 +import lombok.Builder;
18 import lombok.Data; 20 import lombok.Data;
19 import org.thingsboard.server.common.data.id.EntityId; 21 import org.thingsboard.server.common.data.id.EntityId;
  22 +import org.thingsboard.server.common.data.id.TenantId;
20 import org.thingsboard.server.common.data.page.TimePageLink; 23 import org.thingsboard.server.common.data.page.TimePageLink;
21 24
22 /** 25 /**
23 * Created by ashvayka on 11.05.17. 26 * Created by ashvayka on 11.05.17.
24 */ 27 */
25 @Data 28 @Data
  29 +@Builder
  30 +@AllArgsConstructor
26 public class AlarmQuery { 31 public class AlarmQuery {
27 32
28 private EntityId affectedEntityId; 33 private EntityId affectedEntityId;
@@ -22,4 +22,12 @@ public enum AlarmStatus { @@ -22,4 +22,12 @@ public enum AlarmStatus {
22 22
23 ACTIVE_UNACK, ACTIVE_ACK, CLEARED_UNACK, CLEARED_ACK; 23 ACTIVE_UNACK, ACTIVE_ACK, CLEARED_UNACK, CLEARED_ACK;
24 24
  25 + public boolean isAck() {
  26 + return this == ACTIVE_ACK || this == CLEARED_ACK;
  27 + }
  28 +
  29 + public boolean isCleared() {
  30 + return this == CLEARED_ACK || this == CLEARED_UNACK;
  31 + }
  32 +
25 } 33 }
@@ -16,12 +16,13 @@ @@ -16,12 +16,13 @@
16 package org.thingsboard.server.common.data.asset; 16 package org.thingsboard.server.common.data.asset;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import org.thingsboard.server.common.data.HasName;
19 import org.thingsboard.server.common.data.SearchTextBased; 20 import org.thingsboard.server.common.data.SearchTextBased;
20 import org.thingsboard.server.common.data.id.AssetId; 21 import org.thingsboard.server.common.data.id.AssetId;
21 import org.thingsboard.server.common.data.id.CustomerId; 22 import org.thingsboard.server.common.data.id.CustomerId;
22 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
23 24
24 -public class Asset extends SearchTextBased<AssetId> { 25 +public class Asset extends SearchTextBased<AssetId> implements HasName {
25 26
26 private static final long serialVersionUID = 2807343040519543363L; 27 private static final long serialVersionUID = 2807343040519543363L;
27 28
@@ -64,6 +65,7 @@ public class Asset extends SearchTextBased<AssetId> { @@ -64,6 +65,7 @@ public class Asset extends SearchTextBased<AssetId> {
64 this.customerId = customerId; 65 this.customerId = customerId;
65 } 66 }
66 67
  68 + @Override
67 public String getName() { 69 public String getName() {
68 return name; 70 return name;
69 } 71 }
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.asset;
  17 +
  18 +import org.thingsboard.server.common.data.id.TenantId;
  19 +
  20 +public class TenantAssetType {
  21 +
  22 + private static final long serialVersionUID = 8057290243855622101L;
  23 +
  24 + private String type;
  25 + private TenantId tenantId;
  26 +
  27 + public TenantAssetType() {
  28 + super();
  29 + }
  30 +
  31 + public TenantAssetType(String type, TenantId tenantId) {
  32 + this.type = type;
  33 + this.tenantId = tenantId;
  34 + }
  35 +
  36 + public String getType() {
  37 + return type;
  38 + }
  39 +
  40 + public void setType(String type) {
  41 + this.type = type;
  42 + }
  43 +
  44 + public TenantId getTenantId() {
  45 + return tenantId;
  46 + }
  47 +
  48 + public void setTenantId(TenantId tenantId) {
  49 + this.tenantId = tenantId;
  50 + }
  51 +
  52 + @Override
  53 + public int hashCode() {
  54 + int result = type != null ? type.hashCode() : 0;
  55 + result = 31 * result + (tenantId != null ? tenantId.hashCode() : 0);
  56 + return result;
  57 + }
  58 +
  59 + @Override
  60 + public boolean equals(Object o) {
  61 + if (this == o) return true;
  62 + if (o == null || getClass() != o.getClass()) return false;
  63 +
  64 + TenantAssetType that = (TenantAssetType) o;
  65 +
  66 + if (type != null ? !type.equals(that.type) : that.type != null) return false;
  67 + return tenantId != null ? tenantId.equals(that.tenantId) : that.tenantId == null;
  68 +
  69 + }
  70 +
  71 + @Override
  72 + public String toString() {
  73 + final StringBuilder sb = new StringBuilder("TenantAssetType{");
  74 + sb.append("type='").append(type).append('\'');
  75 + sb.append(", tenantId=").append(tenantId);
  76 + sb.append('}');
  77 + return sb.toString();
  78 + }
  79 +}
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 package org.thingsboard.server.common.data.id; 16 package org.thingsboard.server.common.data.id;
17 17
18 import org.thingsboard.server.common.data.EntityType; 18 import org.thingsboard.server.common.data.EntityType;
  19 +import org.thingsboard.server.common.data.alarm.AlarmId;
19 20
20 import java.util.UUID; 21 import java.util.UUID;
21 22
@@ -50,6 +51,8 @@ public class EntityIdFactory { @@ -50,6 +51,8 @@ public class EntityIdFactory {
50 return new DeviceId(uuid); 51 return new DeviceId(uuid);
51 case ASSET: 52 case ASSET:
52 return new AssetId(uuid); 53 return new AssetId(uuid);
  54 + case ALARM:
  55 + return new AlarmId(uuid);
53 } 56 }
54 throw new IllegalArgumentException("EntityType " + type + " is not supported!"); 57 throw new IllegalArgumentException("EntityType " + type + " is not supported!");
55 } 58 }
@@ -15,13 +15,14 @@ @@ -15,13 +15,14 @@
15 */ 15 */
16 package org.thingsboard.server.common.data.plugin; 16 package org.thingsboard.server.common.data.plugin;
17 17
  18 +import org.thingsboard.server.common.data.HasName;
18 import org.thingsboard.server.common.data.SearchTextBased; 19 import org.thingsboard.server.common.data.SearchTextBased;
19 import org.thingsboard.server.common.data.id.PluginId; 20 import org.thingsboard.server.common.data.id.PluginId;
20 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
21 22
22 import com.fasterxml.jackson.databind.JsonNode; 23 import com.fasterxml.jackson.databind.JsonNode;
23 24
24 -public class PluginMetaData extends SearchTextBased<PluginId> { 25 +public class PluginMetaData extends SearchTextBased<PluginId> implements HasName {
25 26
26 private static final long serialVersionUID = 1L; 27 private static final long serialVersionUID = 1L;
27 28
@@ -75,6 +76,7 @@ public class PluginMetaData extends SearchTextBased<PluginId> { @@ -75,6 +76,7 @@ public class PluginMetaData extends SearchTextBased<PluginId> {
75 this.tenantId = tenantId; 76 this.tenantId = tenantId;
76 } 77 }
77 78
  79 + @Override
78 public String getName() { 80 public String getName() {
79 return name; 81 return name;
80 } 82 }
@@ -30,6 +30,7 @@ public class EntityRelation { @@ -30,6 +30,7 @@ public class EntityRelation {
30 private EntityId from; 30 private EntityId from;
31 private EntityId to; 31 private EntityId to;
32 private String type; 32 private String type;
  33 + private RelationTypeGroup typeGroup;
33 private JsonNode additionalInfo; 34 private JsonNode additionalInfo;
34 35
35 public EntityRelation() { 36 public EntityRelation() {
@@ -37,21 +38,27 @@ public class EntityRelation { @@ -37,21 +38,27 @@ public class EntityRelation {
37 } 38 }
38 39
39 public EntityRelation(EntityId from, EntityId to, String type) { 40 public EntityRelation(EntityId from, EntityId to, String type) {
40 - this(from, to, type, null); 41 + this(from, to, type, RelationTypeGroup.COMMON);
41 } 42 }
42 43
43 - public EntityRelation(EntityId from, EntityId to, String type, JsonNode additionalInfo) { 44 + public EntityRelation(EntityId from, EntityId to, String type, RelationTypeGroup typeGroup) {
  45 + this(from, to, type, typeGroup, null);
  46 + }
  47 +
  48 + public EntityRelation(EntityId from, EntityId to, String type, RelationTypeGroup typeGroup, JsonNode additionalInfo) {
44 this.from = from; 49 this.from = from;
45 this.to = to; 50 this.to = to;
46 this.type = type; 51 this.type = type;
  52 + this.typeGroup = typeGroup;
47 this.additionalInfo = additionalInfo; 53 this.additionalInfo = additionalInfo;
48 } 54 }
49 55
50 - public EntityRelation(EntityRelation device) {  
51 - this.from = device.getFrom();  
52 - this.to = device.getTo();  
53 - this.type = device.getType();  
54 - this.additionalInfo = device.getAdditionalInfo(); 56 + public EntityRelation(EntityRelation entityRelation) {
  57 + this.from = entityRelation.getFrom();
  58 + this.to = entityRelation.getTo();
  59 + this.type = entityRelation.getType();
  60 + this.typeGroup = entityRelation.getTypeGroup();
  61 + this.additionalInfo = entityRelation.getAdditionalInfo();
55 } 62 }
56 63
57 public EntityId getFrom() { 64 public EntityId getFrom() {
@@ -78,6 +85,14 @@ public class EntityRelation { @@ -78,6 +85,14 @@ public class EntityRelation {
78 this.type = type; 85 this.type = type;
79 } 86 }
80 87
  88 + public RelationTypeGroup getTypeGroup() {
  89 + return typeGroup;
  90 + }
  91 +
  92 + public void setTypeGroup(RelationTypeGroup typeGroup) {
  93 + this.typeGroup = typeGroup;
  94 + }
  95 +
81 public JsonNode getAdditionalInfo() { 96 public JsonNode getAdditionalInfo() {
82 return additionalInfo; 97 return additionalInfo;
83 } 98 }
@@ -90,14 +105,22 @@ public class EntityRelation { @@ -90,14 +105,22 @@ public class EntityRelation {
90 public boolean equals(Object o) { 105 public boolean equals(Object o) {
91 if (this == o) return true; 106 if (this == o) return true;
92 if (o == null || getClass() != o.getClass()) return false; 107 if (o == null || getClass() != o.getClass()) return false;
93 - EntityRelation relation = (EntityRelation) o;  
94 - return Objects.equals(from, relation.from) &&  
95 - Objects.equals(to, relation.to) &&  
96 - Objects.equals(type, relation.type); 108 +
  109 + EntityRelation that = (EntityRelation) o;
  110 +
  111 + if (from != null ? !from.equals(that.from) : that.from != null) return false;
  112 + if (to != null ? !to.equals(that.to) : that.to != null) return false;
  113 + if (type != null ? !type.equals(that.type) : that.type != null) return false;
  114 + return typeGroup == that.typeGroup;
  115 +
97 } 116 }
98 117
99 @Override 118 @Override
100 public int hashCode() { 119 public int hashCode() {
101 - return Objects.hash(from, to, type); 120 + int result = from != null ? from.hashCode() : 0;
  121 + result = 31 * result + (to != null ? to.hashCode() : 0);
  122 + result = 31 * result + (type != null ? type.hashCode() : 0);
  123 + result = 31 * result + (typeGroup != null ? typeGroup.hashCode() : 0);
  124 + return result;
102 } 125 }
103 } 126 }
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.common.data.relation;
  18 +
  19 +public class EntityRelationInfo extends EntityRelation {
  20 +
  21 + private static final long serialVersionUID = 2807343097519543363L;
  22 +
  23 + private String fromName;
  24 + private String toName;
  25 +
  26 + public EntityRelationInfo() {
  27 + super();
  28 + }
  29 +
  30 + public EntityRelationInfo(EntityRelation entityRelation) {
  31 + super(entityRelation);
  32 + }
  33 +
  34 + public String getFromName() {
  35 + return fromName;
  36 + }
  37 +
  38 + public void setFromName(String fromName) {
  39 + this.fromName = fromName;
  40 + }
  41 +
  42 + public String getToName() {
  43 + return toName;
  44 + }
  45 +
  46 + public void setToName(String toName) {
  47 + this.toName = toName;
  48 + }
  49 +
  50 + @Override
  51 + public boolean equals(Object o) {
  52 + if (this == o) return true;
  53 + if (o == null || getClass() != o.getClass()) return false;
  54 + if (!super.equals(o)) return false;
  55 +
  56 + EntityRelationInfo that = (EntityRelationInfo) o;
  57 +
  58 + return toName != null ? toName.equals(that.toName) : that.toName == null;
  59 +
  60 + }
  61 +
  62 + @Override
  63 + public int hashCode() {
  64 + int result = super.hashCode();
  65 + result = 31 * result + (toName != null ? toName.hashCode() : 0);
  66 + return result;
  67 + }
  68 +}
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.relation;
  17 +
  18 +public enum RelationTypeGroup {
  19 +
  20 + COMMON,
  21 + ALARM
  22 +
  23 +}
@@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.rule; @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.rule;
17 17
18 import lombok.Data; 18 import lombok.Data;
19 import lombok.ToString; 19 import lombok.ToString;
  20 +import org.thingsboard.server.common.data.HasName;
20 import org.thingsboard.server.common.data.SearchTextBased; 21 import org.thingsboard.server.common.data.SearchTextBased;
21 import org.thingsboard.server.common.data.id.CustomerId; 22 import org.thingsboard.server.common.data.id.CustomerId;
22 import org.thingsboard.server.common.data.id.RuleId; 23 import org.thingsboard.server.common.data.id.RuleId;
@@ -26,7 +27,7 @@ import com.fasterxml.jackson.databind.JsonNode; @@ -26,7 +27,7 @@ import com.fasterxml.jackson.databind.JsonNode;
26 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; 27 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
27 28
28 @Data 29 @Data
29 -public class RuleMetaData extends SearchTextBased<RuleId> { 30 +public class RuleMetaData extends SearchTextBased<RuleId> implements HasName {
30 31
31 private static final long serialVersionUID = -5656679015122935465L; 32 private static final long serialVersionUID = -5656679015122935465L;
32 33
@@ -66,4 +67,9 @@ public class RuleMetaData extends SearchTextBased<RuleId> { @@ -66,4 +67,9 @@ public class RuleMetaData extends SearchTextBased<RuleId> {
66 return name; 67 return name;
67 } 68 }
68 69
  70 + @Override
  71 + public String getName() {
  72 + return name;
  73 + }
  74 +
69 } 75 }
@@ -127,7 +127,7 @@ public abstract class AbstractModelDao<T extends BaseEntity<?>> extends Abstract @@ -127,7 +127,7 @@ public abstract class AbstractModelDao<T extends BaseEntity<?>> extends Abstract
127 log.debug("Save entity {}", entity); 127 log.debug("Save entity {}", entity);
128 if (entity.getId() == null) { 128 if (entity.getId() == null) {
129 entity.setId(UUIDs.timeBased()); 129 entity.setId(UUIDs.timeBased());
130 - } else { 130 + } else if (isDeleteOnSave()) {
131 removeById(entity.getId()); 131 removeById(entity.getId());
132 } 132 }
133 Statement saveStatement = getSaveQuery(entity); 133 Statement saveStatement = getSaveQuery(entity);
@@ -136,6 +136,10 @@ public abstract class AbstractModelDao<T extends BaseEntity<?>> extends Abstract @@ -136,6 +136,10 @@ public abstract class AbstractModelDao<T extends BaseEntity<?>> extends Abstract
136 return new EntityResultSet<>(resultSet, entity); 136 return new EntityResultSet<>(resultSet, entity);
137 } 137 }
138 138
  139 + protected boolean isDeleteOnSave() {
  140 + return true;
  141 + }
  142 +
139 public T save(T entity) { 143 public T save(T entity) {
140 return saveWithResult(entity).getEntity(); 144 return saveWithResult(entity).getEntity();
141 } 145 }
@@ -161,9 +165,18 @@ public abstract class AbstractModelDao<T extends BaseEntity<?>> extends Abstract @@ -161,9 +165,18 @@ public abstract class AbstractModelDao<T extends BaseEntity<?>> extends Abstract
161 return getSession().execute(delete); 165 return getSession().execute(delete);
162 } 166 }
163 167
164 -  
165 public List<T> find() { 168 public List<T> find() {
166 log.debug("Get all entities from column family {}", getColumnFamilyName()); 169 log.debug("Get all entities from column family {}", getColumnFamilyName());
167 return findListByStatement(QueryBuilder.select().all().from(getColumnFamilyName()).setConsistencyLevel(cluster.getDefaultReadConsistencyLevel())); 170 return findListByStatement(QueryBuilder.select().all().from(getColumnFamilyName()).setConsistencyLevel(cluster.getDefaultReadConsistencyLevel()));
168 } 171 }
  172 +
  173 + protected static <T> Function<BaseEntity<T>, T> toDataFunction() {
  174 + return new Function<BaseEntity<T>, T>() {
  175 + @Nullable
  176 + @Override
  177 + public T apply(@Nullable BaseEntity<T> entity) {
  178 + return entity != null ? entity.toData() : null;
  179 + }
  180 + };
  181 + }
169 } 182 }
@@ -47,8 +47,27 @@ public abstract class AbstractSearchTimeDao<T extends BaseEntity<?>> extends Abs @@ -47,8 +47,27 @@ public abstract class AbstractSearchTimeDao<T extends BaseEntity<?>> extends Abs
47 return findPageWithTimeSearch(searchView, clauses, Collections.singletonList(ordering), pageLink); 47 return findPageWithTimeSearch(searchView, clauses, Collections.singletonList(ordering), pageLink);
48 } 48 }
49 49
50 -  
51 protected List<T> findPageWithTimeSearch(String searchView, List<Clause> clauses, List<Ordering> topLevelOrderings, TimePageLink pageLink) { 50 protected List<T> findPageWithTimeSearch(String searchView, List<Clause> clauses, List<Ordering> topLevelOrderings, TimePageLink pageLink) {
  51 + return findPageWithTimeSearch(searchView, clauses, topLevelOrderings, pageLink, ModelConstants.ID_PROPERTY);
  52 + }
  53 +
  54 + protected List<T> findPageWithTimeSearch(String searchView, List<Clause> clauses, TimePageLink pageLink, String idColumn) {
  55 + return findPageWithTimeSearch(searchView, clauses, Collections.emptyList(), pageLink, idColumn);
  56 + }
  57 +
  58 + protected List<T> findPageWithTimeSearch(String searchView, List<Clause> clauses, List<Ordering> topLevelOrderings, TimePageLink pageLink, String idColumn) {
  59 + return findListByStatement(buildQuery(searchView, clauses, topLevelOrderings, pageLink, idColumn));
  60 + }
  61 +
  62 + public static Where buildQuery(String searchView, List<Clause> clauses, TimePageLink pageLink, String idColumn) {
  63 + return buildQuery(searchView, clauses, Collections.emptyList(), pageLink, idColumn);
  64 + }
  65 +
  66 + public static Where buildQuery(String searchView, List<Clause> clauses, Ordering order, TimePageLink pageLink, String idColumn) {
  67 + return buildQuery(searchView, clauses, Collections.singletonList(order), pageLink, idColumn);
  68 + }
  69 +
  70 + public static Where buildQuery(String searchView, List<Clause> clauses, List<Ordering> topLevelOrderings, TimePageLink pageLink, String idColumn) {
52 Select select = select().from(searchView); 71 Select select = select().from(searchView);
53 Where query = select.where(); 72 Where query = select.where();
54 for (Clause clause : clauses) { 73 for (Clause clause : clauses) {
@@ -57,34 +76,35 @@ public abstract class AbstractSearchTimeDao<T extends BaseEntity<?>> extends Abs @@ -57,34 +76,35 @@ public abstract class AbstractSearchTimeDao<T extends BaseEntity<?>> extends Abs
57 query.limit(pageLink.getLimit()); 76 query.limit(pageLink.getLimit());
58 if (pageLink.isAscOrder()) { 77 if (pageLink.isAscOrder()) {
59 if (pageLink.getIdOffset() != null) { 78 if (pageLink.getIdOffset() != null) {
60 - query.and(QueryBuilder.gt(ModelConstants.ID_PROPERTY, pageLink.getIdOffset())); 79 + query.and(QueryBuilder.gt(idColumn, pageLink.getIdOffset()));
61 } else if (pageLink.getStartTime() != null) { 80 } else if (pageLink.getStartTime() != null) {
62 final UUID startOf = UUIDs.startOf(pageLink.getStartTime()); 81 final UUID startOf = UUIDs.startOf(pageLink.getStartTime());
63 - query.and(QueryBuilder.gte(ModelConstants.ID_PROPERTY, startOf)); 82 + query.and(QueryBuilder.gte(idColumn, startOf));
64 } 83 }
65 if (pageLink.getEndTime() != null) { 84 if (pageLink.getEndTime() != null) {
66 final UUID endOf = UUIDs.endOf(pageLink.getEndTime()); 85 final UUID endOf = UUIDs.endOf(pageLink.getEndTime());
67 - query.and(QueryBuilder.lte(ModelConstants.ID_PROPERTY, endOf)); 86 + query.and(QueryBuilder.lte(idColumn, endOf));
68 } 87 }
69 } else { 88 } else {
70 if (pageLink.getIdOffset() != null) { 89 if (pageLink.getIdOffset() != null) {
71 - query.and(QueryBuilder.lt(ModelConstants.ID_PROPERTY, pageLink.getIdOffset())); 90 + query.and(QueryBuilder.lt(idColumn, pageLink.getIdOffset()));
72 } else if (pageLink.getEndTime() != null) { 91 } else if (pageLink.getEndTime() != null) {
73 final UUID endOf = UUIDs.endOf(pageLink.getEndTime()); 92 final UUID endOf = UUIDs.endOf(pageLink.getEndTime());
74 - query.and(QueryBuilder.lte(ModelConstants.ID_PROPERTY, endOf)); 93 + query.and(QueryBuilder.lte(idColumn, endOf));
75 } 94 }
76 if (pageLink.getStartTime() != null) { 95 if (pageLink.getStartTime() != null) {
77 final UUID startOf = UUIDs.startOf(pageLink.getStartTime()); 96 final UUID startOf = UUIDs.startOf(pageLink.getStartTime());
78 - query.and(QueryBuilder.gte(ModelConstants.ID_PROPERTY, startOf)); 97 + query.and(QueryBuilder.gte(idColumn, startOf));
79 } 98 }
80 } 99 }
81 List<Ordering> orderings = new ArrayList<>(topLevelOrderings); 100 List<Ordering> orderings = new ArrayList<>(topLevelOrderings);
82 if (pageLink.isAscOrder()) { 101 if (pageLink.isAscOrder()) {
83 - orderings.add(QueryBuilder.asc(ModelConstants.ID_PROPERTY)); 102 + orderings.add(QueryBuilder.asc(idColumn));
84 } else { 103 } else {
85 - orderings.add(QueryBuilder.desc(ModelConstants.ID_PROPERTY)); 104 + orderings.add(QueryBuilder.desc(idColumn));
86 } 105 }
87 query.orderBy(orderings.toArray(new Ordering[orderings.size()])); 106 query.orderBy(orderings.toArray(new Ordering[orderings.size()]));
88 - return findListByStatement(query); 107 + return query;
89 } 108 }
  109 +
90 } 110 }
@@ -15,8 +15,27 @@ @@ -15,8 +15,27 @@
15 */ 15 */
16 package org.thingsboard.server.dao.alarm; 16 package org.thingsboard.server.dao.alarm;
17 17
  18 +import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.common.data.alarm.Alarm;
  20 +import org.thingsboard.server.common.data.alarm.AlarmQuery;
  21 +import org.thingsboard.server.common.data.id.EntityId;
  22 +import org.thingsboard.server.common.data.id.TenantId;
  23 +import org.thingsboard.server.dao.Dao;
  24 +import org.thingsboard.server.dao.model.AlarmEntity;
  25 +
  26 +import java.util.List;
  27 +import java.util.UUID;
  28 +
18 /** 29 /**
19 * Created by ashvayka on 11.05.17. 30 * Created by ashvayka on 11.05.17.
20 */ 31 */
21 -public interface AlarmDao { 32 +public interface AlarmDao extends Dao<AlarmEntity> {
  33 +
  34 + ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type);
  35 +
  36 + ListenableFuture<Alarm> findAlarmByIdAsync(UUID key);
  37 +
  38 + AlarmEntity save(Alarm alarm);
  39 +
  40 + ListenableFuture<List<Alarm>> findAlarms(AlarmQuery query);
22 } 41 }
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.alarm;
  17 +
  18 +import com.datastax.driver.core.querybuilder.QueryBuilder;
  19 +import com.datastax.driver.core.querybuilder.Select;
  20 +import com.google.common.util.concurrent.AsyncFunction;
  21 +import com.google.common.util.concurrent.Futures;
  22 +import com.google.common.util.concurrent.ListenableFuture;
  23 +import lombok.extern.slf4j.Slf4j;
  24 +import org.springframework.beans.factory.annotation.Autowired;
  25 +import org.springframework.stereotype.Component;
  26 +import org.thingsboard.server.common.data.EntityType;
  27 +import org.thingsboard.server.common.data.alarm.Alarm;
  28 +import org.thingsboard.server.common.data.alarm.AlarmQuery;
  29 +import org.thingsboard.server.common.data.id.EntityId;
  30 +import org.thingsboard.server.common.data.id.TenantId;
  31 +import org.thingsboard.server.common.data.relation.EntityRelation;
  32 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
  33 +import org.thingsboard.server.dao.AbstractModelDao;
  34 +import org.thingsboard.server.dao.AbstractSearchTimeDao;
  35 +import org.thingsboard.server.dao.model.AlarmEntity;
  36 +import org.thingsboard.server.dao.model.ModelConstants;
  37 +import org.thingsboard.server.dao.relation.RelationDao;
  38 +
  39 +import java.util.ArrayList;
  40 +import java.util.List;
  41 +import java.util.UUID;
  42 +
  43 +import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
  44 +import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
  45 +import static org.thingsboard.server.dao.model.ModelConstants.*;
  46 +
  47 +@Component
  48 +@Slf4j
  49 +public class AlarmDaoImpl extends AbstractModelDao<AlarmEntity> implements AlarmDao {
  50 +
  51 + @Autowired
  52 + private RelationDao relationDao;
  53 +
  54 + @Override
  55 + protected Class<AlarmEntity> getColumnFamilyClass() {
  56 + return AlarmEntity.class;
  57 + }
  58 +
  59 + @Override
  60 + protected String getColumnFamilyName() {
  61 + return ALARM_COLUMN_FAMILY_NAME;
  62 + }
  63 +
  64 + protected boolean isDeleteOnSave() {
  65 + return false;
  66 + }
  67 +
  68 + @Override
  69 + public AlarmEntity save(Alarm alarm) {
  70 + log.debug("Save asset [{}] ", alarm);
  71 + return save(new AlarmEntity(alarm));
  72 + }
  73 +
  74 + @Override
  75 + public ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type) {
  76 + Select select = select().from(ALARM_COLUMN_FAMILY_NAME);
  77 + Select.Where query = select.where();
  78 + query.and(eq(ALARM_TENANT_ID_PROPERTY, tenantId.getId()));
  79 + query.and(eq(ALARM_ORIGINATOR_ID_PROPERTY, originator.getId()));
  80 + query.and(eq(ALARM_ORIGINATOR_TYPE_PROPERTY, originator.getEntityType()));
  81 + query.and(eq(ALARM_TYPE_PROPERTY, type));
  82 + query.limit(1);
  83 + query.orderBy(QueryBuilder.asc(ModelConstants.ALARM_TYPE_PROPERTY), QueryBuilder.desc(ModelConstants.ID_PROPERTY));
  84 + return Futures.transform(findOneByStatementAsync(query), toDataFunction());
  85 + }
  86 +
  87 + @Override
  88 + public ListenableFuture<Alarm> findAlarmByIdAsync(UUID key) {
  89 + log.debug("Get alarm by id {}", key);
  90 + Select.Where query = select().from(ALARM_BY_ID_VIEW_NAME).where(eq(ModelConstants.ID_PROPERTY, key));
  91 + query.limit(1);
  92 + log.trace("Execute query {}", query);
  93 + return Futures.transform(findOneByStatementAsync(query), toDataFunction());
  94 + }
  95 +
  96 + @Override
  97 + public ListenableFuture<List<Alarm>> findAlarms(AlarmQuery query) {
  98 + log.trace("Try to find alarms by entity [{}], status [{}] and pageLink [{}]", query.getAffectedEntityId(), query.getStatus(), query.getPageLink());
  99 + EntityId affectedEntity = query.getAffectedEntityId();
  100 + String relationType = query.getStatus() == null ? BaseAlarmService.ALARM_RELATION : BaseAlarmService.ALARM_RELATION_PREFIX + query.getStatus().name();
  101 + ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(affectedEntity, relationType, RelationTypeGroup.ALARM, EntityType.ALARM, query.getPageLink());
  102 + return Futures.transform(relations, (AsyncFunction<List<EntityRelation>, List<Alarm>>) input -> {
  103 + List<ListenableFuture<Alarm>> alarmFutures = new ArrayList<>(input.size());
  104 + for (EntityRelation relation : input) {
  105 + alarmFutures.add(findAlarmByIdAsync(relation.getTo().getId()));
  106 + }
  107 + return Futures.successfulAsList(alarmFutures);
  108 + });
  109 + }
  110 +}
@@ -21,20 +21,18 @@ import org.thingsboard.server.common.data.alarm.AlarmId; @@ -21,20 +21,18 @@ import org.thingsboard.server.common.data.alarm.AlarmId;
21 import org.thingsboard.server.common.data.alarm.AlarmQuery; 21 import org.thingsboard.server.common.data.alarm.AlarmQuery;
22 import org.thingsboard.server.common.data.page.TimePageData; 22 import org.thingsboard.server.common.data.page.TimePageData;
23 23
24 -import java.util.Optional;  
25 -  
26 /** 24 /**
27 * Created by ashvayka on 11.05.17. 25 * Created by ashvayka on 11.05.17.
28 */ 26 */
29 public interface AlarmService { 27 public interface AlarmService {
30 28
31 - Optional<Alarm> saveIfNotExists(Alarm alarm); 29 + Alarm createOrUpdateAlarm(Alarm alarm);
32 30
33 - ListenableFuture<Boolean> updateAlarm(Alarm alarm); 31 + ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTs);
34 32
35 - ListenableFuture<Boolean> ackAlarm(Alarm alarm); 33 + ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long ackTs);
36 34
37 - ListenableFuture<Boolean> clearAlarm(AlarmId alarmId); 35 + ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId);
38 36
39 ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query); 37 ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query);
40 38
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.alarm;
  17 +
  18 +
  19 +import com.google.common.base.Function;
  20 +import com.google.common.util.concurrent.Futures;
  21 +import com.google.common.util.concurrent.ListenableFuture;
  22 +import lombok.extern.slf4j.Slf4j;
  23 +import org.springframework.beans.factory.annotation.Autowired;
  24 +import org.springframework.stereotype.Service;
  25 +import org.springframework.util.StringUtils;
  26 +import org.thingsboard.server.common.data.alarm.Alarm;
  27 +import org.thingsboard.server.common.data.alarm.AlarmId;
  28 +import org.thingsboard.server.common.data.alarm.AlarmQuery;
  29 +import org.thingsboard.server.common.data.alarm.AlarmStatus;
  30 +import org.thingsboard.server.common.data.id.EntityId;
  31 +import org.thingsboard.server.common.data.page.TimePageData;
  32 +import org.thingsboard.server.common.data.relation.EntityRelation;
  33 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
  34 +import org.thingsboard.server.dao.entity.AbstractEntityService;
  35 +import org.thingsboard.server.dao.entity.BaseEntityService;
  36 +import org.thingsboard.server.dao.exception.DataValidationException;
  37 +import org.thingsboard.server.dao.model.*;
  38 +import org.thingsboard.server.dao.relation.EntityRelationsQuery;
  39 +import org.thingsboard.server.dao.relation.EntitySearchDirection;
  40 +import org.thingsboard.server.dao.relation.RelationService;
  41 +import org.thingsboard.server.dao.relation.RelationsSearchParameters;
  42 +import org.thingsboard.server.dao.service.DataValidator;
  43 +import org.thingsboard.server.dao.tenant.TenantDao;
  44 +
  45 +import javax.annotation.Nullable;
  46 +import javax.annotation.PostConstruct;
  47 +import javax.annotation.PreDestroy;
  48 +import java.util.List;
  49 +import java.util.concurrent.ExecutionException;
  50 +import java.util.concurrent.ExecutorService;
  51 +import java.util.concurrent.Executors;
  52 +import java.util.stream.Collectors;
  53 +
  54 +import static org.thingsboard.server.dao.DaoUtil.*;
  55 +import static org.thingsboard.server.dao.service.Validator.*;
  56 +
  57 +@Service
  58 +@Slf4j
  59 +public class BaseAlarmService extends AbstractEntityService implements AlarmService {
  60 +
  61 + public static final String ALARM_RELATION_PREFIX = "ALARM_";
  62 + public static final String ALARM_RELATION = "ALARM_ANY";
  63 +
  64 + @Autowired
  65 + private AlarmDao alarmDao;
  66 +
  67 + @Autowired
  68 + private TenantDao tenantDao;
  69 +
  70 + @Autowired
  71 + private RelationService relationService;
  72 +
  73 + protected ExecutorService readResultsProcessingExecutor;
  74 +
  75 + @PostConstruct
  76 + public void startExecutor() {
  77 + readResultsProcessingExecutor = Executors.newCachedThreadPool();
  78 + }
  79 +
  80 + @PreDestroy
  81 + public void stopExecutor() {
  82 + if (readResultsProcessingExecutor != null) {
  83 + readResultsProcessingExecutor.shutdownNow();
  84 + }
  85 + }
  86 +
  87 + @Override
  88 + public Alarm createOrUpdateAlarm(Alarm alarm) {
  89 + alarmDataValidator.validate(alarm);
  90 + try {
  91 + if (alarm.getStartTs() == 0L) {
  92 + alarm.setStartTs(System.currentTimeMillis());
  93 + }
  94 + if (alarm.getEndTs() == 0L) {
  95 + alarm.setEndTs(alarm.getStartTs());
  96 + }
  97 + if (alarm.getId() == null) {
  98 + Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get();
  99 + if (existing == null || existing.getStatus().isCleared()) {
  100 + return createAlarm(alarm);
  101 + } else {
  102 + return updateAlarm(existing, alarm);
  103 + }
  104 + } else {
  105 + return updateAlarm(alarm).get();
  106 + }
  107 + } catch (ExecutionException | InterruptedException e) {
  108 + throw new RuntimeException(e);
  109 + }
  110 + }
  111 +
  112 + private Alarm createAlarm(Alarm alarm) throws InterruptedException, ExecutionException {
  113 + log.debug("New Alarm : {}", alarm);
  114 + Alarm saved = getData(alarmDao.save(new AlarmEntity(alarm)));
  115 + EntityRelationsQuery query = new EntityRelationsQuery();
  116 + query.setParameters(new RelationsSearchParameters(saved.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE));
  117 + List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList());
  118 + for (EntityId parentId : parentEntities) {
  119 + createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION, RelationTypeGroup.ALARM));
  120 + createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name(), RelationTypeGroup.ALARM));
  121 + }
  122 + createRelation(new EntityRelation(alarm.getOriginator(), saved.getId(), ALARM_RELATION, RelationTypeGroup.ALARM));
  123 + createRelation(new EntityRelation(alarm.getOriginator(), saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name(), RelationTypeGroup.ALARM));
  124 + return saved;
  125 + }
  126 +
  127 + protected ListenableFuture<Alarm> updateAlarm(Alarm update) {
  128 + alarmDataValidator.validate(update);
  129 + return getAndUpdate(update.getId(), new Function<Alarm, Alarm>() {
  130 + @Nullable
  131 + @Override
  132 + public Alarm apply(@Nullable Alarm alarm) {
  133 + if (alarm == null) {
  134 + return null;
  135 + } else {
  136 + return updateAlarm(alarm, update);
  137 + }
  138 + }
  139 + });
  140 + }
  141 +
  142 + private Alarm updateAlarm(Alarm oldAlarm, Alarm newAlarm) {
  143 + AlarmStatus oldStatus = oldAlarm.getStatus();
  144 + AlarmStatus newStatus = newAlarm.getStatus();
  145 + AlarmEntity result = alarmDao.save(new AlarmEntity(merge(oldAlarm, newAlarm)));
  146 + if (oldStatus != newStatus) {
  147 + updateRelations(oldAlarm, oldStatus, newStatus);
  148 + }
  149 + return result.toData();
  150 + }
  151 +
  152 + @Override
  153 + public ListenableFuture<Boolean> ackAlarm(AlarmId alarmId, long ackTime) {
  154 + return getAndUpdate(alarmId, new Function<Alarm, Boolean>() {
  155 + @Nullable
  156 + @Override
  157 + public Boolean apply(@Nullable Alarm alarm) {
  158 + if (alarm == null || alarm.getStatus().isAck()) {
  159 + return false;
  160 + } else {
  161 + AlarmStatus oldStatus = alarm.getStatus();
  162 + AlarmStatus newStatus = oldStatus.isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK;
  163 + alarm.setStatus(newStatus);
  164 + alarm.setAckTs(ackTime);
  165 + alarmDao.save(new AlarmEntity(alarm));
  166 + updateRelations(alarm, oldStatus, newStatus);
  167 + return true;
  168 + }
  169 + }
  170 + });
  171 + }
  172 +
  173 + @Override
  174 + public ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long clearTime) {
  175 + return getAndUpdate(alarmId, new Function<Alarm, Boolean>() {
  176 + @Nullable
  177 + @Override
  178 + public Boolean apply(@Nullable Alarm alarm) {
  179 + if (alarm == null || alarm.getStatus().isCleared()) {
  180 + return false;
  181 + } else {
  182 + AlarmStatus oldStatus = alarm.getStatus();
  183 + AlarmStatus newStatus = oldStatus.isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK;
  184 + alarm.setStatus(newStatus);
  185 + alarm.setClearTs(clearTime);
  186 + alarmDao.save(new AlarmEntity(alarm));
  187 + updateRelations(alarm, oldStatus, newStatus);
  188 + return true;
  189 + }
  190 + }
  191 + });
  192 + }
  193 +
  194 + @Override
  195 + public ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId) {
  196 + log.trace("Executing findAlarmById [{}]", alarmId);
  197 + validateId(alarmId, "Incorrect alarmId " + alarmId);
  198 + return alarmDao.findAlarmByIdAsync(alarmId.getId());
  199 + }
  200 +
  201 + @Override
  202 + public ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query) {
  203 + ListenableFuture<List<Alarm>> alarms = alarmDao.findAlarms(query);
  204 + return Futures.transform(alarms, new Function<List<Alarm>, TimePageData<Alarm>>() {
  205 + @Nullable
  206 + @Override
  207 + public TimePageData<Alarm> apply(@Nullable List<Alarm> alarms) {
  208 + return new TimePageData<>(alarms, query.getPageLink());
  209 + }
  210 + });
  211 + }
  212 +
  213 + private void deleteRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException {
  214 + log.debug("Deleting Alarm relation: {}", alarmRelation);
  215 + relationService.deleteRelation(alarmRelation).get();
  216 + }
  217 +
  218 + private void createRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException {
  219 + log.debug("Creating Alarm relation: {}", alarmRelation);
  220 + relationService.saveRelation(alarmRelation).get();
  221 + }
  222 +
  223 + private Alarm merge(Alarm existing, Alarm alarm) {
  224 + if (alarm.getStartTs() > existing.getEndTs()) {
  225 + existing.setEndTs(alarm.getStartTs());
  226 + }
  227 + if (alarm.getEndTs() > existing.getEndTs()) {
  228 + existing.setEndTs(alarm.getEndTs());
  229 + }
  230 + if (alarm.getClearTs() > existing.getClearTs()) {
  231 + existing.setClearTs(alarm.getClearTs());
  232 + }
  233 + if (alarm.getAckTs() > existing.getAckTs()) {
  234 + existing.setAckTs(alarm.getAckTs());
  235 + }
  236 + existing.setStatus(alarm.getStatus());
  237 + existing.setSeverity(alarm.getSeverity());
  238 + existing.setDetails(alarm.getDetails());
  239 + return existing;
  240 + }
  241 +
  242 + private void updateRelations(Alarm alarm, AlarmStatus oldStatus, AlarmStatus newStatus) {
  243 + try {
  244 + EntityRelationsQuery query = new EntityRelationsQuery();
  245 + query.setParameters(new RelationsSearchParameters(alarm.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE));
  246 + List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList());
  247 + for (EntityId parentId : parentEntities) {
  248 + deleteRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + oldStatus.name(), RelationTypeGroup.ALARM));
  249 + createRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + newStatus.name(), RelationTypeGroup.ALARM));
  250 + }
  251 + deleteRelation(new EntityRelation(alarm.getOriginator(), alarm.getId(), ALARM_RELATION_PREFIX + oldStatus.name(), RelationTypeGroup.ALARM));
  252 + createRelation(new EntityRelation(alarm.getOriginator(), alarm.getId(), ALARM_RELATION_PREFIX + newStatus.name(), RelationTypeGroup.ALARM));
  253 + } catch (ExecutionException | InterruptedException e) {
  254 + log.warn("[{}] Failed to update relations. Old status: [{}], New status: [{}]", alarm.getId(), oldStatus, newStatus);
  255 + throw new RuntimeException(e);
  256 + }
  257 + }
  258 +
  259 + private <T> ListenableFuture<T> getAndUpdate(AlarmId alarmId, Function<Alarm, T> function) {
  260 + validateId(alarmId, "Alarm id should be specified!");
  261 + ListenableFuture<Alarm> entity = alarmDao.findAlarmByIdAsync(alarmId.getId());
  262 + return Futures.transform(entity, function, readResultsProcessingExecutor);
  263 + }
  264 +
  265 + private DataValidator<Alarm> alarmDataValidator =
  266 + new DataValidator<Alarm>() {
  267 +
  268 + @Override
  269 + protected void validateDataImpl(Alarm alarm) {
  270 + if (StringUtils.isEmpty(alarm.getType())) {
  271 + throw new DataValidationException("Alarm type should be specified!");
  272 + }
  273 + if (alarm.getOriginator() == null) {
  274 + throw new DataValidationException("Alarm originator should be specified!");
  275 + }
  276 + if (alarm.getSeverity() == null) {
  277 + throw new DataValidationException("Alarm severity should be specified!");
  278 + }
  279 + if (alarm.getStatus() == null) {
  280 + throw new DataValidationException("Alarm status should be specified!");
  281 + }
  282 + if (alarm.getTenantId() == null) {
  283 + throw new DataValidationException("Alarm should be assigned to tenant!");
  284 + } else {
  285 + TenantEntity tenant = tenantDao.findById(alarm.getTenantId().getId());
  286 + if (tenant == null) {
  287 + throw new DataValidationException("Alarm is referencing to non-existent tenant!");
  288 + }
  289 + }
  290 + }
  291 + };
  292 +}
@@ -16,12 +16,11 @@ @@ -16,12 +16,11 @@
16 package org.thingsboard.server.dao.asset; 16 package org.thingsboard.server.dao.asset;
17 17
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
19 -import org.thingsboard.server.common.data.Device;  
20 import org.thingsboard.server.common.data.asset.Asset; 19 import org.thingsboard.server.common.data.asset.Asset;
21 import org.thingsboard.server.common.data.page.TextPageLink; 20 import org.thingsboard.server.common.data.page.TextPageLink;
22 import org.thingsboard.server.dao.Dao; 21 import org.thingsboard.server.dao.Dao;
23 import org.thingsboard.server.dao.model.AssetEntity; 22 import org.thingsboard.server.dao.model.AssetEntity;
24 -import org.thingsboard.server.dao.model.DeviceEntity; 23 +import org.thingsboard.server.dao.model.TenantAssetTypeEntity;
25 24
26 import java.util.List; 25 import java.util.List;
27 import java.util.Optional; 26 import java.util.Optional;
@@ -51,6 +50,16 @@ public interface AssetDao extends Dao<AssetEntity> { @@ -51,6 +50,16 @@ public interface AssetDao extends Dao<AssetEntity> {
51 List<AssetEntity> findAssetsByTenantId(UUID tenantId, TextPageLink pageLink); 50 List<AssetEntity> findAssetsByTenantId(UUID tenantId, TextPageLink pageLink);
52 51
53 /** 52 /**
  53 + * Find assets by tenantId, type and page link.
  54 + *
  55 + * @param tenantId the tenantId
  56 + * @param type the type
  57 + * @param pageLink the page link
  58 + * @return the list of asset objects
  59 + */
  60 + List<AssetEntity> findAssetsByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink);
  61 +
  62 + /**
54 * Find assets by tenantId and assets Ids. 63 * Find assets by tenantId and assets Ids.
55 * 64 *
56 * @param tenantId the tenantId 65 * @param tenantId the tenantId
@@ -70,6 +79,17 @@ public interface AssetDao extends Dao<AssetEntity> { @@ -70,6 +79,17 @@ public interface AssetDao extends Dao<AssetEntity> {
70 List<AssetEntity> findAssetsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); 79 List<AssetEntity> findAssetsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink);
71 80
72 /** 81 /**
  82 + * Find assets by tenantId, customerId, type and page link.
  83 + *
  84 + * @param tenantId the tenantId
  85 + * @param customerId the customerId
  86 + * @param type the type
  87 + * @param pageLink the page link
  88 + * @return the list of asset objects
  89 + */
  90 + List<AssetEntity> findAssetsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink);
  91 +
  92 + /**
73 * Find assets by tenantId, customerId and assets Ids. 93 * Find assets by tenantId, customerId and assets Ids.
74 * 94 *
75 * @param tenantId the tenantId 95 * @param tenantId the tenantId
@@ -87,4 +107,12 @@ public interface AssetDao extends Dao<AssetEntity> { @@ -87,4 +107,12 @@ public interface AssetDao extends Dao<AssetEntity> {
87 * @return the optional asset object 107 * @return the optional asset object
88 */ 108 */
89 Optional<AssetEntity> findAssetsByTenantIdAndName(UUID tenantId, String name); 109 Optional<AssetEntity> findAssetsByTenantIdAndName(UUID tenantId, String name);
  110 +
  111 + /**
  112 + * Find tenants asset types.
  113 + *
  114 + * @return the list of tenant asset type objects
  115 + */
  116 + ListenableFuture<List<TenantAssetTypeEntity>> findTenantAssetTypesAsync();
  117 +
90 } 118 }
@@ -15,7 +15,12 @@ @@ -15,7 +15,12 @@
15 */ 15 */
16 package org.thingsboard.server.dao.asset; 16 package org.thingsboard.server.dao.asset;
17 17
  18 +import com.datastax.driver.core.ResultSet;
  19 +import com.datastax.driver.core.ResultSetFuture;
18 import com.datastax.driver.core.querybuilder.Select; 20 import com.datastax.driver.core.querybuilder.Select;
  21 +import com.datastax.driver.mapping.Result;
  22 +import com.google.common.base.Function;
  23 +import com.google.common.util.concurrent.Futures;
19 import com.google.common.util.concurrent.ListenableFuture; 24 import com.google.common.util.concurrent.ListenableFuture;
20 import lombok.extern.slf4j.Slf4j; 25 import lombok.extern.slf4j.Slf4j;
21 import org.springframework.stereotype.Component; 26 import org.springframework.stereotype.Component;
@@ -23,7 +28,9 @@ import org.thingsboard.server.common.data.asset.Asset; @@ -23,7 +28,9 @@ import org.thingsboard.server.common.data.asset.Asset;
23 import org.thingsboard.server.common.data.page.TextPageLink; 28 import org.thingsboard.server.common.data.page.TextPageLink;
24 import org.thingsboard.server.dao.AbstractSearchTextDao; 29 import org.thingsboard.server.dao.AbstractSearchTextDao;
25 import org.thingsboard.server.dao.model.AssetEntity; 30 import org.thingsboard.server.dao.model.AssetEntity;
  31 +import org.thingsboard.server.dao.model.TenantAssetTypeEntity;
26 32
  33 +import javax.annotation.Nullable;
27 import java.util.*; 34 import java.util.*;
28 35
29 import static com.datastax.driver.core.querybuilder.QueryBuilder.*; 36 import static com.datastax.driver.core.querybuilder.QueryBuilder.*;
@@ -60,6 +67,16 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements @@ -60,6 +67,16 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
60 } 67 }
61 68
62 @Override 69 @Override
  70 + public List<AssetEntity> findAssetsByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
  71 + log.debug("Try to find assets by tenantId [{}], type [{}] and pageLink [{}]", tenantId, type, pageLink);
  72 + List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
  73 + Arrays.asList(eq(ASSET_TYPE_PROPERTY, type),
  74 + eq(ASSET_TENANT_ID_PROPERTY, tenantId)), pageLink);
  75 + log.trace("Found assets [{}] by tenantId [{}], type [{}] and pageLink [{}]", assetEntities, tenantId, type, pageLink);
  76 + return assetEntities;
  77 + }
  78 +
  79 + @Override
63 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetIds) { 80 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdAndIdsAsync(UUID tenantId, List<UUID> assetIds) {
64 log.debug("Try to find assets by tenantId [{}] and asset Ids [{}]", tenantId, assetIds); 81 log.debug("Try to find assets by tenantId [{}] and asset Ids [{}]", tenantId, assetIds);
65 Select select = select().from(getColumnFamilyName()); 82 Select select = select().from(getColumnFamilyName());
@@ -82,6 +99,19 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements @@ -82,6 +99,19 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
82 } 99 }
83 100
84 @Override 101 @Override
  102 + public List<AssetEntity> findAssetsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
  103 + log.debug("Try to find assets by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink);
  104 + List<AssetEntity> assetEntities = findPageWithTextSearch(ASSET_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
  105 + Arrays.asList(eq(ASSET_TYPE_PROPERTY, type),
  106 + eq(ASSET_CUSTOMER_ID_PROPERTY, customerId),
  107 + eq(ASSET_TENANT_ID_PROPERTY, tenantId)),
  108 + pageLink);
  109 +
  110 + log.trace("Found assets [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", assetEntities, tenantId, customerId, type, pageLink);
  111 + return assetEntities;
  112 + }
  113 +
  114 + @Override
85 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> assetIds) { 115 public ListenableFuture<List<AssetEntity>> findAssetsByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> assetIds) {
86 log.debug("Try to find assets by tenantId [{}], customerId [{}] and asset Ids [{}]", tenantId, customerId, assetIds); 116 log.debug("Try to find assets by tenantId [{}], customerId [{}] and asset Ids [{}]", tenantId, customerId, assetIds);
87 Select select = select().from(getColumnFamilyName()); 117 Select select = select().from(getColumnFamilyName());
@@ -101,4 +131,24 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements @@ -101,4 +131,24 @@ public class AssetDaoImpl extends AbstractSearchTextDao<AssetEntity> implements
101 return Optional.ofNullable(findOneByStatement(query)); 131 return Optional.ofNullable(findOneByStatement(query));
102 } 132 }
103 133
  134 + @Override
  135 + public ListenableFuture<List<TenantAssetTypeEntity>> findTenantAssetTypesAsync() {
  136 + Select statement = select().distinct().column(ASSET_TYPE_PROPERTY).column(ASSET_TENANT_ID_PROPERTY).from(ASSET_TYPES_BY_TENANT_VIEW_NAME);
  137 + statement.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
  138 + ResultSetFuture resultSetFuture = getSession().executeAsync(statement);
  139 + ListenableFuture<List<TenantAssetTypeEntity>> result = Futures.transform(resultSetFuture, new Function<ResultSet, List<TenantAssetTypeEntity>>() {
  140 + @Nullable
  141 + @Override
  142 + public List<TenantAssetTypeEntity> apply(@Nullable ResultSet resultSet) {
  143 + Result<TenantAssetTypeEntity> result = cluster.getMapper(TenantAssetTypeEntity.class).map(resultSet);
  144 + if (result != null) {
  145 + return result.all();
  146 + } else {
  147 + return Collections.emptyList();
  148 + }
  149 + }
  150 + });
  151 + return result;
  152 + }
  153 +
104 } 154 }
@@ -17,6 +17,7 @@ package org.thingsboard.server.dao.asset; @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.asset;
17 17
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
19 import org.thingsboard.server.common.data.asset.Asset; 19 import org.thingsboard.server.common.data.asset.Asset;
  20 +import org.thingsboard.server.common.data.asset.TenantAssetType;
20 import org.thingsboard.server.common.data.id.AssetId; 21 import org.thingsboard.server.common.data.id.AssetId;
21 import org.thingsboard.server.common.data.id.CustomerId; 22 import org.thingsboard.server.common.data.id.CustomerId;
22 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
@@ -34,7 +35,7 @@ public interface AssetService { @@ -34,7 +35,7 @@ public interface AssetService {
34 35
35 Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name); 36 Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name);
36 37
37 - Asset saveAsset(Asset device); 38 + Asset saveAsset(Asset asset);
38 39
39 Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId); 40 Asset assignAssetToCustomer(AssetId assetId, CustomerId customerId);
40 41
@@ -44,16 +45,21 @@ public interface AssetService { @@ -44,16 +45,21 @@ public interface AssetService {
44 45
45 TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink); 46 TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink);
46 47
  48 + TextPageData<Asset> findAssetsByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink);
  49 +
47 ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds); 50 ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds);
48 51
49 void deleteAssetsByTenantId(TenantId tenantId); 52 void deleteAssetsByTenantId(TenantId tenantId);
50 53
51 TextPageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); 54 TextPageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink);
52 55
  56 + TextPageData<Asset> findAssetsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink);
  57 +
53 ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds); 58 ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds);
54 59
55 void unassignCustomerAssets(TenantId tenantId, CustomerId customerId); 60 void unassignCustomerAssets(TenantId tenantId, CustomerId customerId);
56 61
57 ListenableFuture<List<Asset>> findAssetsByQuery(AssetSearchQuery query); 62 ListenableFuture<List<Asset>> findAssetsByQuery(AssetSearchQuery query);
58 63
  64 + ListenableFuture<List<TenantAssetType>> findAssetTypesByTenantId(TenantId tenantId);
59 } 65 }
@@ -26,6 +26,7 @@ import org.springframework.stereotype.Service; @@ -26,6 +26,7 @@ import org.springframework.stereotype.Service;
26 import org.springframework.util.StringUtils; 26 import org.springframework.util.StringUtils;
27 import org.thingsboard.server.common.data.EntityType; 27 import org.thingsboard.server.common.data.EntityType;
28 import org.thingsboard.server.common.data.asset.Asset; 28 import org.thingsboard.server.common.data.asset.Asset;
  29 +import org.thingsboard.server.common.data.asset.TenantAssetType;
29 import org.thingsboard.server.common.data.id.AssetId; 30 import org.thingsboard.server.common.data.id.AssetId;
30 import org.thingsboard.server.common.data.id.CustomerId; 31 import org.thingsboard.server.common.data.id.CustomerId;
31 import org.thingsboard.server.common.data.id.EntityId; 32 import org.thingsboard.server.common.data.id.EntityId;
@@ -34,12 +35,9 @@ import org.thingsboard.server.common.data.page.TextPageData; @@ -34,12 +35,9 @@ import org.thingsboard.server.common.data.page.TextPageData;
34 import org.thingsboard.server.common.data.page.TextPageLink; 35 import org.thingsboard.server.common.data.page.TextPageLink;
35 import org.thingsboard.server.common.data.relation.EntityRelation; 36 import org.thingsboard.server.common.data.relation.EntityRelation;
36 import org.thingsboard.server.dao.customer.CustomerDao; 37 import org.thingsboard.server.dao.customer.CustomerDao;
37 -import org.thingsboard.server.dao.entity.BaseEntityService; 38 +import org.thingsboard.server.dao.entity.AbstractEntityService;
38 import org.thingsboard.server.dao.exception.DataValidationException; 39 import org.thingsboard.server.dao.exception.DataValidationException;
39 -import org.thingsboard.server.dao.model.AssetEntity;  
40 -import org.thingsboard.server.dao.model.CustomerEntity;  
41 -import org.thingsboard.server.dao.model.TenantEntity;  
42 -import org.thingsboard.server.dao.relation.EntityRelationsQuery; 40 +import org.thingsboard.server.dao.model.*;
43 import org.thingsboard.server.dao.relation.EntitySearchDirection; 41 import org.thingsboard.server.dao.relation.EntitySearchDirection;
44 import org.thingsboard.server.dao.service.DataValidator; 42 import org.thingsboard.server.dao.service.DataValidator;
45 import org.thingsboard.server.dao.service.PaginatedRemover; 43 import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -57,7 +55,7 @@ import static org.thingsboard.server.dao.service.Validator.*; @@ -57,7 +55,7 @@ import static org.thingsboard.server.dao.service.Validator.*;
57 55
58 @Service 56 @Service
59 @Slf4j 57 @Slf4j
60 -public class BaseAssetService extends BaseEntityService implements AssetService { 58 +public class BaseAssetService extends AbstractEntityService implements AssetService {
61 59
62 @Autowired 60 @Autowired
63 private AssetDao assetDao; 61 private AssetDao assetDao;
@@ -132,7 +130,18 @@ public class BaseAssetService extends BaseEntityService implements AssetService @@ -132,7 +130,18 @@ public class BaseAssetService extends BaseEntityService implements AssetService
132 validatePageLink(pageLink, "Incorrect page link " + pageLink); 130 validatePageLink(pageLink, "Incorrect page link " + pageLink);
133 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantId(tenantId.getId(), pageLink); 131 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantId(tenantId.getId(), pageLink);
134 List<Asset> assets = convertDataList(assetEntities); 132 List<Asset> assets = convertDataList(assetEntities);
135 - return new TextPageData<Asset>(assets, pageLink); 133 + return new TextPageData<>(assets, pageLink);
  134 + }
  135 +
  136 + @Override
  137 + public TextPageData<Asset> findAssetsByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink) {
  138 + log.trace("Executing findAssetsByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
  139 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  140 + validateString(type, "Incorrect type " + type);
  141 + validatePageLink(pageLink, "Incorrect page link " + pageLink);
  142 + List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndType(tenantId.getId(), type, pageLink);
  143 + List<Asset> assets = convertDataList(assetEntities);
  144 + return new TextPageData<>(assets, pageLink);
136 } 145 }
137 146
138 @Override 147 @Override
@@ -159,7 +168,19 @@ public class BaseAssetService extends BaseEntityService implements AssetService @@ -159,7 +168,19 @@ public class BaseAssetService extends BaseEntityService implements AssetService
159 validatePageLink(pageLink, "Incorrect page link " + pageLink); 168 validatePageLink(pageLink, "Incorrect page link " + pageLink);
160 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); 169 List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
161 List<Asset> assets = convertDataList(assetEntities); 170 List<Asset> assets = convertDataList(assetEntities);
162 - return new TextPageData<Asset>(assets, pageLink); 171 + return new TextPageData<>(assets, pageLink);
  172 + }
  173 +
  174 + @Override
  175 + public TextPageData<Asset> findAssetsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink) {
  176 + log.trace("Executing findAssetsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink);
  177 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  178 + validateId(customerId, "Incorrect customerId " + customerId);
  179 + validateString(type, "Incorrect type " + type);
  180 + validatePageLink(pageLink, "Incorrect page link " + pageLink);
  181 + List<AssetEntity> assetEntities = assetDao.findAssetsByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
  182 + List<Asset> assets = convertDataList(assetEntities);
  183 + return new TextPageData<>(assets, pageLink);
163 } 184 }
164 185
165 @Override 186 @Override
@@ -207,6 +228,25 @@ public class BaseAssetService extends BaseEntityService implements AssetService @@ -207,6 +228,25 @@ public class BaseAssetService extends BaseEntityService implements AssetService
207 return assets; 228 return assets;
208 } 229 }
209 230
  231 + @Override
  232 + public ListenableFuture<List<TenantAssetType>> findAssetTypesByTenantId(TenantId tenantId) {
  233 + log.trace("Executing findAssetTypesByTenantId, tenantId [{}]", tenantId);
  234 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  235 + ListenableFuture<List<TenantAssetTypeEntity>> tenantAssetTypeEntities = assetDao.findTenantAssetTypesAsync();
  236 + ListenableFuture<List<TenantAssetType>> tenantAssetTypes = Futures.transform(tenantAssetTypeEntities,
  237 + (Function<List<TenantAssetTypeEntity>, List<TenantAssetType>>) assetTypeEntities -> {
  238 + List<TenantAssetType> assetTypes = new ArrayList<>();
  239 + for (TenantAssetTypeEntity assetTypeEntity : assetTypeEntities) {
  240 + if (assetTypeEntity.getTenantId().equals(tenantId.getId())) {
  241 + assetTypes.add(assetTypeEntity.toTenantAssetType());
  242 + }
  243 + }
  244 + assetTypes.sort((TenantAssetType o1, TenantAssetType o2) -> o1.getType().compareTo(o2.getType()));
  245 + return assetTypes;
  246 + });
  247 + return tenantAssetTypes;
  248 + }
  249 +
210 private DataValidator<Asset> assetValidator = 250 private DataValidator<Asset> assetValidator =
211 new DataValidator<Asset>() { 251 new DataValidator<Asset>() {
212 252
@@ -232,6 +272,9 @@ public class BaseAssetService extends BaseEntityService implements AssetService @@ -232,6 +272,9 @@ public class BaseAssetService extends BaseEntityService implements AssetService
232 272
233 @Override 273 @Override
234 protected void validateDataImpl(Asset asset) { 274 protected void validateDataImpl(Asset asset) {
  275 + if (StringUtils.isEmpty(asset.getType())) {
  276 + throw new DataValidationException("Asset type should be specified!");
  277 + }
235 if (StringUtils.isEmpty(asset.getName())) { 278 if (StringUtils.isEmpty(asset.getName())) {
236 throw new DataValidationException("Asset name should be specified!"); 279 throw new DataValidationException("Asset name should be specified!");
237 } 280 }
@@ -45,7 +45,6 @@ public class ServiceCacheConfiguration { @@ -45,7 +45,6 @@ public class ServiceCacheConfiguration {
45 @Value("${cache.device_credentials.time_to_live}") 45 @Value("${cache.device_credentials.time_to_live}")
46 private Integer cacheDeviceCredentialsTTL; 46 private Integer cacheDeviceCredentialsTTL;
47 47
48 -  
49 @Value("${zk.enabled}") 48 @Value("${zk.enabled}")
50 private boolean zkEnabled; 49 private boolean zkEnabled;
51 @Value("${zk.url}") 50 @Value("${zk.url}")
@@ -31,17 +31,15 @@ import com.google.common.util.concurrent.ListenableFuture; @@ -31,17 +31,15 @@ import com.google.common.util.concurrent.ListenableFuture;
31 import lombok.extern.slf4j.Slf4j; 31 import lombok.extern.slf4j.Slf4j;
32 import org.apache.commons.lang3.StringUtils; 32 import org.apache.commons.lang3.StringUtils;
33 import org.thingsboard.server.common.data.Customer; 33 import org.thingsboard.server.common.data.Customer;
34 -import org.thingsboard.server.common.data.asset.Asset;  
35 import org.thingsboard.server.common.data.id.CustomerId; 34 import org.thingsboard.server.common.data.id.CustomerId;
36 import org.thingsboard.server.common.data.id.TenantId; 35 import org.thingsboard.server.common.data.id.TenantId;
37 import org.thingsboard.server.common.data.page.TextPageData; 36 import org.thingsboard.server.common.data.page.TextPageData;
38 import org.thingsboard.server.common.data.page.TextPageLink; 37 import org.thingsboard.server.common.data.page.TextPageLink;
39 import org.thingsboard.server.dao.dashboard.DashboardService; 38 import org.thingsboard.server.dao.dashboard.DashboardService;
40 import org.thingsboard.server.dao.device.DeviceService; 39 import org.thingsboard.server.dao.device.DeviceService;
41 -import org.thingsboard.server.dao.entity.BaseEntityService; 40 +import org.thingsboard.server.dao.entity.AbstractEntityService;
42 import org.thingsboard.server.dao.exception.DataValidationException; 41 import org.thingsboard.server.dao.exception.DataValidationException;
43 import org.thingsboard.server.dao.exception.IncorrectParameterException; 42 import org.thingsboard.server.dao.exception.IncorrectParameterException;
44 -import org.thingsboard.server.dao.model.AssetEntity;  
45 import org.thingsboard.server.dao.model.CustomerEntity; 43 import org.thingsboard.server.dao.model.CustomerEntity;
46 import org.thingsboard.server.dao.model.TenantEntity; 44 import org.thingsboard.server.dao.model.TenantEntity;
47 import org.thingsboard.server.dao.service.DataValidator; 45 import org.thingsboard.server.dao.service.DataValidator;
@@ -53,7 +51,7 @@ import org.springframework.stereotype.Service; @@ -53,7 +51,7 @@ import org.springframework.stereotype.Service;
53 import org.thingsboard.server.dao.service.Validator; 51 import org.thingsboard.server.dao.service.Validator;
54 @Service 52 @Service
55 @Slf4j 53 @Slf4j
56 -public class CustomerServiceImpl extends BaseEntityService implements CustomerService { 54 +public class CustomerServiceImpl extends AbstractEntityService implements CustomerService {
57 55
58 private static final String PUBLIC_CUSTOMER_TITLE = "Public"; 56 private static final String PUBLIC_CUSTOMER_TITLE = "Public";
59 57
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.dao.dashboard; 16 package org.thingsboard.server.dao.dashboard;
17 17
  18 +import com.google.common.util.concurrent.ListenableFuture;
18 import org.thingsboard.server.common.data.Dashboard; 19 import org.thingsboard.server.common.data.Dashboard;
19 import org.thingsboard.server.common.data.DashboardInfo; 20 import org.thingsboard.server.common.data.DashboardInfo;
20 import org.thingsboard.server.common.data.id.CustomerId; 21 import org.thingsboard.server.common.data.id.CustomerId;
@@ -27,8 +28,12 @@ public interface DashboardService { @@ -27,8 +28,12 @@ public interface DashboardService {
27 28
28 public Dashboard findDashboardById(DashboardId dashboardId); 29 public Dashboard findDashboardById(DashboardId dashboardId);
29 30
  31 + public ListenableFuture<Dashboard> findDashboardByIdAsync(DashboardId dashboardId);
  32 +
30 public DashboardInfo findDashboardInfoById(DashboardId dashboardId); 33 public DashboardInfo findDashboardInfoById(DashboardId dashboardId);
31 34
  35 + public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(DashboardId dashboardId);
  36 +
32 public Dashboard saveDashboard(Dashboard dashboard); 37 public Dashboard saveDashboard(Dashboard dashboard);
33 38
34 public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId); 39 public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId);
@@ -17,9 +17,13 @@ package org.thingsboard.server.dao.dashboard; @@ -17,9 +17,13 @@ package org.thingsboard.server.dao.dashboard;
17 17
18 import static org.thingsboard.server.dao.DaoUtil.convertDataList; 18 import static org.thingsboard.server.dao.DaoUtil.convertDataList;
19 import static org.thingsboard.server.dao.DaoUtil.getData; 19 import static org.thingsboard.server.dao.DaoUtil.getData;
  20 +import static org.thingsboard.server.dao.service.Validator.validateId;
20 21
21 import java.util.List; 22 import java.util.List;
22 23
  24 +import com.google.common.base.Function;
  25 +import com.google.common.util.concurrent.Futures;
  26 +import com.google.common.util.concurrent.ListenableFuture;
23 import lombok.extern.slf4j.Slf4j; 27 import lombok.extern.slf4j.Slf4j;
24 import org.apache.commons.lang3.StringUtils; 28 import org.apache.commons.lang3.StringUtils;
25 import org.thingsboard.server.common.data.Dashboard; 29 import org.thingsboard.server.common.data.Dashboard;
@@ -30,7 +34,7 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -30,7 +34,7 @@ import org.thingsboard.server.common.data.id.TenantId;
30 import org.thingsboard.server.common.data.page.TextPageData; 34 import org.thingsboard.server.common.data.page.TextPageData;
31 import org.thingsboard.server.common.data.page.TextPageLink; 35 import org.thingsboard.server.common.data.page.TextPageLink;
32 import org.thingsboard.server.dao.customer.CustomerDao; 36 import org.thingsboard.server.dao.customer.CustomerDao;
33 -import org.thingsboard.server.dao.entity.BaseEntityService; 37 +import org.thingsboard.server.dao.entity.AbstractEntityService;
34 import org.thingsboard.server.dao.exception.DataValidationException; 38 import org.thingsboard.server.dao.exception.DataValidationException;
35 import org.thingsboard.server.dao.model.*; 39 import org.thingsboard.server.dao.model.*;
36 import org.thingsboard.server.dao.service.DataValidator; 40 import org.thingsboard.server.dao.service.DataValidator;
@@ -42,7 +46,7 @@ import org.thingsboard.server.dao.service.Validator; @@ -42,7 +46,7 @@ import org.thingsboard.server.dao.service.Validator;
42 46
43 @Service 47 @Service
44 @Slf4j 48 @Slf4j
45 -public class DashboardServiceImpl extends BaseEntityService implements DashboardService { 49 +public class DashboardServiceImpl extends AbstractEntityService implements DashboardService {
46 50
47 @Autowired 51 @Autowired
48 private DashboardDao dashboardDao; 52 private DashboardDao dashboardDao;
@@ -65,6 +69,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard @@ -65,6 +69,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard
65 } 69 }
66 70
67 @Override 71 @Override
  72 + public ListenableFuture<Dashboard> findDashboardByIdAsync(DashboardId dashboardId) {
  73 + log.trace("Executing findDashboardByIdAsync [{}]", dashboardId);
  74 + validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
  75 + ListenableFuture<DashboardEntity> dashboardEntity = dashboardDao.findByIdAsync(dashboardId.getId());
  76 + return Futures.transform(dashboardEntity, (Function<? super DashboardEntity, ? extends Dashboard>) input -> getData(input));
  77 + }
  78 +
  79 + @Override
68 public DashboardInfo findDashboardInfoById(DashboardId dashboardId) { 80 public DashboardInfo findDashboardInfoById(DashboardId dashboardId) {
69 log.trace("Executing findDashboardInfoById [{}]", dashboardId); 81 log.trace("Executing findDashboardInfoById [{}]", dashboardId);
70 Validator.validateId(dashboardId, "Incorrect dashboardId " + dashboardId); 82 Validator.validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
@@ -73,6 +85,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard @@ -73,6 +85,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard
73 } 85 }
74 86
75 @Override 87 @Override
  88 + public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(DashboardId dashboardId) {
  89 + log.trace("Executing findDashboardInfoByIdAsync [{}]", dashboardId);
  90 + validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
  91 + ListenableFuture<DashboardInfoEntity> dashboardInfoEntity = dashboardInfoDao.findByIdAsync(dashboardId.getId());
  92 + return Futures.transform(dashboardInfoEntity, (Function<? super DashboardInfoEntity, ? extends DashboardInfo>) input -> getData(input));
  93 + }
  94 +
  95 + @Override
76 public Dashboard saveDashboard(Dashboard dashboard) { 96 public Dashboard saveDashboard(Dashboard dashboard) {
77 log.trace("Executing saveDashboard [{}]", dashboard); 97 log.trace("Executing saveDashboard [{}]", dashboard);
78 dashboardValidator.validate(dashboard); 98 dashboardValidator.validate(dashboard);
@@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.Device; @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.Device;
24 import org.thingsboard.server.common.data.page.TextPageLink; 24 import org.thingsboard.server.common.data.page.TextPageLink;
25 import org.thingsboard.server.dao.Dao; 25 import org.thingsboard.server.dao.Dao;
26 import org.thingsboard.server.dao.model.DeviceEntity; 26 import org.thingsboard.server.dao.model.DeviceEntity;
  27 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
27 28
28 /** 29 /**
29 * The Interface DeviceDao. 30 * The Interface DeviceDao.
@@ -49,6 +50,16 @@ public interface DeviceDao extends Dao<DeviceEntity> { @@ -49,6 +50,16 @@ public interface DeviceDao extends Dao<DeviceEntity> {
49 List<DeviceEntity> findDevicesByTenantId(UUID tenantId, TextPageLink pageLink); 50 List<DeviceEntity> findDevicesByTenantId(UUID tenantId, TextPageLink pageLink);
50 51
51 /** 52 /**
  53 + * Find devices by tenantId, type and page link.
  54 + *
  55 + * @param tenantId the tenantId
  56 + * @param type the type
  57 + * @param pageLink the page link
  58 + * @return the list of device objects
  59 + */
  60 + List<DeviceEntity> findDevicesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink);
  61 +
  62 + /**
52 * Find devices by tenantId and devices Ids. 63 * Find devices by tenantId and devices Ids.
53 * 64 *
54 * @param tenantId the tenantId 65 * @param tenantId the tenantId
@@ -68,6 +79,18 @@ public interface DeviceDao extends Dao<DeviceEntity> { @@ -68,6 +79,18 @@ public interface DeviceDao extends Dao<DeviceEntity> {
68 List<DeviceEntity> findDevicesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink); 79 List<DeviceEntity> findDevicesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink);
69 80
70 /** 81 /**
  82 + * Find devices by tenantId, customerId, type and page link.
  83 + *
  84 + * @param tenantId the tenantId
  85 + * @param customerId the customerId
  86 + * @param type the type
  87 + * @param pageLink the page link
  88 + * @return the list of device objects
  89 + */
  90 + List<DeviceEntity> findDevicesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink);
  91 +
  92 +
  93 + /**
71 * Find devices by tenantId, customerId and devices Ids. 94 * Find devices by tenantId, customerId and devices Ids.
72 * 95 *
73 * @param tenantId the tenantId 96 * @param tenantId the tenantId
@@ -85,4 +108,11 @@ public interface DeviceDao extends Dao<DeviceEntity> { @@ -85,4 +108,11 @@ public interface DeviceDao extends Dao<DeviceEntity> {
85 * @return the optional device object 108 * @return the optional device object
86 */ 109 */
87 Optional<DeviceEntity> findDevicesByTenantIdAndName(UUID tenantId, String name); 110 Optional<DeviceEntity> findDevicesByTenantIdAndName(UUID tenantId, String name);
  111 +
  112 + /**
  113 + * Find tenants device types.
  114 + *
  115 + * @return the list of tenant device type objects
  116 + */
  117 + ListenableFuture<List<TenantDeviceTypeEntity>> findTenantDeviceTypesAsync();
88 } 118 }
@@ -22,7 +22,12 @@ import static org.thingsboard.server.dao.model.ModelConstants.*; @@ -22,7 +22,12 @@ import static org.thingsboard.server.dao.model.ModelConstants.*;
22 22
23 import java.util.*; 23 import java.util.*;
24 24
  25 +import com.datastax.driver.core.ResultSet;
  26 +import com.datastax.driver.core.ResultSetFuture;
25 import com.datastax.driver.core.querybuilder.Select; 27 import com.datastax.driver.core.querybuilder.Select;
  28 +import com.datastax.driver.mapping.Result;
  29 +import com.google.common.base.Function;
  30 +import com.google.common.util.concurrent.Futures;
26 import com.google.common.util.concurrent.ListenableFuture; 31 import com.google.common.util.concurrent.ListenableFuture;
27 import lombok.extern.slf4j.Slf4j; 32 import lombok.extern.slf4j.Slf4j;
28 import org.springframework.stereotype.Component; 33 import org.springframework.stereotype.Component;
@@ -32,6 +37,9 @@ import org.thingsboard.server.dao.AbstractSearchTextDao; @@ -32,6 +37,9 @@ import org.thingsboard.server.dao.AbstractSearchTextDao;
32 import org.thingsboard.server.dao.model.DeviceEntity; 37 import org.thingsboard.server.dao.model.DeviceEntity;
33 import org.slf4j.Logger; 38 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory; 39 import org.slf4j.LoggerFactory;
  40 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
  41 +
  42 +import javax.annotation.Nullable;
35 43
36 @Component 44 @Component
37 @Slf4j 45 @Slf4j
@@ -64,6 +72,16 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement @@ -64,6 +72,16 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
64 } 72 }
65 73
66 @Override 74 @Override
  75 + public List<DeviceEntity> findDevicesByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
  76 + log.debug("Try to find devices by tenantId [{}], type [{}] and pageLink [{}]", tenantId, type, pageLink);
  77 + List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
  78 + Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type),
  79 + eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), pageLink);
  80 + log.trace("Found devices [{}] by tenantId [{}], type [{}] and pageLink [{}]", deviceEntities, tenantId, type, pageLink);
  81 + return deviceEntities;
  82 + }
  83 +
  84 + @Override
67 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> deviceIds) { 85 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdAndIdsAsync(UUID tenantId, List<UUID> deviceIds) {
68 log.debug("Try to find devices by tenantId [{}] and device Ids [{}]", tenantId, deviceIds); 86 log.debug("Try to find devices by tenantId [{}] and device Ids [{}]", tenantId, deviceIds);
69 Select select = select().from(getColumnFamilyName()); 87 Select select = select().from(getColumnFamilyName());
@@ -75,7 +93,7 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement @@ -75,7 +93,7 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
75 93
76 @Override 94 @Override
77 public List<DeviceEntity> findDevicesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) { 95 public List<DeviceEntity> findDevicesByTenantIdAndCustomerId(UUID tenantId, UUID customerId, TextPageLink pageLink) {
78 - log.debug("Try to find devices by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink); 96 + log.debug("Try to find devices by tenantId [{}], customerId [{}] and pageLink [{}]", tenantId, customerId, pageLink);
79 List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, 97 List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
80 Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId), 98 Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId),
81 eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), 99 eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
@@ -86,6 +104,19 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement @@ -86,6 +104,19 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
86 } 104 }
87 105
88 @Override 106 @Override
  107 + public List<DeviceEntity> findDevicesByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
  108 + log.debug("Try to find devices by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink);
  109 + List<DeviceEntity> deviceEntities = findPageWithTextSearch(DEVICE_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
  110 + Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type),
  111 + eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId),
  112 + eq(DEVICE_TENANT_ID_PROPERTY, tenantId)),
  113 + pageLink);
  114 +
  115 + log.trace("Found devices [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", deviceEntities, tenantId, customerId, type, pageLink);
  116 + return deviceEntities;
  117 + }
  118 +
  119 + @Override
89 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> deviceIds) { 120 public ListenableFuture<List<DeviceEntity>> findDevicesByTenantIdCustomerIdAndIdsAsync(UUID tenantId, UUID customerId, List<UUID> deviceIds) {
90 log.debug("Try to find devices by tenantId [{}], customerId [{}] and device Ids [{}]", tenantId, customerId, deviceIds); 121 log.debug("Try to find devices by tenantId [{}], customerId [{}] and device Ids [{}]", tenantId, customerId, deviceIds);
91 Select select = select().from(getColumnFamilyName()); 122 Select select = select().from(getColumnFamilyName());
@@ -105,4 +136,24 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement @@ -105,4 +136,24 @@ public class DeviceDaoImpl extends AbstractSearchTextDao<DeviceEntity> implement
105 return Optional.ofNullable(findOneByStatement(query)); 136 return Optional.ofNullable(findOneByStatement(query));
106 } 137 }
107 138
  139 + @Override
  140 + public ListenableFuture<List<TenantDeviceTypeEntity>> findTenantDeviceTypesAsync() {
  141 + Select statement = select().distinct().column(DEVICE_TYPE_PROPERTY).column(DEVICE_TENANT_ID_PROPERTY).from(DEVICE_TYPES_BY_TENANT_VIEW_NAME);
  142 + statement.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
  143 + ResultSetFuture resultSetFuture = getSession().executeAsync(statement);
  144 + ListenableFuture<List<TenantDeviceTypeEntity>> result = Futures.transform(resultSetFuture, new Function<ResultSet, List<TenantDeviceTypeEntity>>() {
  145 + @Nullable
  146 + @Override
  147 + public List<TenantDeviceTypeEntity> apply(@Nullable ResultSet resultSet) {
  148 + Result<TenantDeviceTypeEntity> result = cluster.getMapper(TenantDeviceTypeEntity.class).map(resultSet);
  149 + if (result != null) {
  150 + return result.all();
  151 + } else {
  152 + return Collections.emptyList();
  153 + }
  154 + }
  155 + });
  156 + return result;
  157 + }
  158 +
108 } 159 }
@@ -17,6 +17,7 @@ package org.thingsboard.server.dao.device; @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.device;
17 17
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
19 import org.thingsboard.server.common.data.Device; 19 import org.thingsboard.server.common.data.Device;
  20 +import org.thingsboard.server.common.data.TenantDeviceType;
20 import org.thingsboard.server.common.data.id.CustomerId; 21 import org.thingsboard.server.common.data.id.CustomerId;
21 import org.thingsboard.server.common.data.id.DeviceId; 22 import org.thingsboard.server.common.data.id.DeviceId;
22 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
@@ -44,16 +45,22 @@ public interface DeviceService { @@ -44,16 +45,22 @@ public interface DeviceService {
44 45
45 TextPageData<Device> findDevicesByTenantId(TenantId tenantId, TextPageLink pageLink); 46 TextPageData<Device> findDevicesByTenantId(TenantId tenantId, TextPageLink pageLink);
46 47
  48 + TextPageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink);
  49 +
47 ListenableFuture<List<Device>> findDevicesByTenantIdAndIdsAsync(TenantId tenantId, List<DeviceId> deviceIds); 50 ListenableFuture<List<Device>> findDevicesByTenantIdAndIdsAsync(TenantId tenantId, List<DeviceId> deviceIds);
48 51
49 void deleteDevicesByTenantId(TenantId tenantId); 52 void deleteDevicesByTenantId(TenantId tenantId);
50 53
51 TextPageData<Device> findDevicesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); 54 TextPageData<Device> findDevicesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink);
52 55
  56 + TextPageData<Device> findDevicesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink);
  57 +
53 ListenableFuture<List<Device>> findDevicesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<DeviceId> deviceIds); 58 ListenableFuture<List<Device>> findDevicesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<DeviceId> deviceIds);
54 59
55 void unassignCustomerDevices(TenantId tenantId, CustomerId customerId); 60 void unassignCustomerDevices(TenantId tenantId, CustomerId customerId);
56 61
57 ListenableFuture<List<Device>> findDevicesByQuery(DeviceSearchQuery query); 62 ListenableFuture<List<Device>> findDevicesByQuery(DeviceSearchQuery query);
58 63
  64 + ListenableFuture<List<TenantDeviceType>> findDeviceTypesByTenantId(TenantId tenantId);
  65 +
59 } 66 }
@@ -26,6 +26,7 @@ import org.springframework.stereotype.Service; @@ -26,6 +26,7 @@ import org.springframework.stereotype.Service;
26 import org.springframework.util.StringUtils; 26 import org.springframework.util.StringUtils;
27 import org.thingsboard.server.common.data.Device; 27 import org.thingsboard.server.common.data.Device;
28 import org.thingsboard.server.common.data.EntityType; 28 import org.thingsboard.server.common.data.EntityType;
  29 +import org.thingsboard.server.common.data.TenantDeviceType;
29 import org.thingsboard.server.common.data.id.CustomerId; 30 import org.thingsboard.server.common.data.id.CustomerId;
30 import org.thingsboard.server.common.data.id.DeviceId; 31 import org.thingsboard.server.common.data.id.DeviceId;
31 import org.thingsboard.server.common.data.id.EntityId; 32 import org.thingsboard.server.common.data.id.EntityId;
@@ -36,10 +37,11 @@ import org.thingsboard.server.common.data.relation.EntityRelation; @@ -36,10 +37,11 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
36 import org.thingsboard.server.common.data.security.DeviceCredentials; 37 import org.thingsboard.server.common.data.security.DeviceCredentials;
37 import org.thingsboard.server.common.data.security.DeviceCredentialsType; 38 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
38 import org.thingsboard.server.dao.customer.CustomerDao; 39 import org.thingsboard.server.dao.customer.CustomerDao;
39 -import org.thingsboard.server.dao.entity.BaseEntityService; 40 +import org.thingsboard.server.dao.entity.AbstractEntityService;
40 import org.thingsboard.server.dao.exception.DataValidationException; 41 import org.thingsboard.server.dao.exception.DataValidationException;
41 import org.thingsboard.server.dao.model.CustomerEntity; 42 import org.thingsboard.server.dao.model.CustomerEntity;
42 import org.thingsboard.server.dao.model.DeviceEntity; 43 import org.thingsboard.server.dao.model.DeviceEntity;
  44 +import org.thingsboard.server.dao.model.TenantDeviceTypeEntity;
43 import org.thingsboard.server.dao.model.TenantEntity; 45 import org.thingsboard.server.dao.model.TenantEntity;
44 import org.thingsboard.server.dao.relation.EntitySearchDirection; 46 import org.thingsboard.server.dao.relation.EntitySearchDirection;
45 import org.thingsboard.server.dao.service.DataValidator; 47 import org.thingsboard.server.dao.service.DataValidator;
@@ -47,9 +49,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover; @@ -47,9 +49,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover;
47 import org.thingsboard.server.dao.tenant.TenantDao; 49 import org.thingsboard.server.dao.tenant.TenantDao;
48 50
49 import javax.annotation.Nullable; 51 import javax.annotation.Nullable;
50 -import java.util.ArrayList;  
51 -import java.util.List;  
52 -import java.util.Optional; 52 +import java.util.*;
53 import java.util.stream.Collectors; 53 import java.util.stream.Collectors;
54 54
55 import static org.thingsboard.server.dao.DaoUtil.*; 55 import static org.thingsboard.server.dao.DaoUtil.*;
@@ -58,7 +58,7 @@ import static org.thingsboard.server.dao.service.Validator.*; @@ -58,7 +58,7 @@ import static org.thingsboard.server.dao.service.Validator.*;
58 58
59 @Service 59 @Service
60 @Slf4j 60 @Slf4j
61 -public class DeviceServiceImpl extends BaseEntityService implements DeviceService { 61 +public class DeviceServiceImpl extends AbstractEntityService implements DeviceService {
62 62
63 @Autowired 63 @Autowired
64 private DeviceDao deviceDao; 64 private DeviceDao deviceDao;
@@ -148,7 +148,18 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic @@ -148,7 +148,18 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
148 validatePageLink(pageLink, "Incorrect page link " + pageLink); 148 validatePageLink(pageLink, "Incorrect page link " + pageLink);
149 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantId(tenantId.getId(), pageLink); 149 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantId(tenantId.getId(), pageLink);
150 List<Device> devices = convertDataList(deviceEntities); 150 List<Device> devices = convertDataList(deviceEntities);
151 - return new TextPageData<Device>(devices, pageLink); 151 + return new TextPageData<>(devices, pageLink);
  152 + }
  153 +
  154 + @Override
  155 + public TextPageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink) {
  156 + log.trace("Executing findDevicesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
  157 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  158 + validateString(type, "Incorrect type " + type);
  159 + validatePageLink(pageLink, "Incorrect page link " + pageLink);
  160 + List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantIdAndType(tenantId.getId(), type, pageLink);
  161 + List<Device> devices = convertDataList(deviceEntities);
  162 + return new TextPageData<>(devices, pageLink);
152 } 163 }
153 164
154 @Override 165 @Override
@@ -176,7 +187,19 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic @@ -176,7 +187,19 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
176 validatePageLink(pageLink, "Incorrect page link " + pageLink); 187 validatePageLink(pageLink, "Incorrect page link " + pageLink);
177 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); 188 List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
178 List<Device> devices = convertDataList(deviceEntities); 189 List<Device> devices = convertDataList(deviceEntities);
179 - return new TextPageData<Device>(devices, pageLink); 190 + return new TextPageData<>(devices, pageLink);
  191 + }
  192 +
  193 + @Override
  194 + public TextPageData<Device> findDevicesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink) {
  195 + log.trace("Executing findDevicesByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}], type [{}], pageLink [{}]", tenantId, customerId, type, pageLink);
  196 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  197 + validateId(customerId, "Incorrect customerId " + customerId);
  198 + validateString(type, "Incorrect type " + type);
  199 + validatePageLink(pageLink, "Incorrect page link " + pageLink);
  200 + List<DeviceEntity> deviceEntities = deviceDao.findDevicesByTenantIdAndCustomerIdAndType(tenantId.getId(), customerId.getId(), type, pageLink);
  201 + List<Device> devices = convertDataList(deviceEntities);
  202 + return new TextPageData<>(devices, pageLink);
180 } 203 }
181 204
182 @Override 205 @Override
@@ -224,6 +247,25 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic @@ -224,6 +247,25 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
224 return devices; 247 return devices;
225 } 248 }
226 249
  250 + @Override
  251 + public ListenableFuture<List<TenantDeviceType>> findDeviceTypesByTenantId(TenantId tenantId) {
  252 + log.trace("Executing findDeviceTypesByTenantId, tenantId [{}]", tenantId);
  253 + validateId(tenantId, "Incorrect tenantId " + tenantId);
  254 + ListenableFuture<List<TenantDeviceTypeEntity>> tenantDeviceTypeEntities = deviceDao.findTenantDeviceTypesAsync();
  255 + ListenableFuture<List<TenantDeviceType>> tenantDeviceTypes = Futures.transform(tenantDeviceTypeEntities,
  256 + (Function<List<TenantDeviceTypeEntity>, List<TenantDeviceType>>) deviceTypeEntities -> {
  257 + List<TenantDeviceType> deviceTypes = new ArrayList<>();
  258 + for (TenantDeviceTypeEntity deviceTypeEntity : deviceTypeEntities) {
  259 + if (deviceTypeEntity.getTenantId().equals(tenantId.getId())) {
  260 + deviceTypes.add(deviceTypeEntity.toTenantDeviceType());
  261 + }
  262 + }
  263 + deviceTypes.sort((TenantDeviceType o1, TenantDeviceType o2) -> o1.getType().compareTo(o2.getType()));
  264 + return deviceTypes;
  265 + });
  266 + return tenantDeviceTypes;
  267 + }
  268 +
227 private DataValidator<Device> deviceValidator = 269 private DataValidator<Device> deviceValidator =
228 new DataValidator<Device>() { 270 new DataValidator<Device>() {
229 271
@@ -249,6 +291,9 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic @@ -249,6 +291,9 @@ public class DeviceServiceImpl extends BaseEntityService implements DeviceServic
249 291
250 @Override 292 @Override
251 protected void validateDataImpl(Device device) { 293 protected void validateDataImpl(Device device) {
  294 + if (StringUtils.isEmpty(device.getType())) {
  295 + throw new DataValidationException("Device type should be specified!");
  296 + }
252 if (StringUtils.isEmpty(device.getName())) { 297 if (StringUtils.isEmpty(device.getName())) {
253 throw new DataValidationException("Device name should be specified!"); 298 throw new DataValidationException("Device name should be specified!");
254 } 299 }
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.dao.entity;
  18 +
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.beans.factory.annotation.Autowired;
  21 +import org.thingsboard.server.common.data.id.EntityId;
  22 +import org.thingsboard.server.dao.relation.RelationService;
  23 +
  24 +@Slf4j
  25 +public abstract class AbstractEntityService {
  26 +
  27 + @Autowired
  28 + protected RelationService relationService;
  29 +
  30 + protected void deleteEntityRelations(EntityId entityId) {
  31 + log.trace("Executing deleteEntityRelations [{}]", entityId);
  32 + relationService.deleteEntityRelations(entityId);
  33 + }
  34 +
  35 +
  36 +}
@@ -15,23 +15,102 @@ @@ -15,23 +15,102 @@
15 */ 15 */
16 package org.thingsboard.server.dao.entity; 16 package org.thingsboard.server.dao.entity;
17 17
  18 +import com.google.common.base.Function;
  19 +import com.google.common.util.concurrent.Futures;
  20 +import com.google.common.util.concurrent.ListenableFuture;
18 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
19 import org.springframework.beans.factory.annotation.Autowired; 22 import org.springframework.beans.factory.annotation.Autowired;
20 -import org.thingsboard.server.common.data.id.EntityId;  
21 -import org.thingsboard.server.dao.relation.RelationService; 23 +import org.springframework.stereotype.Service;
  24 +import org.thingsboard.server.common.data.*;
  25 +import org.thingsboard.server.common.data.alarm.AlarmId;
  26 +import org.thingsboard.server.common.data.id.*;
  27 +import org.thingsboard.server.dao.alarm.AlarmService;
  28 +import org.thingsboard.server.dao.asset.AssetService;
  29 +import org.thingsboard.server.dao.customer.CustomerService;
  30 +import org.thingsboard.server.dao.dashboard.DashboardService;
  31 +import org.thingsboard.server.dao.device.DeviceService;
  32 +import org.thingsboard.server.dao.plugin.PluginService;
  33 +import org.thingsboard.server.dao.rule.RuleService;
  34 +import org.thingsboard.server.dao.tenant.TenantService;
  35 +import org.thingsboard.server.dao.user.UserService;
22 36
23 /** 37 /**
24 * Created by ashvayka on 04.05.17. 38 * Created by ashvayka on 04.05.17.
25 */ 39 */
  40 +@Service
26 @Slf4j 41 @Slf4j
27 -public class BaseEntityService { 42 +public class BaseEntityService extends AbstractEntityService implements EntityService {
28 43
29 @Autowired 44 @Autowired
30 - protected RelationService relationService; 45 + private AssetService assetService;
31 46
32 - protected void deleteEntityRelations(EntityId entityId) {  
33 - log.trace("Executing deleteEntityRelations [{}]", entityId);  
34 - relationService.deleteEntityRelations(entityId); 47 + @Autowired
  48 + private DeviceService deviceService;
  49 +
  50 + @Autowired
  51 + private RuleService ruleService;
  52 +
  53 + @Autowired
  54 + private PluginService pluginService;
  55 +
  56 + @Autowired
  57 + private TenantService tenantService;
  58 +
  59 + @Autowired
  60 + private CustomerService customerService;
  61 +
  62 + @Autowired
  63 + private UserService userService;
  64 +
  65 + @Autowired
  66 + private DashboardService dashboardService;
  67 +
  68 + @Autowired
  69 + private AlarmService alarmService;
  70 +
  71 + @Override
  72 + public void deleteEntityRelations(EntityId entityId) {
  73 + super.deleteEntityRelations(entityId);
  74 + }
  75 +
  76 + @Override
  77 + public ListenableFuture<String> fetchEntityNameAsync(EntityId entityId) {
  78 + log.trace("Executing fetchEntityNameAsync [{}]", entityId);
  79 + ListenableFuture<String> entityName;
  80 + ListenableFuture<? extends HasName> hasName;
  81 + switch (entityId.getEntityType()) {
  82 + case ASSET:
  83 + hasName = assetService.findAssetByIdAsync(new AssetId(entityId.getId()));
  84 + break;
  85 + case DEVICE:
  86 + hasName = deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId()));
  87 + break;
  88 + case RULE:
  89 + hasName = ruleService.findRuleByIdAsync(new RuleId(entityId.getId()));
  90 + break;
  91 + case PLUGIN:
  92 + hasName = pluginService.findPluginByIdAsync(new PluginId(entityId.getId()));
  93 + break;
  94 + case TENANT:
  95 + hasName = tenantService.findTenantByIdAsync(new TenantId(entityId.getId()));
  96 + break;
  97 + case CUSTOMER:
  98 + hasName = customerService.findCustomerByIdAsync(new CustomerId(entityId.getId()));
  99 + break;
  100 + case USER:
  101 + hasName = userService.findUserByIdAsync(new UserId(entityId.getId()));
  102 + break;
  103 + case DASHBOARD:
  104 + hasName = dashboardService.findDashboardInfoByIdAsync(new DashboardId(entityId.getId()));
  105 + break;
  106 + case ALARM:
  107 + hasName = alarmService.findAlarmByIdAsync(new AlarmId(entityId.getId()));
  108 + break;
  109 + default:
  110 + throw new IllegalStateException("Not Implemented!");
  111 + }
  112 + entityName = Futures.transform(hasName, (Function<HasName, String>) hasName1 -> hasName1.getName() );
  113 + return entityName;
35 } 114 }
36 115
37 } 116 }
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.dao.entity;
  18 +
  19 +import com.google.common.util.concurrent.ListenableFuture;
  20 +import org.thingsboard.server.common.data.id.EntityId;
  21 +
  22 +public interface EntityService {
  23 +
  24 + ListenableFuture<String> fetchEntityNameAsync(EntityId entityId);
  25 +
  26 + void deleteEntityRelations(EntityId entityId);
  27 +
  28 +}
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.model;
  17 +
  18 +import com.datastax.driver.core.utils.UUIDs;
  19 +import com.datastax.driver.mapping.annotations.*;
  20 +import com.fasterxml.jackson.databind.JsonNode;
  21 +import org.thingsboard.server.common.data.EntityType;
  22 +import org.thingsboard.server.common.data.alarm.Alarm;
  23 +import org.thingsboard.server.common.data.alarm.AlarmId;
  24 +import org.thingsboard.server.common.data.alarm.AlarmSeverity;
  25 +import org.thingsboard.server.common.data.alarm.AlarmStatus;
  26 +import org.thingsboard.server.common.data.id.EntityIdFactory;
  27 +import org.thingsboard.server.common.data.id.TenantId;
  28 +import org.thingsboard.server.dao.model.type.AlarmSeverityCodec;
  29 +import org.thingsboard.server.dao.model.type.AlarmStatusCodec;
  30 +import org.thingsboard.server.dao.model.type.EntityTypeCodec;
  31 +import org.thingsboard.server.dao.model.type.JsonCodec;
  32 +
  33 +import java.util.UUID;
  34 +
  35 +import static org.thingsboard.server.dao.model.ModelConstants.*;
  36 +
  37 +@Table(name = ALARM_COLUMN_FAMILY_NAME)
  38 +public final class AlarmEntity implements BaseEntity<Alarm> {
  39 +
  40 + @Transient
  41 + private static final long serialVersionUID = -1265181166886910152L;
  42 +
  43 + @ClusteringColumn(value = 1)
  44 + @Column(name = ID_PROPERTY)
  45 + private UUID id;
  46 +
  47 + @PartitionKey(value = 0)
  48 + @Column(name = ALARM_TENANT_ID_PROPERTY)
  49 + private UUID tenantId;
  50 +
  51 + @PartitionKey(value = 1)
  52 + @Column(name = ALARM_ORIGINATOR_ID_PROPERTY)
  53 + private UUID originatorId;
  54 +
  55 + @PartitionKey(value = 2)
  56 + @Column(name = ALARM_ORIGINATOR_TYPE_PROPERTY, codec = EntityTypeCodec.class)
  57 + private EntityType originatorType;
  58 +
  59 + @ClusteringColumn(value = 0)
  60 + @Column(name = ALARM_TYPE_PROPERTY)
  61 + private String type;
  62 +
  63 + @Column(name = ALARM_SEVERITY_PROPERTY, codec = AlarmSeverityCodec.class)
  64 + private AlarmSeverity severity;
  65 +
  66 + @Column(name = ALARM_STATUS_PROPERTY, codec = AlarmStatusCodec.class)
  67 + private AlarmStatus status;
  68 +
  69 + @Column(name = ALARM_START_TS_PROPERTY)
  70 + private Long startTs;
  71 +
  72 + @Column(name = ALARM_END_TS_PROPERTY)
  73 + private Long endTs;
  74 +
  75 + @Column(name = ALARM_ACK_TS_PROPERTY)
  76 + private Long ackTs;
  77 +
  78 + @Column(name = ALARM_CLEAR_TS_PROPERTY)
  79 + private Long clearTs;
  80 +
  81 + @Column(name = ALARM_DETAILS_PROPERTY, codec = JsonCodec.class)
  82 + private JsonNode details;
  83 +
  84 + @Column(name = ALARM_PROPAGATE_PROPERTY)
  85 + private Boolean propagate;
  86 +
  87 + public AlarmEntity() {
  88 + super();
  89 + }
  90 +
  91 + public AlarmEntity(Alarm alarm) {
  92 + if (alarm.getId() != null) {
  93 + this.id = alarm.getId().getId();
  94 + }
  95 + if (alarm.getTenantId() != null) {
  96 + this.tenantId = alarm.getTenantId().getId();
  97 + }
  98 + this.type = alarm.getType();
  99 + this.originatorId = alarm.getOriginator().getId();
  100 + this.originatorType = alarm.getOriginator().getEntityType();
  101 + this.type = alarm.getType();
  102 + this.severity = alarm.getSeverity();
  103 + this.status = alarm.getStatus();
  104 + this.propagate = alarm.isPropagate();
  105 + this.startTs = alarm.getStartTs();
  106 + this.endTs = alarm.getEndTs();
  107 + this.ackTs = alarm.getAckTs();
  108 + this.clearTs = alarm.getClearTs();
  109 + this.details = alarm.getDetails();
  110 + }
  111 +
  112 + public UUID getId() {
  113 + return id;
  114 + }
  115 +
  116 + public void setId(UUID id) {
  117 + this.id = id;
  118 + }
  119 +
  120 + public UUID getTenantId() {
  121 + return tenantId;
  122 + }
  123 +
  124 + public void setTenantId(UUID tenantId) {
  125 + this.tenantId = tenantId;
  126 + }
  127 +
  128 + public UUID getOriginatorId() {
  129 + return originatorId;
  130 + }
  131 +
  132 + public void setOriginatorId(UUID originatorId) {
  133 + this.originatorId = originatorId;
  134 + }
  135 +
  136 + public EntityType getOriginatorType() {
  137 + return originatorType;
  138 + }
  139 +
  140 + public void setOriginatorType(EntityType originatorType) {
  141 + this.originatorType = originatorType;
  142 + }
  143 +
  144 + public String getType() {
  145 + return type;
  146 + }
  147 +
  148 + public void setType(String type) {
  149 + this.type = type;
  150 + }
  151 +
  152 + public AlarmSeverity getSeverity() {
  153 + return severity;
  154 + }
  155 +
  156 + public void setSeverity(AlarmSeverity severity) {
  157 + this.severity = severity;
  158 + }
  159 +
  160 + public AlarmStatus getStatus() {
  161 + return status;
  162 + }
  163 +
  164 + public void setStatus(AlarmStatus status) {
  165 + this.status = status;
  166 + }
  167 +
  168 + public Long getStartTs() {
  169 + return startTs;
  170 + }
  171 +
  172 + public void setStartTs(Long startTs) {
  173 + this.startTs = startTs;
  174 + }
  175 +
  176 + public Long getEndTs() {
  177 + return endTs;
  178 + }
  179 +
  180 + public void setEndTs(Long endTs) {
  181 + this.endTs = endTs;
  182 + }
  183 +
  184 + public Long getAckTs() {
  185 + return ackTs;
  186 + }
  187 +
  188 + public void setAckTs(Long ackTs) {
  189 + this.ackTs = ackTs;
  190 + }
  191 +
  192 + public Long getClearTs() {
  193 + return clearTs;
  194 + }
  195 +
  196 + public void setClearTs(Long clearTs) {
  197 + this.clearTs = clearTs;
  198 + }
  199 +
  200 + public JsonNode getDetails() {
  201 + return details;
  202 + }
  203 +
  204 + public void setDetails(JsonNode details) {
  205 + this.details = details;
  206 + }
  207 +
  208 + public Boolean getPropagate() {
  209 + return propagate;
  210 + }
  211 +
  212 + public void setPropagate(Boolean propagate) {
  213 + this.propagate = propagate;
  214 + }
  215 +
  216 + @Override
  217 + public Alarm toData() {
  218 + Alarm alarm = new Alarm(new AlarmId(id));
  219 + alarm.setCreatedTime(UUIDs.unixTimestamp(id));
  220 + if (tenantId != null) {
  221 + alarm.setTenantId(new TenantId(tenantId));
  222 + }
  223 + alarm.setOriginator(EntityIdFactory.getByTypeAndUuid(originatorType, originatorId));
  224 + alarm.setType(type);
  225 + alarm.setSeverity(severity);
  226 + alarm.setStatus(status);
  227 + alarm.setPropagate(propagate);
  228 + alarm.setStartTs(startTs);
  229 + alarm.setEndTs(endTs);
  230 + alarm.setAckTs(ackTs);
  231 + alarm.setClearTs(clearTs);
  232 + alarm.setDetails(details);
  233 + return alarm;
  234 + }
  235 +
  236 +}
@@ -49,12 +49,13 @@ public final class AssetEntity implements SearchTextEntity<Asset> { @@ -49,12 +49,13 @@ public final class AssetEntity implements SearchTextEntity<Asset> {
49 @Column(name = ASSET_CUSTOMER_ID_PROPERTY) 49 @Column(name = ASSET_CUSTOMER_ID_PROPERTY)
50 private UUID customerId; 50 private UUID customerId;
51 51
52 - @Column(name = ASSET_NAME_PROPERTY)  
53 - private String name;  
54 - 52 + @PartitionKey(value = 3)
55 @Column(name = ASSET_TYPE_PROPERTY) 53 @Column(name = ASSET_TYPE_PROPERTY)
56 private String type; 54 private String type;
57 55
  56 + @Column(name = ASSET_NAME_PROPERTY)
  57 + private String name;
  58 +
58 @Column(name = SEARCH_TEXT_PROPERTY) 59 @Column(name = SEARCH_TEXT_PROPERTY)
59 private String searchText; 60 private String searchText;
60 61
@@ -49,12 +49,13 @@ public final class DeviceEntity implements SearchTextEntity<Device> { @@ -49,12 +49,13 @@ public final class DeviceEntity implements SearchTextEntity<Device> {
49 @Column(name = DEVICE_CUSTOMER_ID_PROPERTY) 49 @Column(name = DEVICE_CUSTOMER_ID_PROPERTY)
50 private UUID customerId; 50 private UUID customerId;
51 51
52 - @Column(name = DEVICE_NAME_PROPERTY)  
53 - private String name;  
54 - 52 + @PartitionKey(value = 3)
55 @Column(name = DEVICE_TYPE_PROPERTY) 53 @Column(name = DEVICE_TYPE_PROPERTY)
56 private String type; 54 private String type;
57 55
  56 + @Column(name = DEVICE_NAME_PROPERTY)
  57 + private String name;
  58 +
58 @Column(name = SEARCH_TEXT_PROPERTY) 59 @Column(name = SEARCH_TEXT_PROPERTY)
59 private String searchText; 60 private String searchText;
60 61
@@ -124,8 +124,11 @@ public class ModelConstants { @@ -124,8 +124,11 @@ public class ModelConstants {
124 public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; 124 public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
125 125
126 public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text"; 126 public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text";
  127 + public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text";
127 public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text"; 128 public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text";
  129 + public static final String DEVICE_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_by_type_and_search_text";
128 public static final String DEVICE_BY_TENANT_AND_NAME_VIEW_NAME = "device_by_tenant_and_name"; 130 public static final String DEVICE_BY_TENANT_AND_NAME_VIEW_NAME = "device_by_tenant_and_name";
  131 + public static final String DEVICE_TYPES_BY_TENANT_VIEW_NAME = "device_types_by_tenant";
129 132
130 /** 133 /**
131 * Cassandra asset constants. 134 * Cassandra asset constants.
@@ -138,8 +141,30 @@ public class ModelConstants { @@ -138,8 +141,30 @@ public class ModelConstants {
138 public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; 141 public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
139 142
140 public static final String ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_and_search_text"; 143 public static final String ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_and_search_text";
  144 + public static final String ASSET_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_by_type_and_search_text";
141 public static final String ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_customer_and_search_text"; 145 public static final String ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_customer_and_search_text";
  146 + public static final String ASSET_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_customer_by_type_and_search_text";
142 public static final String ASSET_BY_TENANT_AND_NAME_VIEW_NAME = "asset_by_tenant_and_name"; 147 public static final String ASSET_BY_TENANT_AND_NAME_VIEW_NAME = "asset_by_tenant_and_name";
  148 + public static final String ASSET_TYPES_BY_TENANT_VIEW_NAME = "asset_types_by_tenant";
  149 +
  150 + /**
  151 + * Cassandra alarm constants.
  152 + */
  153 + public static final String ALARM_COLUMN_FAMILY_NAME = "alarm";
  154 + public static final String ALARM_TENANT_ID_PROPERTY = TENTANT_ID_PROPERTY;
  155 + public static final String ALARM_TYPE_PROPERTY = "type";
  156 + public static final String ALARM_DETAILS_PROPERTY = "details";
  157 + public static final String ALARM_ORIGINATOR_ID_PROPERTY = "originator_id";
  158 + public static final String ALARM_ORIGINATOR_TYPE_PROPERTY = "originator_type";
  159 + public static final String ALARM_SEVERITY_PROPERTY = "severity";
  160 + public static final String ALARM_STATUS_PROPERTY = "status";
  161 + public static final String ALARM_START_TS_PROPERTY = "start_ts";
  162 + public static final String ALARM_END_TS_PROPERTY = "end_ts";
  163 + public static final String ALARM_ACK_TS_PROPERTY = "ack_ts";
  164 + public static final String ALARM_CLEAR_TS_PROPERTY = "clear_ts";
  165 + public static final String ALARM_PROPAGATE_PROPERTY = "propagate";
  166 +
  167 + public static final String ALARM_BY_ID_VIEW_NAME = "alarm_by_id";
143 168
144 /** 169 /**
145 * Cassandra entity relation constants. 170 * Cassandra entity relation constants.
@@ -150,7 +175,9 @@ public class ModelConstants { @@ -150,7 +175,9 @@ public class ModelConstants {
150 public static final String RELATION_TO_ID_PROPERTY = "to_id"; 175 public static final String RELATION_TO_ID_PROPERTY = "to_id";
151 public static final String RELATION_TO_TYPE_PROPERTY = "to_type"; 176 public static final String RELATION_TO_TYPE_PROPERTY = "to_type";
152 public static final String RELATION_TYPE_PROPERTY = "relation_type"; 177 public static final String RELATION_TYPE_PROPERTY = "relation_type";
  178 + public static final String RELATION_TYPE_GROUP_PROPERTY = "relation_type_group";
153 179
  180 + public static final String RELATION_BY_TYPE_AND_CHILD_TYPE_VIEW_NAME = "relation_by_type_and_child_type";
154 public static final String RELATION_REVERSE_VIEW_NAME = "reverse_relation"; 181 public static final String RELATION_REVERSE_VIEW_NAME = "reverse_relation";
155 182
156 183
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.dao.model;
  18 +
  19 +import com.datastax.driver.mapping.annotations.Column;
  20 +import com.datastax.driver.mapping.annotations.PartitionKey;
  21 +import com.datastax.driver.mapping.annotations.Table;
  22 +import com.datastax.driver.mapping.annotations.Transient;
  23 +import org.thingsboard.server.common.data.asset.TenantAssetType;
  24 +import org.thingsboard.server.common.data.id.TenantId;
  25 +
  26 +import java.util.UUID;
  27 +
  28 +import static org.thingsboard.server.dao.model.ModelConstants.*;
  29 +
  30 +@Table(name = ASSET_TYPES_BY_TENANT_VIEW_NAME)
  31 +public class TenantAssetTypeEntity {
  32 +
  33 + @Transient
  34 + private static final long serialVersionUID = -1268181161886910152L;
  35 +
  36 + @PartitionKey(value = 0)
  37 + @Column(name = ASSET_TYPE_PROPERTY)
  38 + private String type;
  39 +
  40 + @PartitionKey(value = 1)
  41 + @Column(name = ASSET_TENANT_ID_PROPERTY)
  42 + private UUID tenantId;
  43 +
  44 + public TenantAssetTypeEntity() {
  45 + super();
  46 + }
  47 +
  48 + public TenantAssetTypeEntity(TenantAssetType tenantAssetType) {
  49 + this.type = tenantAssetType.getType();
  50 + if (tenantAssetType.getTenantId() != null) {
  51 + this.tenantId = tenantAssetType.getTenantId().getId();
  52 + }
  53 + }
  54 +
  55 + public String getType() {
  56 + return type;
  57 + }
  58 +
  59 + public void setType(String type) {
  60 + this.type = type;
  61 + }
  62 +
  63 + public UUID getTenantId() {
  64 + return tenantId;
  65 + }
  66 +
  67 + public void setTenantId(UUID tenantId) {
  68 + this.tenantId = tenantId;
  69 + }
  70 +
  71 + @Override
  72 + public int hashCode() {
  73 + int result = type != null ? type.hashCode() : 0;
  74 + result = 31 * result + (tenantId != null ? tenantId.hashCode() : 0);
  75 + return result;
  76 + }
  77 +
  78 + @Override
  79 + public boolean equals(Object o) {
  80 + if (this == o) return true;
  81 + if (o == null || getClass() != o.getClass()) return false;
  82 +
  83 + TenantAssetTypeEntity that = (TenantAssetTypeEntity) o;
  84 +
  85 + if (type != null ? !type.equals(that.type) : that.type != null) return false;
  86 + return tenantId != null ? tenantId.equals(that.tenantId) : that.tenantId == null;
  87 +
  88 + }
  89 +
  90 + @Override
  91 + public String toString() {
  92 + final StringBuilder sb = new StringBuilder("TenantAssetTypeEntity{");
  93 + sb.append("type='").append(type).append('\'');
  94 + sb.append(", tenantId=").append(tenantId);
  95 + sb.append('}');
  96 + return sb.toString();
  97 + }
  98 +
  99 + public TenantAssetType toTenantAssetType() {
  100 + TenantAssetType tenantAssetType = new TenantAssetType();
  101 + tenantAssetType.setType(type);
  102 + if (tenantId != null) {
  103 + tenantAssetType.setTenantId(new TenantId(tenantId));
  104 + }
  105 + return tenantAssetType;
  106 + }
  107 +}
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package org.thingsboard.server.dao.model;
  18 +
  19 +import com.datastax.driver.mapping.annotations.Column;
  20 +import com.datastax.driver.mapping.annotations.PartitionKey;
  21 +import com.datastax.driver.mapping.annotations.Table;
  22 +import com.datastax.driver.mapping.annotations.Transient;
  23 +import org.thingsboard.server.common.data.TenantDeviceType;
  24 +import org.thingsboard.server.common.data.id.TenantId;
  25 +
  26 +import java.util.UUID;
  27 +
  28 +import static org.thingsboard.server.dao.model.ModelConstants.*;
  29 +
  30 +@Table(name = DEVICE_TYPES_BY_TENANT_VIEW_NAME)
  31 +public class TenantDeviceTypeEntity {
  32 +
  33 + @Transient
  34 + private static final long serialVersionUID = -1268181166886910152L;
  35 +
  36 + @PartitionKey(value = 0)
  37 + @Column(name = DEVICE_TYPE_PROPERTY)
  38 + private String type;
  39 +
  40 + @PartitionKey(value = 1)
  41 + @Column(name = DEVICE_TENANT_ID_PROPERTY)
  42 + private UUID tenantId;
  43 +
  44 + public TenantDeviceTypeEntity() {
  45 + super();
  46 + }
  47 +
  48 + public TenantDeviceTypeEntity(TenantDeviceType tenantDeviceType) {
  49 + this.type = tenantDeviceType.getType();
  50 + if (tenantDeviceType.getTenantId() != null) {
  51 + this.tenantId = tenantDeviceType.getTenantId().getId();
  52 + }
  53 + }
  54 +
  55 + public String getType() {
  56 + return type;
  57 + }
  58 +
  59 + public void setType(String type) {
  60 + this.type = type;
  61 + }
  62 +
  63 + public UUID getTenantId() {
  64 + return tenantId;
  65 + }
  66 +
  67 + public void setTenantId(UUID tenantId) {
  68 + this.tenantId = tenantId;
  69 + }
  70 +
  71 + @Override
  72 + public int hashCode() {
  73 + int result = type != null ? type.hashCode() : 0;
  74 + result = 31 * result + (tenantId != null ? tenantId.hashCode() : 0);
  75 + return result;
  76 + }
  77 +
  78 + @Override
  79 + public boolean equals(Object o) {
  80 + if (this == o) return true;
  81 + if (o == null || getClass() != o.getClass()) return false;
  82 +
  83 + TenantDeviceTypeEntity that = (TenantDeviceTypeEntity) o;
  84 +
  85 + if (type != null ? !type.equals(that.type) : that.type != null) return false;
  86 + return tenantId != null ? tenantId.equals(that.tenantId) : that.tenantId == null;
  87 +
  88 + }
  89 +
  90 + @Override
  91 + public String toString() {
  92 + final StringBuilder sb = new StringBuilder("TenantDeviceTypeEntity{");
  93 + sb.append("type='").append(type).append('\'');
  94 + sb.append(", tenantId=").append(tenantId);
  95 + sb.append('}');
  96 + return sb.toString();
  97 + }
  98 +
  99 + public TenantDeviceType toTenantDeviceType() {
  100 + TenantDeviceType tenantDeviceType = new TenantDeviceType();
  101 + tenantDeviceType.setType(type);
  102 + if (tenantId != null) {
  103 + tenantDeviceType.setTenantId(new TenantId(tenantId));
  104 + }
  105 + return tenantDeviceType;
  106 + }
  107 +}
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.model.type;
  17 +
  18 +import com.datastax.driver.extras.codecs.enums.EnumNameCodec;
  19 +import org.thingsboard.server.common.data.alarm.AlarmSeverity;
  20 +import org.thingsboard.server.common.data.alarm.AlarmStatus;
  21 +import org.thingsboard.server.dao.alarm.AlarmService;
  22 +
  23 +public class AlarmSeverityCodec extends EnumNameCodec<AlarmSeverity> {
  24 +
  25 + public AlarmSeverityCodec() {
  26 + super(AlarmSeverity.class);
  27 + }
  28 +
  29 +}
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.model.type;
  17 +
  18 +import com.datastax.driver.extras.codecs.enums.EnumNameCodec;
  19 +import org.thingsboard.server.common.data.alarm.AlarmStatus;
  20 +
  21 +public class AlarmStatusCodec extends EnumNameCodec<AlarmStatus> {
  22 +
  23 + public AlarmStatusCodec() {
  24 + super(AlarmStatus.class);
  25 + }
  26 +
  27 +}
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.model.type;
  17 +
  18 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
  19 +
  20 +import com.datastax.driver.extras.codecs.enums.EnumNameCodec;
  21 +
  22 +public class RelationTypeGroupCodec extends EnumNameCodec<RelationTypeGroup> {
  23 +
  24 + public RelationTypeGroupCodec() {
  25 + super(RelationTypeGroup.class);
  26 + }
  27 +
  28 +}
@@ -22,7 +22,6 @@ import org.apache.commons.lang3.StringUtils; @@ -22,7 +22,6 @@ import org.apache.commons.lang3.StringUtils;
22 import org.springframework.beans.factory.annotation.Autowired; 22 import org.springframework.beans.factory.annotation.Autowired;
23 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
24 import org.thingsboard.server.common.data.id.PluginId; 24 import org.thingsboard.server.common.data.id.PluginId;
25 -import org.thingsboard.server.common.data.id.RuleId;  
26 import org.thingsboard.server.common.data.id.TenantId; 25 import org.thingsboard.server.common.data.id.TenantId;
27 import org.thingsboard.server.common.data.page.TextPageData; 26 import org.thingsboard.server.common.data.page.TextPageData;
28 import org.thingsboard.server.common.data.page.TextPageLink; 27 import org.thingsboard.server.common.data.page.TextPageLink;
@@ -30,9 +29,8 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor; @@ -30,9 +29,8 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
30 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; 29 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
31 import org.thingsboard.server.common.data.plugin.ComponentType; 30 import org.thingsboard.server.common.data.plugin.ComponentType;
32 import org.thingsboard.server.common.data.plugin.PluginMetaData; 31 import org.thingsboard.server.common.data.plugin.PluginMetaData;
33 -import org.thingsboard.server.common.data.rule.RuleMetaData;  
34 import org.thingsboard.server.dao.component.ComponentDescriptorService; 32 import org.thingsboard.server.dao.component.ComponentDescriptorService;
35 -import org.thingsboard.server.dao.entity.BaseEntityService; 33 +import org.thingsboard.server.dao.entity.AbstractEntityService;
36 import org.thingsboard.server.dao.exception.DataValidationException; 34 import org.thingsboard.server.dao.exception.DataValidationException;
37 import org.thingsboard.server.dao.exception.DatabaseException; 35 import org.thingsboard.server.dao.exception.DatabaseException;
38 import org.thingsboard.server.dao.exception.IncorrectParameterException; 36 import org.thingsboard.server.dao.exception.IncorrectParameterException;
@@ -55,7 +53,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId; @@ -55,7 +53,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
55 53
56 @Service 54 @Service
57 @Slf4j 55 @Slf4j
58 -public class BasePluginService extends BaseEntityService implements PluginService { 56 +public class BasePluginService extends AbstractEntityService implements PluginService {
59 57
60 //TODO: move to a better place. 58 //TODO: move to a better place.
61 public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); 59 public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
@@ -16,23 +16,34 @@ @@ -16,23 +16,34 @@
16 package org.thingsboard.server.dao.relation; 16 package org.thingsboard.server.dao.relation;
17 17
18 import com.datastax.driver.core.*; 18 import com.datastax.driver.core.*;
  19 +import com.datastax.driver.core.querybuilder.QueryBuilder;
  20 +import com.datastax.driver.core.querybuilder.Select;
19 import com.fasterxml.jackson.databind.JsonNode; 21 import com.fasterxml.jackson.databind.JsonNode;
20 import com.google.common.base.Function; 22 import com.google.common.base.Function;
21 import com.google.common.util.concurrent.Futures; 23 import com.google.common.util.concurrent.Futures;
22 import com.google.common.util.concurrent.ListenableFuture; 24 import com.google.common.util.concurrent.ListenableFuture;
23 import lombok.extern.slf4j.Slf4j; 25 import lombok.extern.slf4j.Slf4j;
24 import org.springframework.stereotype.Component; 26 import org.springframework.stereotype.Component;
  27 +import org.thingsboard.server.common.data.EntityType;
25 import org.thingsboard.server.common.data.id.EntityId; 28 import org.thingsboard.server.common.data.id.EntityId;
26 import org.thingsboard.server.common.data.id.EntityIdFactory; 29 import org.thingsboard.server.common.data.id.EntityIdFactory;
  30 +import org.thingsboard.server.common.data.page.TimePageLink;
27 import org.thingsboard.server.common.data.relation.EntityRelation; 31 import org.thingsboard.server.common.data.relation.EntityRelation;
  32 +import org.thingsboard.server.common.data.relation.RelationTypeGroup;
28 import org.thingsboard.server.dao.AbstractAsyncDao; 33 import org.thingsboard.server.dao.AbstractAsyncDao;
  34 +import org.thingsboard.server.dao.AbstractSearchTimeDao;
29 import org.thingsboard.server.dao.model.ModelConstants; 35 import org.thingsboard.server.dao.model.ModelConstants;
  36 +import org.thingsboard.server.dao.model.type.RelationTypeGroupCodec;
30 37
31 import javax.annotation.Nullable; 38 import javax.annotation.Nullable;
32 import javax.annotation.PostConstruct; 39 import javax.annotation.PostConstruct;
33 import java.util.ArrayList; 40 import java.util.ArrayList;
  41 +import java.util.Arrays;
34 import java.util.List; 42 import java.util.List;
35 43
  44 +import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
  45 +import static org.thingsboard.server.dao.model.ModelConstants.RELATION_COLUMN_FAMILY_NAME;
  46 +
36 /** 47 /**
37 * Created by ashvayka on 25.04.17. 48 * Created by ashvayka on 25.04.17.
38 */ 49 */
@@ -45,12 +56,15 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { @@ -45,12 +56,15 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
45 ModelConstants.RELATION_FROM_TYPE_PROPERTY + "," + 56 ModelConstants.RELATION_FROM_TYPE_PROPERTY + "," +
46 ModelConstants.RELATION_TO_ID_PROPERTY + "," + 57 ModelConstants.RELATION_TO_ID_PROPERTY + "," +
47 ModelConstants.RELATION_TO_TYPE_PROPERTY + "," + 58 ModelConstants.RELATION_TO_TYPE_PROPERTY + "," +
  59 + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + "," +
48 ModelConstants.RELATION_TYPE_PROPERTY + "," + 60 ModelConstants.RELATION_TYPE_PROPERTY + "," +
49 ModelConstants.ADDITIONAL_INFO_PROPERTY; 61 ModelConstants.ADDITIONAL_INFO_PROPERTY;
50 public static final String FROM = " FROM "; 62 public static final String FROM = " FROM ";
51 public static final String WHERE = " WHERE "; 63 public static final String WHERE = " WHERE ";
52 public static final String AND = " AND "; 64 public static final String AND = " AND ";
53 65
  66 + private static final RelationTypeGroupCodec relationTypeGroupCodec = new RelationTypeGroupCodec();
  67 +
54 private PreparedStatement saveStmt; 68 private PreparedStatement saveStmt;
55 private PreparedStatement findAllByFromStmt; 69 private PreparedStatement findAllByFromStmt;
56 private PreparedStatement findAllByFromAndTypeStmt; 70 private PreparedStatement findAllByFromAndTypeStmt;
@@ -66,43 +80,52 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { @@ -66,43 +80,52 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
66 } 80 }
67 81
68 @Override 82 @Override
69 - public ListenableFuture<List<EntityRelation>> findAllByFrom(EntityId from) {  
70 - BoundStatement stmt = getFindAllByFromStmt().bind().setUUID(0, from.getId()).setString(1, from.getEntityType().name()); 83 + public ListenableFuture<List<EntityRelation>> findAllByFrom(EntityId from, RelationTypeGroup typeGroup) {
  84 + BoundStatement stmt = getFindAllByFromStmt().bind()
  85 + .setUUID(0, from.getId())
  86 + .setString(1, from.getEntityType().name())
  87 + .set(2, typeGroup, relationTypeGroupCodec);
71 return executeAsyncRead(from, stmt); 88 return executeAsyncRead(from, stmt);
72 } 89 }
73 90
74 @Override 91 @Override
75 - public ListenableFuture<List<EntityRelation>> findAllByFromAndType(EntityId from, String relationType) { 92 + public ListenableFuture<List<EntityRelation>> findAllByFromAndType(EntityId from, String relationType, RelationTypeGroup typeGroup) {
76 BoundStatement stmt = getFindAllByFromAndTypeStmt().bind() 93 BoundStatement stmt = getFindAllByFromAndTypeStmt().bind()
77 .setUUID(0, from.getId()) 94 .setUUID(0, from.getId())
78 .setString(1, from.getEntityType().name()) 95 .setString(1, from.getEntityType().name())
79 - .setString(2, relationType); 96 + .set(2, typeGroup, relationTypeGroupCodec)
  97 + .setString(3, relationType);
80 return executeAsyncRead(from, stmt); 98 return executeAsyncRead(from, stmt);
81 } 99 }
82 100
83 @Override 101 @Override
84 - public ListenableFuture<List<EntityRelation>> findAllByTo(EntityId to) {  
85 - BoundStatement stmt = getFindAllByToStmt().bind().setUUID(0, to.getId()).setString(1, to.getEntityType().name()); 102 + public ListenableFuture<List<EntityRelation>> findAllByTo(EntityId to, RelationTypeGroup typeGroup) {
  103 + BoundStatement stmt = getFindAllByToStmt().bind()
  104 + .setUUID(0, to.getId())
  105 + .setString(1, to.getEntityType().name())
  106 + .set(2, typeGroup, relationTypeGroupCodec);
86 return executeAsyncRead(to, stmt); 107 return executeAsyncRead(to, stmt);
87 } 108 }
88 109
89 @Override 110 @Override
90 - public ListenableFuture<List<EntityRelation>> findAllByToAndType(EntityId to, String relationType) { 111 + public ListenableFuture<List<EntityRelation>> findAllByToAndType(EntityId to, String relationType, RelationTypeGroup typeGroup) {
91 BoundStatement stmt = getFindAllByToAndTypeStmt().bind() 112 BoundStatement stmt = getFindAllByToAndTypeStmt().bind()
92 .setUUID(0, to.getId()) 113 .setUUID(0, to.getId())
93 .setString(1, to.getEntityType().name()) 114 .setString(1, to.getEntityType().name())
94 - .setString(2, relationType); 115 + .set(2, typeGroup, relationTypeGroupCodec)
  116 + .setString(3, relationType);
95 return executeAsyncRead(to, stmt); 117 return executeAsyncRead(to, stmt);
96 } 118 }
97 119
98 @Override 120 @Override
99 - public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType) { 121 + public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
100 BoundStatement stmt = getCheckRelationStmt().bind() 122 BoundStatement stmt = getCheckRelationStmt().bind()
101 .setUUID(0, from.getId()) 123 .setUUID(0, from.getId())
102 .setString(1, from.getEntityType().name()) 124 .setString(1, from.getEntityType().name())
103 .setUUID(2, to.getId()) 125 .setUUID(2, to.getId())
104 .setString(3, to.getEntityType().name()) 126 .setString(3, to.getEntityType().name())
105 - .setString(4, relationType); 127 + .set(4, typeGroup, relationTypeGroupCodec)
  128 + .setString(5, relationType);
106 return getFuture(executeAsyncRead(stmt), rs -> rs != null ? rs.one() != null : false); 129 return getFuture(executeAsyncRead(stmt), rs -> rs != null ? rs.one() != null : false);
107 } 130 }
108 131
@@ -113,25 +136,27 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { @@ -113,25 +136,27 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
113 .setString(1, relation.getFrom().getEntityType().name()) 136 .setString(1, relation.getFrom().getEntityType().name())
114 .setUUID(2, relation.getTo().getId()) 137 .setUUID(2, relation.getTo().getId())
115 .setString(3, relation.getTo().getEntityType().name()) 138 .setString(3, relation.getTo().getEntityType().name())
116 - .setString(4, relation.getType())  
117 - .set(5, relation.getAdditionalInfo(), JsonNode.class); 139 + .set(4, relation.getTypeGroup(), relationTypeGroupCodec)
  140 + .setString(5, relation.getType())
  141 + .set(6, relation.getAdditionalInfo(), JsonNode.class);
118 ResultSetFuture future = executeAsyncWrite(stmt); 142 ResultSetFuture future = executeAsyncWrite(stmt);
119 return getBooleanListenableFuture(future); 143 return getBooleanListenableFuture(future);
120 } 144 }
121 145
122 @Override 146 @Override
123 public ListenableFuture<Boolean> deleteRelation(EntityRelation relation) { 147 public ListenableFuture<Boolean> deleteRelation(EntityRelation relation) {
124 - return deleteRelation(relation.getFrom(), relation.getTo(), relation.getType()); 148 + return deleteRelation(relation.getFrom(), relation.getTo(), relation.getType(), relation.getTypeGroup());
125 } 149 }
126 150
127 @Override 151 @Override
128 - public ListenableFuture<Boolean> deleteRelation(EntityId from, EntityId to, String relationType) { 152 + public ListenableFuture<Boolean> deleteRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
129 BoundStatement stmt = getDeleteStmt().bind() 153 BoundStatement stmt = getDeleteStmt().bind()
130 .setUUID(0, from.getId()) 154 .setUUID(0, from.getId())
131 .setString(1, from.getEntityType().name()) 155 .setString(1, from.getEntityType().name())
132 .setUUID(2, to.getId()) 156 .setUUID(2, to.getId())
133 .setString(3, to.getEntityType().name()) 157 .setString(3, to.getEntityType().name())
134 - .setString(4, relationType); 158 + .set(4, typeGroup, relationTypeGroupCodec)
  159 + .setString(5, relationType);
135 ResultSetFuture future = executeAsyncWrite(stmt); 160 ResultSetFuture future = executeAsyncWrite(stmt);
136 return getBooleanListenableFuture(future); 161 return getBooleanListenableFuture(future);
137 } 162 }
@@ -145,6 +170,21 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { @@ -145,6 +170,21 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
145 return getBooleanListenableFuture(future); 170 return getBooleanListenableFuture(future);
146 } 171 }
147 172
  173 + @Override
  174 + public ListenableFuture<List<EntityRelation>> findRelations(EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType childType, TimePageLink pageLink) {
  175 + Select.Where query = AbstractSearchTimeDao.buildQuery(ModelConstants.RELATION_BY_TYPE_AND_CHILD_TYPE_VIEW_NAME,
  176 + Arrays.asList(eq(ModelConstants.RELATION_FROM_ID_PROPERTY, from.getId()),
  177 + eq(ModelConstants.RELATION_FROM_TYPE_PROPERTY, from.getEntityType().name()),
  178 + eq(ModelConstants.RELATION_TYPE_GROUP_PROPERTY, typeGroup.name()),
  179 + eq(ModelConstants.RELATION_TYPE_PROPERTY, relationType),
  180 + eq(ModelConstants.RELATION_TO_TYPE_PROPERTY, childType.name())),
  181 + Arrays.asList(QueryBuilder.asc(ModelConstants.RELATION_TYPE_GROUP_PROPERTY),
  182 + QueryBuilder.asc(ModelConstants.RELATION_TYPE_PROPERTY),
  183 + QueryBuilder.asc(ModelConstants.RELATION_TO_TYPE_PROPERTY)),
  184 + pageLink, ModelConstants.RELATION_TO_ID_PROPERTY);
  185 + return getFuture(executeAsyncRead(query), rs -> getEntityRelations(rs));
  186 + }
  187 +
148 private PreparedStatement getSaveStmt() { 188 private PreparedStatement getSaveStmt() {
149 if (saveStmt == null) { 189 if (saveStmt == null) {
150 saveStmt = getSession().prepare("INSERT INTO " + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " + 190 saveStmt = getSession().prepare("INSERT INTO " + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " +
@@ -152,9 +192,10 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { @@ -152,9 +192,10 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
152 "," + ModelConstants.RELATION_FROM_TYPE_PROPERTY + 192 "," + ModelConstants.RELATION_FROM_TYPE_PROPERTY +
153 "," + ModelConstants.RELATION_TO_ID_PROPERTY + 193 "," + ModelConstants.RELATION_TO_ID_PROPERTY +
154 "," + ModelConstants.RELATION_TO_TYPE_PROPERTY + 194 "," + ModelConstants.RELATION_TO_TYPE_PROPERTY +
  195 + "," + ModelConstants.RELATION_TYPE_GROUP_PROPERTY +
155 "," + ModelConstants.RELATION_TYPE_PROPERTY + 196 "," + ModelConstants.RELATION_TYPE_PROPERTY +
156 "," + ModelConstants.ADDITIONAL_INFO_PROPERTY + ")" + 197 "," + ModelConstants.ADDITIONAL_INFO_PROPERTY + ")" +
157 - " VALUES(?, ?, ?, ?, ?, ?)"); 198 + " VALUES(?, ?, ?, ?, ?, ?, ?)");
158 } 199 }
159 return saveStmt; 200 return saveStmt;
160 } 201 }
@@ -166,6 +207,7 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { @@ -166,6 +207,7 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
166 AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ?" + 207 AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ?" +
167 AND + ModelConstants.RELATION_TO_ID_PROPERTY + " = ?" + 208 AND + ModelConstants.RELATION_TO_ID_PROPERTY + " = ?" +
168 AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ?" + 209 AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ?" +
  210 + AND + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + " = ?" +
169 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ?"); 211 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ?");
170 } 212 }
171 return deleteStmt; 213 return deleteStmt;
@@ -185,7 +227,8 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { @@ -185,7 +227,8 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
185 findAllByFromStmt = getSession().prepare(SELECT_COLUMNS + " " + 227 findAllByFromStmt = getSession().prepare(SELECT_COLUMNS + " " +
186 FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " + 228 FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " +
187 WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ? " + 229 WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ? " +
188 - AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? "); 230 + AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? " +
  231 + AND + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + " = ? ");
189 } 232 }
190 return findAllByFromStmt; 233 return findAllByFromStmt;
191 } 234 }
@@ -196,17 +239,20 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { @@ -196,17 +239,20 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
196 FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " + 239 FROM + ModelConstants.RELATION_COLUMN_FAMILY_NAME + " " +
197 WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ? " + 240 WHERE + ModelConstants.RELATION_FROM_ID_PROPERTY + " = ? " +
198 AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? " + 241 AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? " +
  242 + AND + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + " = ? " +
199 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? "); 243 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? ");
200 } 244 }
201 return findAllByFromAndTypeStmt; 245 return findAllByFromAndTypeStmt;
202 } 246 }
203 247
  248 +
204 private PreparedStatement getFindAllByToStmt() { 249 private PreparedStatement getFindAllByToStmt() {
205 if (findAllByToStmt == null) { 250 if (findAllByToStmt == null) {
206 findAllByToStmt = getSession().prepare(SELECT_COLUMNS + " " + 251 findAllByToStmt = getSession().prepare(SELECT_COLUMNS + " " +
207 FROM + ModelConstants.RELATION_REVERSE_VIEW_NAME + " " + 252 FROM + ModelConstants.RELATION_REVERSE_VIEW_NAME + " " +
208 WHERE + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " + 253 WHERE + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " +
209 - AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? "); 254 + AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? " +
  255 + AND + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + " = ? ");
210 } 256 }
211 return findAllByToStmt; 257 return findAllByToStmt;
212 } 258 }
@@ -217,11 +263,13 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { @@ -217,11 +263,13 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
217 FROM + ModelConstants.RELATION_REVERSE_VIEW_NAME + " " + 263 FROM + ModelConstants.RELATION_REVERSE_VIEW_NAME + " " +
218 WHERE + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " + 264 WHERE + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " +
219 AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? " + 265 AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? " +
  266 + AND + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + " = ? " +
220 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? "); 267 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? ");
221 } 268 }
222 return findAllByToAndTypeStmt; 269 return findAllByToAndTypeStmt;
223 } 270 }
224 271
  272 +
225 private PreparedStatement getCheckRelationStmt() { 273 private PreparedStatement getCheckRelationStmt() {
226 if (checkRelationStmt == null) { 274 if (checkRelationStmt == null) {
227 checkRelationStmt = getSession().prepare(SELECT_COLUMNS + " " + 275 checkRelationStmt = getSession().prepare(SELECT_COLUMNS + " " +
@@ -230,36 +278,19 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { @@ -230,36 +278,19 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
230 AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? " + 278 AND + ModelConstants.RELATION_FROM_TYPE_PROPERTY + " = ? " +
231 AND + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " + 279 AND + ModelConstants.RELATION_TO_ID_PROPERTY + " = ? " +
232 AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? " + 280 AND + ModelConstants.RELATION_TO_TYPE_PROPERTY + " = ? " +
  281 + AND + ModelConstants.RELATION_TYPE_GROUP_PROPERTY + " = ? " +
233 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? "); 282 AND + ModelConstants.RELATION_TYPE_PROPERTY + " = ? ");
234 } 283 }
235 return checkRelationStmt; 284 return checkRelationStmt;
236 } 285 }
237 286
238 - private EntityRelation getEntityRelation(Row row) {  
239 - EntityRelation relation = new EntityRelation();  
240 - relation.setType(row.getString(ModelConstants.RELATION_TYPE_PROPERTY));  
241 - relation.setAdditionalInfo(row.get(ModelConstants.ADDITIONAL_INFO_PROPERTY, JsonNode.class));  
242 - relation.setFrom(toEntity(row, ModelConstants.RELATION_FROM_ID_PROPERTY, ModelConstants.RELATION_FROM_TYPE_PROPERTY));  
243 - relation.setTo(toEntity(row, ModelConstants.RELATION_TO_ID_PROPERTY, ModelConstants.RELATION_TO_TYPE_PROPERTY));  
244 - return relation;  
245 - }  
246 -  
247 private EntityId toEntity(Row row, String uuidColumn, String typeColumn) { 287 private EntityId toEntity(Row row, String uuidColumn, String typeColumn) {
248 return EntityIdFactory.getByTypeAndUuid(row.getString(typeColumn), row.getUUID(uuidColumn)); 288 return EntityIdFactory.getByTypeAndUuid(row.getString(typeColumn), row.getUUID(uuidColumn));
249 } 289 }
250 290
251 private ListenableFuture<List<EntityRelation>> executeAsyncRead(EntityId from, BoundStatement stmt) { 291 private ListenableFuture<List<EntityRelation>> executeAsyncRead(EntityId from, BoundStatement stmt) {
252 log.debug("Generated query [{}] for entity {}", stmt, from); 292 log.debug("Generated query [{}] for entity {}", stmt, from);
253 - return getFuture(executeAsyncRead(stmt), rs -> {  
254 - List<Row> rows = rs.all();  
255 - List<EntityRelation> entries = new ArrayList<>(rows.size());  
256 - if (!rows.isEmpty()) {  
257 - rows.forEach(row -> {  
258 - entries.add(getEntityRelation(row));  
259 - });  
260 - }  
261 - return entries;  
262 - }); 293 + return getFuture(executeAsyncRead(stmt), rs -> getEntityRelations(rs));
263 } 294 }
264 295
265 private ListenableFuture<Boolean> getBooleanListenableFuture(ResultSetFuture rsFuture) { 296 private ListenableFuture<Boolean> getBooleanListenableFuture(ResultSetFuture rsFuture) {
@@ -276,4 +307,25 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { @@ -276,4 +307,25 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao {
276 }, readResultsProcessingExecutor); 307 }, readResultsProcessingExecutor);
277 } 308 }
278 309
  310 + private List<EntityRelation> getEntityRelations(ResultSet rs) {
  311 + List<Row> rows = rs.all();
  312 + List<EntityRelation> entries = new ArrayList<>(rows.size());
  313 + if (!rows.isEmpty()) {
  314 + rows.forEach(row -> {
  315 + entries.add(getEntityRelation(row));
  316 + });
  317 + }
  318 + return entries;
  319 + }
  320 +
  321 + private EntityRelation getEntityRelation(Row row) {
  322 + EntityRelation relation = new EntityRelation();
  323 + relation.setTypeGroup(row.get(ModelConstants.RELATION_TYPE_GROUP_PROPERTY, relationTypeGroupCodec));
  324 + relation.setType(row.getString(ModelConstants.RELATION_TYPE_PROPERTY));
  325 + relation.setAdditionalInfo(row.get(ModelConstants.ADDITIONAL_INFO_PROPERTY, JsonNode.class));
  326 + relation.setFrom(toEntity(row, ModelConstants.RELATION_FROM_ID_PROPERTY, ModelConstants.RELATION_FROM_TYPE_PROPERTY));
  327 + relation.setTo(toEntity(row, ModelConstants.RELATION_TO_ID_PROPERTY, ModelConstants.RELATION_TO_TYPE_PROPERTY));
  328 + return relation;
  329 + }
  330 +
279 } 331 }